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:
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user