#!/usr/bin/env node /** * PMM / reserve-style flash-loan "push trade": slippage, VWAP, PnL, break-even external price, * and quote-seeding / liquidity-loop planning. * * Matches the quote-in → base-out fallback used in DODOPMMProvider._fallbackReserveQuote: * amountOut = (netAmountIn * baseReserve) / (quoteReserve + netAmountIn) * (see smom-dbis-138/contracts/liquidity/providers/DODOPMMProvider.sol) * * Not a full DODO PMM (i, k, oracle) simulation — use pool querySellQuote on-chain for production. * Amounts: use consistent token base units (e.g. USDC 6 decimals, so 1 USDC = 1_000_000 raw units). * JS Number is safe below ~9e15. * * ----------------------------------------------------------------------------- * Ethereum Mainnet — live cWUSDC / USDC PMM (repo registry) * ----------------------------------------------------------------------------- * "xWUSDC" in ops shorthand = **cWUSDC** (compliant wrapped USDC on public mesh). * Canonical addresses + pool row: cross-chain-pmm-lps/config/deployment-status.json (chain "1"). * * **Funded loop (not necessarily Aave flash):** USDC working capital x funds: * (1) USDC → ETH on Uniswap (or other deep venue) — fees + slippage → factor f_eth * (2) ETH → cWUSDC — often extra hop if no WETH/cWUSDC book; fold into composite acquisition cost * (3) cWUSDC → USDC on DODO PMM — **sell base** leg: * quoteOut = (netBaseIn * Q) / (B + netBaseIn) [sellBase branch] * Model the first two legs as a single **effective USDC per cWUSDC** you need before the PMM exit, * or run this script on the PMM leg only with -B/-Q from getVaultReserve(). * * **Deepening the pool with cWUSDC:** increases base reserve B. For **USDC → cWUSDC** (quote in), * larger B → **more** Δy and **lower** VWAP for the same x (tighter book for buyers). For **cWUSDC → USDC** * (base in), larger B → **less** USDC per unit base for a large sell (pool absorbs more base without * draining quote). Size both sides for balanced inventory if you route flow in both directions. * * ----------------------------------------------------------------------------- * Baseline recalc (vs liquidity-ratio heuristic) * ----------------------------------------------------------------------------- * Reserves B = Q = 10e6 (10M each side). Gross quote in x = 10e6. * * Zero LP fee: * Δy = B * x / (Q + x) = 10M * 10M / 20M = 5M base out * VWAP = x / Δy = 2.00 quote per base (not ~1.25 from impact/2 linearization) * * With DEFAULT_LP_FEE = 3 bps (netIn = x * 9997/10000): * Δy slightly below 5M; VWAP slightly above 2.00 * * x = 2e6 quote in, B = Q = 10e6, no LP fee: * Δy = 2 * 10 / 12 M ≈ 1.667M, VWAP ≈ 1.20 (not ~1.083) * * ----------------------------------------------------------------------------- * Break-even (plug-in) * ----------------------------------------------------------------------------- * Let x = gross quote swapped in, f_lp = LP fee on pool input (fraction of x), * Δx_net = x * (1 - f_lp) [same as contract: netAmountIn] * Δy = B * Δx_net / (Q + Δx_net) * Flash fee f_flash on repayment: repay = x * (1 + f_flash) * Effective external proceeds: model exit DEX fee / impact as P_eff = P_ext * (1 - f_exit) * * Π = P_eff * Δy - x * (1 + f_flash) * * Break-even spot P_ext (given exit fee on sell proceeds): * P_ext* = x * (1 + f_flash) / (Δy * (1 - f_exit)) * * Fold routing into one number: set --external-price to your net USDC per base after all exits. * * Usage: * node scripts/analytics/pmm-flash-push-break-even.mjs --examples * node scripts/analytics/pmm-flash-push-break-even.mjs -B 10000000 -Q 10000000 -x 10000000 \ * --lp-fee-bps 3 --flash-fee-bps 5 --external-price 1.0 * node scripts/analytics/pmm-flash-push-break-even.mjs -B 10e6 -Q 10e6 --scan 1e6,2e6,5e6,10e6 \ * --lp-fee-bps 3 --flash-fee-bps 5 * node scripts/analytics/pmm-flash-push-break-even.mjs --mainnet-map * node scripts/analytics/pmm-flash-push-break-even.mjs --mainnet-map --compare-deepen 5e6 \ * -B 2000000 -Q 2000000 --scan 500000,1000000,2000000 --flash-fee-bps 0 * node scripts/analytics/pmm-flash-push-break-even.mjs -B 4000000 -Q 12000000 \ * --seed-pools 6 --target-quote-per-pool 500000000000 --lp-fee-bps 10 --inventory-base 8000000 * node scripts/analytics/pmm-flash-push-break-even.mjs --external-price 0.992 \ * --seed-pools 6 --target-quote-per-pool 500000000000 --exit-fee-bps 20 --inventory-base 4000000 * node scripts/analytics/pmm-flash-push-break-even.mjs -B 4854640 -Q 4854839 \ * --inventory-loop-scan --scan 50000,100000,150000,200000,250000 --lp-fee-bps 10 \ * --flash-fee-bps 5 --min-retained-usdc 10000 * node scripts/analytics/pmm-flash-push-break-even.mjs -B 4854640 -Q 4854839 \ * --inventory-loop-rank --scan 50000,100000,150000,200000,250000 --lp-fee-bps 10 \ * --flash-fee-bps 5 --min-retained-usdc 10000 --target-flash-borrow 90000 * node scripts/analytics/pmm-flash-push-break-even.mjs -B 4854640 -Q 4854839 \ * --inventory-loop-rank --scan 50000,100000,150000 --lp-fee-bps 10 --flash-fee-bps 5 \ * --min-retained-usdc 10000 --inventory-base 1000000 --gas-tx-count 3 --gas-per-tx 250000 \ * --max-fee-gwei 40 --native-token-price 3200 --max-post-trade-deviation-bps 250 \ * --max-cw-burn-fraction 0.1 --cooldown-blocks 12 --rank-profile conservative * node scripts/analytics/pmm-flash-push-break-even.mjs -B 4854640 -Q 4854839 \ * --inventory-loop-rank --scan 100000,250000,500000 --lp-fee-bps 10 --flash-fee-bps 5 \ * --target-flash-borrow 1000000 --flash-add-to-pool * node scripts/analytics/pmm-flash-push-break-even.mjs -B 4854640 -Q 4854839 -x 1000000 \ * --full-loop-dry-run --external-price 1.01 --flash-fee-bps 5 --lp-fee-bps 10 \ * --seed-pools 3 --target-quote-per-pool 250000 --gas-tx-count 3 --gas-per-tx 250000 \ * --max-fee-gwei 40 --native-token-price 3200 --max-post-trade-deviation-bps 500 * node scripts/analytics/pmm-flash-push-break-even.mjs -B 4854640 -Q 4854839 -x 1000000 \ * --full-loop-dry-run --owned-base-add 500000 --external-exit-price 1.12 --flash-fee-bps 5 \ * --lp-fee-bps 10 --base-asset cWUSDC --quote-asset USDC * node scripts/analytics/pmm-flash-push-break-even.mjs --public-live-sweep --loop-strategy both \ * --external-exit-price 1.12 --external-entry-price 0.74 --external-via-asset ETH \ * --gas-tx-count 3 --gas-per-tx 250000 --max-fee-gwei 40 --native-token-price 3200 \ * --max-post-trade-deviation-bps 500 * node scripts/analytics/pmm-flash-push-break-even.mjs --sequential-matched-loops 100 \ * -B 256763253 -Q 256763253 --loop-strategy quote-push \ * --base-asset cWUSDC --quote-decimals 6 --quote-asset USDC \ * --external-exit-price 1.12 --lp-fee-bps 3 --flash-fee-bps 5 \ * --gas-tx-count 3 --gas-per-tx 185000 --max-fee-gwei 60 --native-token-price 3200 \ * --max-post-trade-deviation-bps 500 --oracle-price 1 --flash-provider-cap 1000000000000 */ import { parseArgs } from 'node:util' import { readFileSync, existsSync, readdirSync } from 'node:fs' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { execFileSync } from 'node:child_process' const __dirname = dirname(fileURLToPath(import.meta.url)) const REPO_ROOT = resolve(__dirname, '../..') const DEPLOYMENT_STATUS = resolve(REPO_ROOT, 'cross-chain-pmm-lps/config/deployment-status.json') const SMART_CONTRACTS_MASTER = resolve(REPO_ROOT, 'config/smart-contracts-master.json') const DEPLOYER_TOKEN_AUDIT_DIR = resolve(REPO_ROOT, 'reports/deployer-token-audit') const DEFAULT_MAINNET_BALANCER_VAULT = process.env.MAINNET_BALANCER_VAULT ?? '0xBA12222222228d8Ba445958a75a0704d566BF2C8' const DEFAULT_MAINNET_AAVE_V3_POOL = process.env.MAINNET_AAVE_V3_POOL ?? '0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2' const DEFAULT_MAINNET_AAVE_V3_PROVIDER = process.env.MAINNET_AAVE_V3_POOL_ADDRESSES_PROVIDER ?? '0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e' function netQuoteIn(grossX, lpFeeBps) { const bps = Math.min(10000, Math.max(0, lpFeeBps)) return (grossX * (10000 - bps)) / 10000 } function grossInputForNet(netIn, lpFeeBps) { const bps = Math.min(10000, Math.max(0, lpFeeBps)) const mult = (10000 - bps) / 10000 if (mult <= 0) return Infinity return netIn / mult } /** Quote in → base out (same branch as sellBase === false in DODOPMMProvider) */ function quoteInToBaseOut(baseReserve, quoteReserve, grossQuoteIn, lpFeeBps) { if (baseReserve <= 0 || quoteReserve <= 0 || grossQuoteIn <= 0) { return { deltaXNet: 0, baseOut: 0, vwap: NaN } } const deltaXNet = netQuoteIn(grossQuoteIn, lpFeeBps) if (deltaXNet <= 0) return { deltaXNet: 0, baseOut: 0, vwap: NaN } const baseOut = (deltaXNet * baseReserve) / (quoteReserve + deltaXNet) const vwap = grossQuoteIn / baseOut return { deltaXNet, baseOut, vwap } } /** Base in → quote out (sellBase branch in DODOPMMProvider) */ function baseInToQuoteOut(baseReserve, quoteReserve, grossBaseIn, lpFeeBps) { if (baseReserve <= 0 || quoteReserve <= 0 || grossBaseIn <= 0) { return { deltaBaseNet: 0, quoteOut: 0, vwapQuotePerBase: NaN } } const deltaBaseNet = netQuoteIn(grossBaseIn, lpFeeBps) if (deltaBaseNet <= 0) return { deltaBaseNet: 0, quoteOut: 0, vwapQuotePerBase: NaN } const quoteOut = (deltaBaseNet * quoteReserve) / (baseReserve + deltaBaseNet) const vwapQuotePerBase = quoteOut / grossBaseIn return { deltaBaseNet, quoteOut, vwapQuotePerBase } } /** Inverse of sell-base branch: required base in to harvest a target quote amount */ function baseInRequiredForQuoteOut(baseReserve, quoteReserve, targetQuoteOut, lpFeeBps) { if (baseReserve <= 0 || quoteReserve <= 0 || targetQuoteOut <= 0) { return { feasible: false, deltaBaseNet: 0, grossBaseIn: 0, feeBase: 0, vwapQuotePerBase: NaN, } } if (targetQuoteOut >= quoteReserve) { return { feasible: false, deltaBaseNet: Infinity, grossBaseIn: Infinity, feeBase: Infinity, vwapQuotePerBase: 0, } } const deltaBaseNet = (targetQuoteOut * baseReserve) / (quoteReserve - targetQuoteOut) const grossBaseIn = grossInputForNet(deltaBaseNet, lpFeeBps) const feeBase = grossBaseIn - deltaBaseNet const vwapQuotePerBase = targetQuoteOut / grossBaseIn return { feasible: true, deltaBaseNet, grossBaseIn, feeBase, vwapQuotePerBase } } function loadMainnetCwUsdcUsdc() { if (!existsSync(DEPLOYMENT_STATUS)) return null const raw = JSON.parse(readFileSync(DEPLOYMENT_STATUS, 'utf8')) const chain = raw.chains?.['1'] if (!chain?.pmmPools || !chain.cwTokens) return null const row = chain.pmmPools.find((p) => p.base === 'cWUSDC' && p.quote === 'USDC') if (!row) return null const cWUSDC = chain.cwTokens.cWUSDC const USDC = chain.anchorAddresses?.USDC return { row, cWUSDC, USDC, feeBps: row.feeBps ?? 10, poolAddress: row.poolAddress } } function loadMainnetPool(base, quote) { if (!existsSync(DEPLOYMENT_STATUS)) return null const raw = JSON.parse(readFileSync(DEPLOYMENT_STATUS, 'utf8')) const chain = raw.chains?.['1'] if (!chain?.pmmPools) return null const row = chain.pmmPools.find((p) => p.base === base && p.quote === quote) if (!row) return null return { row, chain, baseAddress: chain.cwTokens?.[base] ?? chain.anchorAddresses?.[base] ?? null, quoteAddress: chain.anchorAddresses?.[quote] ?? chain.cwTokens?.[quote] ?? null, feeBps: row.feeBps ?? 10, poolAddress: row.poolAddress, } } function loadLiveMainnetPublicUsdPools() { if (!existsSync(DEPLOYMENT_STATUS)) return [] const raw = JSON.parse(readFileSync(DEPLOYMENT_STATUS, 'utf8')) const chain = raw.chains?.['1'] if (!chain?.pmmPools) return [] return chain.pmmPools .filter( (row) => ['cWUSDT', 'cWUSDC'].includes(row.base) && ['USDC', 'USDT'].includes(row.quote) && row.poolAddress, ) .map((row) => ({ ...row, baseAddress: chain.cwTokens?.[row.base] ?? null, quoteAddress: chain.anchorAddresses?.[row.quote] ?? null, feeBps: row.feeBps ?? 10, })) } function loadChain138TokenAddress(symbol) { if (!existsSync(SMART_CONTRACTS_MASTER)) return null const raw = JSON.parse(readFileSync(SMART_CONTRACTS_MASTER, 'utf8')) return raw.chains?.['138']?.contracts?.[symbol] ?? null } function inferSourceAsset(inventoryAsset) { const match = /^cW(.+)$/.exec(inventoryAsset) return match ? `c${match[1]}` : inventoryAsset } function latestBalanceReportPath() { if (!existsSync(DEPLOYER_TOKEN_AUDIT_DIR)) return null const entries = readdirSync(DEPLOYER_TOKEN_AUDIT_DIR) .filter((name) => /^deployer-token-balances-.*\.json$/.test(name)) .sort() if (entries.length === 0) return null return resolve(DEPLOYER_TOKEN_AUDIT_DIR, entries[entries.length - 1]) } function loadBalanceReport(reportPath) { if (!reportPath || !existsSync(reportPath)) return null return JSON.parse(readFileSync(reportPath, 'utf8')) } function sumReportBalance(report, chainId, symbol) { if (!report?.balances) return null let total = 0 let matched = false for (const row of report.balances) { if ( row?.chain_id === chainId && row?.token_symbol === symbol && row?.query_status === 'ok' && row?.balance_raw != null && row?.decimals != null ) { total += Number(row.balance_raw) / 10 ** Number(row.decimals) matched = true } } return matched ? total : null } function sumReportBalanceInfo(report, chainId, symbol) { if (!report?.balances) return null let totalRaw = 0 let decimals = null let matched = false for (const row of report.balances) { if ( row?.chain_id === chainId && row?.token_symbol === symbol && row?.query_status === 'ok' && row?.balance_raw != null && row?.decimals != null ) { const rowDecimals = Number(row.decimals) if (!Number.isFinite(rowDecimals)) continue if (decimals == null) decimals = rowDecimals if (decimals !== rowDecimals) return null totalRaw += Number(row.balance_raw) matched = true } } if (!matched || decimals == null) return null return { balance: totalRaw / 10 ** decimals, raw: totalRaw, decimals, } } function rpcUrlForChain(chainId) { switch (chainId) { case 1: return process.env.ETHEREUM_MAINNET_RPC ?? process.env.ETH_MAINNET_RPC ?? null case 138: return process.env.CHAIN138_RPC_URL ?? process.env.RPC_URL_138 ?? null default: return null } } function tryReadTokenDecimalsViaCast(chainId, tokenAddress) { const rpcUrl = rpcUrlForChain(chainId) if (!rpcUrl || !tokenAddress) return null try { const raw = execFileSync( 'cast', ['call', tokenAddress, 'decimals()(uint8)', '--rpc-url', rpcUrl], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) const decimals = Number(parseCastScalar(raw)) return Number.isFinite(decimals) ? decimals : null } catch { return null } } function parseCastScalar(raw) { if (!raw) return null const token = String(raw).trim().split(/\s+/)[0] if (token === '') return null return token } function extractNthAddress(raw, index) { if (!raw || !(index > 0)) return null const matches = String(raw).match(/0x[a-fA-F0-9]{40}/g) ?? [] return matches[index - 1] ?? null } function tryCastCallRaw(address, signature, args, rpcUrl) { if (!address || !signature || !rpcUrl) return null try { return execFileSync( 'cast', ['call', address, signature, ...args.map(String), '--rpc-url', rpcUrl], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ).trim() } catch { return null } } function tryReadCastCode(address, rpcUrl) { if (!address || !rpcUrl) return null try { return execFileSync('cast', ['code', address, '--rpc-url', rpcUrl], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], }).trim() } catch { return null } } function tryReadTokenRawBalanceViaCast(rpcUrl, tokenAddress, walletAddress) { if (!rpcUrl || !tokenAddress || !walletAddress) return null const raw = tryCastCallRaw(tokenAddress, 'balanceOf(address)(uint256)', [walletAddress], rpcUrl) const scalar = raw != null ? Number(parseCastScalar(raw)) : NaN return Number.isFinite(scalar) ? scalar : null } function resolveDeployerAddressViaCast() { if (!process.env.PRIVATE_KEY) return null try { return execFileSync('cast', ['wallet', 'address', '--private-key', process.env.PRIVATE_KEY], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], }).trim() } catch { return null } } function tryReadPoolReservesViaCast(chainId, poolAddress) { const rpcUrl = rpcUrlForChain(chainId) if (!rpcUrl || !poolAddress) return null try { const out = execFileSync( 'cast', ['call', poolAddress, 'getVaultReserve()(uint256,uint256)', '--rpc-url', rpcUrl], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) .trim() .split(/\r?\n/) .map((line) => parseCastScalar(line)) .filter(Boolean) if (out.length < 2) return null return { baseReserve: Number(out[0]), quoteReserve: Number(out[1]), source: `live cast via chain ${chainId} RPC`, } } catch { return null } } function tryReadTokenBalanceViaCast(chainId, tokenAddress, walletAddress) { const rpcUrl = rpcUrlForChain(chainId) if (!rpcUrl || !tokenAddress || !walletAddress) return null try { const decimalsRaw = execFileSync( 'cast', ['call', tokenAddress, 'decimals()(uint8)', '--rpc-url', rpcUrl], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) const balanceRaw = execFileSync( 'cast', ['call', tokenAddress, 'balanceOf(address)(uint256)', walletAddress, '--rpc-url', rpcUrl], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) const decimals = Number(parseCastScalar(decimalsRaw)) const raw = Number(parseCastScalar(balanceRaw)) if (!Number.isFinite(decimals) || !Number.isFinite(raw)) return null return { balance: raw / 10 ** decimals, decimals, raw, source: `live cast via chain ${chainId} RPC`, } } catch { return null } } function tryReadPoolFeeBpsViaCast(chainId, poolAddress) { const rpcUrl = rpcUrlForChain(chainId) if (!rpcUrl || !poolAddress) return null try { const raw = execFileSync( 'cast', ['call', poolAddress, '_LP_FEE_RATE_()(uint256)', '--rpc-url', rpcUrl], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) const feeBps = Number(parseCastScalar(raw)) return Number.isFinite(feeBps) ? feeBps : null } catch { return null } } function tryProbePoolQuoteSurfaceViaCast(chainId, poolAddress, traderAddress, probeAmount = 1_000_000) { const rpcUrl = rpcUrlForChain(chainId) if (!rpcUrl || !poolAddress || !traderAddress || !(probeAmount > 0)) return null const baseToken = tryCastCallRaw(poolAddress, '_BASE_TOKEN_()(address)', [], rpcUrl) const quoteToken = tryCastCallRaw(poolAddress, '_QUOTE_TOKEN_()(address)', [], rpcUrl) const midPrice = tryCastCallRaw(poolAddress, 'getMidPrice()(uint256)', [], rpcUrl) let sellBaseOk = false let sellQuoteOk = false let integrationSellBaseOk = false let integrationSellQuoteOk = false try { execFileSync( 'cast', [ 'call', poolAddress, 'querySellBase(address,uint256)(uint256,uint256)', traderAddress, String(probeAmount), '--rpc-url', rpcUrl, ], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) sellBaseOk = true } catch {} try { execFileSync( 'cast', [ 'call', poolAddress, 'querySellQuote(address,uint256)(uint256,uint256)', traderAddress, String(probeAmount), '--rpc-url', rpcUrl, ], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) sellQuoteOk = true } catch {} if (chainId === 1 && baseToken && quoteToken) { const integrationAddress = process.env.DODO_PMM_INTEGRATION_MAINNET ?? null if (integrationAddress) { try { execFileSync( 'cast', [ 'call', integrationAddress, 'swapExactIn(address,address,uint256,uint256)(uint256)', poolAddress, String(parseCastScalar(quoteToken)), String(probeAmount), '1', '--from', traderAddress, '--rpc-url', rpcUrl, ], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) integrationSellQuoteOk = true } catch {} try { execFileSync( 'cast', [ 'call', integrationAddress, 'swapExactIn(address,address,uint256,uint256)(uint256)', poolAddress, String(parseCastScalar(baseToken)), String(probeAmount), '1', '--from', traderAddress, '--rpc-url', rpcUrl, ], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) integrationSellBaseOk = true } catch {} } } const hasReserveSurface = tryReadPoolReservesViaCast(chainId, poolAddress) != null const hasMidPriceSurface = midPrice != null const quotePushOk = sellQuoteOk || integrationSellQuoteOk const baseUnwindOk = sellBaseOk || integrationSellBaseOk let surface = 'unknown' if (quotePushOk && baseUnwindOk) { surface = 'full_quote_surface' } else if (quotePushOk || baseUnwindOk) { surface = 'strategy_specific_quote_surface' } else if (hasReserveSurface && hasMidPriceSurface) { surface = 'partial_dodo_surface_integration_only' } else if (hasReserveSurface) { surface = 'reserve_only' } return { surface, sellBaseOk, sellQuoteOk, integrationSellBaseOk, integrationSellQuoteOk, quotePushOk, baseUnwindOk, hasReserveSurface, hasMidPriceSurface, baseToken: baseToken ? String(parseCastScalar(baseToken)) : null, quoteToken: quoteToken ? String(parseCastScalar(quoteToken)) : null, source: `live pool probe via chain ${chainId} RPC`, } } function extractFirstNumericToken(raw) { if (!raw) return null const match = String(raw).match(/-?\d+(?:\.\d+)?(?:e[+-]?\d+)?/i) if (!match) return null const value = Number(match[0]) return Number.isFinite(value) ? value : null } function tryReadNumericCommand(command, sourceLabel) { if (!command) return null try { const raw = execFileSync('bash', ['-lc', command], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], }).trim() const value = extractFirstNumericToken(raw) if (!(value > 0)) return null return { value, source: sourceLabel ?? `live command: ${command}`, raw, } } catch { return null } } function tryEstimateIntegrationSwapGasViaCast({ integrationAddress, poolAddress, tokenIn, amountIn, minOut, fromAddress, rpcUrl, }) { if (!integrationAddress || !poolAddress || !tokenIn || !fromAddress || !rpcUrl || !(amountIn > 0)) { return null } try { const raw = execFileSync( 'cast', [ 'estimate', '--from', fromAddress, integrationAddress, 'swapExactIn(address,address,uint256,uint256)(uint256)', poolAddress, tokenIn, String(amountIn), String(Math.max(1, minOut ?? 1)), '--rpc-url', rpcUrl, ], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) const gasUnits = Number(parseCastScalar(raw)) return Number.isFinite(gasUnits) ? gasUnits : null } catch { return null } } function tryProbeErc3156FlashProvider(providerAddress, tokenAddress, amount, rpcUrl) { if (!providerAddress || !tokenAddress || !(amount >= 0) || !rpcUrl) return null try { const maxLoanRaw = execFileSync( 'cast', ['call', providerAddress, 'maxFlashLoan(address)(uint256)', tokenAddress, '--rpc-url', rpcUrl], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) const feeRaw = execFileSync( 'cast', ['call', providerAddress, 'flashFee(address,uint256)(uint256)', tokenAddress, String(amount), '--rpc-url', rpcUrl], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }, ) const maxFlashLoan = Number(parseCastScalar(maxLoanRaw)) const flashFeeAmount = Number(parseCastScalar(feeRaw)) if (!Number.isFinite(maxFlashLoan) || !Number.isFinite(flashFeeAmount)) return null return { maxFlashLoan, flashFeeAmount, source: `live ERC-3156 probe via ${providerAddress}`, } } catch { return null } } function tryReadMainnetBalancerFlashSource(tokenAddress) { const rpcUrl = rpcUrlForChain(1) if (!rpcUrl || !tokenAddress) return null const code = tryReadCastCode(DEFAULT_MAINNET_BALANCER_VAULT, rpcUrl) if (!code || code === '0x') return null const collector = tryCastCallRaw( DEFAULT_MAINNET_BALANCER_VAULT, 'getProtocolFeesCollector()(address)', [], rpcUrl, ) const feeRaw = collector ? tryCastCallRaw(collector, 'getFlashLoanFeePercentage()(uint256)', [], rpcUrl) : null const feeScalar = feeRaw != null ? Number(parseCastScalar(feeRaw)) : NaN const feeBps = Number.isFinite(feeScalar) ? feeScalar / 1e14 : 0 const capRaw = tryReadTokenRawBalanceViaCast(rpcUrl, tokenAddress, DEFAULT_MAINNET_BALANCER_VAULT) return { providerKey: 'balancer', providerName: 'Balancer mainnet vault', providerAddress: DEFAULT_MAINNET_BALANCER_VAULT, capRaw, feeBps, feeRaw: feeRaw != null ? parseCastScalar(feeRaw) : null, source: 'live Balancer mainnet vault probe', } } function tryReadMainnetAaveFlashSource(tokenAddress) { const rpcUrl = rpcUrlForChain(1) if (!rpcUrl || !tokenAddress) return null const code = tryReadCastCode(DEFAULT_MAINNET_AAVE_V3_POOL, rpcUrl) if (!code || code === '0x') return null const provider = tryCastCallRaw( DEFAULT_MAINNET_AAVE_V3_POOL, 'ADDRESSES_PROVIDER()(address)', [], rpcUrl, ) const feeRaw = tryCastCallRaw( DEFAULT_MAINNET_AAVE_V3_POOL, 'FLASHLOAN_PREMIUM_TOTAL()(uint128)', [], rpcUrl, ) const feeBps = feeRaw != null ? Number(parseCastScalar(feeRaw)) : NaN const reserveData = tryCastCallRaw( DEFAULT_MAINNET_AAVE_V3_POOL, 'getReserveData(address)((uint256,uint128,uint128,uint128,uint128,uint128,uint40,address,address,address,address,uint8))', [tokenAddress], rpcUrl, ) const aTokenAddress = extractNthAddress(reserveData, 2) const capRaw = aTokenAddress != null ? tryReadTokenRawBalanceViaCast(rpcUrl, tokenAddress, aTokenAddress) : null return { providerKey: 'aave', providerName: 'Aave V3 mainnet', providerAddress: DEFAULT_MAINNET_AAVE_V3_POOL, providerAuxAddress: provider ?? DEFAULT_MAINNET_AAVE_V3_PROVIDER, capRaw, feeBps: Number.isFinite(feeBps) ? feeBps : null, feeRaw: feeRaw != null ? parseCastScalar(feeRaw) : null, source: 'live Aave V3 mainnet probe', } } function tryEstimateMainnetIntegrationGasQuote({ poolAddress, tokenIn, amountIn, quoteDecimals, nativeTokenPrice, fromAddress, }) { const rpcUrl = rpcUrlForChain(1) const integrationAddress = process.env.DODO_PMM_INTEGRATION_MAINNET ?? null if ( !rpcUrl || !integrationAddress || !poolAddress || !tokenIn || !(amountIn > 0) || !(quoteDecimals >= 0) || !(nativeTokenPrice > 0) || !fromAddress ) { return null } const gasUnits = tryEstimateIntegrationSwapGasViaCast({ integrationAddress, poolAddress, tokenIn, amountIn, minOut: 1, fromAddress, rpcUrl, }) if (!(gasUnits > 0)) return null let gasPriceWei = null try { const raw = execFileSync('cast', ['gas-price', '--rpc-url', rpcUrl], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], }) gasPriceWei = Number(parseCastScalar(raw)) } catch {} if (!(gasPriceWei > 0)) return null const nativeCost = gasUnits * gasPriceWei * 1e-18 const quoteCost = nativeCost * nativeTokenPrice if (!(quoteCost > 0)) return null return { gasUnits, gasPriceWei, quoteCost, source: `live cast estimate on DODOPMMIntegration mainnet swap path (${gasUnits} gas @ ${fmt(gasPriceWei)} wei)`, } } function resolveTokenBalance({ chainId, symbol, tokenAddress, report, reportPath, deployerAddress, }) { const live = tokenAddress && deployerAddress ? tryReadTokenBalanceViaCast(chainId, tokenAddress, deployerAddress) : null if (live) return live const reportBalance = sumReportBalance(report, chainId, symbol) const reportInfo = sumReportBalanceInfo(report, chainId, symbol) if (reportInfo) { return { ...reportInfo, source: reportPath ? `audit report ${reportPath}` : 'audit report', } } if (reportBalance != null) { return { balance: reportBalance, source: reportPath ? `audit report ${reportPath}` : 'audit report', } } return null } function repayUsdc(grossQuoteIn, flashFeeBps) { const bps = Math.max(0, flashFeeBps) return grossQuoteIn * (1 + bps / 10000) } function repayUsdcWithExactFee(grossQuoteIn, flashFeeAmount, flashFeeBps) { if (flashFeeAmount != null) return grossQuoteIn + flashFeeAmount return repayUsdc(grossQuoteIn, flashFeeBps) } /** Net USDC per base after external sale (fold slippage + fees into P_eff) */ function effectiveExternalPrice(externalPrice, exitFeeBps) { const bps = Math.min(10000, Math.max(0, exitFeeBps)) return externalPrice * ((10000 - bps) / 10000) } function effectiveExternalEntryPrice(externalPrice, entryFeeBps) { const bps = Math.min(10000, Math.max(0, entryFeeBps)) return externalPrice * ((10000 + bps) / 10000) } function externalQuoteToBaseOut(grossQuoteIn, externalPrice, entryFeeBps, quoteDecimals, baseDecimals) { const pEff = effectiveExternalEntryPrice(externalPrice, entryFeeBps) const quoteInHuman = rawToHuman(grossQuoteIn, quoteDecimals) const baseOutHuman = pEff > 0 ? quoteInHuman / pEff : 0 const baseOut = humanToRaw(baseOutHuman, baseDecimals) return { effectivePrice: pEff, baseOut } } function externalBaseToQuoteOut(baseIn, externalPrice, exitFeeBps, baseDecimals, quoteDecimals) { const pEff = effectiveExternalPrice(externalPrice, exitFeeBps) const baseInHuman = rawToHuman(baseIn, baseDecimals) const quoteOutHuman = baseInHuman * pEff const quoteOut = humanToRaw(quoteOutHuman, quoteDecimals) return { effectivePrice: pEff, quoteOut } } function formatExternalRoute(fromAsset, toAsset, viaAsset) { return viaAsset ? `${fromAsset} -> ${viaAsset} -> ${toAsset}` : `${fromAsset} -> ${toAsset}` } function profit(grossQuoteIn, baseOut, externalPrice, flashFeeBps, exitFeeBps) { const pEff = effectiveExternalPrice(externalPrice, exitFeeBps) const proceeds = pEff * baseOut const repay = repayUsdc(grossQuoteIn, flashFeeBps) return proceeds - repay } function breakEvenExternalPrice(grossQuoteIn, baseOut, flashFeeBps, exitFeeBps) { if (baseOut <= 0) return Infinity const repay = repayUsdc(grossQuoteIn, flashFeeBps) const exitMult = (10000 - Math.min(10000, Math.max(0, exitFeeBps))) / 10000 if (exitMult <= 0) return Infinity return repay / (baseOut * exitMult) } function fmt(n) { if (!Number.isFinite(n)) return String(n) if (Math.abs(n) >= 1e9) return n.toExponential(4) return n.toLocaleString('en-US', { maximumFractionDigits: 6 }) } function rawToHuman(raw, decimals) { if (!Number.isFinite(raw) || !Number.isFinite(decimals)) return NaN return raw / 10 ** decimals } function humanToRaw(amount, decimals) { if (!Number.isFinite(amount) || !Number.isFinite(decimals)) return NaN return amount * 10 ** decimals } function convertRawAmount(raw, fromDecimals, toDecimals) { if (!Number.isFinite(raw) || !Number.isFinite(fromDecimals) || !Number.isFinite(toDecimals)) { return NaN } return humanToRaw(rawToHuman(raw, fromDecimals), toDecimals) } function fmtAmount(raw, decimals, symbol) { if (!Number.isFinite(raw) || !Number.isFinite(decimals)) { return symbol ? `${fmt(raw)} ${symbol}` : fmt(raw) } const human = rawToHuman(raw, decimals) const humanLabel = symbol ? `${fmt(human)} ${symbol}` : fmt(human) return `${humanLabel} (raw ${fmt(raw)})` } function approxBpsFromAmount(amount, feeAmount) { if (!(amount > 0) || !Number.isFinite(feeAmount)) return NaN return (feeAmount / amount) * 10000 } function parseNum(s) { const n = Number(s) if (!Number.isFinite(n)) throw new Error(`Invalid number: ${s}`) return n } function parsePositiveInt(s, label) { const n = parseNum(s) if (!Number.isInteger(n) || n <= 0) { throw new Error(`${label} must be a positive integer`) } return n } function parseNonNegativeInt(s, label) { const n = parseNum(s) if (!Number.isInteger(n) || n < 0) { throw new Error(`${label} must be a non-negative integer`) } return n } function marginalQuotePerBase(baseReserve, quoteReserve) { if (!(baseReserve > 0) || !(quoteReserve >= 0)) return NaN return quoteReserve / baseReserve } function deviationBps(price, oraclePrice) { if (!(price >= 0) || !(oraclePrice > 0)) return NaN return ((price - oraclePrice) / oraclePrice) * 10000 } function calcNativeGasReserve(gasTxCount, gasPerTx, maxFeeGwei) { if (!(gasTxCount > 0) || !(gasPerTx > 0) || !(maxFeeGwei > 0)) return 0 return gasTxCount * gasPerTx * maxFeeGwei * 1e-9 } function buildInventoryLoopGuardConfig({ minRetainedUsdc, gasTxCount, gasPerTx, maxFeeGwei, nativeTokenPrice, quoteDecimals, oraclePrice, maxPostTradeDeviationBps, maxCwBurnFraction, cooldownBlocks, measuredGasQuote, measuredGasSource, estimatedGasQuote, estimatedGasSource, }) { const measuredGasQuoteRaw = measuredGasQuote != null && measuredGasQuote > 0 ? humanToRaw(measuredGasQuote, quoteDecimals) : 0 const estimatedGasQuoteRaw = estimatedGasQuote != null && estimatedGasQuote > 0 ? humanToRaw(estimatedGasQuote, quoteDecimals) : 0 const gasReserveNative = gasTxCount != null && gasPerTx != null && maxFeeGwei != null ? calcNativeGasReserve(gasTxCount, gasPerTx, maxFeeGwei) : 0 const modeledGasReserveQuoteHuman = gasReserveNative > 0 && nativeTokenPrice != null ? gasReserveNative * nativeTokenPrice : 0 const gasReserveQuoteRaw = measuredGasQuoteRaw > 0 ? measuredGasQuoteRaw : estimatedGasQuoteRaw > 0 ? estimatedGasQuoteRaw : modeledGasReserveQuoteHuman > 0 ? humanToRaw(modeledGasReserveQuoteHuman, quoteDecimals) : 0 const gasReserveQuoteHuman = measuredGasQuoteRaw > 0 ? measuredGasQuote : estimatedGasQuoteRaw > 0 ? estimatedGasQuote : modeledGasReserveQuoteHuman return { minRetainedUsdc, gasTxCount, gasPerTx, maxFeeGwei, nativeTokenPrice, quoteDecimals, gasReserveNative, gasReserveQuoteHuman, gasReserveQuote: gasReserveQuoteRaw, gasReserveMode: measuredGasQuoteRaw > 0 ? 'measured_quote' : estimatedGasQuoteRaw > 0 ? 'estimated_quote' : 'modeled_native', gasReserveSource: measuredGasQuoteRaw > 0 ? measuredGasSource ?? 'CLI measured gas quote override' : estimatedGasQuoteRaw > 0 ? estimatedGasSource ?? 'live integration gas estimate' : 'modeled from gas policy inputs', requiredRetainedUsdc: minRetainedUsdc + gasReserveQuoteRaw, oraclePrice, maxPostTradeDeviationBps, maxCwBurnFraction, cooldownBlocks, } } function summarizeGasReserve(guardConfig) { if (!(guardConfig.gasReserveQuote > 0)) return null if (guardConfig.gasReserveMode === 'measured_quote') { return `${fmt(guardConfig.gasReserveQuoteHuman ?? rawToHuman(guardConfig.gasReserveQuote, guardConfig.quoteDecimals))} quote units from ${guardConfig.gasReserveSource}` } if (guardConfig.gasReserveMode === 'estimated_quote') { return `${fmt(guardConfig.gasReserveQuoteHuman ?? rawToHuman(guardConfig.gasReserveQuote, guardConfig.quoteDecimals))} quote units from ${guardConfig.gasReserveSource}` } return `${guardConfig.gasTxCount} tx * ${fmt(guardConfig.gasPerTx)} gas * ${fmt(guardConfig.maxFeeGwei)} gwei @ native price ${fmt(guardConfig.nativeTokenPrice)}` } function classifyExecutionReadiness({ strategyLabel, quoteSurface, externalEntrySource, externalExitSource, gasReserveMode, maxPostTradeDeviationBps, }) { const missing = listExecutionReadinessBlocks({ strategyLabel, quoteSurface, externalEntrySource, externalExitSource, gasReserveMode, maxPostTradeDeviationBps, }) if (missing.length === 0) return 'execution-ready' if (missing.some((item) => item.includes('live pool quote surface'))) return 'blocked' return 'planning' } function hasRequiredLivePoolQuoteSurface(strategyLabel, quoteSurface) { if (!quoteSurface) return false if (typeof quoteSurface === 'string') return quoteSurface === 'full_quote_surface' if (quoteSurface.surface === 'full_quote_surface') return true if (strategyLabel === 'quote-push') return quoteSurface.quotePushOk === true if (strategyLabel === 'base-unwind') return quoteSurface.baseUnwindOk === true if (strategyLabel === 'both') { return quoteSurface.quotePushOk === true && quoteSurface.baseUnwindOk === true } return false } function listExecutionReadinessBlocks({ strategyLabel, quoteSurface, externalEntrySource, externalExitSource, gasReserveMode, maxPostTradeDeviationBps, }) { const hasLivePoolQuote = hasRequiredLivePoolQuoteSurface(strategyLabel, quoteSurface) const needsLiveEntry = strategyLabel === 'base-unwind' || strategyLabel === 'both' const needsLiveExit = strategyLabel === 'quote-push' || strategyLabel === 'both' const hasLiveExternalEntry = !needsLiveEntry || externalEntrySource == null || externalEntrySource === 'live' const hasLiveExternalExit = !needsLiveExit || externalExitSource == null || externalExitSource === 'live' const hasMeasuredGas = gasReserveMode === 'measured_quote' || gasReserveMode === 'estimated_quote' const hasExplicitDeviationCap = maxPostTradeDeviationBps != null const missing = [] if (!hasLivePoolQuote) { missing.push( strategyLabel === 'both' ? 'full live pool quote surface' : `live pool quote surface for ${strategyLabel}`, ) } if (!hasLiveExternalEntry) missing.push('live external entry quote source') if (!hasLiveExternalExit) missing.push('live external exit quote source') if (!hasMeasuredGas) missing.push('measured or live-estimated gas') if (!hasExplicitDeviationCap) missing.push('explicit post-trade deviation cap') return missing } function formatGuardStatus(candidate) { return candidate.recommendationOk ? 'pass' : candidate.guardFailures.join('+') } function cmpAsc(a, b) { return a - b } function cmpDesc(a, b) { return b - a } function compareRankProfileMetrics(a, b, metrics) { for (const metric of metrics) { const av = metric.pick(a) const bv = metric.pick(b) if (av !== bv) return metric.order(av, bv) } return 0 } function eligibleRankMetrics(targetFlashBorrow, rankProfile) { const efficiencyMetric = targetFlashBorrow != null ? (candidate) => candidate.retainedAfterTargetFlashPerCw : (candidate) => candidate.retainedPerCw switch (rankProfile) { case 'conservative': return [ { pick: (candidate) => candidate.postTradeDeviationAbsBps, order: cmpAsc }, { pick: (candidate) => candidate.inventoryBurnFraction ?? Infinity, order: cmpAsc }, { pick: (candidate) => candidate.grossBaseIn, order: cmpAsc }, ...(targetFlashBorrow != null ? [ { pick: (candidate) => candidate.floorMarginAfterTargetFlash, order: cmpDesc }, { pick: (candidate) => candidate.repayMargin, order: cmpDesc }, ] : [ { pick: (candidate) => candidate.maxFlashKeepFloor, order: cmpDesc }, { pick: (candidate) => candidate.floorSurplusNoFlash, order: cmpDesc }, ]), { pick: efficiencyMetric, order: cmpDesc }, ] case 'efficiency': return [ { pick: efficiencyMetric, order: cmpDesc }, ...(targetFlashBorrow != null ? [ { pick: (candidate) => candidate.floorMarginAfterTargetFlash, order: cmpDesc }, { pick: (candidate) => candidate.repayMargin, order: cmpDesc }, ] : [ { pick: (candidate) => candidate.maxFlashKeepFloor, order: cmpDesc }, { pick: (candidate) => candidate.floorSurplusNoFlash, order: cmpDesc }, ]), { pick: (candidate) => candidate.postTradeDeviationAbsBps, order: cmpAsc }, { pick: (candidate) => candidate.inventoryBurnFraction ?? Infinity, order: cmpAsc }, { pick: (candidate) => candidate.grossBaseIn, order: cmpAsc }, ] case 'balanced': default: return [ ...(targetFlashBorrow != null ? [ { pick: (candidate) => candidate.repayMargin, order: cmpDesc }, { pick: (candidate) => candidate.floorMarginAfterTargetFlash, order: cmpDesc }, ] : [ { pick: (candidate) => candidate.maxFlashKeepFloor, order: cmpDesc }, { pick: (candidate) => candidate.floorSurplusNoFlash, order: cmpDesc }, ]), { pick: efficiencyMetric, order: cmpDesc }, { pick: (candidate) => candidate.postTradeDeviationAbsBps, order: cmpAsc }, { pick: (candidate) => candidate.inventoryBurnFraction ?? Infinity, order: cmpAsc }, { pick: (candidate) => candidate.grossBaseIn, order: cmpAsc }, ] } } function efficiencyMetricLabel(targetFlashBorrow) { return targetFlashBorrow != null ? 'retained_after_repay_per_cw' : 'retained_per_cw' } function candidateEfficiencyValue(candidate, targetFlashBorrow) { return targetFlashBorrow != null ? candidate.retainedAfterTargetFlashPerCw : candidate.retainedPerCw } function rankProfileSummary(rankProfile, targetFlashBorrow) { switch (rankProfile) { case 'conservative': return targetFlashBorrow != null ? 'lowest post-trade deviation, lowest cW burn, then stronger post-repay safety headroom' : 'lowest post-trade deviation, lowest cW burn, then stronger retained-floor headroom' case 'efficiency': return targetFlashBorrow != null ? 'best retained USDC after repay per cW, then safety headroom, then lower impact' : 'best retained USDC per cW, then retained-floor headroom, then lower impact' case 'balanced': default: return targetFlashBorrow != null ? 'strongest repay margin and post-repay floor headroom, then better efficiency and lower impact' : 'largest flash/floor headroom, then better efficiency and lower impact' } } function explainWinningCandidate(recommended, runnerUp, rankProfile, targetFlashBorrow) { if (!recommended) return null const efficiencyLabel = efficiencyMetricLabel(targetFlashBorrow) const recommendedEfficiency = fmt(candidateEfficiencyValue(recommended, targetFlashBorrow)) switch (rankProfile) { case 'conservative': if (runnerUp) { return `Won on lower post-trade deviation (${fmt(recommended.postTradeDeviationAbsBps)} vs ${fmt(runnerUp.postTradeDeviationAbsBps)} bps) and lower cW burn (${fmt(recommended.inventoryBurnFraction)} vs ${fmt(runnerUp.inventoryBurnFraction)}).` } return `Won by minimizing post-trade deviation (${fmt(recommended.postTradeDeviationAbsBps)} bps) and cW burn (${fmt(recommended.inventoryBurnFraction)}).` case 'efficiency': if (runnerUp) { return `Won on better ${efficiencyLabel} (${recommendedEfficiency} vs ${fmt(candidateEfficiencyValue(runnerUp, targetFlashBorrow))}) while still passing the active guard set.` } return `Won on best ${efficiencyLabel} (${recommendedEfficiency}) among the eligible set.` case 'balanced': default: if (targetFlashBorrow != null) { if (runnerUp) { return `Won on stronger repay margin (${fmt(recommended.repayMargin)} vs ${fmt(runnerUp.repayMargin)}) and post-repay floor margin (${fmt(recommended.floorMarginAfterTargetFlash)} vs ${fmt(runnerUp.floorMarginAfterTargetFlash)}).` } return `Won on strongest repay margin (${fmt(recommended.repayMargin)}) and post-repay floor margin (${fmt(recommended.floorMarginAfterTargetFlash)}).` } if (runnerUp) { return `Won on higher max flash-with-floor headroom (${fmt(recommended.maxFlashKeepFloor)} vs ${fmt(runnerUp.maxFlashKeepFloor)}) and higher floor surplus (${fmt(recommended.floorSurplusNoFlash)} vs ${fmt(runnerUp.floorSurplusNoFlash)}).` } return `Won on highest flash-with-floor headroom (${fmt(recommended.maxFlashKeepFloor)}) and floor surplus (${fmt(recommended.floorSurplusNoFlash)}).` } } function printScenario(label, B, Q, x, lpFeeBps, flashFeeBps, externalPrice, exitFeeBps) { const { deltaXNet, baseOut, vwap } = quoteInToBaseOut(B, Q, x, lpFeeBps) const repay = repayUsdc(x, flashFeeBps) const pStar = breakEvenExternalPrice(x, baseOut, flashFeeBps, exitFeeBps) const pi = externalPrice != null && Number.isFinite(externalPrice) ? profit(x, baseOut, externalPrice, flashFeeBps, exitFeeBps) : null console.log(`--- ${label} ---`) console.log(` baseReserve B=${fmt(B)} quoteReserve Q=${fmt(Q)} gross quote in x=${fmt(x)}`) console.log(` lpFeeBps=${lpFeeBps} flashFeeBps=${flashFeeBps} exitFeeBps=${exitFeeBps}`) console.log(` Δx_net (after LP fee)=${fmt(deltaXNet)}`) console.log(` base out Δy=${fmt(baseOut)}`) console.log(` VWAP (gross quote / base)=${fmt(vwap)}`) console.log(` repay (x * (1+flash))=${fmt(repay)}`) console.log(` break-even P_ext*=${fmt(pStar)} quote per base`) if (pi != null) console.log(` PnL @ externalPrice=${externalPrice} (after exit fee)=${fmt(pi)}`) console.log('') } function printMainnetMap( compareDeepenDelta, B, Q, scanStr, lpFeeBps, registryFeeBps, preferRegistryFeeForDeepen, ) { const m = loadMainnetCwUsdcUsdc() console.log('Ethereum Mainnet — cWUSDC / USDC PMM mapping (repo registry)\n') if (!m) { console.log(' (Could not read cross-chain-pmm-lps/config/deployment-status.json)\n') return } const feeForTables = compareDeepenDelta != null && preferRegistryFeeForDeepen && registryFeeBps != null ? registryFeeBps : lpFeeBps const feeSource = compareDeepenDelta != null && preferRegistryFeeForDeepen && registryFeeBps != null ? 'registry row fee (default for --compare-deepen)' : '--lp-fee-bps' console.log(' Token cWUSDC (ops shorthand xWUSDC):', m.cWUSDC) console.log(' Token USDC (anchor): ', m.USDC) console.log(' DODO PMM pool: ', m.poolAddress) console.log(' Registered LP fee: ', m.feeBps, 'bps') console.log('') console.log(' Loop (funded USDC inventory, not necessarily flash credit):') console.log(' USDC → ETH (Uniswap / deep CLOB): charge slippage + pool fee into leg-1') console.log(' ETH → cWUSDC: use any liquid route; if none, extra hop(s) — fold into acquisition cost') console.log(' cWUSDC → USDC on this PMM: sell-base formula') console.log(' quoteOut = netBaseIn * Q / (B + netBaseIn)') console.log('') console.log(' For acquisition via PMM (USDC → cWUSDC) use quote-in branch (this script default):') console.log(' baseOut = netQuoteIn * B / (Q + netQuoteIn)') console.log('') console.log(' Model Aave-style flash: keep --flash-fee-bps 5; funded pool loop: often --flash-fee-bps 0.') console.log('') if (compareDeepenDelta != null && Number.isFinite(compareDeepenDelta) && compareDeepenDelta > 0) { if (B == null || Q == null) { console.log(' --compare-deepen requires -B and -Q (live reserves from pool getVaultReserve).') return } const sizes = scanStr ? scanStr.split(',').map((s) => parseNum(s.trim())) : [500_000, 1_000_000, 2_000_000, 5_000_000] const B2 = B + compareDeepenDelta console.log( ` Depth add: +${fmt(compareDeepenDelta)} cWUSDC to base → B: ${fmt(B)} → ${fmt(B2)} (Q fixed ${fmt(Q)})`, ) console.log(` Table LP fee: ${feeForTables} bps (${feeSource})`) console.log('') console.log(' USDC→cWUSDC (quote in): trade_x | baseOut_before | VWAP_before | baseOut_after | VWAP_after') for (const x of sizes) { const a = quoteInToBaseOut(B, Q, x, feeForTables) const b = quoteInToBaseOut(B2, Q, x, feeForTables) console.log( [fmt(x), fmt(a.baseOut), fmt(a.vwap), fmt(b.baseOut), fmt(b.vwap)].join('\t'), ) } console.log('') console.log(' cWUSDC→USDC (base in, same sizes as cWUSDC sold): | quoteOut_before | USDC/base | quoteOut_after | USDC/base') for (const x of sizes) { const a = baseInToQuoteOut(B, Q, x, feeForTables) const b = baseInToQuoteOut(B2, Q, x, feeForTables) console.log( [fmt(x), fmt(a.quoteOut), fmt(a.vwapQuotePerBase), fmt(b.quoteOut), fmt(b.vwapQuotePerBase)].join( '\t', ), ) } console.log('') } } function printInventoryCoverage(inventoryBase, requiredBase, label = 'Required cW base inventory') { if (inventoryBase == null) return const remaining = inventoryBase - requiredBase console.log(` inventoryBase available=${fmt(inventoryBase)}`) console.log(` ${label}=${fmt(requiredBase)}`) console.log( ` inventory coverage=${remaining >= 0 ? 'enough' : 'short'} (${remaining >= 0 ? 'remaining' : 'shortfall'} ${fmt(Math.abs(remaining))})`, ) } function printSeedingPlanFromPmm( B, Q, totalQuoteTarget, lpFeeBps, inventoryBase, loopCount, seedPools, targetQuotePerPool, ) { console.log('Quote seeding plan — source PMM sell-base path\n') console.log(` source reserves: B=${fmt(B)} cW base, Q=${fmt(Q)} USDC quote`) console.log(` pool fee=${lpFeeBps} bps`) console.log(` target USDC to raise=${fmt(totalQuoteTarget)}`) if (seedPools != null) console.log(` target pools=${seedPools}`) if (targetQuotePerPool != null) console.log(` target USDC per pool=${fmt(targetQuotePerPool)}`) console.log(` loop count=${loopCount}`) console.log('') const direct = baseInRequiredForQuoteOut(B, Q, totalQuoteTarget, lpFeeBps) if (!direct.feasible) { console.log(' Target quote exceeds available source quote reserve; cannot fully harvest that much in this PMM.') return } console.log(' Single-shot requirement from current reserves:') console.log(` gross cW base sacrifice=${fmt(direct.grossBaseIn)}`) console.log(` net cW base into pool=${fmt(direct.deltaBaseNet)}`) console.log(` LP fee paid in base=${fmt(direct.feeBase)}`) console.log(` realized USDC per gross cW base=${fmt(direct.vwapQuotePerBase)}`) printInventoryCoverage(inventoryBase, direct.grossBaseIn) console.log('') const splitTargets = targetQuotePerPool != null && seedPools != null && loopCount === seedPools ? Array.from({ length: loopCount }, () => targetQuotePerPool) : Array.from({ length: loopCount }, () => totalQuoteTarget / loopCount) let runningB = B let runningQ = Q let cumulativeQuote = 0 let cumulativeGrossBase = 0 let cumulativeNetBase = 0 let cumulativeFeeBase = 0 console.log(' Liquidity loop table:') console.log( 'loop\tquote_target\tgross_base_in\tnet_base_in\tfee_base\tUSDC/gross_base\tend_B\tend_Q\tcum_quote\tcum_gross_base', ) for (let i = 0; i < splitTargets.length; i += 1) { const quoteTarget = splitTargets[i] const leg = baseInRequiredForQuoteOut(runningB, runningQ, quoteTarget, lpFeeBps) if (!leg.feasible) { console.log(`${i + 1}\t${fmt(quoteTarget)}\tINFEASIBLE\tINFEASIBLE\tINFEASIBLE\tINFEASIBLE\t${fmt(runningB)}\t${fmt(runningQ)}\t${fmt(cumulativeQuote)}\t${fmt(cumulativeGrossBase)}`) break } runningB += leg.deltaBaseNet runningQ -= quoteTarget cumulativeQuote += quoteTarget cumulativeGrossBase += leg.grossBaseIn cumulativeNetBase += leg.deltaBaseNet cumulativeFeeBase += leg.feeBase console.log( [ i + 1, fmt(quoteTarget), fmt(leg.grossBaseIn), fmt(leg.deltaBaseNet), fmt(leg.feeBase), fmt(leg.vwapQuotePerBase), fmt(runningB), fmt(runningQ), fmt(cumulativeQuote), fmt(cumulativeGrossBase), ].join('\t'), ) } console.log('') console.log(' End state after loops:') console.log(` total quote raised=${fmt(cumulativeQuote)}`) console.log(` cumulative gross cW base sacrifice=${fmt(cumulativeGrossBase)}`) console.log(` cumulative net cW base into source pool=${fmt(cumulativeNetBase)}`) console.log(` cumulative LP fee paid in base=${fmt(cumulativeFeeBase)}`) console.log(` final source reserves: B=${fmt(runningB)} Q=${fmt(runningQ)}`) printInventoryCoverage(inventoryBase, cumulativeGrossBase, 'Looped cW base inventory required') console.log('') } function printSeedingPlanExternal( totalQuoteTarget, externalPrice, exitFeeBps, inventoryBase, loopCount, seedPools, targetQuotePerPool, ) { const pEff = effectiveExternalPrice(externalPrice, exitFeeBps) console.log('Quote seeding plan — external monetization rate\n') console.log(` gross external price=${fmt(externalPrice)} USDC per cW base`) console.log(` net effective price=${fmt(pEff)} USDC per cW base`) console.log(` target USDC to raise=${fmt(totalQuoteTarget)}`) if (seedPools != null) console.log(` target pools=${seedPools}`) if (targetQuotePerPool != null) console.log(` target USDC per pool=${fmt(targetQuotePerPool)}`) console.log(` loop count=${loopCount}`) console.log('') if (!(pEff > 0)) { console.log(' Effective monetization price is zero or negative; cannot size required cW inventory.') return } const grossBaseRequired = totalQuoteTarget / pEff console.log(` gross cW base sacrifice required=${fmt(grossBaseRequired)}`) console.log(` realized USDC per gross cW base=${fmt(pEff)}`) printInventoryCoverage(inventoryBase, grossBaseRequired) console.log('') if (loopCount > 1) { const perLoopQuote = totalQuoteTarget / loopCount const perLoopBase = perLoopQuote / pEff let cumulativeQuote = 0 let cumulativeBase = 0 console.log(' Liquidity loop table:') console.log('loop\tquote_target\tgross_base_in\tUSDC/gross_base\tcum_quote\tcum_gross_base') for (let i = 0; i < loopCount; i += 1) { cumulativeQuote += perLoopQuote cumulativeBase += perLoopBase console.log( [i + 1, fmt(perLoopQuote), fmt(perLoopBase), fmt(pEff), fmt(cumulativeQuote), fmt(cumulativeBase)].join( '\t', ), ) } console.log('') } } function printFundingReadiness({ inventoryAsset, sourceAsset, quoteAsset, totalQuoteTarget, lpFeeBps, baseReserve, quoteReserve, reserveSource, poolAddress, report, reportPath, }) { const mainnetPool = loadMainnetPool(inventoryAsset, quoteAsset) const direct = baseInRequiredForQuoteOut(baseReserve, quoteReserve, totalQuoteTarget, lpFeeBps) const deployerAddress = resolveDeployerAddressViaCast() const mainnetTokenAddress = mainnetPool?.baseAddress ?? null const mainnetQuoteAddress = mainnetPool?.quoteAddress ?? null const chain138TokenAddress = loadChain138TokenAddress(sourceAsset) const mainnetBalance = resolveTokenBalance({ chainId: 1, symbol: inventoryAsset, tokenAddress: mainnetTokenAddress, report, reportPath, deployerAddress, }) const chain138Balance = resolveTokenBalance({ chainId: 138, symbol: sourceAsset, tokenAddress: chain138TokenAddress, report, reportPath, deployerAddress, }) const inventoryDecimals = mainnetBalance?.decimals ?? tryReadTokenDecimalsViaCast(1, mainnetTokenAddress) ?? 6 const sourceDecimals = chain138Balance?.decimals ?? tryReadTokenDecimalsViaCast(138, chain138TokenAddress) ?? inventoryDecimals const quoteDecimals = tryReadTokenDecimalsViaCast(1, mainnetQuoteAddress) ?? inventoryDecimals const mainnetAvailableHuman = mainnetBalance?.balance ?? 0 const chain138AvailableHuman = chain138Balance?.balance ?? 0 const mainnetAvailableRawOnPoolScale = humanToRaw(mainnetAvailableHuman, inventoryDecimals) const chain138AvailableRawOnPoolScale = humanToRaw(chain138AvailableHuman, inventoryDecimals) const mainnetImmediateQuoteRaw = mainnetAvailableRawOnPoolScale > 0 ? baseInToQuoteOut(baseReserve, quoteReserve, mainnetAvailableRawOnPoolScale, lpFeeBps).quoteOut : 0 const bridgeReachableQuoteRaw = chain138AvailableRawOnPoolScale > 0 ? baseInToQuoteOut(baseReserve, quoteReserve, chain138AvailableRawOnPoolScale, lpFeeBps).quoteOut : 0 const requiredGrossHuman = rawToHuman(direct.grossBaseIn, inventoryDecimals) const requiredNetHuman = rawToHuman(direct.deltaBaseNet, inventoryDecimals) const feeBaseHuman = rawToHuman(direct.feeBase, inventoryDecimals) const mainnetEnough = direct.feasible && mainnetAvailableHuman >= requiredGrossHuman const bridgeEnough = direct.feasible && chain138AvailableHuman >= requiredGrossHuman console.log('Funding readiness — live mainnet vs bridge-reachable inventory\n') console.log(` inventory asset=${inventoryAsset} source asset=${sourceAsset} quote asset=${quoteAsset}`) console.log(` target ${quoteAsset} to raise=${fmtAmount(totalQuoteTarget, quoteDecimals, quoteAsset)}`) console.log(` pool fee=${lpFeeBps} bps`) console.log( ` mainnet pool reserves: B=${fmtAmount(baseReserve, inventoryDecimals, inventoryAsset)}, Q=${fmtAmount(quoteReserve, quoteDecimals, quoteAsset)}`, ) console.log(` reserve source=${reserveSource}`) if (poolAddress) console.log(` mainnet pool=${poolAddress}`) if (deployerAddress) console.log(` deployer=${deployerAddress}`) if (reportPath) console.log(` balance report fallback=${reportPath}`) console.log('') if (!direct.feasible) { console.log(' Target quote exceeds available quote reserve in the current PMM; no readiness conclusion can be made.') console.log('') return } console.log(' Requirement at current live pool state:') console.log(` required gross ${inventoryAsset}=${fmt(requiredGrossHuman)} ${inventoryAsset} (raw ${fmt(direct.grossBaseIn)})`) console.log(` required net ${inventoryAsset} into pool=${fmt(requiredNetHuman)} ${inventoryAsset} (raw ${fmt(direct.deltaBaseNet)})`) console.log(` implied LP fee in base=${fmt(feeBaseHuman)} ${inventoryAsset} (raw ${fmt(direct.feeBase)})`) console.log(` realized ${quoteAsset} per gross ${inventoryAsset}=${fmt(direct.vwapQuotePerBase)}`) console.log('') console.log(' View 1 — already funded on mainnet today:') console.log(` available ${inventoryAsset} on mainnet=${fmt(mainnetAvailableHuman)} ${inventoryAsset}${mainnetBalance?.raw != null ? ` (raw ${fmt(mainnetBalance.raw)})` : ''}`) console.log(` balance source=${mainnetBalance?.source ?? 'unavailable'}`) console.log(` immediate quote capacity at current pool=${fmt(rawToHuman(mainnetImmediateQuoteRaw, quoteDecimals))} ${quoteAsset} (raw ${fmt(mainnetImmediateQuoteRaw)})`) console.log( ` status=${mainnetEnough ? 'enough now' : 'short'} (${mainnetEnough ? 'remaining' : 'shortfall'} ${fmt(Math.abs(mainnetAvailableHuman - requiredGrossHuman))} ${inventoryAsset})`, ) console.log('') console.log(' View 2 — reachable after bridging from current Chain 138 inventory:') console.log(` available ${sourceAsset} on Chain 138=${fmt(chain138AvailableHuman)} ${sourceAsset}${chain138Balance?.raw != null ? ` (raw ${fmt(chain138Balance.raw)})` : ''}`) console.log(` balance source=${chain138Balance?.source ?? 'unavailable'}`) console.log(` bridge-reachable quote capacity at current pool=${fmt(rawToHuman(bridgeReachableQuoteRaw, quoteDecimals))} ${quoteAsset} (raw ${fmt(bridgeReachableQuoteRaw)})`) console.log( ` status=${bridgeEnough ? 'enough after bridge' : 'short'} (${bridgeEnough ? 'remaining' : 'shortfall'} ${fmt(Math.abs(chain138AvailableHuman - requiredGrossHuman))} ${sourceAsset})`, ) console.log('') console.log(' Assumption for View 2: 1:1 nominal c* -> cW* corridor, ignoring bridge fees, caps, and transfer latency.') console.log('') } function buildQuoteDeploymentSteps({ retainedQuote, seedPools, targetQuotePerPool, targetTotalQuote, loopCount, }) { if (targetQuotePerPool == null && targetTotalQuote == null) return null const totalTarget = targetTotalQuote != null ? targetTotalQuote : (seedPools ?? loopCount ?? 1) * targetQuotePerPool const steps = targetQuotePerPool != null && seedPools != null ? Array.from({ length: seedPools }, (_, index) => ({ label: `pool_${index + 1}`, targetQuote: targetQuotePerPool, })) : Array.from({ length: loopCount ?? 1 }, (_, index) => ({ label: `loop_${index + 1}`, targetQuote: totalTarget / (loopCount ?? 1), })) let remainingQuote = Math.max(0, retainedQuote) const rows = steps.map((step) => { const deployedQuote = Math.min(step.targetQuote, remainingQuote) remainingQuote -= deployedQuote return { ...step, deployedQuote, shortfallQuote: step.targetQuote - deployedQuote, fullyFunded: deployedQuote >= step.targetQuote, remainingQuote, } }) const fullyFundedCount = rows.filter((row) => row.fullyFunded).length const deployedTotal = rows.reduce((sum, row) => sum + row.deployedQuote, 0) return { totalTarget, rows, fullyFundedCount, deployedTotal, remainingQuote, shortfallQuote: Math.max(0, totalTarget - deployedTotal), } } function printQuoteDeploymentPlan({ retainedQuote, quoteAsset, quoteDecimals, seedPools, targetQuotePerPool, targetTotalQuote, loopCount, }) { const plan = buildQuoteDeploymentSteps({ retainedQuote, seedPools, targetQuotePerPool, targetTotalQuote, loopCount, }) if (!plan) { console.log(` no destination pool target provided; retained ${quoteAsset} remains unallocated`) return } console.log('Destination pool deployment') console.log(` retained ${quoteAsset} available=${fmtAmount(retainedQuote, quoteDecimals, quoteAsset)}`) if (seedPools != null) console.log(` target pools=${seedPools}`) if (targetQuotePerPool != null) console.log(` target ${quoteAsset} per pool=${fmtAmount(targetQuotePerPool, quoteDecimals, quoteAsset)}`) if (targetTotalQuote != null) console.log(` target total ${quoteAsset}=${fmtAmount(targetTotalQuote, quoteDecimals, quoteAsset)}`) if (loopCount != null) console.log(` deployment loops=${loopCount}`) console.log( ` status=${plan.shortfallQuote > 0 ? 'short' : 'enough'} (${plan.shortfallQuote > 0 ? 'shortfall' : 'leftover'} ${fmtAmount( plan.shortfallQuote > 0 ? plan.shortfallQuote : plan.remainingQuote, quoteDecimals, quoteAsset, )})`, ) if (targetQuotePerPool != null) { console.log(` fully funded pools=${plan.fullyFundedCount}`) } console.log('') console.log('step\ttarget_quote\tdeployed_quote\tshortfall_quote\tremaining_quote\tstatus') for (const row of plan.rows) { console.log( [ row.label, fmtAmount(row.targetQuote, quoteDecimals, quoteAsset), fmtAmount(row.deployedQuote, quoteDecimals, quoteAsset), fmtAmount(row.shortfallQuote, quoteDecimals, quoteAsset), fmtAmount(row.remainingQuote, quoteDecimals, quoteAsset), row.fullyFunded ? 'funded' : 'partial', ].join('\t'), ) } console.log('') } function simulateFullLoopDryRun({ B, Q, x, lpFeeBps, flashFeeBps, loopStrategy, ownedBaseAdd, flashTopupQuote, externalEntryPrice, externalExitPrice, externalEntryFeeBps, externalExitFeeBps, externalViaAsset, quoteAsset, baseAsset, quoteDecimals, baseDecimals, guardConfig, flashProviderCap, flashProviderName, flashFeeAmount, flashFeeSource, seedPools, targetQuotePerPool, targetTotalQuote, loopCount, atomicBridgeBaseAmount, atomicDestinationAmount, atomicDestinationAsset, atomicDestinationDecimals, atomicCorridorLabel, }) { const repay = repayUsdcWithExactFee(x, flashFeeAmount, flashFeeBps) const effectiveBaseReserve = B + ownedBaseAdd const effectiveQuoteReserve = Q + flashTopupQuote const strategyQuote = Math.max(0, x - flashTopupQuote) const strategyLabel = loopStrategy === 'base-unwind' ? 'base-unwind' : 'quote-push' let leg let externalLeg let availableForRepay let endBaseReserve let endQuoteReserve let step2MetricA let step2MetricB let step2MetricC let step3MetricA let step3MetricB let strategyNote let atomicBaseReserved = 0 let atomicBaseRequested = atomicBridgeBaseAmount ?? 0 let atomicDestinationFulfilled = 0 let unwindBaseAmount = 0 let atomicBridgeShortfall = 0 if (strategyLabel === 'base-unwind') { externalLeg = externalQuoteToBaseOut( strategyQuote, externalEntryPrice, externalEntryFeeBps, quoteDecimals, baseDecimals, ) leg = baseInToQuoteOut(effectiveBaseReserve, effectiveQuoteReserve, externalLeg.baseOut, lpFeeBps) availableForRepay = leg.quoteOut endBaseReserve = effectiveBaseReserve + leg.deltaBaseNet endQuoteReserve = Math.max(0, effectiveQuoteReserve - leg.quoteOut) step2MetricA = ['2', `external_route_${formatExternalRoute(quoteAsset, baseAsset, externalViaAsset).replaceAll(' ', '_')}`, fmtAmount(strategyQuote, quoteDecimals, quoteAsset)] step2MetricB = ['2', 'external_entry_price_effective', fmt(externalLeg.effectivePrice)] step2MetricC = ['2', 'external_base_acquired', fmtAmount(externalLeg.baseOut, baseDecimals, baseAsset)] step3MetricA = ['3', 'pmm_base_in_net', fmtAmount(leg.deltaBaseNet, baseDecimals, baseAsset)] step3MetricB = ['3', 'pmm_quote_out', fmtAmount(leg.quoteOut, quoteDecimals, quoteAsset)] strategyNote = ownedBaseAdd > 0 ? ' note: this is the owned-base-add + external-acquire -> PMM sell-base path, so the source pool starts deeper on base, then gains more base reserve and loses quote reserve. Any temporary flash quote top-up left in the source pool is bounded by the PMM quote out used for repayment.' : ' note: this is the external-acquire -> PMM sell-base path, so the source pool gains base reserve and loses quote reserve. Any temporary flash quote top-up left in the source pool is bounded by the PMM quote out used for repayment.' } else { leg = quoteInToBaseOut(effectiveBaseReserve, effectiveQuoteReserve, strategyQuote, lpFeeBps) atomicBaseReserved = Math.min(Math.max(0, atomicBaseRequested), leg.baseOut) atomicBridgeShortfall = Math.max(0, atomicBaseRequested - leg.baseOut) unwindBaseAmount = Math.max(0, leg.baseOut - atomicBaseReserved) atomicDestinationFulfilled = atomicBaseReserved > 0 ? (atomicDestinationAmount ?? convertRawAmount( atomicBaseReserved, baseDecimals, atomicDestinationDecimals ?? baseDecimals, )) : 0 externalLeg = externalBaseToQuoteOut( unwindBaseAmount, externalExitPrice, externalExitFeeBps, baseDecimals, quoteDecimals, ) availableForRepay = externalLeg.quoteOut endBaseReserve = effectiveBaseReserve - leg.baseOut endQuoteReserve = effectiveQuoteReserve + leg.deltaXNet step2MetricA = ['2', 'pmm_quote_in_net', fmtAmount(leg.deltaXNet, quoteDecimals, quoteAsset)] step2MetricB = ['2', 'pmm_base_out', fmtAmount(leg.baseOut, baseDecimals, baseAsset)] step2MetricC = ['2', 'pmm_vwap_quote_per_base', fmt(rawToHuman(strategyQuote, quoteDecimals) / rawToHuman(leg.baseOut, baseDecimals))] step3MetricA = ['3', `external_route_${formatExternalRoute(baseAsset, quoteAsset, externalViaAsset).replaceAll(' ', '_')}`, fmtAmount(unwindBaseAmount, baseDecimals, baseAsset)] step3MetricB = ['3', 'external_exit_price_effective', fmt(externalLeg.effectivePrice)] strategyNote = ownedBaseAdd > 0 ? ' note: this is the owned-base-add + flash-backed quote-in path, so the source pool starts deeper on base, then permanently gains quote reserve and loses some base reserve if the external unwind covers repayment.' : ' note: this is the flash-backed quote-in path, so the source pool permanently gains quote reserve and loses base reserve if the external unwind covers repayment.' if (atomicBaseReserved > 0) { strategyNote += ` ${fmtAmount(atomicBaseReserved, baseDecimals, baseAsset)} is reserved into the atomic corridor${atomicCorridorLabel ? ` (${atomicCorridorLabel})` : ''}, and only the remaining ${fmtAmount(unwindBaseAmount, baseDecimals, baseAsset)} is unwound back into ${quoteAsset} for flash repayment.` } } const retainedBeforeGas = availableForRepay - repay const retainedAfterGas = retainedBeforeGas - guardConfig.gasReserveQuote const postTradeMarginalPrice = rawToHuman(endBaseReserve, baseDecimals) > 0 ? rawToHuman(endQuoteReserve, quoteDecimals) / rawToHuman(endBaseReserve, baseDecimals) : NaN const postTradeDeviationBps = deviationBps(postTradeMarginalPrice, guardConfig.oraclePrice) const postTradeDeviationAbsBps = Math.abs(postTradeDeviationBps) const gasReserveSummary = summarizeGasReserve(guardConfig) const providerCapOk = flashProviderCap == null ? null : x <= flashProviderCap const effectiveFlashFeeBps = flashFeeAmount != null ? approxBpsFromAmount(x, flashFeeAmount) : flashFeeBps const deviationOk = guardConfig.maxPostTradeDeviationBps == null ? null : postTradeDeviationAbsBps <= guardConfig.maxPostTradeDeviationBps const deploymentPlan = buildQuoteDeploymentSteps({ retainedQuote: retainedAfterGas, seedPools, targetQuotePerPool, targetTotalQuote, loopCount, }) const retainedFloorActive = guardConfig.minRetainedUsdc > 0 const retainedFloorOk = retainedAfterGas >= guardConfig.minRetainedUsdc const deploymentOk = deploymentPlan == null ? null : deploymentPlan.shortfallQuote <= 0 const guardFailures = [] if (providerCapOk === false) guardFailures.push('flash_cap') if (!(availableForRepay >= repay)) guardFailures.push('repay') if (!(retainedAfterGas >= 0)) guardFailures.push('gas') if (retainedFloorActive && !retainedFloorOk) guardFailures.push('retained_floor') if (deviationOk === false) guardFailures.push('post_trade_dev') if (deploymentOk === false) guardFailures.push('deploy_target') if (strategyLabel !== 'quote-push' && atomicBaseRequested > 0) guardFailures.push('atomic_bridge_strategy') if (atomicBridgeShortfall > 0) guardFailures.push('atomic_bridge_base') return { strategyLabel, effectiveBaseReserve, effectiveQuoteReserve, strategyQuote, repay, retainedBeforeGas, retainedAfterGas, endBaseReserve, endQuoteReserve, postTradeMarginalPrice, postTradeDeviationBps, postTradeDeviationAbsBps, gasReserveSummary, providerCapOk, effectiveFlashFeeBps, deviationOk, deploymentPlan, retainedFloorActive, retainedFloorOk, deploymentOk, guardFailures, leg, externalLeg, availableForRepay, step2MetricA, step2MetricB, step2MetricC, step3MetricA, step3MetricB, strategyNote, atomicBaseRequested, atomicBaseReserved, atomicBridgeShortfall, atomicDestinationFulfilled, atomicDestinationAsset: atomicDestinationAsset ?? baseAsset, atomicDestinationDecimals: atomicDestinationDecimals ?? baseDecimals, atomicCorridorLabel, unwindBaseAmount, } } /** * Whitepaper-style ladder: repeated quote-push full-loop dry-runs; after each iteration, * rebalance reserves to matched at the post-trade quote depth (B := Q := endQuoteReserve). * Flash size per step: round(matched * flashNumerator / flashDenominator); defaults match * MAINNET_CWUSD_HYBRID_FLASH_LOOP_CALCULATION_WHITEPAPER.md row 0→1 (6342691 / 256763253). */ function printSequentialMatchedLadder({ iterations, startB, startQ, flashNumerator, flashDenominator, lpFeeBps, flashFeeBps, externalExitPrice, externalExitFeeBps, externalViaAsset, quoteAsset, baseAsset, quoteDecimals, baseDecimals, guardConfig, flashProviderCap, flashProviderName, ownedBaseAdd, flashTopupQuote, atomicBridgeBaseAmount, atomicDestinationAmount, atomicDestinationAsset, atomicDestinationDecimals, atomicCorridorLabel, }) { if (startB !== startQ) { console.error('Error: --sequential-matched-loops requires matched -B and -Q (equal raw reserves)') process.exit(1) } if (!(flashNumerator > 0) || !(flashDenominator > 0)) { console.error('Error: matched flash fraction numerator/denominator must be positive') process.exit(1) } let B = startB let Q = startQ let cumRetained = 0 let cumFlash = 0 let cumBaseRebalance = 0 let completed = 0 let firstFailure = null console.log('Sequential matched-ladder simulation (modeled quote-push + rebalance B=Q=endQuote)\n') console.log(` iterations=${iterations}`) console.log( ` flash sizing: x=round(matched*${flashNumerator}/${flashDenominator}) raw ${quoteAsset} per loop`, ) console.log(` start matched=${rawToHuman(B, quoteDecimals)} ${baseAsset} / ${rawToHuman(Q, quoteDecimals)} ${quoteAsset} (raw ${B})\n`) for (let i = 1; i <= iterations; i++) { const matched = Math.min(B, Q) const x = Math.max(1, Math.round((matched * flashNumerator) / flashDenominator)) const sim = simulateFullLoopDryRun({ B, Q, x, lpFeeBps, flashFeeBps, loopStrategy: 'quote-push', ownedBaseAdd, flashTopupQuote, externalEntryPrice: null, externalExitPrice, externalEntryFeeBps: 0, externalExitFeeBps, externalViaAsset, quoteAsset, baseAsset, quoteDecimals, baseDecimals, guardConfig, flashProviderCap, flashProviderName, flashFeeAmount: null, flashFeeSource: null, seedPools: null, targetQuotePerPool: null, targetTotalQuote: null, loopCount: null, atomicBridgeBaseAmount, atomicDestinationAmount, atomicDestinationAsset, atomicDestinationDecimals, atomicCorridorLabel, }) cumRetained += sim.retainedAfterGas cumFlash += x const baseAddRaw = Math.max(0, Math.round(sim.endQuoteReserve - sim.endBaseReserve)) cumBaseRebalance += baseAddRaw completed = i if (sim.guardFailures.length > 0) { firstFailure = { i, x, sim } break } const nextMatched = Math.round(sim.endQuoteReserve) B = nextMatched Q = nextMatched } const endMatchedHuman = rawToHuman(B, quoteDecimals) console.log('Summary') console.log(` completed_loops=${completed}${firstFailure ? ` (stopped at failure on loop ${firstFailure.i})` : ''}`) console.log( ` end_matched_pool=${fmtAmount(B, quoteDecimals, baseAsset)} / ${fmtAmount(Q, quoteDecimals, quoteAsset)} (human ${endMatchedHuman} each side)`, ) console.log(` cumulative_retained_after_gas=${fmtAmount(cumRetained, quoteDecimals, quoteAsset)}`) console.log(` cumulative_flash_borrowed=${fmtAmount(cumFlash, quoteDecimals, quoteAsset)}`) console.log( ` cumulative_modeled_base_rebalance_raw=${Math.round(cumBaseRebalance)} (${fmtAmount(Math.round(cumBaseRebalance), baseDecimals, baseAsset)} ${baseAsset} added to match quote depth)`, ) console.log('') if (firstFailure) { const { i, x, sim } = firstFailure console.log(`Loop ${i} failed guards: ${sim.guardFailures.join(', ')} (x=${x} raw)`) console.log( ` post_trade_marginal_price=${fmt(sim.postTradeMarginalPrice)} quote/base, deviation_bps=${fmt(sim.postTradeDeviationBps)}`, ) process.exit(2) } } function deriveEstimatedGasQuoteForMainnetStrategy({ strategy, poolAddress, baseAddress, quoteAddress, amountInQuoteRaw, externalEntryPrice, externalEntryFeeBps, quoteDecimals, baseDecimals, nativeTokenPrice, fromAddress, }) { if (!(nativeTokenPrice > 0)) return null if (strategy === 'quote-push') { return tryEstimateMainnetIntegrationGasQuote({ poolAddress, tokenIn: quoteAddress, amountIn: amountInQuoteRaw, quoteDecimals, nativeTokenPrice, fromAddress, }) } if (strategy === 'base-unwind' && externalEntryPrice != null) { const externalLeg = externalQuoteToBaseOut( amountInQuoteRaw, externalEntryPrice, externalEntryFeeBps ?? 0, quoteDecimals, baseDecimals, ) return tryEstimateMainnetIntegrationGasQuote({ poolAddress, tokenIn: baseAddress, amountIn: externalLeg.baseOut, quoteDecimals, nativeTokenPrice, fromAddress, }) } return null } function scaleFixableGuardFailures(guardFailures) { return guardFailures.filter((failure) => failure !== 'flash_cap') } function findMinimumUniformDepthMultiplierForPass(params, maxFactor = 1e6, iterations = 40) { const baseline = simulateFullLoopDryRun(params) if (scaleFixableGuardFailures(baseline.guardFailures).length === 0) { return { factor: 1, addedBase: 0, addedQuote: 0, simulation: baseline, } } let lo = 1 let hi = 1 let hiSimulation = baseline while (hi < maxFactor) { hi *= 2 hiSimulation = simulateFullLoopDryRun({ ...params, B: params.B * hi, Q: params.Q * hi, }) if (scaleFixableGuardFailures(hiSimulation.guardFailures).length === 0) break } if (scaleFixableGuardFailures(hiSimulation.guardFailures).length !== 0) { return null } for (let i = 0; i < iterations; i += 1) { const mid = (lo + hi) / 2 const midSimulation = simulateFullLoopDryRun({ ...params, B: params.B * mid, Q: params.Q * mid, }) if (scaleFixableGuardFailures(midSimulation.guardFailures).length === 0) { hi = mid hiSimulation = midSimulation } else { lo = mid } } return { factor: hi, addedBase: params.B * (hi - 1), addedQuote: params.Q * (hi - 1), simulation: hiSimulation, } } function findMaxAtomicBridgeReservation(params, maxBaseReserve = null, iterations = 40) { if (params.loopStrategy !== 'quote-push') return null const baseline = simulateFullLoopDryRun({ ...params, atomicBridgeBaseAmount: 0, atomicDestinationAmount: 0, }) const availableBase = Math.max(0, maxBaseReserve ?? baseline.leg?.baseOut ?? 0) if (!(availableBase > 0)) { return { maxBaseAvailable: 0, positiveAfterGas: { amount: 0, simulation: baseline }, repayOnly: { amount: 0, simulation: baseline }, } } const positivePredicate = (simulation) => simulation.guardFailures.length === 0 const repayOnlyPredicate = (simulation) => { const failures = simulation.guardFailures.filter((failure) => !['gas', 'retained_floor', 'deploy_target'].includes(failure)) return failures.length === 0 && simulation.availableForRepay >= simulation.repay } function solve(predicate) { let lo = 0 let hi = availableBase let bestSimulation = baseline for (let i = 0; i < iterations; i += 1) { const mid = Math.floor((lo + hi + 1) / 2) const simulation = simulateFullLoopDryRun({ ...params, atomicBridgeBaseAmount: mid, atomicDestinationAmount: params.atomicDestinationAmount ?? mid, }) if (predicate(simulation)) { lo = mid bestSimulation = simulation } else { hi = mid - 1 } } const finalSimulation = lo === 0 ? simulateFullLoopDryRun({ ...params, atomicBridgeBaseAmount: 0, atomicDestinationAmount: params.atomicDestinationAmount ?? 0, }) : bestSimulation return { amount: lo, simulation: finalSimulation } } return { maxBaseAvailable: availableBase, positiveAfterGas: solve(positivePredicate), repayOnly: solve(repayOnlyPredicate), } } function fullLoopFailureScore(candidate) { const { simulation, x } = candidate let score = simulation.guardFailures.length * 1e12 if (simulation.guardFailures.includes('flash_cap') && candidate.flashProviderCap != null) { score += Math.max(0, x - candidate.flashProviderCap) * 1e3 } if (simulation.guardFailures.includes('repay')) { score += Math.max(0, simulation.repay - simulation.availableForRepay) * 1e2 } if (simulation.guardFailures.includes('gas')) { score += Math.max(0, -simulation.retainedAfterGas) * 10 } if (simulation.guardFailures.includes('retained_floor')) { score += Math.max(0, candidate.guardConfig.minRetainedUsdc - simulation.retainedAfterGas) * 10 } if (simulation.guardFailures.includes('deploy_target') && simulation.deploymentPlan?.totalTarget > 0) { score += (simulation.deploymentPlan.shortfallQuote / simulation.deploymentPlan.totalTarget) * 1e6 } if (simulation.guardFailures.includes('post_trade_dev')) { score += simulation.postTradeDeviationAbsBps } return score } function compareFullLoopCandidates(a, b) { const aPass = a.simulation.guardFailures.length === 0 const bPass = b.simulation.guardFailures.length === 0 if (aPass !== bPass) return Number(bPass) - Number(aPass) if (aPass && bPass) { const aFunded = a.simulation.deploymentPlan?.fullyFundedCount ?? 0 const bFunded = b.simulation.deploymentPlan?.fullyFundedCount ?? 0 if (aFunded !== bFunded) return bFunded - aFunded const aDeployed = a.simulation.deploymentPlan?.deployedTotal ?? 0 const bDeployed = b.simulation.deploymentPlan?.deployedTotal ?? 0 if (aDeployed !== bDeployed) return bDeployed - aDeployed if (a.simulation.retainedAfterGas !== b.simulation.retainedAfterGas) { return b.simulation.retainedAfterGas - a.simulation.retainedAfterGas } if (a.simulation.postTradeDeviationAbsBps !== b.simulation.postTradeDeviationAbsBps) { return a.simulation.postTradeDeviationAbsBps - b.simulation.postTradeDeviationAbsBps } return b.x - a.x } if (a.simulation.guardFailures.length !== b.simulation.guardFailures.length) { return a.simulation.guardFailures.length - b.simulation.guardFailures.length } const aScore = fullLoopFailureScore(a) const bScore = fullLoopFailureScore(b) if (aScore !== bScore) return aScore - bScore if (a.simulation.postTradeDeviationAbsBps !== b.simulation.postTradeDeviationAbsBps) { return a.simulation.postTradeDeviationAbsBps - b.simulation.postTradeDeviationAbsBps } if (a.simulation.retainedAfterGas !== b.simulation.retainedAfterGas) { return b.simulation.retainedAfterGas - a.simulation.retainedAfterGas } return a.x - b.x } function buildFullLoopMethodologies(params, simulation, depthPlan) { const methods = [] const { strategyLabel, deploymentPlan, retainedAfterGas, guardFailures, availableForRepay, repay, } = simulation const { x, baseAsset, quoteAsset, baseDecimals, quoteDecimals, ownedBaseAdd, flashTopupQuote, flashProviderCap, guardConfig, atomicBridgeBaseAmount, atomicDestinationAsset, } = params if (guardFailures.length === 0) { methods.push( `Repay first, then seed only retained ${quoteAsset}. This run leaves ${fmtAmount(retainedAfterGas, quoteDecimals, quoteAsset)} after gas${deploymentPlan ? ` and can fully fund ${deploymentPlan.fullyFundedCount}/${deploymentPlan.rows.length} planned pool targets` : ''}.`, ) if (ownedBaseAdd > 0) { methods.push( `The owned ${baseAsset} contribution is durable base-side depth. In this hybrid mode, the flash loan is only temporary ${quoteAsset} working capital while the owned base stays in the pool.`, ) } } else { if (depthPlan && depthPlan.factor > 1) { methods.push( `Uniformly deepen the source PMM by about ${fmt(depthPlan.factor)}x before retrying this exact tranche: add roughly ${fmtAmount(depthPlan.addedBase, baseDecimals, baseAsset)} and ${fmtAmount(depthPlan.addedQuote, quoteDecimals, quoteAsset)}.`, ) } if (guardFailures.includes('repay')) { methods.push( `Improve the external unwind or reduce size before retrying: current proceeds ${fmtAmount(availableForRepay, quoteDecimals, quoteAsset)} do not cover flash repayment ${fmtAmount(repay, quoteDecimals, quoteAsset)}.`, ) } if (guardFailures.includes('gas')) { methods.push( `Reserve or top up native gas before execution. Retained quote after gas is ${fmtAmount(retainedAfterGas, quoteDecimals, quoteAsset)} under the current gas assumptions.`, ) } if (guardFailures.includes('retained_floor')) { methods.push( `Lower the retained-${quoteAsset} floor, improve external execution, or shrink the tranche so the loop leaves at least ${fmtAmount(guardConfig.minRetainedUsdc, quoteDecimals, quoteAsset)} after gas.`, ) } if (guardFailures.includes('deploy_target') && deploymentPlan) { methods.push( `Current retained quote only funds ${deploymentPlan.fullyFundedCount}/${deploymentPlan.rows.length} target pool steps. Either lower the deployment target or accumulate retained ${quoteAsset} off-venue first, then seed the public pools.`, ) } if (guardFailures.includes('flash_cap')) { methods.push( `The requested borrow ${fmtAmount(x, quoteDecimals, quoteAsset)} exceeds the current flash source cap${flashProviderCap != null ? ` ${fmtAmount(flashProviderCap, quoteDecimals, quoteAsset)}` : ''}. Switch flash source or shrink the tranche.`, ) } } if (strategyLabel === 'quote-push') { methods.push( `${strategyLabel} permanently deepens quote reserve Q and drains base reserve B. If your end goal is stronger public quote liquidity, this is the right direction, but seed base-side depth first or use smaller staged tranches so the base side does not become the peg bottleneck.`, ) } else { methods.push( `${strategyLabel} deepens base reserve B but drains quote reserve Q. Use it when the public pool needs more ${baseAsset}, but pair it with direct ${quoteAsset} seeding or a prior quote-build phase if quote-side liquidity is the end goal.`, ) } if (flashTopupQuote > 0) { methods.push( `Treat --flash-topup-quote as temporary execution support only. It helps the strategy leg, but it does not create durable pool depth unless retained ${quoteAsset} remains after repayment and is left in the pool on purpose.`, ) } if (ownedBaseAdd > 0) { methods.push( `Hybrid methodology: add owned ${baseAsset} first, use flash-borrowed ${quoteAsset} only for the execution leg, repay from external ${quoteAsset} proceeds, and leave only retained ${quoteAsset} behind. That is the durable two-sided depth-building path.`, ) } if (atomicBridgeBaseAmount > 0) { methods.push( `Atomic bridge split methodology: reserve ${fmtAmount(atomicBridgeBaseAmount, baseDecimals, baseAsset)} of acquired ${baseAsset} into the destination corridor${atomicDestinationAsset ? ` for immediate ${atomicDestinationAsset} fulfillment` : ''}, and only unwind the remaining ${baseAsset} back into ${quoteAsset}. This improves cross-chain destination liquidity but reduces same-chain repayment headroom.`, ) } if (guardFailures.includes('post_trade_dev')) { methods.push( 'If the public pool is still canary-sized, run the profit leg on a deeper internal/private venue first and only deploy the retained quote into the public PMM afterward. The flash loop should support deployment, not force the public pool to absorb the whole trade at once.', ) methods.push( 'Use staged tranches from --scan to find the largest size that stays inside the deviation cap, then only scale size after the prior loop has already deepened the pool.', ) } return [...new Set(methods)] } function printFullLoopRecommendation(params, simulation, options = {}) { const { executionClass = null, executionGradeRequired = false } = options const depthPlan = simulation.guardFailures.length === 0 ? null : findMinimumUniformDepthMultiplierForPass(params) const methods = buildFullLoopMethodologies(params, simulation, depthPlan) const deploymentPlan = simulation.deploymentPlan const canaryThreshold = humanToRaw(1, params.quoteDecimals) const canarySizedPass = simulation.guardFailures.length === 0 && !deploymentPlan && simulation.retainedAfterGas < canaryThreshold console.log('Recommendation') if (simulation.guardFailures.length === 0) { if (executionGradeRequired && executionClass !== 'execution-ready') { console.log( ` Economically passes as modeled, but do not execute it yet. The tranche at ${fmtAmount(params.x, params.quoteDecimals, params.quoteAsset)} using ${simulation.strategyLabel} is still blocked by the execution-grade gate.`, ) } else if (executionClass != null && executionClass !== 'execution-ready') { console.log( ` Economically passes as modeled at ${fmtAmount(params.x, params.quoteDecimals, params.quoteAsset)} using ${simulation.strategyLabel}, but this remains planning-only until the live execution inputs are upgraded.`, ) } else { console.log( ` Executable as modeled: start with ${fmtAmount(params.x, params.quoteDecimals, params.quoteAsset)} using ${simulation.strategyLabel}. It retains ${fmtAmount(simulation.retainedAfterGas, params.quoteDecimals, params.quoteAsset)} after gas${deploymentPlan ? ` and deploys ${fmtAmount(deploymentPlan.deployedTotal, params.quoteDecimals, params.quoteAsset)} into target pools` : ''}.`, ) } if (canarySizedPass) { console.log( ` This is still canary-sized, not a meaningful public depth program yet: retained quote is below ${fmtAmount(canaryThreshold, params.quoteDecimals, params.quoteAsset)}.`, ) } } else { console.log( ` Do not execute this tranche as modeled. Failing guards=${simulation.guardFailures.join(', ')}.`, ) if (depthPlan && depthPlan.factor > 1) { console.log( ` Closest structural fix: deepen the source pool by about ${fmt(depthPlan.factor)}x before retrying this exact tranche.`, ) } else if (simulation.guardFailures.includes('post_trade_dev')) { console.log( ' Current external assumptions plus current public-pool depth are not enough; improve venue economics, lower size, or seed depth first.', ) } } console.log('') console.log('Methodologies to increase depth') methods.forEach((method, index) => { console.log(` ${index + 1}. ${method}`) }) console.log('') } function isMaterialPublicCandidate(candidate) { if (!candidate || candidate.simulation.guardFailures.length !== 0) return false if (candidate.simulation.deploymentPlan) { return candidate.simulation.deploymentPlan.deployedTotal > 0 } return candidate.simulation.retainedAfterGas >= humanToRaw(1, candidate.params.quoteDecimals) } function printFullLoopDryRun(params) { const { B, Q, x, lpFeeBps, ownedBaseAdd, flashTopupQuote, externalEntryFeeBps, externalExitFeeBps, quoteAsset, baseAsset, quoteDecimals, baseDecimals, guardConfig, flashProviderCap, flashProviderName, flashFeeSource, seedPools, targetQuotePerPool, targetTotalQuote, loopCount, quoteSurface, externalEntrySource, externalExitSource, livePoolFeeBps, executionGradeRequired, atomicBridgeBaseAmount, atomicDestinationAmount, atomicDestinationAsset, atomicDestinationDecimals, atomicCorridorLabel, } = params const simulation = simulateFullLoopDryRun(params) const executionBlocks = listExecutionReadinessBlocks({ strategyLabel: params.loopStrategy, quoteSurface, externalEntrySource, externalExitSource, gasReserveMode: guardConfig.gasReserveMode, maxPostTradeDeviationBps: guardConfig.maxPostTradeDeviationBps, }) const executionClass = classifyExecutionReadiness({ strategyLabel: params.loopStrategy, quoteSurface, externalEntrySource, externalExitSource, gasReserveMode: guardConfig.gasReserveMode, maxPostTradeDeviationBps: guardConfig.maxPostTradeDeviationBps, }) const modeledStatusLabel = executionClass === 'execution-ready' ? 'status' : 'modeled status' const { strategyLabel, effectiveBaseReserve, effectiveQuoteReserve, strategyQuote, repay, retainedBeforeGas, retainedAfterGas, endBaseReserve, endQuoteReserve, postTradeMarginalPrice, postTradeDeviationBps, postTradeDeviationAbsBps, gasReserveSummary, providerCapOk, effectiveFlashFeeBps, deviationOk, deploymentPlan, retainedFloorActive, retainedFloorOk, guardFailures, leg, availableForRepay, step2MetricA, step2MetricB, step2MetricC, step3MetricA, step3MetricB, strategyNote, atomicBaseRequested, atomicBaseReserved, atomicBridgeShortfall, atomicDestinationFulfilled, unwindBaseAmount, } = simulation const atomicBridgeScan = params.scanAtomicBridgeMax && strategyLabel === 'quote-push' ? findMaxAtomicBridgeReservation(params, leg?.baseOut ?? null) : null console.log('Full loop dry-run — flexible flash-backed PMM loop, repay, and retained quote deployment\n') console.log(` strategy=${strategyLabel}`) console.log(` execution class=${executionClass}`) if (quoteSurface) { console.log(` pool quote surface=${quoteSurface.surface} (${quoteSurface.source})`) } console.log(` flash provider=${flashProviderName}`) console.log( ` source PMM reserves: B=${fmtAmount(B, baseDecimals, baseAsset)}, Q=${fmtAmount(Q, quoteDecimals, quoteAsset)}`, ) if (ownedBaseAdd > 0) { console.log( ` owned base add to source pool=${fmtAmount(ownedBaseAdd, baseDecimals, baseAsset)} (effective source B=${fmtAmount(effectiveBaseReserve, baseDecimals, baseAsset)})`, ) } console.log(` flash borrow size=${fmtAmount(x, quoteDecimals, quoteAsset)}`) if (flashTopupQuote > 0) { console.log( ` temporary flash quote top-up to source pool=${fmtAmount(flashTopupQuote, quoteDecimals, quoteAsset)} (effective source Q=${fmtAmount(effectiveQuoteReserve, quoteDecimals, quoteAsset)})`, ) } console.log(` strategy quote budget=${fmtAmount(strategyQuote, quoteDecimals, quoteAsset)}`) console.log( ` pool fee=${fmt(livePoolFeeBps ?? lpFeeBps)} bps flash fee=${fmt(effectiveFlashFeeBps)} bps external entry fee=${fmt(externalEntryFeeBps)} bps external exit fee=${fmt(externalExitFeeBps)} bps`, ) if (flashFeeSource) { console.log(` flash fee source=${flashFeeSource}`) } console.log(` external entry source=${externalEntrySource ?? 'n/a'}`) console.log(` external exit source=${externalExitSource ?? 'n/a'}`) if (atomicBridgeBaseAmount > 0) { console.log( ` atomic corridor reservation=${fmtAmount(atomicBridgeBaseAmount, baseDecimals, baseAsset)}${atomicCorridorLabel ? ` via ${atomicCorridorLabel}` : ''}`, ) console.log( ` atomic destination fulfillment target=${fmtAmount( atomicDestinationAmount ?? convertRawAmount(atomicBridgeBaseAmount, baseDecimals, atomicDestinationDecimals), atomicDestinationDecimals, atomicDestinationAsset, )}`, ) } console.log(` oracle price=${fmt(guardConfig.oraclePrice)} ${quoteAsset} per ${baseAsset}`) if (flashProviderCap != null) { console.log( ` flash source cap=${fmtAmount(flashProviderCap, quoteDecimals, quoteAsset)} (${providerCapOk ? 'pass' : 'exceeds cap'})`, ) } else { console.log(' flash source cap=not checked (set --flash-provider-cap to enforce borrow ceiling)') } if (guardConfig.gasReserveQuote > 0) { console.log( ` native gas reserve=${fmt(guardConfig.gasReserveNative)} native = ${fmt(guardConfig.gasReserveQuoteHuman)} ${quoteAsset} (${gasReserveSummary})`, ) } if (executionClass !== 'execution-ready') { console.log( ' warning: this output is planning-only until the tool has the required live pool quote surface, live external quote source(s), measured or live-estimated gas, and an explicit post-trade deviation cap.', ) } if (retainedFloorActive) { console.log(` retained ${quoteAsset} floor after gas=${fmtAmount(guardConfig.minRetainedUsdc, quoteDecimals, quoteAsset)}`) } if (guardConfig.maxPostTradeDeviationBps != null) { console.log(` max post-trade deviation=${fmt(guardConfig.maxPostTradeDeviationBps)} bps`) } console.log('') console.log('step\tmetric\tvalue') if (ownedBaseAdd > 0) { console.log(`0\towned_base_added_to_pool\t${fmtAmount(ownedBaseAdd, baseDecimals, baseAsset)}`) console.log(`0\teffective_source_base_reserve\t${fmtAmount(effectiveBaseReserve, baseDecimals, baseAsset)}`) } console.log(`1\tflash_quote_borrowed\t${fmtAmount(x, quoteDecimals, quoteAsset)}`) if (flashTopupQuote > 0) { console.log(`1\tflash_quote_temp_pool_topup\t${fmtAmount(flashTopupQuote, quoteDecimals, quoteAsset)}`) console.log(`1\tflash_quote_left_for_strategy\t${fmtAmount(strategyQuote, quoteDecimals, quoteAsset)}`) } console.log(step2MetricA.join('\t')) console.log(step2MetricB.join('\t')) console.log(step2MetricC.join('\t')) if (atomicBaseRequested > 0) { console.log(`3\tatomic_base_requested\t${fmtAmount(atomicBaseRequested, baseDecimals, baseAsset)}`) console.log(`3\tatomic_base_reserved\t${fmtAmount(atomicBaseReserved, baseDecimals, baseAsset)}`) console.log( `3\tatomic_destination_fulfilled\t${fmtAmount(atomicDestinationFulfilled, atomicDestinationDecimals, atomicDestinationAsset)}`, ) console.log(`3\tbase_remaining_for_unwind\t${fmtAmount(unwindBaseAmount, baseDecimals, baseAsset)}`) if (atomicBridgeShortfall > 0) { console.log(`3\tatomic_bridge_shortfall\t${fmtAmount(atomicBridgeShortfall, baseDecimals, baseAsset)}`) } } console.log(step3MetricA.join('\t')) console.log(step3MetricB.join('\t')) if (strategyLabel === 'quote-push') { console.log(`3\texternal_quote_proceeds\t${fmtAmount(availableForRepay, quoteDecimals, quoteAsset)}`) } else { console.log(`3\tpmm_vwap_quote_per_base\t${fmt(leg.vwapQuotePerBase)}`) console.log(`3\tquote_available_for_repay\t${fmtAmount(availableForRepay, quoteDecimals, quoteAsset)}`) } console.log(`4\tflash_fee_amount\t${fmtAmount(repay - x, quoteDecimals, quoteAsset)}`) console.log(`4\tflash_repay\t${fmtAmount(repay, quoteDecimals, quoteAsset)}`) console.log(`4\tretained_before_gas\t${fmtAmount(retainedBeforeGas, quoteDecimals, quoteAsset)}`) console.log(`5\tgas_reserve_quote\t${fmtAmount(guardConfig.gasReserveQuote, quoteDecimals, quoteAsset)}`) console.log(`5\tretained_after_gas\t${fmtAmount(retainedAfterGas, quoteDecimals, quoteAsset)}`) console.log(`6\tsource_pool_base_delta\t${fmtAmount(endBaseReserve - B, baseDecimals, baseAsset)}`) console.log(`6\tsource_pool_quote_delta\t${fmtAmount(endQuoteReserve - Q, quoteDecimals, quoteAsset)}`) console.log(`6\tpost_trade_marginal_price\t${fmt(postTradeMarginalPrice)}`) console.log(`6\tpost_trade_dev_bps\t${fmt(postTradeDeviationBps)}`) console.log('') console.log( ` ${modeledStatusLabel}=${guardFailures.length === 0 ? 'pass' : 'fail'}${guardFailures.length === 0 ? '' : ` (${guardFailures.join('+')})`}`, ) console.log( ` repay check=${availableForRepay >= repay ? 'pass' : 'fail'} (${fmtAmount(availableForRepay, quoteDecimals, quoteAsset)} proceeds vs ${fmtAmount(repay, quoteDecimals, quoteAsset)} repay)`, ) console.log( ` retained after gas=${retainedAfterGas >= 0 ? 'pass' : 'fail'} (${fmtAmount(retainedAfterGas, quoteDecimals, quoteAsset)})`, ) if (retainedFloorActive) { console.log( ` retained floor after gas=${retainedFloorOk ? 'pass' : 'fail'} (${fmtAmount(retainedAfterGas, quoteDecimals, quoteAsset)} vs floor ${fmtAmount( guardConfig.minRetainedUsdc, quoteDecimals, quoteAsset, )})`, ) } if (deviationOk != null) { console.log( ` post-trade deviation guard=${deviationOk ? 'pass' : 'fail'} (${fmt(postTradeDeviationAbsBps)} bps abs)`, ) } console.log( ` source pool end state: B=${fmtAmount(endBaseReserve, baseDecimals, baseAsset)}, Q=${fmtAmount(endQuoteReserve, quoteDecimals, quoteAsset)}`, ) console.log(` source pool base deepening=${endBaseReserve > B ? 'yes' : 'no'} quote deepening=${endQuoteReserve > Q ? 'yes' : 'no'}`) console.log(strategyNote) console.log('') if (atomicBridgeScan) { console.log('Atomic bridge reservation scan') console.log( ` PMM-acquired base available=${fmtAmount(atomicBridgeScan.maxBaseAvailable, baseDecimals, baseAsset)}`, ) console.log( ` max reservation with positive retained-after-gas=${fmtAmount( atomicBridgeScan.positiveAfterGas.amount, baseDecimals, baseAsset, )}`, ) console.log( ` retained_after_gas=${fmtAmount( atomicBridgeScan.positiveAfterGas.simulation.retainedAfterGas, quoteDecimals, quoteAsset, )}`, ) console.log( ` max reservation with repay-only pass=${fmtAmount( atomicBridgeScan.repayOnly.amount, baseDecimals, baseAsset, )}`, ) console.log( ` retained_after_gas=${fmtAmount( atomicBridgeScan.repayOnly.simulation.retainedAfterGas, quoteDecimals, quoteAsset, )}`, ) console.log('') } if (executionGradeRequired && executionClass !== 'execution-ready') { console.log('Execution-grade gate') console.log(' status=blocked') console.log(` reason=missing ${executionBlocks.join(', ')}`) console.log('') return } printQuoteDeploymentPlan({ retainedQuote: retainedAfterGas, quoteAsset, quoteDecimals, seedPools, targetQuotePerPool, targetTotalQuote, loopCount, }) printFullLoopRecommendation(params, simulation, { executionClass, executionGradeRequired, }) } function strategyListForPublicSweep(loopStrategy) { return loopStrategy === 'both' ? ['quote-push', 'base-unwind'] : [loopStrategy] } function defaultPublicSweepSizes(quoteDecimals) { return [0.1, 0.25, 0.5, 1, 2, 4].map((amount) => humanToRaw(amount, quoteDecimals)) } function resolvePublicFlashSource({ publicFlashSource, quoteAddress, flashProviderCap, flashProviderName, flashFeeBps, }) { if (publicFlashSource === 'manual') { return { providerKey: 'manual', providerName: flashProviderName, providerAddress: null, capRaw: flashProviderCap, feeBps: flashFeeBps, feeRaw: null, source: 'manual CLI/env flash source', } } const liveSource = publicFlashSource === 'balancer' ? tryReadMainnetBalancerFlashSource(quoteAddress) : tryReadMainnetAaveFlashSource(quoteAddress) if (!liveSource) return null return { ...liveSource, capRaw: liveSource.capRaw != null && flashProviderCap != null ? Math.min(liveSource.capRaw, flashProviderCap) : (flashProviderCap ?? liveSource.capRaw), } } function buildPublicFlashTerms(flashSource, amount, fallbackFlashFeeBps) { const effectiveFlashFeeBps = flashSource?.feeBps ?? fallbackFlashFeeBps return { flashProviderCap: flashSource?.capRaw ?? null, flashProviderName: flashSource?.providerName ?? 'flash provider', flashFeeAmount: null, flashFeeBps: effectiveFlashFeeBps, flashFeeSource: flashSource?.source ?? `manual flash fee bps (${fmt(effectiveFlashFeeBps)})`, effectiveFlashFeeBps, } } function buildPublicLiveSweepCandidate({ pool, reserves, livePoolFeeBps, quoteSurface, x, strategy, ownedBaseAdd, flashSource, fallbackFlashFeeBps, baseDecimals, quoteDecimals, guardConfig, flashTopupQuote, externalEntryPrice, externalExitPrice, externalEntryFeeBps, externalExitFeeBps, externalViaAsset, atomicBridgeBaseAmount, atomicDestinationAmount, atomicDestinationAsset, atomicDestinationDecimals, atomicCorridorLabel, seedPools, targetQuotePerPool, targetTotalQuote, loopCount, externalEntrySource, externalExitSource, fromAddress, }) { const estimatedGasQuote = deriveEstimatedGasQuoteForMainnetStrategy({ strategy, poolAddress: pool.poolAddress, baseAddress: pool.baseAddress, quoteAddress: pool.quoteAddress, amountInQuoteRaw: x, externalEntryPrice, externalEntryFeeBps, quoteDecimals, baseDecimals, nativeTokenPrice: guardConfig.nativeTokenPrice, fromAddress, }) const candidateGuardConfig = guardConfig.gasReserveMode === 'modeled_native' && estimatedGasQuote ? buildInventoryLoopGuardConfig({ minRetainedUsdc: guardConfig.minRetainedUsdc, gasTxCount: null, gasPerTx: null, maxFeeGwei: null, nativeTokenPrice: guardConfig.nativeTokenPrice, quoteDecimals, oraclePrice: guardConfig.oraclePrice, maxPostTradeDeviationBps: guardConfig.maxPostTradeDeviationBps, maxCwBurnFraction: guardConfig.maxCwBurnFraction, cooldownBlocks: guardConfig.cooldownBlocks, measuredGasQuote: null, measuredGasSource: null, estimatedGasQuote: estimatedGasQuote.quoteCost, estimatedGasSource: estimatedGasQuote.source, }) : guardConfig const flashTerms = buildPublicFlashTerms(flashSource, x, fallbackFlashFeeBps) const params = { B: reserves.baseReserve, Q: reserves.quoteReserve, x, lpFeeBps: livePoolFeeBps ?? pool.feeBps ?? 10, flashFeeBps: flashTerms.flashFeeBps, loopStrategy: strategy, ownedBaseAdd, flashTopupQuote, externalEntryPrice, externalExitPrice, externalEntryFeeBps, externalExitFeeBps, externalViaAsset, quoteAsset: pool.quote, baseAsset: pool.base, quoteDecimals, baseDecimals, guardConfig: candidateGuardConfig, flashProviderCap: flashTerms.flashProviderCap, flashProviderName: flashTerms.flashProviderName, flashFeeAmount: flashTerms.flashFeeAmount, flashFeeSource: flashTerms.flashFeeSource, atomicBridgeBaseAmount, atomicDestinationAmount, atomicDestinationAsset, atomicDestinationDecimals, atomicCorridorLabel, seedPools, targetQuotePerPool, targetTotalQuote, loopCount, } const simulation = simulateFullLoopDryRun(params) const depthPlan = simulation.guardFailures.length === 0 ? null : findMinimumUniformDepthMultiplierForPass(params) return { pool, x, strategy, flashSource, quoteSurface, livePoolFeeBps, params, simulation, depthPlan, flashProviderCap: flashTerms.flashProviderCap, executionClass: classifyExecutionReadiness({ strategyLabel: strategy, quoteSurface, externalEntrySource, externalExitSource, gasReserveMode: candidateGuardConfig.gasReserveMode, maxPostTradeDeviationBps: candidateGuardConfig.maxPostTradeDeviationBps, }), } } function printPublicLiveSweep({ scanStr, loopStrategy, ownedBaseAdd, flashTopupQuote, flashProviderCap, flashProviderName, flashFeeBps, externalEntryPrice, externalExitPrice, externalEntryFeeBps, externalExitFeeBps, externalViaAsset, atomicBridgeBaseAmount, atomicDestinationAmount, atomicDestinationAsset, atomicDestinationDecimals, atomicCorridorLabel, seedPools, targetQuotePerPool, targetTotalQuote, loopCount, guardConfig, publicFlashSource, externalEntrySource, externalExitSource, executionGradeRequired, }) { const pools = loadLiveMainnetPublicUsdPools() if (pools.length === 0) { console.error('Error: no live mainnet cWUSD*/USD* PMM pools were found in deployment-status.json') process.exit(1) } const rpcUrl = rpcUrlForChain(1) if (!rpcUrl) { console.error('Error: --public-live-sweep requires ETHEREUM_MAINNET_RPC') process.exit(1) } const strategies = strategyListForPublicSweep(loopStrategy) const sweepRows = [] const fromAddress = process.env.DEPLOYER_ADDRESS ?? '0x4A666F96fC8764181194447A7dFdb7d471b301C8' for (const pool of pools) { const reserves = tryReadPoolReservesViaCast(1, pool.poolAddress) if (!reserves) { sweepRows.push({ pool, strategy: 'n/a', best: null, error: `could not read live reserves for ${pool.poolAddress}`, }) continue } const baseDecimals = tryReadTokenDecimalsViaCast(1, pool.baseAddress) ?? 6 const quoteDecimals = tryReadTokenDecimalsViaCast(1, pool.quoteAddress) ?? 6 const scanSizes = scanStr ? scanStr.split(',').map((size) => parseNum(size.trim())) : defaultPublicSweepSizes(quoteDecimals) const flashSource = resolvePublicFlashSource({ publicFlashSource, quoteAddress: pool.quoteAddress, flashProviderCap, flashProviderName, flashFeeBps, }) const livePoolFeeBps = tryReadPoolFeeBpsViaCast(1, pool.poolAddress) const quoteSurface = tryProbePoolQuoteSurfaceViaCast( 1, pool.poolAddress, fromAddress, ) for (const strategy of strategies) { const candidates = scanSizes.map((x) => buildPublicLiveSweepCandidate({ pool, reserves, livePoolFeeBps, quoteSurface, x, strategy, ownedBaseAdd, flashSource, fallbackFlashFeeBps: flashFeeBps, baseDecimals, quoteDecimals, guardConfig, flashTopupQuote, externalEntryPrice, externalExitPrice, externalEntryFeeBps, externalExitFeeBps, externalViaAsset, atomicBridgeBaseAmount, atomicDestinationAmount, atomicDestinationAsset, atomicDestinationDecimals, atomicCorridorLabel, seedPools, targetQuotePerPool, targetTotalQuote, loopCount, externalEntrySource, externalExitSource, fromAddress, }), ) const best = [...candidates].sort(compareFullLoopCandidates)[0] ?? null sweepRows.push({ pool, strategy, best, candidates, reserves, flashSource, quoteSurface, livePoolFeeBps, error: flashSource == null ? `could not resolve ${publicFlashSource} flash source for ${pool.quote}` : null, }) } } console.log('Public live sweep — mainnet cWUSD*/USD* PMM pools\n') console.log(' chain=Ethereum mainnet') console.log(` flash source mode=${publicFlashSource}`) console.log(` strategies=${strategies.join(', ')}`) console.log( ` scan sizes=${(scanStr ? scanStr.split(',').map((size) => parseNum(size.trim())) : defaultPublicSweepSizes(6)) .map((size) => fmt(size)) .join(', ')} raw quote units`, ) if (guardConfig.gasReserveQuote > 0) { console.log( ` gas reserve=${fmt(guardConfig.gasReserveQuote)} raw quote units (${summarizeGasReserve(guardConfig)})`, ) } if (guardConfig.maxPostTradeDeviationBps != null) { console.log(` max post-trade deviation=${fmt(guardConfig.maxPostTradeDeviationBps)} bps`) } console.log('') console.log( 'pool\tstrategy\texecution_class\tquote_surface\tfee_bps\tbest_x\tstatus\tguards\tretained_after_gas\tpost_trade_dev_bps\tfunded_steps\tdepth_needed', ) for (const row of sweepRows) { if (row.error || !row.best) { console.log( [ row.pool?.poolAddress ?? 'unknown', row.strategy, 'blocked', 'unknown', 'n/a', 'n/a', 'error', row.error ?? 'n/a', 'n/a', 'n/a', 'n/a', 'n/a', ].join('\t'), ) continue } const { best } = row const fundedSteps = best.simulation.deploymentPlan ? `${best.simulation.deploymentPlan.fullyFundedCount}/${best.simulation.deploymentPlan.rows.length}` : 'n/a' const depthNeeded = best.depthPlan && best.depthPlan.factor > 1 ? `${fmt(best.depthPlan.factor)}x` : 'pass' const executionClass = row.best.executionClass const rowModeledPass = best.simulation.guardFailures.length === 0 const rowStatus = executionGradeRequired && executionClass !== 'execution-ready' ? 'blocked' : rowModeledPass ? executionClass === 'execution-ready' ? 'pass' : 'planning-pass' : 'closest' const rowGuards = executionGradeRequired && executionClass !== 'execution-ready' ? 'execution_gate' : rowModeledPass ? executionClass === 'execution-ready' ? 'pass' : 'modeled_only' : best.simulation.guardFailures.join('+') console.log( [ `${row.pool.base}/${row.pool.quote}`, row.strategy, executionClass, row.quoteSurface?.surface ?? 'unknown', fmt(row.livePoolFeeBps ?? row.pool.feeBps ?? NaN), fmtAmount(best.x, best.params.quoteDecimals, best.params.quoteAsset), rowStatus, rowGuards, fmtAmount( best.simulation.retainedAfterGas, best.params.quoteDecimals, best.params.quoteAsset, ), fmt(best.simulation.postTradeDeviationBps), fundedSteps, depthNeeded, ].join('\t'), ) } const viable = sweepRows .map((row) => row.best) .filter( (candidate) => candidate && candidate.simulation.guardFailures.length === 0 && (!executionGradeRequired || candidate.executionClass === 'execution-ready'), ) .sort(compareFullLoopCandidates) const materiallyUseful = viable.filter(isMaterialPublicCandidate) const closest = sweepRows .map((row) => row.best) .filter(Boolean) .sort(compareFullLoopCandidates)[0] const failedCandidates = sweepRows .flatMap((row) => row.candidates ?? []) .filter((candidate) => candidate.simulation.guardFailures.length > 0) const preferredFailedCandidates = failedCandidates.filter( (candidate) => candidate.strategy === 'quote-push', ) const closestFail = [...(preferredFailedCandidates.length > 0 ? preferredFailedCandidates : failedCandidates)].sort( compareFullLoopCandidates, )[0] console.log('') console.log('Overall recommendation') if (materiallyUseful.length > 0) { const winner = materiallyUseful[0] const winnerExecutionClass = winner.executionClass console.log( ` Best current live public candidate: ${winner.pool.base}/${winner.pool.quote} via ${winner.strategy} at ${fmtAmount(winner.x, winner.params.quoteDecimals, winner.params.quoteAsset)} using ${winner.flashSource?.providerName ?? 'manual flash source'}.`, ) printFullLoopRecommendation(winner.params, winner.simulation, { executionClass: winnerExecutionClass, executionGradeRequired, }) } else if (viable.length > 0) { const canary = viable[0] const recommendationCandidate = closestFail ?? canary const recommendationExecutionClass = recommendationCandidate.executionClass console.log( ` Only canary-sized pass candidates exist right now. Best technical pass: ${canary.pool.base}/${canary.pool.quote} via ${canary.strategy} at ${fmtAmount(canary.x, canary.params.quoteDecimals, canary.params.quoteAsset)}, but it does not retain enough quote to count as a meaningful public-liquidity program.`, ) printFullLoopRecommendation(recommendationCandidate.params, recommendationCandidate.simulation, { executionClass: recommendationExecutionClass, executionGradeRequired, }) } else if (closest) { const closestExecutionClass = closest.executionClass console.log( ` No current live public pool passes the active guard set. Closest candidate: ${closest.pool.base}/${closest.pool.quote} via ${closest.strategy} at ${fmtAmount(closest.x, closest.params.quoteDecimals, closest.params.quoteAsset)}.`, ) printFullLoopRecommendation(closest.params, closest.simulation, { executionClass: closestExecutionClass, executionGradeRequired, }) } else { console.log(' No live public sweep candidates could be evaluated.') console.log('') } } function buildInventoryLoopCandidates( B, Q, scanStr, lpFeeBps, flashFeeBps, inventoryBase, targetFlashBorrow, guardConfig, flashAddToPool, ) { const sizes = scanStr ? scanStr.split(',').map((s) => parseNum(s.trim())) : [50_000, 100_000, 150_000, 200_000, 250_000] return sizes.map((grossBaseIn) => { const effectiveQuoteReserve = flashAddToPool && targetFlashBorrow != null ? Q + targetFlashBorrow : Q const leg = baseInToQuoteOut(B, effectiveQuoteReserve, grossBaseIn, lpFeeBps) const endBaseReserve = B + leg.deltaBaseNet const endQuoteReserve = Math.max(0, effectiveQuoteReserve - leg.quoteOut) const postTradeMarginalPrice = marginalQuotePerBase(endBaseReserve, endQuoteReserve) const postTradeDeviationBps = deviationBps(postTradeMarginalPrice, guardConfig.oraclePrice) const postTradeDeviationAbsBps = Math.abs(postTradeDeviationBps) const maxFlashNoLoss = leg.quoteOut / (1 + flashFeeBps / 10000) const maxFlashKeepFloor = Math.max( 0, (leg.quoteOut - guardConfig.requiredRetainedUsdc) / (1 + flashFeeBps / 10000), ) const retainedNoFlash = leg.quoteOut const floorSurplusNoFlash = retainedNoFlash - guardConfig.requiredRetainedUsdc const retainedPerCw = retainedNoFlash / grossBaseIn const inventoryOk = inventoryBase == null ? null : inventoryBase >= grossBaseIn const inventoryBurnFraction = inventoryBase == null || inventoryBase <= 0 ? null : grossBaseIn / inventoryBase const postTradeDeviationOk = guardConfig.maxPostTradeDeviationBps == null ? null : postTradeDeviationAbsBps <= guardConfig.maxPostTradeDeviationBps const cwBurnFractionOk = guardConfig.maxCwBurnFraction == null ? null : inventoryBurnFraction <= guardConfig.maxCwBurnFraction const targetRepay = targetFlashBorrow == null ? null : repayUsdc(targetFlashBorrow, flashFeeBps) const repayMargin = targetRepay == null ? null : leg.quoteOut - targetRepay const retainedAfterTargetFlash = targetRepay == null ? null : leg.quoteOut - targetRepay const retainedAfterTargetFlashPerCw = retainedAfterTargetFlash == null ? null : retainedAfterTargetFlash / grossBaseIn const floorMarginAfterTargetFlash = retainedAfterTargetFlash == null ? null : retainedAfterTargetFlash - guardConfig.requiredRetainedUsdc const poolBaseDelta = endBaseReserve - B const poolQuoteDelta = endQuoteReserve - Q const samePoolRepayPossible = targetRepay == null ? null : leg.quoteOut >= targetRepay const samePoolQuoteEndsHigher = flashAddToPool ? endQuoteReserve > Q : null const samePoolQuoteDeepeningWithPmmRepayPossible = flashAddToPool && targetRepay != null ? samePoolRepayPossible && samePoolQuoteEndsHigher : null const guardFailures = [] if (inventoryOk === false) guardFailures.push('inventory') if (postTradeDeviationOk === false) guardFailures.push('post_trade_dev') if (cwBurnFractionOk === false) guardFailures.push('cw_burn') if (targetFlashBorrow != null) { if (!(repayMargin >= 0)) guardFailures.push('repay') if (!(floorMarginAfterTargetFlash >= 0)) guardFailures.push('retained_floor') } else if (!(floorSurplusNoFlash >= 0)) { guardFailures.push('retained_floor') } return { grossBaseIn, deltaBaseNet: leg.deltaBaseNet, quoteOut: leg.quoteOut, usdcPerCw: leg.vwapQuotePerBase, endBaseReserve, endQuoteReserve, postTradeMarginalPrice, postTradeDeviationBps, postTradeDeviationAbsBps, maxFlashNoLoss, maxFlashKeepFloor, retainedNoFlash, floorSurplusNoFlash, retainedPerCw, inventoryOk, inventoryBurnFraction, postTradeDeviationOk, cwBurnFractionOk, targetRepay, repayMargin, retainedAfterTargetFlash, retainedAfterTargetFlashPerCw, floorMarginAfterTargetFlash, effectiveQuoteReserve, poolBaseDelta, poolQuoteDelta, samePoolRepayPossible, samePoolQuoteEndsHigher, samePoolQuoteDeepeningWithPmmRepayPossible, guardFailures, recommendationOk: guardFailures.length === 0, } }) } function compareInventoryLoopCandidates(a, b, targetFlashBorrow, rankProfile) { if (a.recommendationOk !== b.recommendationOk) { return Number(b.recommendationOk) - Number(a.recommendationOk) } if (a.recommendationOk && b.recommendationOk) { const eligibleCompare = compareRankProfileMetrics( a, b, eligibleRankMetrics(targetFlashBorrow, rankProfile), ) if (eligibleCompare !== 0) return eligibleCompare } if (a.guardFailures.length !== b.guardFailures.length) { return a.guardFailures.length - b.guardFailures.length } if (targetFlashBorrow != null) { if ((a.repayMargin >= 0) !== (b.repayMargin >= 0)) return Number(b.repayMargin >= 0) - Number(a.repayMargin >= 0) if ((a.floorMarginAfterTargetFlash >= 0) !== (b.floorMarginAfterTargetFlash >= 0)) { return Number(b.floorMarginAfterTargetFlash >= 0) - Number(a.floorMarginAfterTargetFlash >= 0) } if (a.repayMargin !== b.repayMargin) return b.repayMargin - a.repayMargin if (a.floorMarginAfterTargetFlash !== b.floorMarginAfterTargetFlash) { return b.floorMarginAfterTargetFlash - a.floorMarginAfterTargetFlash } } else { if (a.maxFlashKeepFloor !== b.maxFlashKeepFloor) return b.maxFlashKeepFloor - a.maxFlashKeepFloor if (a.floorSurplusNoFlash !== b.floorSurplusNoFlash) return b.floorSurplusNoFlash - a.floorSurplusNoFlash } if (a.retainedPerCw !== b.retainedPerCw) return b.retainedPerCw - a.retainedPerCw return a.grossBaseIn - b.grossBaseIn } function printInventoryLoopSafetyScan( B, Q, scanStr, lpFeeBps, flashFeeBps, inventoryBase, targetFlashBorrow, guardConfig, flashAddToPool, ) { const candidates = buildInventoryLoopCandidates( B, Q, scanStr, lpFeeBps, flashFeeBps, inventoryBase, targetFlashBorrow, guardConfig, flashAddToPool, ) const eligibleCandidates = candidates.filter((candidate) => candidate.recommendationOk) const gasReserveSummary = summarizeGasReserve(guardConfig) const currentMarginalPrice = marginalQuotePerBase(B, Q) const currentDeviation = deviationBps(currentMarginalPrice, guardConfig.oraclePrice) console.log('Inventory-backed flash safety scan — sell cW base into PMM, borrow only what can be repaid\n') console.log(` source reserves: B=${fmt(B)} cW base, Q=${fmt(Q)} USDC quote`) console.log(` pool fee=${lpFeeBps} bps`) console.log(` flash fee=${flashFeeBps} bps`) console.log(` oracle price=${fmt(guardConfig.oraclePrice)} quote per cW base`) console.log(` current marginal price=${fmt(currentMarginalPrice)} current deviation=${fmt(currentDeviation)} bps`) console.log(` retained USDC floor=${fmtAmount(guardConfig.requiredRetainedUsdc, guardConfig.quoteDecimals, 'USDC')}`) if (guardConfig.gasReserveQuote > 0) { console.log( ` native gas reserve=${fmt(guardConfig.gasReserveNative)} native = ${fmt(guardConfig.gasReserveQuoteHuman)} USDC (${gasReserveSummary})`, ) } if (inventoryBase != null) console.log(` inventoryBase available=${fmt(inventoryBase)}`) if (targetFlashBorrow != null) console.log(` target flash borrow=${fmt(targetFlashBorrow)} target repay=${fmt(repayUsdc(targetFlashBorrow, flashFeeBps))}`) if (flashAddToPool && targetFlashBorrow != null) { console.log(` flash loop mode=temporary quote top-up before PMM leg (effective Q=${fmt(Q + targetFlashBorrow)})`) } if (guardConfig.maxPostTradeDeviationBps != null) { console.log(` max post-trade deviation=${fmt(guardConfig.maxPostTradeDeviationBps)} bps`) } if (guardConfig.maxCwBurnFraction != null) { console.log(` max cW burn fraction=${fmt(guardConfig.maxCwBurnFraction)} of inventory-base`) } if (guardConfig.cooldownBlocks > 0) { console.log(` cooldown after execution=${guardConfig.cooldownBlocks} blocks before next tranche`) } console.log('') console.log( 'gross_cw_in\tquote_out\tUSDC_per_cw\tmax_flash_no_loss\tmax_flash_keep_floor\tpool_base_delta\tpool_quote_delta\tpost_trade_dev_bps\tcw_burn_frac\tguard_status', ) let bestBorrow = null let bestEfficiency = null for (const candidate of candidates) { if ( candidate.recommendationOk && (bestBorrow == null || candidate.maxFlashKeepFloor > bestBorrow.maxFlashKeepFloor) ) { bestBorrow = candidate } if ( candidate.recommendationOk && (bestEfficiency == null || candidate.retainedPerCw > bestEfficiency.retainedPerCw) ) { bestEfficiency = candidate } console.log( [ fmt(candidate.grossBaseIn), fmt(candidate.quoteOut), fmt(candidate.usdcPerCw), fmt(candidate.maxFlashNoLoss), fmt(candidate.maxFlashKeepFloor), fmt(candidate.poolBaseDelta), fmt(candidate.poolQuoteDelta), fmt(candidate.postTradeDeviationBps), candidate.inventoryBurnFraction == null ? 'n/a' : fmt(candidate.inventoryBurnFraction), formatGuardStatus(candidate), ].join('\t'), ) } console.log('') if (bestBorrow) { console.log( ` Max safe flash borrow while keeping the floor is highest at gross_cw_in=${fmt(bestBorrow.grossBaseIn)} → max_flash_keep_floor=${fmt(bestBorrow.maxFlashKeepFloor)}.`, ) } if (bestEfficiency) { console.log( ` Best USDC retained per cW sacrificed is the smallest tested leg: gross_cw_in=${fmt(bestEfficiency.grossBaseIn)} → retained_per_cw=${fmt(bestEfficiency.retainedPerCw)}.`, ) } if (eligibleCandidates.length === 0) { const closest = candidates[0] console.log( ` No tranche passes the active guards. Top-ranked ineligible candidate gross_cw_in=${fmt(closest.grossBaseIn)} fails ${formatGuardStatus(closest)}.`, ) } if (guardConfig.cooldownBlocks > 0 && eligibleCandidates.length > 0) { console.log(` Execute at most one eligible tranche per ${guardConfig.cooldownBlocks}-block window.`) } if (flashAddToPool && targetFlashBorrow != null) { const anySamePoolQuoteDeepening = candidates.some( (candidate) => candidate.samePoolQuoteDeepeningWithPmmRepayPossible, ) if (!anySamePoolQuoteDeepening) { console.log( ' Invariant: if the flash-borrowed quote is temporarily added to the same PMM and repaid from that same PMM quote-out leg, the pool cannot finish with a higher quote reserve Q. This loop deepens base B; permanent quote-side deepening requires outside proceeds.', ) } } console.log(' Execution rule: repay flash first, then seed only the retained USDC remainder.') console.log('') } function printInventoryLoopRanking( B, Q, scanStr, lpFeeBps, flashFeeBps, inventoryBase, targetFlashBorrow, guardConfig, rankProfile, flashAddToPool, ) { const candidates = buildInventoryLoopCandidates( B, Q, scanStr, lpFeeBps, flashFeeBps, inventoryBase, targetFlashBorrow, guardConfig, flashAddToPool, ).sort((a, b) => compareInventoryLoopCandidates(a, b, targetFlashBorrow, rankProfile)) const eligibleCandidates = candidates.filter((candidate) => candidate.recommendationOk) const recommended = eligibleCandidates[0] ?? null const runnerUp = eligibleCandidates[1] ?? null const gasReserveSummary = summarizeGasReserve(guardConfig) const currentMarginalPrice = marginalQuotePerBase(B, Q) const currentDeviation = deviationBps(currentMarginalPrice, guardConfig.oraclePrice) const profileSummary = rankProfileSummary(rankProfile, targetFlashBorrow) const winningExplanation = explainWinningCandidate(recommended, runnerUp, rankProfile, targetFlashBorrow) const efficiencyLabel = efficiencyMetricLabel(targetFlashBorrow) console.log('Inventory-backed tranche ranking\n') console.log(` source reserves: B=${fmt(B)} cW base, Q=${fmt(Q)} USDC quote`) console.log(` pool fee=${lpFeeBps} bps`) console.log(` flash fee=${flashFeeBps} bps`) console.log(` oracle price=${fmt(guardConfig.oraclePrice)} quote per cW base`) console.log(` current marginal price=${fmt(currentMarginalPrice)} current deviation=${fmt(currentDeviation)} bps`) console.log(` retained USDC floor=${fmtAmount(guardConfig.requiredRetainedUsdc, guardConfig.quoteDecimals, 'USDC')}`) if (guardConfig.gasReserveQuote > 0) { console.log( ` native gas reserve=${fmt(guardConfig.gasReserveNative)} native = ${fmt(guardConfig.gasReserveQuoteHuman)} USDC (${gasReserveSummary})`, ) } if (inventoryBase != null) console.log(` inventoryBase available=${fmt(inventoryBase)}`) if (targetFlashBorrow != null) { console.log(` ranking against target flash borrow=${fmt(targetFlashBorrow)} repay=${fmt(repayUsdc(targetFlashBorrow, flashFeeBps))}`) } else { console.log(' ranking mode: eligible tranches are ordered by the selected rank profile') } if (flashAddToPool && targetFlashBorrow != null) { console.log(` flash loop mode=temporary quote top-up before PMM leg (effective Q=${fmt(Q + targetFlashBorrow)})`) } console.log(` rank profile=${rankProfile}`) console.log(` profile priorities=${profileSummary}`) if (guardConfig.maxPostTradeDeviationBps != null) { console.log(` max post-trade deviation=${fmt(guardConfig.maxPostTradeDeviationBps)} bps`) } if (guardConfig.maxCwBurnFraction != null) { console.log(` max cW burn fraction=${fmt(guardConfig.maxCwBurnFraction)} of inventory-base`) } if (guardConfig.cooldownBlocks > 0) { console.log(` cooldown after execution=${guardConfig.cooldownBlocks} blocks before next tranche`) } console.log('') if (targetFlashBorrow != null) { console.log( `rank\tgross_cw_in\trepay_margin\tfloor_margin_after_repay\tpool_base_delta\tpool_quote_delta\tpost_trade_dev_bps\tcw_burn_frac\t${efficiencyLabel}\tguard_status`, ) } else { console.log( `rank\tgross_cw_in\tmax_flash_keep_floor\tfloor_surplus_no_flash\tpool_base_delta\tpool_quote_delta\tpost_trade_dev_bps\tcw_burn_frac\t${efficiencyLabel}\tguard_status`, ) } candidates.forEach((candidate, index) => { if (targetFlashBorrow != null) { console.log( [ index + 1, fmt(candidate.grossBaseIn), fmt(candidate.repayMargin), fmt(candidate.floorMarginAfterTargetFlash), fmt(candidate.poolBaseDelta), fmt(candidate.poolQuoteDelta), fmt(candidate.postTradeDeviationBps), candidate.inventoryBurnFraction == null ? 'n/a' : fmt(candidate.inventoryBurnFraction), fmt(candidateEfficiencyValue(candidate, targetFlashBorrow)), formatGuardStatus(candidate), ].join('\t'), ) return } console.log( [ index + 1, fmt(candidate.grossBaseIn), fmt(candidate.maxFlashKeepFloor), fmt(candidate.floorSurplusNoFlash), fmt(candidate.poolBaseDelta), fmt(candidate.poolQuoteDelta), fmt(candidate.postTradeDeviationBps), candidate.inventoryBurnFraction == null ? 'n/a' : fmt(candidate.inventoryBurnFraction), fmt(candidateEfficiencyValue(candidate, targetFlashBorrow)), formatGuardStatus(candidate), ].join('\t'), ) }) if (recommended) { console.log('') if (targetFlashBorrow != null) { console.log( ` Recommended tranche: gross_cw_in=${fmt(recommended.grossBaseIn)} with repay_margin=${fmt(recommended.repayMargin)}, floor_margin_after_repay=${fmt(recommended.floorMarginAfterTargetFlash)}, post_trade_dev_bps=${fmt(recommended.postTradeDeviationBps)}, ${efficiencyLabel}=${fmt(candidateEfficiencyValue(recommended, targetFlashBorrow))}.`, ) } else { console.log( ` Recommended tranche: gross_cw_in=${fmt(recommended.grossBaseIn)} with max_flash_keep_floor=${fmt(recommended.maxFlashKeepFloor)}, floor_surplus_no_flash=${fmt(recommended.floorSurplusNoFlash)}, post_trade_dev_bps=${fmt(recommended.postTradeDeviationBps)}, ${efficiencyLabel}=${fmt(candidateEfficiencyValue(recommended, targetFlashBorrow))}.`, ) } if (winningExplanation) console.log(` Why it won: ${winningExplanation}`) if (guardConfig.cooldownBlocks > 0) { console.log(` Execute once, then wait ${guardConfig.cooldownBlocks} blocks before the next tranche.`) } if (flashAddToPool && targetFlashBorrow != null && !recommended.samePoolQuoteDeepeningWithPmmRepayPossible) { console.log( ' Reserve invariant: this recommendation can still deepen base B, but it cannot both repay the same PMM-funded flash top-up and leave quote reserve Q above the starting level without outside proceeds.', ) } } else if (candidates[0]) { console.log('') console.log( ` No tranche passes the active guards. Top-ranked ineligible candidate gross_cw_in=${fmt(candidates[0].grossBaseIn)} fails ${formatGuardStatus(candidates[0])}.`, ) } if (flashAddToPool && targetFlashBorrow != null) { const anySamePoolQuoteDeepening = candidates.some( (candidate) => candidate.samePoolQuoteDeepeningWithPmmRepayPossible, ) if (!anySamePoolQuoteDeepening) { console.log( ' Invariant: no tested tranche can both repay the same-pool flash top-up and end with higher quote reserve Q. Use outside proceeds if quote-side deepening is the goal.', ) } } console.log('') } function runExamples() { console.log('PMM flash push — baseline recalc (same units on all amounts)\n') const B = 10e6 const Q = 10e6 const flash = 5 printScenario('$10M trade, 0 LP fee, external 1.00', B, Q, 10e6, 0, flash, 1.0, 0) printScenario('$10M trade, 3 LP fee bps, external 1.00', B, Q, 10e6, 3, flash, 1.0, 0) printScenario('$2M trade, 0 LP fee, external 1.00', B, Q, 2e6, 0, flash, 1.0, 0) printScenario('$2M trade, 3 LP fee bps, external 1.00', B, Q, 2e6, 3, flash, 1.0, 0) printScenario('$10M trade, 0 LP fee — break-even check P_ext=2.001', B, Q, 10e6, 0, flash, 2.001, 0) printScenario('$2M trade, 0 LP fee — break-even check P_ext≈1.201', B, Q, 2e6, 0, flash, 1.2006, 0) } function main() { const { values, tokens } = parseArgs({ options: { examples: { type: 'boolean', short: 'e' }, 'base-reserve': { type: 'string', short: 'B' }, 'quote-reserve': { type: 'string', short: 'Q' }, trade: { type: 'string', short: 'x' }, 'lp-fee-bps': { type: 'string', default: '3' }, 'flash-fee-bps': { type: 'string', default: '5' }, 'external-price': { type: 'string' }, 'exit-fee-bps': { type: 'string', default: '0' }, scan: { type: 'string' }, 'seed-pools': { type: 'string' }, 'target-quote-per-pool': { type: 'string' }, 'target-total-quote': { type: 'string' }, 'inventory-base': { type: 'string' }, 'loop-count': { type: 'string' }, 'sequential-matched-loops': { type: 'string' }, 'matched-flash-numerator': { type: 'string' }, 'matched-flash-denominator': { type: 'string' }, 'inventory-loop-scan': { type: 'boolean' }, 'inventory-loop-rank': { type: 'boolean' }, 'min-retained-usdc': { type: 'string', default: '0' }, 'target-flash-borrow': { type: 'string' }, 'flash-add-to-pool': { type: 'boolean' }, 'full-loop-dry-run': { type: 'boolean' }, 'public-live-sweep': { type: 'boolean' }, 'public-flash-source': { type: 'string', default: 'aave' }, 'loop-strategy': { type: 'string', default: 'quote-push' }, 'owned-base-add': { type: 'string', default: '0' }, 'flash-topup-quote': { type: 'string', default: '0' }, 'atomic-bridge-base-amount': { type: 'string', default: '0' }, 'atomic-destination-amount': { type: 'string' }, 'atomic-destination-asset': { type: 'string' }, 'atomic-destination-decimals': { type: 'string' }, 'atomic-corridor-label': { type: 'string' }, 'scan-atomic-bridge-max': { type: 'boolean' }, 'flash-provider-cap': { type: 'string' }, 'flash-provider-name': { type: 'string', default: 'flash provider' }, 'flash-provider-address': { type: 'string' }, 'flash-provider-token-address': { type: 'string' }, 'flash-provider-rpc-url': { type: 'string' }, 'external-via-asset': { type: 'string' }, 'external-fee-bps': { type: 'string' }, 'external-entry-price': { type: 'string' }, 'external-exit-price': { type: 'string' }, 'external-entry-fee-bps': { type: 'string' }, 'external-exit-fee-bps': { type: 'string' }, 'external-entry-price-cmd': { type: 'string' }, 'external-exit-price-cmd': { type: 'string' }, 'external-entry-source': { type: 'string', default: 'manual' }, 'external-exit-source': { type: 'string', default: 'manual' }, 'measured-gas-quote': { type: 'string' }, 'measured-gas-source': { type: 'string', default: 'CLI measured gas quote override' }, 'execution-grade': { type: 'boolean' }, 'rank-profile': { type: 'string', default: 'balanced' }, 'funding-readiness': { type: 'boolean' }, 'inventory-asset': { type: 'string', default: 'cWUSDC' }, 'base-asset': { type: 'string', default: 'base' }, 'base-decimals': { type: 'string', default: '6' }, 'source-asset': { type: 'string' }, 'quote-asset': { type: 'string', default: 'USDC' }, 'quote-decimals': { type: 'string', default: '6' }, 'balance-report': { type: 'string' }, 'gas-tx-count': { type: 'string' }, 'gas-per-tx': { type: 'string' }, 'max-fee-gwei': { type: 'string' }, 'native-token-price': { type: 'string' }, 'oracle-price': { type: 'string', default: '1' }, 'max-post-trade-deviation-bps': { type: 'string' }, 'max-cw-burn-fraction': { type: 'string' }, 'cooldown-blocks': { type: 'string', default: '0' }, 'mainnet-map': { type: 'boolean' }, 'compare-deepen': { type: 'string' }, help: { type: 'boolean', short: 'h' }, }, allowPositionals: false, tokens: true, }) if (values.help) { console.log(`Usage: --examples, -e Print $10M / $2M baseline vs plan (10M/10M reserves) --mainnet-map Print Ethereum mainnet cWUSDC/USDC pool map from deployment-status.json --compare-deepen D With --mainnet-map: add D to base reserve and tabulate slippage (-B -Q required) -B, --base-reserve Base token reserve (units) -Q, --quote-reserve Quote token reserve (units) -x, --trade Gross quote amount in (flash borrow / swap size) --lp-fee-bps Pool fee on input (default 3 = 0.03%%; with --compare-deepen, overrides registry fee) --flash-fee-bps Flash fee on repayment (default 5 = 0.05%%; use 0 for funded-inventory loop) --external-price Generic gross quote-per-base external price; used as exit price in quote-push mode or entry price in base-unwind mode --exit-fee-bps Legacy generic external fee/slippage bps (default 0); full-loop mode prefers the more specific external-* fee flags --scan Comma-separated trade sizes (same units as -x) --seed-pools Number of destination pools to seed with USDC quote --target-quote-per-pool Target quote to add per pool in raw token units (e.g. 1000000 = 1 USDC if decimals=6) --target-total-quote Total quote to raise in raw token units (alternative to per-pool target) --inventory-base Available cW base inventory to compare against requirement --loop-count Split the seeding plan into this many sequential loops (defaults to seed-pools or 1) --sequential-matched-loops N Run N modeled quote-push loops; after each, set B=Q=endQuote (whitepaper ladder). Requires matched -B/-Q. Flash size: round(matched*num/den); defaults num/den=6342691/256763253 --matched-flash-numerator Override numerator for --sequential-matched-loops flash sizing (default 6342691) --matched-flash-denominator Override denominator for --sequential-matched-loops flash sizing (default 256763253) --inventory-loop-scan Treat --scan as gross cW sizes; compute safe flash ceilings and retained USDC --inventory-loop-rank Rank tranche sizes by repay safety, retained floor, and retained-USDC-per-cW efficiency --min-retained-usdc In inventory-loop-scan mode, keep at least this much USDC after flash repayment --target-flash-borrow Optional borrow size to rank against actual repay/floor margins --flash-add-to-pool Assume --target-flash-borrow is temporarily added to PMM quote reserve before the PMM leg --full-loop-dry-run Simulate borrow -> strategy legs -> repay -> gas reserve -> pool seeding --public-live-sweep Probe live mainnet public cWUSD*/USD* PMM pools and scan tranche sizes with recommendations --public-flash-source Flash source for --public-live-sweep: aave|balancer|manual (default aave) --loop-strategy quote-push (PMM quote-in then external unwind) or base-unwind (external acquire then PMM base-in) --owned-base-add Permanently add this much owned base inventory to the source PMM before the modeled flash loop --flash-topup-quote Temporarily add this much borrowed quote to source PMM before the modeled strategy leg --atomic-bridge-base-amount Reserve this much PMM-acquired base into the atomic corridor before the external unwind --atomic-destination-amount Immediate destination fulfillment amount to report for the atomic corridor (defaults to the reserved base amount, scaled by decimals) --atomic-destination-asset Destination asset label for the atomic corridor report (e.g. cUSDC) --atomic-destination-decimals Destination asset decimals for the atomic corridor report (default base decimals) --atomic-corridor-label Human label for the atomic corridor, e.g. 1->138 cWUSDC->cUSDC --scan-atomic-bridge-max Solve for the largest atomic corridor reservation that still passes repay-only and full positive-after-gas guards --flash-provider-cap Optional flash source cap to enforce in full-loop dry-run or public-live-sweep --flash-provider-name Label for the flash source in full-loop dry-run or manual public-live-sweep output --flash-provider-address ERC-3156 flash lender address to probe live in full-loop dry-run (defaults to env FLASH_VAULT) --flash-provider-token-address Token address to use with the ERC-3156 flash lender probe (defaults to env FLASH_VAULT_TOKEN) --flash-provider-rpc-url RPC URL for the flash lender probe (defaults to FLASH_PROVIDER_RPC_URL, then RPC_URL_138_PUBLIC, RPC_URL_138, CHAIN138_RPC_URL, ETHEREUM_MAINNET_RPC) --external-via-asset Optional intermediate asset label for reporting, e.g. ETH --external-fee-bps Generic external-route fee/slippage bps fallback for full-loop mode --external-entry-price Effective gross quote-per-base acquisition price for external quote->base leg --external-exit-price Effective gross quote-per-base monetization price for external base->quote leg --external-entry-fee-bps Entry-leg fee/slippage bps override for full-loop mode --external-exit-fee-bps Exit-leg fee/slippage bps override for full-loop mode --external-entry-price-cmd Shell command that prints a live entry price; overrides --external-entry-price and marks the source live --external-exit-price-cmd Shell command that prints a live exit price; overrides --external-exit-price and marks the source live --external-entry-source Source label for entry pricing: live|manual|scenario (default manual) --external-exit-source Source label for exit pricing: live|manual|scenario (default manual) --measured-gas-quote Measured end-to-end gas reserve in human quote units; overrides modeled gas reserve --measured-gas-source Label for the measured gas input --execution-grade Require live pool quote surface + the strategy's live external quote source(s) + measured or live-estimated gas + an explicit post-trade deviation cap before calling a tranche executable --rank-profile Rank eligible tranches as conservative|balanced|efficiency (default balanced) --funding-readiness Compare live mainnet funded inventory vs bridge-reachable Chain 138 inventory for a target raise --inventory-asset Inventory asset on mainnet for readiness mode (default cWUSDC) --base-asset Base asset label for --full-loop-dry-run output (default base) --base-decimals Base asset decimals for --full-loop-dry-run output/math (default 6) --source-asset Source asset on Chain 138 for readiness mode (default inferred from inventory asset) --quote-asset Quote asset label for readiness mode and --full-loop-dry-run (default USDC) --quote-decimals Quote asset decimals for --full-loop-dry-run output/math (default 6) --balance-report Optional explicit deployer balance report JSON path for readiness fallback --gas-tx-count Reserve native gas for this many follow-up transactions (inventory-loop or full-loop dry-run) --gas-per-tx Gas limit per reserved transaction, in native gas units --max-fee-gwei Gas price cap in gwei for native reserve sizing --native-token-price Quote price of the native gas token (e.g. ETH price in USDC) --oracle-price Peg/oracle target in quote per cW base (default 1) --max-post-trade-deviation-bps Hard cap on absolute post-trade peg deviation --max-cw-burn-fraction Hard cap on gross cW burn as a fraction of --inventory-base --cooldown-blocks Execution note: wait this many blocks between eligible tranches -h, --help This help `) process.exit(0) } if (values.examples) { runExamples() process.exit(0) } const B = values['base-reserve'] != null ? parseNum(values['base-reserve']) : null const Q = values['quote-reserve'] != null ? parseNum(values['quote-reserve']) : null const lpFeeBps = parseNum(values['lp-fee-bps'] ?? '3') const lpFeeBpsWasExplicit = tokens.some((token) => token.kind === 'option' && token.name === 'lp-fee-bps') const flashFeeBps = parseNum(values['flash-fee-bps'] ?? '5') const exitFeeBps = parseNum(values['exit-fee-bps'] ?? '0') const externalPrice = values['external-price'] != null ? parseNum(values['external-price']) : undefined const seedPools = values['seed-pools'] != null ? parsePositiveInt(values['seed-pools'], '--seed-pools') : null const targetQuotePerPool = values['target-quote-per-pool'] != null ? parseNum(values['target-quote-per-pool']) : null const targetTotalQuote = values['target-total-quote'] != null ? parseNum(values['target-total-quote']) : null const inventoryBase = values['inventory-base'] != null ? parseNum(values['inventory-base']) : null const loopCountOverride = values['loop-count'] != null ? parsePositiveInt(values['loop-count'], '--loop-count') : null const sequentialMatchedLoops = values['sequential-matched-loops'] != null ? parsePositiveInt(values['sequential-matched-loops'], '--sequential-matched-loops') : null const matchedFlashNumerator = values['matched-flash-numerator'] != null ? parsePositiveInt(values['matched-flash-numerator'], '--matched-flash-numerator') : 6342691 const matchedFlashDenominator = values['matched-flash-denominator'] != null ? parsePositiveInt(values['matched-flash-denominator'], '--matched-flash-denominator') : 256763253 const minRetainedUsdc = parseNum(values['min-retained-usdc'] ?? '0') const targetFlashBorrow = values['target-flash-borrow'] != null ? parseNum(values['target-flash-borrow']) : null const flashAddToPool = values['flash-add-to-pool'] const fullLoopDryRunMode = values['full-loop-dry-run'] const loopStrategy = String(values['loop-strategy'] ?? 'quote-push') const ownedBaseAdd = parseNum(values['owned-base-add'] ?? '0') const flashTopupQuote = parseNum(values['flash-topup-quote'] ?? '0') const atomicBridgeBaseAmount = parseNum(values['atomic-bridge-base-amount'] ?? '0') const atomicDestinationAmount = values['atomic-destination-amount'] != null ? parseNum(values['atomic-destination-amount']) : null const atomicDestinationAsset = values['atomic-destination-asset'] != null ? String(values['atomic-destination-asset']) : null const atomicDestinationDecimals = values['atomic-destination-decimals'] != null ? parseNonNegativeInt(values['atomic-destination-decimals'], '--atomic-destination-decimals') : null const atomicCorridorLabel = values['atomic-corridor-label'] != null ? String(values['atomic-corridor-label']) : null const scanAtomicBridgeMax = values['scan-atomic-bridge-max'] const flashProviderCap = values['flash-provider-cap'] != null ? parseNum(values['flash-provider-cap']) : null const flashProviderName = String(values['flash-provider-name'] ?? 'flash provider') const flashProviderAddress = values['flash-provider-address'] != null ? String(values['flash-provider-address']) : (process.env.FLASH_VAULT ?? null) const flashProviderTokenAddress = values['flash-provider-token-address'] != null ? String(values['flash-provider-token-address']) : (process.env.FLASH_VAULT_TOKEN ?? null) const flashProviderRpcUrl = values['flash-provider-rpc-url'] != null ? String(values['flash-provider-rpc-url']) : process.env.FLASH_PROVIDER_RPC_URL ?? process.env.RPC_URL_138_PUBLIC ?? process.env.RPC_URL_138 ?? process.env.CHAIN138_RPC_URL ?? process.env.ETHEREUM_MAINNET_RPC ?? null const externalViaAsset = values['external-via-asset'] != null ? String(values['external-via-asset']) : null const externalFeeBps = values['external-fee-bps'] != null ? parseNum(values['external-fee-bps']) : exitFeeBps const externalEntryPriceCmd = values['external-entry-price-cmd'] != null ? String(values['external-entry-price-cmd']) : null const externalExitPriceCmd = values['external-exit-price-cmd'] != null ? String(values['external-exit-price-cmd']) : null const liveExternalEntryPrice = tryReadNumericCommand( externalEntryPriceCmd, externalEntryPriceCmd ? `live command: ${externalEntryPriceCmd}` : null, ) const liveExternalExitPrice = tryReadNumericCommand( externalExitPriceCmd, externalExitPriceCmd ? `live command: ${externalExitPriceCmd}` : null, ) const externalEntryPrice = liveExternalEntryPrice?.value ?? (values['external-entry-price'] != null ? parseNum(values['external-entry-price']) : externalPrice) const externalExitPrice = liveExternalExitPrice?.value ?? (values['external-exit-price'] != null ? parseNum(values['external-exit-price']) : externalPrice) const externalEntryFeeBps = values['external-entry-fee-bps'] != null ? parseNum(values['external-entry-fee-bps']) : externalFeeBps const externalExitFeeBps = values['external-exit-fee-bps'] != null ? parseNum(values['external-exit-fee-bps']) : externalFeeBps const externalEntrySource = liveExternalEntryPrice ? 'live' : String(values['external-entry-source'] ?? 'manual') const externalExitSource = liveExternalExitPrice ? 'live' : String(values['external-exit-source'] ?? 'manual') const measuredGasQuote = values['measured-gas-quote'] != null ? parseNum(values['measured-gas-quote']) : null const measuredGasSource = String(values['measured-gas-source'] ?? 'CLI measured gas quote override') const executionGradeRequired = values['execution-grade'] const rankProfile = String(values['rank-profile'] ?? 'balanced') const fundingReadinessMode = values['funding-readiness'] const inventoryAsset = String(values['inventory-asset'] ?? 'cWUSDC') const baseAsset = String(values['base-asset'] ?? 'base') const baseDecimals = parseNonNegativeInt(values['base-decimals'] ?? '6', '--base-decimals') const sourceAsset = values['source-asset'] != null ? String(values['source-asset']) : inferSourceAsset(inventoryAsset) const quoteAsset = String(values['quote-asset'] ?? 'USDC') const quoteDecimals = parseNonNegativeInt(values['quote-decimals'] ?? '6', '--quote-decimals') const balanceReportPath = values['balance-report'] != null ? resolve(process.cwd(), String(values['balance-report'])) : latestBalanceReportPath() const gasTxCount = values['gas-tx-count'] != null ? parsePositiveInt(values['gas-tx-count'], '--gas-tx-count') : null const gasPerTx = values['gas-per-tx'] != null ? parseNum(values['gas-per-tx']) : null const maxFeeGwei = values['max-fee-gwei'] != null ? parseNum(values['max-fee-gwei']) : null const nativeTokenPrice = values['native-token-price'] != null ? parseNum(values['native-token-price']) : null const oraclePrice = parseNum(values['oracle-price'] ?? '1') const maxPostTradeDeviationBps = values['max-post-trade-deviation-bps'] != null ? parseNum(values['max-post-trade-deviation-bps']) : null const maxCwBurnFraction = values['max-cw-burn-fraction'] != null ? parseNum(values['max-cw-burn-fraction']) : null const cooldownBlocks = parseNonNegativeInt(values['cooldown-blocks'] ?? '0', '--cooldown-blocks') const inventoryLoopScanMode = values['inventory-loop-scan'] const inventoryLoopRankMode = values['inventory-loop-rank'] const inventoryLoopMode = inventoryLoopScanMode || inventoryLoopRankMode const publicLiveSweepMode = values['public-live-sweep'] const publicFlashSource = String(values['public-flash-source'] ?? 'aave') const gasReserveFlagsUsed = gasTxCount != null || gasPerTx != null || maxFeeGwei != null const extraGuardFlagsUsed = gasReserveFlagsUsed || measuredGasQuote != null || maxPostTradeDeviationBps != null || maxCwBurnFraction != null || cooldownBlocks > 0 const seedMode = !fundingReadinessMode && !inventoryLoopMode && !publicLiveSweepMode && ( seedPools != null || targetQuotePerPool != null || targetTotalQuote != null || inventoryBase != null || loopCountOverride != null ) if ( !fundingReadinessMode && tokens.some( (token) => token.kind === 'option' && ['inventory-asset', 'source-asset', 'balance-report'].includes(token.name), ) ) { console.error( 'Error: --inventory-asset, --source-asset, and --balance-report are only supported with --funding-readiness', ) process.exit(1) } if (!['conservative', 'balanced', 'efficiency'].includes(rankProfile)) { console.error('Error: --rank-profile must be one of conservative, balanced, efficiency') process.exit(1) } if (!['live', 'manual', 'scenario'].includes(externalEntrySource)) { console.error('Error: --external-entry-source must be one of live, manual, scenario') process.exit(1) } if (!['live', 'manual', 'scenario'].includes(externalExitSource)) { console.error('Error: --external-exit-source must be one of live, manual, scenario') process.exit(1) } if (!['aave', 'balancer', 'manual'].includes(publicFlashSource)) { console.error('Error: --public-flash-source must be one of aave, balancer, manual') process.exit(1) } if (tokens.some((token) => token.kind === 'option' && token.name === 'public-flash-source') && !publicLiveSweepMode) { console.error('Error: --public-flash-source is only supported with --public-live-sweep') process.exit(1) } if (tokens.some((token) => token.kind === 'option' && token.name === 'rank-profile') && !inventoryLoopRankMode) { console.error('Error: --rank-profile is only supported with --inventory-loop-rank') process.exit(1) } if (!['quote-push', 'base-unwind', 'both'].includes(loopStrategy)) { console.error('Error: --loop-strategy must be one of quote-push, base-unwind, both') process.exit(1) } if (loopStrategy === 'both' && !publicLiveSweepMode) { console.error('Error: --loop-strategy both is only supported with --public-live-sweep') process.exit(1) } if (flashAddToPool && !inventoryLoopMode) { console.error('Error: --flash-add-to-pool is only supported with --inventory-loop-scan or --inventory-loop-rank') process.exit(1) } if ( tokens.some((token) => token.kind === 'option' && token.name === 'flash-provider-cap') && !fullLoopDryRunMode && !publicLiveSweepMode && sequentialMatchedLoops == null ) { console.error( 'Error: --flash-provider-cap is only supported with --full-loop-dry-run, --public-live-sweep, or --sequential-matched-loops', ) process.exit(1) } if ( tokens.some((token) => token.kind === 'option' && token.name === 'flash-provider-name') && !fullLoopDryRunMode && !publicLiveSweepMode && sequentialMatchedLoops == null ) { console.error( 'Error: --flash-provider-name is only supported with --full-loop-dry-run, --public-live-sweep, or --sequential-matched-loops', ) process.exit(1) } if ( tokens.some((token) => token.kind === 'option' && ['flash-provider-address', 'flash-provider-token-address', 'flash-provider-rpc-url'].includes(token.name), ) && !fullLoopDryRunMode ) { console.error( 'Error: --flash-provider-address, --flash-provider-token-address, and --flash-provider-rpc-url are only supported with --full-loop-dry-run', ) process.exit(1) } if ( tokens.some((token) => token.kind === 'option' && [ 'loop-strategy', 'owned-base-add', 'flash-topup-quote', 'atomic-bridge-base-amount', 'atomic-destination-amount', 'atomic-destination-asset', 'atomic-destination-decimals', 'atomic-corridor-label', 'scan-atomic-bridge-max', 'external-via-asset', 'external-fee-bps', 'external-entry-price', 'external-exit-price', 'external-entry-fee-bps', 'external-exit-fee-bps', 'external-entry-source', 'external-exit-source', 'measured-gas-quote', 'measured-gas-source', 'execution-grade', ].includes(token.name), ) && !fullLoopDryRunMode && !publicLiveSweepMode && sequentialMatchedLoops == null ) { console.error( 'Error: strategy routing flags are only supported with --full-loop-dry-run, --public-live-sweep, or --sequential-matched-loops', ) process.exit(1) } if (flashAddToPool && targetFlashBorrow == null) { console.error('Error: --flash-add-to-pool requires --target-flash-borrow') process.exit(1) } if ( extraGuardFlagsUsed && !inventoryLoopMode && !fullLoopDryRunMode && !publicLiveSweepMode && sequentialMatchedLoops == null ) { console.error( 'Error: gas reserve and peg-safety guard flags are only supported with --inventory-loop-scan, --inventory-loop-rank, --full-loop-dry-run, --public-live-sweep, or --sequential-matched-loops', ) process.exit(1) } if ((fullLoopDryRunMode || publicLiveSweepMode || sequentialMatchedLoops != null) && maxCwBurnFraction != null) { console.error('Error: --max-cw-burn-fraction is only supported with --inventory-loop-scan or --inventory-loop-rank') process.exit(1) } if ((fullLoopDryRunMode || publicLiveSweepMode || sequentialMatchedLoops != null) && cooldownBlocks > 0) { console.error('Error: --cooldown-blocks is only supported with --inventory-loop-scan or --inventory-loop-rank') process.exit(1) } if (!(flashTopupQuote >= 0)) { console.error('Error: --flash-topup-quote must be non-negative') process.exit(1) } if (!(atomicBridgeBaseAmount >= 0)) { console.error('Error: --atomic-bridge-base-amount must be non-negative') process.exit(1) } if (atomicDestinationAmount != null && !(atomicDestinationAmount >= 0)) { console.error('Error: --atomic-destination-amount must be non-negative') process.exit(1) } if (!(ownedBaseAdd >= 0)) { console.error('Error: --owned-base-add must be non-negative') process.exit(1) } if (!(oraclePrice > 0)) { console.error('Error: --oracle-price must be greater than zero') process.exit(1) } if (gasReserveFlagsUsed && measuredGasQuote != null) { console.error('Error: use either modeled gas inputs or --measured-gas-quote, not both') process.exit(1) } if (gasReserveFlagsUsed) { if (gasTxCount == null || gasPerTx == null || maxFeeGwei == null || nativeTokenPrice == null) { console.error( 'Error: native gas reserve requires --gas-tx-count, --gas-per-tx, --max-fee-gwei, and --native-token-price together', ) process.exit(1) } if (!(gasPerTx > 0) || !(maxFeeGwei > 0) || !(nativeTokenPrice > 0)) { console.error('Error: --gas-per-tx, --max-fee-gwei, and --native-token-price must be greater than zero') process.exit(1) } } if (measuredGasQuote != null && !(measuredGasQuote > 0)) { console.error('Error: --measured-gas-quote must be greater than zero') process.exit(1) } if (maxPostTradeDeviationBps != null && !(maxPostTradeDeviationBps >= 0)) { console.error('Error: --max-post-trade-deviation-bps must be non-negative') process.exit(1) } if (!(externalFeeBps >= 0) || !(externalEntryFeeBps >= 0) || !(externalExitFeeBps >= 0)) { console.error('Error: external fee/slippage bps values must be non-negative') process.exit(1) } if (maxCwBurnFraction != null) { if (inventoryBase == null) { console.error('Error: --max-cw-burn-fraction requires --inventory-base') process.exit(1) } if (!(maxCwBurnFraction >= 0 && maxCwBurnFraction <= 1)) { console.error('Error: --max-cw-burn-fraction must be between 0 and 1') process.exit(1) } } const deployerAddressForLiveProbe = process.env.DEPLOYER_ADDRESS ?? '0x4A666F96fC8764181194447A7dFdb7d471b301C8' const inventoryLoopGuardConfig = buildInventoryLoopGuardConfig({ minRetainedUsdc, gasTxCount, gasPerTx, maxFeeGwei, nativeTokenPrice, quoteDecimals, oraclePrice, maxPostTradeDeviationBps, maxCwBurnFraction, cooldownBlocks, measuredGasQuote, measuredGasSource, estimatedGasQuote: null, estimatedGasSource: null, }) if (sequentialMatchedLoops != null) { if ( fullLoopDryRunMode || publicLiveSweepMode || fundingReadinessMode || inventoryLoopScanMode || inventoryLoopRankMode || seedMode ) { console.error('Error: --sequential-matched-loops cannot be combined with other primary modes') process.exit(1) } if (scanAtomicBridgeMax) { console.error('Error: --scan-atomic-bridge-max is only supported with --full-loop-dry-run') process.exit(1) } if (B == null || Q == null) { console.error('Error: --sequential-matched-loops requires -B and -Q') process.exit(1) } if (loopStrategy !== 'quote-push') { console.error('Error: --sequential-matched-loops requires --loop-strategy quote-push') process.exit(1) } if (externalExitPrice == null) { console.error( 'Error: --sequential-matched-loops (quote-push) requires --external-exit-price or --external-price', ) process.exit(1) } const firstLoopFlash = Math.max( 1, Math.round((Math.min(B, Q) * matchedFlashNumerator) / matchedFlashDenominator), ) if (flashTopupQuote > firstLoopFlash) { console.error('Error: --flash-topup-quote cannot exceed the first-loop modeled flash borrow size') process.exit(1) } if (flashProviderAddress && flashProviderTokenAddress) { console.error( 'Error: --sequential-matched-loops does not support ERC-3156 flash probes; omit --flash-provider-address/--flash-provider-token-address', ) process.exit(1) } const mainnetPoolContextSeq = loadMainnetPool(baseAsset, quoteAsset) const livePoolFeeBpsSeq = mainnetPoolContextSeq?.poolAddress != null ? tryReadPoolFeeBpsViaCast(1, mainnetPoolContextSeq.poolAddress) : null const lpFeeSequential = !lpFeeBpsWasExplicit && livePoolFeeBpsSeq != null ? livePoolFeeBpsSeq : lpFeeBps printSequentialMatchedLadder({ iterations: sequentialMatchedLoops, startB: B, startQ: Q, flashNumerator: matchedFlashNumerator, flashDenominator: matchedFlashDenominator, lpFeeBps: lpFeeSequential, flashFeeBps, externalExitPrice, externalExitFeeBps, externalViaAsset, quoteAsset, baseAsset, quoteDecimals, baseDecimals, guardConfig: inventoryLoopGuardConfig, flashProviderCap, flashProviderName, ownedBaseAdd, flashTopupQuote, atomicBridgeBaseAmount, atomicDestinationAmount, atomicDestinationAsset: atomicDestinationAsset ?? baseAsset, atomicDestinationDecimals: atomicDestinationDecimals ?? baseDecimals, atomicCorridorLabel, }) process.exit(0) } if (fundingReadinessMode) { if (targetQuotePerPool != null && targetTotalQuote != null) { console.error('Error: use either --target-quote-per-pool or --target-total-quote with --funding-readiness, not both') process.exit(1) } if (targetQuotePerPool == null && targetTotalQuote == null) { console.error('Error: --funding-readiness requires --target-quote-per-pool or --target-total-quote') process.exit(1) } if (targetQuotePerPool != null && seedPools == null && loopCountOverride == null) { console.error('Error: --target-quote-per-pool requires --seed-pools or --loop-count with --funding-readiness') process.exit(1) } const totalQuoteTarget = targetTotalQuote != null ? targetTotalQuote : (seedPools ?? loopCountOverride) * targetQuotePerPool if (!(totalQuoteTarget > 0)) { console.error('Error: readiness target quote must be positive') process.exit(1) } const mainnetPool = loadMainnetPool(inventoryAsset, quoteAsset) if (!mainnetPool) { console.error( `Error: could not find a mainnet pool row for ${inventoryAsset}/${quoteAsset} in cross-chain-pmm-lps/config/deployment-status.json`, ) process.exit(1) } const resolvedReserves = B != null && Q != null ? { baseReserve: B, quoteReserve: Q, source: 'CLI -B/-Q' } : tryReadPoolReservesViaCast(1, mainnetPool.poolAddress) if (!resolvedReserves) { console.error( 'Error: --funding-readiness requires -B/-Q or a reachable Ethereum mainnet RPC to read live pool reserves', ) process.exit(1) } const readinessLpFeeBps = !lpFeeBpsWasExplicit && mainnetPool.feeBps != null ? mainnetPool.feeBps : lpFeeBps const report = loadBalanceReport(balanceReportPath) printFundingReadiness({ inventoryAsset, sourceAsset, quoteAsset, totalQuoteTarget, lpFeeBps: readinessLpFeeBps, baseReserve: resolvedReserves.baseReserve, quoteReserve: resolvedReserves.quoteReserve, reserveSource: resolvedReserves.source, poolAddress: mainnetPool.poolAddress, report, reportPath: balanceReportPath, }) process.exit(0) } if (fullLoopDryRunMode) { const x = values.trade != null ? parseNum(values.trade) : null if (B == null || Q == null || x == null) { console.error('Error: --full-loop-dry-run requires -B, -Q, and -x') process.exit(1) } if (!(x > 0)) { console.error('Error: -x must be greater than zero for --full-loop-dry-run') process.exit(1) } if (flashTopupQuote > x) { console.error('Error: --flash-topup-quote cannot exceed the flash borrow size -x') process.exit(1) } if (atomicBridgeBaseAmount > 0 && loopStrategy !== 'quote-push') { console.error('Error: --atomic-bridge-base-amount is only supported with --loop-strategy quote-push') process.exit(1) } if (scanAtomicBridgeMax && loopStrategy !== 'quote-push') { console.error('Error: --scan-atomic-bridge-max is only supported with --loop-strategy quote-push') process.exit(1) } if (loopStrategy === 'quote-push' && externalExitPrice == null) { console.error('Error: quote-push full-loop dry-run requires --external-exit-price or --external-price') process.exit(1) } if (loopStrategy === 'base-unwind' && externalEntryPrice == null) { console.error('Error: base-unwind full-loop dry-run requires --external-entry-price or --external-price') process.exit(1) } if (flashProviderCap != null && !(flashProviderCap > 0)) { console.error('Error: --flash-provider-cap must be greater than zero') process.exit(1) } if ((flashProviderAddress == null) !== (flashProviderTokenAddress == null)) { console.error('Error: --flash-provider-address and --flash-provider-token-address must be provided together') process.exit(1) } if (targetQuotePerPool != null && targetTotalQuote != null) { console.error('Error: use either --target-quote-per-pool or --target-total-quote with --full-loop-dry-run, not both') process.exit(1) } if (targetQuotePerPool != null && seedPools == null && loopCountOverride == null) { console.error('Error: --target-quote-per-pool requires --seed-pools or --loop-count with --full-loop-dry-run') process.exit(1) } const probedFlashProvider = flashProviderAddress && flashProviderTokenAddress ? tryProbeErc3156FlashProvider(flashProviderAddress, flashProviderTokenAddress, x, flashProviderRpcUrl) : null const effectiveFlashProviderCap = probedFlashProvider?.maxFlashLoan != null && flashProviderCap != null ? Math.min(flashProviderCap, probedFlashProvider.maxFlashLoan) : (probedFlashProvider?.maxFlashLoan ?? flashProviderCap) const effectiveFlashFeeAmount = probedFlashProvider?.flashFeeAmount ?? null const effectiveFlashFeeSource = probedFlashProvider?.source ?? (flashProviderAddress && flashProviderTokenAddress ? `manual flash fee bps (${flashFeeBps}) — probe failed via ${flashProviderAddress}` : null) const mainnetPoolContext = loadMainnetPool(baseAsset, quoteAsset) const livePoolFeeBps = mainnetPoolContext?.poolAddress != null ? tryReadPoolFeeBpsViaCast(1, mainnetPoolContext.poolAddress) : null const quoteSurface = mainnetPoolContext?.poolAddress != null ? tryProbePoolQuoteSurfaceViaCast( 1, mainnetPoolContext.poolAddress, deployerAddressForLiveProbe, ) : null const estimatedMainnetGasQuote = measuredGasQuote == null && mainnetPoolContext?.poolAddress != null && mainnetPoolContext.baseAddress != null && mainnetPoolContext.quoteAddress != null ? deriveEstimatedGasQuoteForMainnetStrategy({ strategy: loopStrategy, poolAddress: mainnetPoolContext.poolAddress, baseAddress: mainnetPoolContext.baseAddress, quoteAddress: mainnetPoolContext.quoteAddress, amountInQuoteRaw: x, externalEntryPrice, externalEntryFeeBps, quoteDecimals, baseDecimals, nativeTokenPrice, fromAddress: deployerAddressForLiveProbe, }) : null const fullLoopGuardConfig = measuredGasQuote == null && estimatedMainnetGasQuote ? buildInventoryLoopGuardConfig({ minRetainedUsdc, gasTxCount: null, gasPerTx: null, maxFeeGwei: null, nativeTokenPrice, quoteDecimals, oraclePrice, maxPostTradeDeviationBps, maxCwBurnFraction, cooldownBlocks, measuredGasQuote: null, measuredGasSource: null, estimatedGasQuote: estimatedMainnetGasQuote.quoteCost, estimatedGasSource: estimatedMainnetGasQuote.source, }) : inventoryLoopGuardConfig printFullLoopDryRun({ B, Q, x, lpFeeBps: livePoolFeeBps ?? lpFeeBps, flashFeeBps, loopStrategy, ownedBaseAdd, flashTopupQuote, externalEntryPrice, externalExitPrice, externalEntryFeeBps, externalExitFeeBps, externalViaAsset, quoteAsset, baseAsset, quoteDecimals, baseDecimals, guardConfig: fullLoopGuardConfig, flashProviderCap: effectiveFlashProviderCap, flashProviderName, flashFeeAmount: effectiveFlashFeeAmount, flashFeeSource: effectiveFlashFeeSource, seedPools, targetQuotePerPool, targetTotalQuote, loopCount: loopCountOverride ?? seedPools ?? 1, quoteSurface, externalEntrySource, externalExitSource, livePoolFeeBps, executionGradeRequired, atomicBridgeBaseAmount, atomicDestinationAmount, atomicDestinationAsset: atomicDestinationAsset ?? baseAsset, atomicDestinationDecimals: atomicDestinationDecimals ?? baseDecimals, atomicCorridorLabel, scanAtomicBridgeMax, }) process.exit(0) } if (publicLiveSweepMode) { if (targetQuotePerPool != null && targetTotalQuote != null) { console.error('Error: use either --target-quote-per-pool or --target-total-quote with --public-live-sweep, not both') process.exit(1) } if (targetQuotePerPool != null && seedPools == null && loopCountOverride == null) { console.error('Error: --target-quote-per-pool requires --seed-pools or --loop-count with --public-live-sweep') process.exit(1) } if ((loopStrategy === 'quote-push' || loopStrategy === 'both') && externalExitPrice == null) { console.error('Error: quote-push public live sweep requires --external-exit-price or --external-price') process.exit(1) } if ((loopStrategy === 'base-unwind' || loopStrategy === 'both') && externalEntryPrice == null) { console.error('Error: base-unwind public live sweep requires --external-entry-price or --external-price') process.exit(1) } if (publicFlashSource === 'manual' && flashProviderCap == null) { console.error('Error: --public-flash-source manual requires --flash-provider-cap') process.exit(1) } printPublicLiveSweep({ scanStr: values.scan ?? null, loopStrategy, ownedBaseAdd, flashTopupQuote, flashProviderCap, flashProviderName, flashFeeBps, externalEntryPrice, externalExitPrice, externalEntryFeeBps, externalExitFeeBps, externalViaAsset, atomicBridgeBaseAmount, atomicDestinationAmount, atomicDestinationAsset: atomicDestinationAsset ?? baseAsset, atomicDestinationDecimals: atomicDestinationDecimals ?? baseDecimals, atomicCorridorLabel, seedPools, targetQuotePerPool, targetTotalQuote, loopCount: loopCountOverride ?? seedPools ?? 1, guardConfig: inventoryLoopGuardConfig, publicFlashSource, externalEntrySource, externalExitSource, executionGradeRequired, }) process.exit(0) } if (seedMode) { if (targetQuotePerPool != null && targetTotalQuote != null) { console.error('Error: use either --target-quote-per-pool or --target-total-quote, not both') process.exit(1) } if (targetQuotePerPool == null && targetTotalQuote == null) { console.error('Error: seeding mode requires --target-quote-per-pool or --target-total-quote') process.exit(1) } if (targetQuotePerPool != null && seedPools == null && loopCountOverride == null) { console.error('Error: --target-quote-per-pool requires --seed-pools or --loop-count') process.exit(1) } const totalQuoteTarget = targetTotalQuote != null ? targetTotalQuote : seedPools * targetQuotePerPool const loopCount = loopCountOverride ?? seedPools ?? 1 if (!(totalQuoteTarget > 0)) { console.error('Error: total quote target must be positive') process.exit(1) } if (B != null || Q != null) { if (B == null || Q == null) { console.error('Error: PMM seeding mode requires both -B and -Q') process.exit(1) } printSeedingPlanFromPmm( B, Q, totalQuoteTarget, lpFeeBps, inventoryBase, loopCount, seedPools, targetQuotePerPool, ) process.exit(0) } if (externalPrice == null) { console.error('Error: seeding mode requires either -B/-Q for PMM source math or --external-price for external monetization') process.exit(1) } printSeedingPlanExternal( totalQuoteTarget, externalPrice, exitFeeBps, inventoryBase, loopCount, seedPools, targetQuotePerPool, ) process.exit(0) } if (inventoryLoopScanMode) { if (B == null || Q == null) { console.error('Error: --inventory-loop-scan requires -B and -Q') process.exit(1) } printInventoryLoopSafetyScan( B, Q, values.scan ?? null, lpFeeBps, flashFeeBps, inventoryBase, targetFlashBorrow, inventoryLoopGuardConfig, flashAddToPool, ) process.exit(0) } if (inventoryLoopRankMode) { if (B == null || Q == null) { console.error('Error: --inventory-loop-rank requires -B and -Q') process.exit(1) } printInventoryLoopRanking( B, Q, values.scan ?? null, lpFeeBps, flashFeeBps, inventoryBase, targetFlashBorrow, inventoryLoopGuardConfig, rankProfile, flashAddToPool, ) process.exit(0) } if (values['mainnet-map']) { const delta = values['compare-deepen'] != null ? parseNum(values['compare-deepen']) : null const m = loadMainnetCwUsdcUsdc() printMainnetMap( delta, B, Q, values.scan ?? null, lpFeeBps, m?.feeBps ?? null, !lpFeeBpsWasExplicit, ) process.exit(0) } if (values.scan) { if (B == null || Q == null) { console.error('Error: --scan requires -B and -Q') process.exit(1) } const sizes = values.scan.split(',').map((s) => parseNum(s.trim())) console.log('trade_x\tbase_out\tvwap\trepay\tP_ext*\tPnL@ext') for (const x of sizes) { const { baseOut, vwap } = quoteInToBaseOut(B, Q, x, lpFeeBps) const repay = repayUsdc(x, flashFeeBps) const pStar = breakEvenExternalPrice(x, baseOut, flashFeeBps, exitFeeBps) const pi = externalPrice != null ? profit(x, baseOut, externalPrice, flashFeeBps, exitFeeBps) : NaN console.log( [fmt(x), fmt(baseOut), fmt(vwap), fmt(repay), fmt(pStar), Number.isFinite(pi) ? fmt(pi) : '—'].join( '\t', ), ) } process.exit(0) } const x = values.trade != null ? parseNum(values.trade) : null if (B == null || Q == null || x == null) { console.error('Error: provide -B, -Q, -x or use --examples') process.exit(1) } printScenario('custom', B, Q, x, lpFeeBps, flashFeeBps, externalPrice, exitFeeBps) } main()