chore(sim): refresh deployment status, pool matrix, schemas, and scenario scripts

- deployment-status and pool-matrix snapshots aligned with validate-deployment-status.cjs.
- Micro-trade / scorecard docs and run-scenario wiring.

Made-with: Cursor
This commit is contained in:
defiQUG
2026-04-07 22:56:16 -07:00
parent f7f3e3b020
commit 168dba25d9
13 changed files with 2051 additions and 84 deletions

View File

@@ -355,6 +355,173 @@ function getBridgeRho(scenario, fromChain, toChain) {
return (blocks ?? 10) * rhoPerBlock / 10000;
}
function getMatchedQuoteForBase(base) {
if (base === 'cWUSDT') return 'USDT';
if (base === 'cWUSDC') return 'USDC';
return null;
}
function getMicroTradeCandidates(graph, policy) {
const tokenFilter = new Set(policy.tokens || []);
const quoteFilter = new Set(policy.quoteTokens || []);
let candidates = graph.pmmEdges.filter((e) => {
if (tokenFilter.size > 0 && !tokenFilter.has(e.base)) return false;
if (quoteFilter.size > 0 && !quoteFilter.has(e.quote)) return false;
return true;
});
if (policy.preferMatchedQuote) {
const perChainBase = new Map();
for (const edge of candidates) {
const key = `${edge.chainId}:${edge.base}`;
const preferredQuote = getMatchedQuoteForBase(edge.base);
const existing = perChainBase.get(key);
if (!existing) {
perChainBase.set(key, edge);
continue;
}
const score = edge.quote === preferredQuote ? 0 : 1;
const existingScore = existing.quote === preferredQuote ? 0 : 1;
if (
score < existingScore
|| (score === existingScore && edge.quote.localeCompare(existing.quote) < 0)
) {
perChainBase.set(key, edge);
}
}
candidates = Array.from(perChainBase.values());
}
candidates.sort((a, b) => (
a.chainId.localeCompare(b.chainId)
|| a.base.localeCompare(b.base)
|| a.quote.localeCompare(b.quote)
));
return candidates;
}
function resolveMicroTradeDirection(policy, poolState, epochIndex, tradeIndex) {
const mode = policy.mode || 'inventory_or_alternate';
const bandFrac = Number(policy.inventoryBandFraction ?? 0.05);
const lower = (1 - bandFrac) * poolState.I_T_star;
const upper = (1 + bandFrac) * poolState.I_T_star;
if (mode === 'inventory' || mode === 'inventory_or_alternate') {
if (poolState.I_T < lower) return 'sell_base';
if (poolState.I_T > upper) return 'buy_base';
if (mode === 'inventory') return null;
}
if (mode === 'alternate' || mode === 'inventory_or_alternate') {
return ((epochIndex + tradeIndex) % 2 === 0) ? 'buy_base' : 'sell_base';
}
if (mode === 'buy_base') return 'buy_base';
if (mode === 'sell_base') return 'sell_base';
return null;
}
function runMicroTradeSupportStep(graph, state, scenario, epochIndex) {
const policy = scenario.microTradePolicy || {};
if (policy.enabled === false || Object.keys(policy).length === 0) {
return {
state,
microTradeCount: 0,
microTradeBuyCount: 0,
microTradeSellCount: 0,
microTradeVolumeTotal: 0,
microTradeGasCostTotal: 0,
};
}
const requestedTrades = Math.max(0, parseInt(policy.tradesPerEpoch ?? 0, 10));
if (requestedTrades === 0) {
return {
state,
microTradeCount: 0,
microTradeBuyCount: 0,
microTradeSellCount: 0,
microTradeVolumeTotal: 0,
microTradeGasCostTotal: 0,
};
}
const candidates = getMicroTradeCandidates(graph, policy);
if (candidates.length === 0) {
return {
state,
microTradeCount: 0,
microTradeBuyCount: 0,
microTradeSellCount: 0,
microTradeVolumeTotal: 0,
microTradeGasCostTotal: 0,
};
}
const gasCostPerTrade = Number(policy.gasCostPerTradeUnits ?? 0);
const gasBudgetPerEpoch = Number(policy.gasBudgetPerEpochUnits ?? 0);
let tradesAllowed = requestedTrades;
if (gasCostPerTrade > 0 && gasBudgetPerEpoch > 0) {
tradesAllowed = Math.min(tradesAllowed, Math.floor(gasBudgetPerEpoch / gasCostPerTrade));
}
if (tradesAllowed <= 0) {
return {
state,
microTradeCount: 0,
microTradeBuyCount: 0,
microTradeSellCount: 0,
microTradeVolumeTotal: 0,
microTradeGasCostTotal: 0,
};
}
let curState = state;
let microTradeCount = 0;
let microTradeBuyCount = 0;
let microTradeSellCount = 0;
let microTradeVolumeTotal = 0;
let microTradeGasCostTotal = 0;
for (let i = 0; i < tradesAllowed; i++) {
const edge = candidates[(epochIndex * tradesAllowed + i) % candidates.length];
const poolState = curState[edge.key];
if (!poolState || poolState.I_T_star == null) continue;
const rawTradeSize = Number(policy.tradeSizeUnits ?? 0);
const maxFractionOfTarget = Number(policy.maxFractionOfTarget ?? 0.01);
const maxTradeSize = maxFractionOfTarget > 0 ? poolState.I_T_star * maxFractionOfTarget : rawTradeSize;
const tradeSize = Math.max(0, Math.min(rawTradeSize, maxTradeSize || rawTradeSize));
if (tradeSize <= 0) continue;
const direction = resolveMicroTradeDirection(policy, poolState, epochIndex, i);
if (!direction) continue;
if (direction === 'sell_base') {
const { newState } = pmmSellT(edge.key, tradeSize, curState);
curState = newState;
microTradeSellCount += 1;
microTradeVolumeTotal += tradeSize;
} else {
const quoteSpend = tradeSize * (poolState.P || 1);
const { outputT, newState } = pmmBuyT(edge.key, quoteSpend, curState);
curState = newState;
microTradeBuyCount += 1;
microTradeVolumeTotal += outputT;
}
microTradeCount += 1;
microTradeGasCostTotal += gasCostPerTrade;
}
return {
state: curState,
microTradeCount,
microTradeBuyCount,
microTradeSellCount,
microTradeVolumeTotal,
microTradeGasCostTotal,
};
}
function runBotStep(graph, state, scenario, configs) {
const chains = graph.chains;
let curState = state;
@@ -625,6 +792,11 @@ function runEpoch(scenario, graph, state, configs, epochIndex) {
let pmmVolume = 0;
let churnSum = 0;
const I_T_start = {};
let microTradeCount = 0;
let microTradeBuyCount = 0;
let microTradeSellCount = 0;
let microTradeVolumeTotal = 0;
let microTradeGasCostTotal = 0;
for (const k of Object.keys(state)) {
if (state[k].I_T_star != null) I_T_start[k] = state[k].I_T;
@@ -682,6 +854,15 @@ function runEpoch(scenario, graph, state, configs, epochIndex) {
}
}
const micro = runMicroTradeSupportStep(graph, curState, scenario, epochIndex);
curState = micro.state;
microTradeCount += micro.microTradeCount || 0;
microTradeBuyCount += micro.microTradeBuyCount || 0;
microTradeSellCount += micro.microTradeSellCount || 0;
microTradeVolumeTotal += micro.microTradeVolumeTotal || 0;
microTradeGasCostTotal += micro.microTradeGasCostTotal || 0;
totalVolume += micro.microTradeVolumeTotal || 0;
const peakDeviationBpsPreArb = maxDeviationBpsOverPools(graph, curState);
const worstPreArb = getWorstPoolDiagnostic(graph, curState);
const { state: afterArb, arbVolumeTotal, arbProfitTotal, peakDeviationBps: peakDeviationBpsPostArb } = runArbStep(graph, curState, configs);
@@ -717,6 +898,11 @@ function runEpoch(scenario, graph, state, configs, epochIndex) {
interventionCostInject: interventionCostInject || 0,
interventionCostWithdraw: interventionCostWithdraw || 0,
interventionCostByChain: interventionCostByChain || {},
microTradeCount,
microTradeBuyCount,
microTradeSellCount,
microTradeVolumeTotal,
microTradeGasCostTotal,
peakDeviationBpsPreArb: peakDeviationBpsPreArb || 0,
peakDeviationBpsPostArb: peakDeviationBpsPostArb || 0,
peakDeviationBpsPostBot: peakDeviationBpsPostBot || 0,
@@ -753,6 +939,11 @@ function computeScorecard(scenario, scenarioName, graph, initialState, epochResu
let peakDeviationBpsPreArb = 0;
let peakDeviationBpsPostArb = 0;
let peakDeviationBpsPostBot = 0;
let microTradeCountTotal = 0;
let microTradeBuyCountTotal = 0;
let microTradeSellCountTotal = 0;
let microTradeVolumeTotal = 0;
let microTradeGasCostTotal = 0;
for (const r of epochResults) {
totalVolume += r.totalVolume;
@@ -763,6 +954,11 @@ function computeScorecard(scenario, scenarioName, graph, initialState, epochResu
arbProfitTotal += r.arbProfitTotal || 0;
interventionCostInjectTotal += r.interventionCostInject || 0;
interventionCostWithdrawTotal += r.interventionCostWithdraw || 0;
microTradeCountTotal += r.microTradeCount || 0;
microTradeBuyCountTotal += r.microTradeBuyCount || 0;
microTradeSellCountTotal += r.microTradeSellCount || 0;
microTradeVolumeTotal += r.microTradeVolumeTotal || 0;
microTradeGasCostTotal += r.microTradeGasCostTotal || 0;
for (const [chainId, v] of Object.entries(r.interventionCostByChain || {})) {
if (!interventionCostByChain[chainId]) interventionCostByChain[chainId] = { inject: 0, withdraw: 0 };
interventionCostByChain[chainId].inject += v.inject || 0;
@@ -838,6 +1034,11 @@ function computeScorecard(scenario, scenarioName, graph, initialState, epochResu
intervention_cost_withdraw_total: Math.round(interventionCostWithdrawTotal),
intervention_cost_by_chain: interventionCostByChain,
intervention_cost_per_1M_volume: Math.round(interventionPer1M * 100) / 100,
micro_trade_count: Math.round(microTradeCountTotal),
micro_trade_buy_count: Math.round(microTradeBuyCountTotal),
micro_trade_sell_count: Math.round(microTradeSellCountTotal),
micro_trade_volume_total: Math.round(microTradeVolumeTotal),
micro_trade_gas_cost_total: Math.round(microTradeGasCostTotal * 100) / 100,
peak_deviation_bps: Math.round(Number.isFinite(peakDeviationBpsPostArb) ? peakDeviationBpsPostArb : 0),
peak_deviation_bps_pre_arb: Math.round(peakDeviationBpsPreArb),
peak_deviation_bps_post_arb: Math.round(peakDeviationBpsPostArb),