origin-morpho-utils 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Volumes/origin/morpho-utils/dist/chunk-35AORYVF.cjs","../src/abi/erc20.ts","../src/abi/irm-adaptive-curve.ts","../src/abi/meta-morpho.ts","../src/abi/morpho.ts","../src/fetch.ts","../src/addresses.ts","../src/deposit-impact.ts","../src/withdrawal-impact.ts","../src/find-max.ts","../src/find-max-impact.ts","../src/rpc.ts"],"names":["sim","simulated"],"mappings":"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AAA;AACI,IAAA;AACL,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACF,IAAA;AACF,EAAA;AACO,EAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACD,EAAA;AACH;AVukBa;AACA;AWroBJ;AAiBH;AAEG;AACA,EAAA;AACL,IAAA;AACO,IAAA;AACD,MAAA;AACE,MAAA;AACN,MAAA;AACA,MAAA;AACA,MAAA;AACD,IAAA;AACF,EAAA;AACH;AAEA;AAMS,EAAA;AACT;AAEA;AAMQ,EAAA;AACC,EAAA;AACL,IAAA;AACD,EAAA;AACH;AAEA;AAOS,EAAA;AACT;AAEA;AAOS,EAAA;AACT;AAEA;AAQS,EAAA;AACT;AAEA;AAQS,EAAA;AACT;AX4kBa;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/Volumes/origin/morpho-utils/dist/chunk-35AORYVF.cjs","sourcesContent":[null,"/** Minimal ERC20 ABI — decimals + symbol. */\nexport const erc20Abi = [\n {\n inputs: [],\n name: 'decimals',\n outputs: [{ name: '', type: 'uint8' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [],\n name: 'symbol',\n outputs: [{ name: '', type: 'string' }],\n stateMutability: 'view',\n type: 'function',\n },\n] as const\n","/** Minimal IRM Adaptive Curve ABI — rateAtTarget only. */\nexport const irmAdaptiveCurveAbi = [\n {\n inputs: [{ name: 'id', type: 'bytes32' }],\n name: 'rateAtTarget',\n outputs: [{ name: '', type: 'int256' }],\n stateMutability: 'view',\n type: 'function',\n },\n] as const\n","/** Minimal MetaMorpho (ERC4626 vault) ABI — only view functions used by fetchVaultMarketsViem. */\nexport const metaMorphoAbi = [\n {\n inputs: [],\n name: 'supplyQueueLength',\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [],\n name: 'withdrawQueueLength',\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [],\n name: 'totalAssets',\n outputs: [{ name: 'totalManagedAssets', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [{ name: '', type: 'uint256' }],\n name: 'supplyQueue',\n outputs: [{ name: '', type: 'bytes32' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [{ name: '', type: 'uint256' }],\n name: 'withdrawQueue',\n outputs: [{ name: '', type: 'bytes32' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [{ name: '', type: 'bytes32' }],\n name: 'config',\n outputs: [\n { name: 'cap', type: 'uint184' },\n { name: 'enabled', type: 'bool' },\n { name: 'removableAt', type: 'uint64' },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n] as const\n","/** Minimal Morpho Blue ABI — only view functions used by fetchVaultMarketsViem. */\nexport const morphoAbi = [\n {\n inputs: [{ name: 'id', type: 'bytes32' }],\n name: 'market',\n outputs: [\n { name: 'totalSupplyAssets', type: 'uint128' },\n { name: 'totalSupplyShares', type: 'uint128' },\n { name: 'totalBorrowAssets', type: 'uint128' },\n { name: 'totalBorrowShares', type: 'uint128' },\n { name: 'lastUpdate', type: 'uint128' },\n { name: 'fee', type: 'uint128' },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [\n { name: 'id', type: 'bytes32' },\n { name: 'user', type: 'address' },\n ],\n name: 'position',\n outputs: [\n { name: 'supplyShares', type: 'uint256' },\n { name: 'borrowShares', type: 'uint128' },\n { name: 'collateral', type: 'uint128' },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [{ name: 'id', type: 'bytes32' }],\n name: 'idToMarketParams',\n outputs: [\n { name: 'loanToken', type: 'address' },\n { name: 'collateralToken', type: 'address' },\n { name: 'oracle', type: 'address' },\n { name: 'irm', type: 'address' },\n { name: 'lltv', type: 'uint256' },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n] as const\n","/**\n * Market data fetching for Morpho Blue / MetaMorpho vaults using viem.\n */\nimport type { PublicClient } from 'viem'\nimport { getAddress } from 'viem'\n\nimport { erc20Abi } from './abi/erc20.js'\nimport { irmAdaptiveCurveAbi } from './abi/irm-adaptive-curve.js'\nimport { metaMorphoAbi } from './abi/meta-morpho.js'\nimport { morphoAbi } from './abi/morpho.js'\nimport { weightedVaultApyDetailed } from './math.js'\nimport type { MarketForApy, VaultApyResult, VaultFetchResult } from './types.js'\n\nconst ADDRESS_ZERO = '0x0000000000000000000000000000000000000000'\n\n/**\n * Fetch all market data for a MetaMorpho vault using viem multicall.\n *\n * Returns market data needed for APY computation and simulation,\n * plus the vault's idle (undeployed) assets.\n */\nexport async function fetchVaultMarketsViem(\n client: PublicClient,\n vaultAddress: string,\n morphoAddress: string,\n): Promise<VaultFetchResult> {\n const vault = getAddress(vaultAddress)\n const morpho = getAddress(morphoAddress)\n\n // 1. Queue lengths + total assets\n const [supplyLen, withdrawLen, totalAssets] = await client.multicall({\n contracts: [\n { address: vault, abi: metaMorphoAbi, functionName: 'supplyQueueLength' },\n { address: vault, abi: metaMorphoAbi, functionName: 'withdrawQueueLength' },\n { address: vault, abi: metaMorphoAbi, functionName: 'totalAssets' },\n ],\n allowFailure: false,\n })\n\n const supplyLenN = Number(supplyLen)\n const withdrawLenN = Number(withdrawLen)\n if (supplyLenN === 0 && withdrawLenN === 0) return { markets: [], idleAssets: 0n }\n\n // 2. Market IDs from both queues\n const queueCalls = [\n ...Array.from({ length: supplyLenN }, (_, i) => ({\n address: vault,\n abi: metaMorphoAbi,\n functionName: 'supplyQueue' as const,\n args: [BigInt(i)] as const,\n })),\n ...Array.from({ length: withdrawLenN }, (_, i) => ({\n address: vault,\n abi: metaMorphoAbi,\n functionName: 'withdrawQueue' as const,\n args: [BigInt(i)] as const,\n })),\n ]\n\n const queueResults = await client.multicall({ contracts: queueCalls, allowFailure: false })\n const supplyIds = queueResults.slice(0, supplyLenN) as `0x${string}`[]\n const withdrawIds = queueResults.slice(supplyLenN) as `0x${string}`[]\n\n // 3. Union market IDs + withdraw queue ordering\n const supplySet = new Set(supplyIds)\n const withdrawSet = new Set(withdrawIds)\n const withdrawQueueOrder = new Map<string, number>()\n ;(withdrawIds as string[]).forEach((id, i) => withdrawQueueOrder.set(id, i))\n const allIds = [...new Set([...supplyIds, ...withdrawIds])]\n\n if (allIds.length === 0) return { markets: [], idleAssets: 0n }\n\n // 4. Fetch market state, position, params, config (parallel multicalls)\n const [marketStates, positions, marketParams, configs] = await Promise.all([\n client.multicall({\n contracts: allIds.map((id) => ({\n address: morpho,\n abi: morphoAbi,\n functionName: 'market' as const,\n args: [id] as const,\n })),\n allowFailure: false,\n }),\n client.multicall({\n contracts: allIds.map((id) => ({\n address: morpho,\n abi: morphoAbi,\n functionName: 'position' as const,\n args: [id, vault] as const,\n })),\n allowFailure: false,\n }),\n client.multicall({\n contracts: allIds.map((id) => ({\n address: morpho,\n abi: morphoAbi,\n functionName: 'idToMarketParams' as const,\n args: [id] as const,\n })),\n allowFailure: false,\n }),\n client.multicall({\n contracts: allIds.map((id) => ({\n address: vault,\n abi: metaMorphoAbi,\n functionName: 'config' as const,\n args: [id] as const,\n })),\n allowFailure: false,\n }),\n ])\n\n // 5. Per-market IRM + decimals + token symbols (single multicall batch)\n type MulticallContract = Parameters<PublicClient['multicall']>[0]['contracts'][number]\n const irmAndDecimalCalls: MulticallContract[] = marketParams.flatMap(\n ([loanToken, collateralToken, , irm]: readonly [string, string, string, string, bigint], i: number) => {\n const hasIrm = irm && irm.toLowerCase() !== ADDRESS_ZERO\n const hasCollateral = collateralToken && collateralToken.toLowerCase() !== ADDRESS_ZERO\n const calls: (MulticallContract | null)[] = [\n hasIrm\n ? {\n address: getAddress(irm),\n abi: irmAdaptiveCurveAbi,\n functionName: 'rateAtTarget' as const,\n args: [allIds[i]] as const,\n }\n : null,\n { address: getAddress(loanToken), abi: erc20Abi, functionName: 'decimals' as const },\n { address: getAddress(loanToken), abi: erc20Abi, functionName: 'symbol' as const },\n hasCollateral ? { address: getAddress(collateralToken), abi: erc20Abi, functionName: 'symbol' as const } : null,\n ]\n return calls.filter((c): c is MulticallContract => c !== null)\n },\n )\n\n const irmAndDecimalResults = await client.multicall({\n contracts: irmAndDecimalCalls as readonly MulticallContract[],\n allowFailure: true,\n })\n\n // Map results back, accounting for skipped IRM and collateral symbol calls\n let resultIdx = 0\n const ratesAtTarget: bigint[] = []\n const decimals: number[] = []\n const loanSymbols: string[] = []\n const collateralSymbols: string[] = []\n for (const [, collateralToken, , irm] of marketParams as unknown as readonly [\n string,\n string,\n string,\n string,\n bigint,\n ][]) {\n const hasIrm = irm && irm.toLowerCase() !== ADDRESS_ZERO\n const hasCollateral = collateralToken && collateralToken.toLowerCase() !== ADDRESS_ZERO\n if (hasIrm) {\n const r = irmAndDecimalResults[resultIdx++]\n const rate = r.status === 'success' ? (r.result as bigint) : 0n\n ratesAtTarget.push(rate < 0n ? 0n : rate)\n } else {\n ratesAtTarget.push(0n)\n }\n const d = irmAndDecimalResults[resultIdx++]\n decimals.push(d.status === 'success' ? Number(d.result) : 18)\n const ls = irmAndDecimalResults[resultIdx++]\n loanSymbols.push(ls.status === 'success' ? (ls.result as string) : '???')\n if (hasCollateral) {\n const cs = irmAndDecimalResults[resultIdx++]\n collateralSymbols.push(cs.status === 'success' ? (cs.result as string) : '???')\n } else {\n collateralSymbols.push('—')\n }\n }\n\n // 6. Assemble\n const markets: MarketForApy[] = allIds.map((marketId, i) => {\n const [totalSupplyAssets, totalSupplyShares, totalBorrowAssets, , , fee] = marketStates[i]\n const [supplyShares] = positions[i]\n const [cap] = configs[i]\n\n let vaultSupplyAssets = 0n\n if (supplyShares > 0n && totalSupplyShares > 0n) {\n vaultSupplyAssets = (supplyShares * totalSupplyAssets) / totalSupplyShares\n }\n\n const [loanToken, collateralToken] = marketParams[i] as unknown as [string, string, string, string, bigint]\n\n return {\n marketId,\n name: `${collateralSymbols[i]}/${loanSymbols[i]}`,\n loanToken,\n collateralToken,\n totalSupplyAssets,\n totalBorrowAssets,\n fee,\n vaultSupplyAssets,\n rateAtTarget: ratesAtTarget[i],\n cap,\n decimals: decimals[i],\n inSupplyQueue: supplySet.has(marketId as `0x${string}`),\n inWithdrawQueue: withdrawSet.has(marketId as `0x${string}`),\n withdrawQueueIndex: withdrawQueueOrder.get(marketId) ?? -1,\n }\n })\n\n const sumVaultSupply = markets.reduce((acc, m) => acc + m.vaultSupplyAssets, 0n)\n const idleAssets = totalAssets > sumVaultSupply ? totalAssets - sumVaultSupply : 0n\n\n return { markets, idleAssets }\n}\n\n/**\n * Fetch vault markets and compute the weighted APY in one call.\n * Returns null if the vault has no markets yet (not yet deployed).\n * Returns `apy`, `markets`, and `idleAssets` so callers can reuse for simulation.\n */\nexport async function fetchVaultApyViem(\n client: PublicClient,\n vaultAddress: string,\n morphoAddress: string,\n options?: { includeMarkets?: boolean },\n): Promise<VaultApyResult | null> {\n const { markets, idleAssets } = await fetchVaultMarketsViem(client, vaultAddress, morphoAddress)\n if (markets.length === 0) return null\n const detailed = weightedVaultApyDetailed(markets)\n return { apy: detailed.apy, markets, idleAssets, marketDetails: options?.includeMarkets ? detailed.markets : [] }\n}\n","/** Well-known Morpho Blue singleton addresses per chain. */\nexport const MORPHO_BLUE_ADDRESSES: Record<number, `0x${string}`> = {\n 1: '0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb', // Ethereum\n 8453: '0xbbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb', // Base\n 999: '0x68e37de8d93d3496ae143f2e900490f6280c57cd', // HyperEVM\n}\n\n/** Look up Morpho Blue singleton address by chain ID. Throws if unknown. */\nexport function getMorphoBlueAddress(chainId: number): `0x${string}` {\n const addr = MORPHO_BLUE_ADDRESSES[chainId]\n if (!addr) {\n throw new Error(\n `No Morpho Blue address configured for chainId ${chainId}. ` +\n `Known chains: ${Object.keys(MORPHO_BLUE_ADDRESSES).join(', ')}`,\n )\n }\n return addr\n}\n","import type { PublicClient } from 'viem'\n\nimport { getMorphoBlueAddress } from './addresses.js'\nimport { fetchVaultApyViem } from './fetch.js'\nimport { mergeMarketDetails, simulateDeposit, weightedVaultApyDetailed } from './math.js'\nimport type { DepositImpactResult } from './types.js'\n\n/**\n * Compute the APY impact of a deposit into a MetaMorpho vault.\n * Makes live on-chain RPC calls via the provided viem PublicClient.\n *\n * @param client viem PublicClient for the target chain\n * @param chainId Chain ID (used to resolve the Morpho Blue singleton address)\n * @param vaultAddress MetaMorpho V1.1 vault address\n * @param depositAmount Deposit size in loan-token base units (e.g. 1e18 for 1 ETH)\n * @param morphoAddress Optional override for the Morpho Blue singleton address\n */\nexport async function computeDepositImpact(\n client: PublicClient,\n chainId: number,\n vaultAddress: string,\n depositAmount: bigint,\n options?: { morphoAddress?: string; includeMarkets?: boolean },\n): Promise<DepositImpactResult> {\n const morpho = options?.morphoAddress ?? getMorphoBlueAddress(chainId)\n const incMkts = options?.includeMarkets ?? false\n\n const result = await fetchVaultApyViem(client, vaultAddress, morpho)\n if (!result) {\n return { currentApy: 0, newApy: 0, impact: 0, impactBps: 0, markets: [] }\n }\n\n const { markets } = result\n const current = weightedVaultApyDetailed(markets)\n const sim = simulateDeposit(markets, depositAmount)\n const simulated = weightedVaultApyDetailed(markets, sim)\n const impact = simulated.apy - current.apy\n\n return {\n currentApy: current.apy,\n newApy: simulated.apy,\n impact,\n impactBps: Math.round(impact * 10000),\n markets: incMkts ? mergeMarketDetails(current.markets, simulated.markets) : [],\n }\n}\n","import type { PublicClient } from 'viem'\n\nimport { getMorphoBlueAddress } from './addresses.js'\nimport { fetchVaultApyViem } from './fetch.js'\nimport { mergeMarketDetails, simulateWithdrawal, weightedVaultApyDetailed } from './math.js'\nimport type { WithdrawalImpactResult } from './types.js'\n\n/**\n * Compute the APY impact of a withdrawal from a MetaMorpho vault.\n * Makes live on-chain RPC calls via the provided viem PublicClient.\n *\n * @param client viem PublicClient for the target chain\n * @param chainId Chain ID (used to resolve the Morpho Blue singleton address)\n * @param vaultAddress MetaMorpho V1.1 vault address\n * @param withdrawAmount Withdrawal size in loan-token base units (e.g. 1e18 for 1 ETH)\n * @param morphoAddress Optional override for the Morpho Blue singleton address\n */\nexport async function computeWithdrawalImpact(\n client: PublicClient,\n chainId: number,\n vaultAddress: string,\n withdrawAmount: bigint,\n options?: { morphoAddress?: string; includeMarkets?: boolean },\n): Promise<WithdrawalImpactResult> {\n const morpho = options?.morphoAddress ?? getMorphoBlueAddress(chainId)\n const incMkts = options?.includeMarkets ?? false\n\n const result = await fetchVaultApyViem(client, vaultAddress, morpho)\n if (!result) {\n return {\n currentApy: 0,\n newApy: 0,\n impact: 0,\n impactBps: 0,\n isPartial: false,\n withdrawableAmount: '0',\n markets: [],\n }\n }\n\n const { markets, idleAssets } = result\n const current = weightedVaultApyDetailed(markets)\n const { sim, withdrawable, remaining } = simulateWithdrawal(markets, withdrawAmount, idleAssets)\n\n // Edge case: full withdrawal drains all vault positions\n const totalVaultAssets = markets.reduce((acc, m) => acc + m.vaultSupplyAssets, 0n) + idleAssets\n const simulated =\n withdrawable >= totalVaultAssets ? { apy: 0, markets: [] } : weightedVaultApyDetailed(markets, {}, sim)\n const impact = simulated.apy - current.apy\n\n return {\n currentApy: current.apy,\n newApy: simulated.apy,\n impact,\n impactBps: Math.round(impact * 10000),\n isPartial: remaining > 0n,\n withdrawableAmount: withdrawable.toString(),\n markets: incMkts ? mergeMarketDetails(current.markets, simulated.markets) : [],\n }\n}\n","/**\n * Binary search to find the maximum deposit/withdrawal amount\n * within an APY impact threshold. Pure math — zero external deps.\n */\nimport { mergeMarketDetails, simulateDeposit, simulateWithdrawal, weightedVaultApyDetailed } from './math.js'\nimport type {\n DepositImpactResult,\n FindMaxConstraint,\n FindMaxDepositResult,\n FindMaxWithdrawalResult,\n MarketApyDetail,\n MarketForApy,\n VaultApyDetailed,\n WithdrawalImpactResult,\n} from './types.js'\n\nfunction defaultPrecision(markets: MarketForApy[]): bigint {\n const decimals = markets.length > 0 ? markets[0].decimals : 18\n return 10n ** BigInt(decimals) // 1 whole token\n}\n\nfunction computeMaxDepositable(markets: MarketForApy[]): bigint {\n return markets\n .filter((m) => m.inSupplyQueue && m.cap > m.vaultSupplyAssets)\n .reduce((sum, m) => sum + (m.cap - m.vaultSupplyAssets), 0n)\n}\n\nfunction computeMaxWithdrawable(markets: MarketForApy[], idleAssets: bigint): bigint {\n const fromMarkets = markets\n .filter((m) => m.inWithdrawQueue && m.withdrawQueueIndex >= 0)\n .reduce((sum, m) => {\n const liquidity = m.totalSupplyAssets > m.totalBorrowAssets ? m.totalSupplyAssets - m.totalBorrowAssets : 0n\n const available = m.vaultSupplyAssets < liquidity ? m.vaultSupplyAssets : liquidity\n return sum + (available > 0n ? available : 0n)\n }, 0n)\n return idleAssets + fromMarkets\n}\n\nfunction buildDepositImpact(\n current: VaultApyDetailed,\n simulated: VaultApyDetailed,\n includeMarkets: boolean,\n): DepositImpactResult {\n const impact = simulated.apy - current.apy\n return {\n currentApy: current.apy,\n newApy: simulated.apy,\n impact,\n impactBps: Math.round(impact * 10000),\n markets: includeMarkets ? mergeMarketDetails(current.markets, simulated.markets) : [],\n }\n}\n\nfunction buildWithdrawalImpact(\n current: VaultApyDetailed,\n simulated: VaultApyDetailed,\n withdrawable: bigint,\n remaining: bigint,\n includeMarkets: boolean,\n): WithdrawalImpactResult {\n const impact = simulated.apy - current.apy\n return {\n currentApy: current.apy,\n newApy: simulated.apy,\n impact,\n impactBps: Math.round(impact * 10000),\n isPartial: remaining > 0n,\n withdrawableAmount: withdrawable.toString(),\n markets: includeMarkets ? mergeMarketDetails(current.markets, simulated.markets) : [],\n }\n}\n\nfunction zeroDepositImpact(markets: MarketForApy[], includeMarkets: boolean): DepositImpactResult {\n if (markets.length === 0) {\n return { currentApy: 0, newApy: 0, impact: 0, impactBps: 0, markets: [] }\n }\n const current = weightedVaultApyDetailed(markets)\n return buildDepositImpact(current, current, includeMarkets)\n}\n\nfunction zeroWithdrawalImpact(\n markets: MarketForApy[],\n idleAssets: bigint,\n includeMarkets: boolean,\n): WithdrawalImpactResult {\n if (markets.length === 0) {\n return { currentApy: 0, newApy: 0, impact: 0, impactBps: 0, isPartial: false, withdrawableAmount: '0', markets: [] }\n }\n const current = weightedVaultApyDetailed(markets)\n return buildWithdrawalImpact(current, current, 0n, 0n, includeMarkets)\n}\n\n/**\n * Find the maximum deposit amount within an APY impact threshold using binary search.\n *\n * @param markets - Market data from fetchVaultMarkets\n * @param maxAmount - Ceiling amount in base units\n * @param maxImpactBps - Maximum allowed APY impact in basis points (e.g. 50 = 0.5%)\n * @param options.precision - Search granularity in base units. Default: 1 whole token.\n * @param options.includeMarkets - Include per-market details in impact result. Default: false.\n * @param options.constraint - Custom constraint callback. Must be monotonic: if amount X fails, all X+n must also fail.\n */\nexport async function findMaxDepositAmount(\n markets: MarketForApy[],\n maxAmount: bigint,\n maxImpactBps: number,\n options?: { precision?: bigint; includeMarkets?: boolean; constraint?: FindMaxConstraint },\n): Promise<FindMaxDepositResult> {\n const raw = options?.precision ?? defaultPrecision(markets)\n const step = raw > 0n ? raw : 1n\n const maxImpact = maxImpactBps / 10000\n const incMkts = options?.includeMarkets ?? false\n const constraint = options?.constraint\n\n if (markets.length === 0 || maxAmount === 0n) {\n return {\n amount: 0n,\n maxPossibleAmount: 0n,\n isMaxAmount: maxAmount === 0n,\n isCapped: false,\n impact: zeroDepositImpact(markets, incMkts),\n }\n }\n\n const maxPossible = computeMaxDepositable(markets)\n const effectiveMax = maxAmount < maxPossible ? maxAmount : maxPossible\n\n if (effectiveMax === 0n) {\n return {\n amount: 0n,\n maxPossibleAmount: maxPossible,\n isMaxAmount: false,\n isCapped: maxPossible === 0n,\n impact: zeroDepositImpact(markets, incMkts),\n }\n }\n\n const current = weightedVaultApyDetailed(markets)\n\n // Helper: is this amount acceptable (APY impact + custom constraint)?\n async function isAcceptable(amount: bigint): Promise<boolean> {\n const sim = simulateDeposit(markets, amount)\n const simulated = weightedVaultApyDetailed(markets, sim)\n const impact = Math.abs(simulated.apy - current.apy)\n if (impact > maxImpact) return false\n if (!constraint) return true\n return constraint({\n amount,\n currentApy: current.apy,\n simulatedApy: simulated.apy,\n impactBps: Math.round((simulated.apy - current.apy) * 10000),\n markets: mergeMarketDetails(current.markets, simulated.markets),\n })\n }\n\n // Fast path: full effectiveMax within threshold\n if (await isAcceptable(effectiveMax)) {\n const sim = simulateDeposit(markets, effectiveMax)\n const simulated = weightedVaultApyDetailed(markets, sim)\n return {\n amount: effectiveMax,\n maxPossibleAmount: maxPossible,\n isMaxAmount: effectiveMax === maxAmount,\n isCapped: effectiveMax < maxAmount,\n impact: buildDepositImpact(current, simulated, incMkts),\n }\n }\n\n // Fast path: even smallest step exceeds threshold\n if (step >= effectiveMax || !(await isAcceptable(step))) {\n return {\n amount: 0n,\n maxPossibleAmount: maxPossible,\n isMaxAmount: false,\n isCapped: false,\n impact: zeroDepositImpact(markets, incMkts),\n }\n }\n\n // Binary search: lo is within threshold, hi exceeds it\n let lo = step\n let hi = effectiveMax\n\n while (hi - lo > step) {\n let mid = lo + (hi - lo) / 2n\n mid = (mid / step) * step // snap to precision grid\n if (mid === lo) break\n\n if (await isAcceptable(mid)) {\n lo = mid\n } else {\n hi = mid\n }\n }\n\n const sim = simulateDeposit(markets, lo)\n const simulated = weightedVaultApyDetailed(markets, sim)\n return {\n amount: lo,\n maxPossibleAmount: maxPossible,\n isMaxAmount: false,\n isCapped: false,\n impact: buildDepositImpact(current, simulated, incMkts),\n }\n}\n\n/**\n * Find the maximum withdrawal amount within an APY impact threshold using binary search.\n *\n * @param markets - Market data from fetchVaultMarkets\n * @param idleAssets - Vault idle assets (undeployed)\n * @param maxAmount - Ceiling amount in base units\n * @param maxImpactBps - Maximum allowed APY impact in basis points (e.g. 50 = 0.5%)\n * @param options.precision - Search granularity in base units. Default: 1 whole token.\n * @param options.includeMarkets - Include per-market details in impact result. Default: false.\n * @param options.constraint - Custom constraint callback. Must be monotonic: if amount X fails, all X+n must also fail.\n */\nexport async function findMaxWithdrawalAmount(\n markets: MarketForApy[],\n idleAssets: bigint,\n maxAmount: bigint,\n maxImpactBps: number,\n options?: { precision?: bigint; includeMarkets?: boolean; constraint?: FindMaxConstraint },\n): Promise<FindMaxWithdrawalResult> {\n const raw = options?.precision ?? defaultPrecision(markets)\n const step = raw > 0n ? raw : 1n\n const maxImpact = maxImpactBps / 10000\n const incMkts = options?.includeMarkets ?? false\n const constraint = options?.constraint\n\n if (markets.length === 0 || maxAmount === 0n) {\n return {\n amount: 0n,\n maxPossibleAmount: 0n,\n isMaxAmount: maxAmount === 0n,\n isCapped: false,\n impact: zeroWithdrawalImpact(markets, idleAssets, incMkts),\n }\n }\n\n const maxPossible = computeMaxWithdrawable(markets, idleAssets)\n const effectiveMax = maxAmount < maxPossible ? maxAmount : maxPossible\n\n if (effectiveMax === 0n) {\n return {\n amount: 0n,\n maxPossibleAmount: maxPossible,\n isMaxAmount: false,\n isCapped: maxPossible === 0n,\n impact: zeroWithdrawalImpact(markets, idleAssets, incMkts),\n }\n }\n\n const current = weightedVaultApyDetailed(markets)\n const totalVaultAssets = markets.reduce((acc, m) => acc + m.vaultSupplyAssets, 0n) + idleAssets\n\n // Helper: is this amount acceptable (APY impact + custom constraint)?\n async function isAcceptable(amount: bigint): Promise<boolean> {\n const { sim, withdrawable, remaining } = simulateWithdrawal(markets, amount, idleAssets)\n const isFullDrain = withdrawable >= totalVaultAssets\n const simulated = isFullDrain\n ? { apy: 0, markets: [] as MarketApyDetail[] }\n : weightedVaultApyDetailed(markets, {}, sim)\n const impact = Math.abs(simulated.apy - current.apy)\n if (impact > maxImpact) return false\n if (!constraint) return true\n return constraint({\n amount,\n currentApy: current.apy,\n simulatedApy: simulated.apy,\n impactBps: Math.round((simulated.apy - current.apy) * 10000),\n markets: mergeMarketDetails(current.markets, simulated.markets),\n isPartial: remaining > 0n,\n withdrawableAmount: withdrawable,\n })\n }\n\n // Fast path: idle covers everything (zero APY impact)\n if (effectiveMax <= idleAssets) {\n if (!constraint || (await isAcceptable(effectiveMax))) {\n const { withdrawable, remaining } = simulateWithdrawal(markets, effectiveMax, idleAssets)\n return {\n amount: effectiveMax,\n maxPossibleAmount: maxPossible,\n isMaxAmount: effectiveMax === maxAmount,\n isCapped: effectiveMax < maxAmount,\n impact: buildWithdrawalImpact(current, current, withdrawable, remaining, incMkts),\n }\n }\n // Constraint failed despite zero APY impact — fall through to binary search\n }\n\n // Fast path: full effectiveMax within threshold\n if (await isAcceptable(effectiveMax)) {\n const { sim, withdrawable, remaining } = simulateWithdrawal(markets, effectiveMax, idleAssets)\n const simulated =\n withdrawable >= totalVaultAssets\n ? { apy: 0, markets: [] as MarketApyDetail[] }\n : weightedVaultApyDetailed(markets, {}, sim)\n return {\n amount: effectiveMax,\n maxPossibleAmount: maxPossible,\n isMaxAmount: effectiveMax === maxAmount,\n isCapped: effectiveMax < maxAmount,\n impact: buildWithdrawalImpact(current, simulated, withdrawable, remaining, incMkts),\n }\n }\n\n // Fast path: even smallest step exceeds threshold\n if (step >= effectiveMax || !(await isAcceptable(step))) {\n return {\n amount: 0n,\n maxPossibleAmount: maxPossible,\n isMaxAmount: false,\n isCapped: false,\n impact: zeroWithdrawalImpact(markets, idleAssets, incMkts),\n }\n }\n\n // Binary search\n let lo = step\n let hi = effectiveMax\n\n while (hi - lo > step) {\n let mid = lo + (hi - lo) / 2n\n mid = (mid / step) * step\n if (mid === lo) break\n\n if (await isAcceptable(mid)) {\n lo = mid\n } else {\n hi = mid\n }\n }\n\n const { sim, withdrawable, remaining } = simulateWithdrawal(markets, lo, idleAssets)\n const simulated =\n withdrawable >= totalVaultAssets\n ? { apy: 0, markets: [] as MarketApyDetail[] }\n : weightedVaultApyDetailed(markets, {}, sim)\n return {\n amount: lo,\n maxPossibleAmount: maxPossible,\n isMaxAmount: false,\n isCapped: false,\n impact: buildWithdrawalImpact(current, simulated, withdrawable, remaining, incMkts),\n }\n}\n","import type { PublicClient } from 'viem'\n\nimport { getMorphoBlueAddress } from './addresses.js'\nimport { fetchVaultApyViem } from './fetch.js'\nimport { findMaxDepositAmount, findMaxWithdrawalAmount } from './find-max.js'\nimport type { FindMaxConstraint, FindMaxDepositResult, FindMaxWithdrawalResult } from './types.js'\n\nexport async function findMaxDeposit(\n client: PublicClient,\n chainId: number,\n vaultAddress: string,\n maxAmount: bigint,\n maxImpactBps: number,\n options?: { precision?: bigint; morphoAddress?: string; includeMarkets?: boolean; constraint?: FindMaxConstraint },\n): Promise<FindMaxDepositResult> {\n const morpho = options?.morphoAddress ?? getMorphoBlueAddress(chainId)\n const result = await fetchVaultApyViem(client, vaultAddress, morpho)\n if (!result) {\n return {\n amount: 0n,\n maxPossibleAmount: 0n,\n isMaxAmount: false,\n isCapped: false,\n impact: { currentApy: 0, newApy: 0, impact: 0, impactBps: 0, markets: [] },\n }\n }\n return findMaxDepositAmount(result.markets, maxAmount, maxImpactBps, {\n precision: options?.precision,\n includeMarkets: options?.includeMarkets,\n constraint: options?.constraint,\n })\n}\n\nexport async function findMaxWithdrawal(\n client: PublicClient,\n chainId: number,\n vaultAddress: string,\n maxAmount: bigint,\n maxImpactBps: number,\n options?: { precision?: bigint; morphoAddress?: string; includeMarkets?: boolean; constraint?: FindMaxConstraint },\n): Promise<FindMaxWithdrawalResult> {\n const morpho = options?.morphoAddress ?? getMorphoBlueAddress(chainId)\n const result = await fetchVaultApyViem(client, vaultAddress, morpho)\n if (!result) {\n return {\n amount: 0n,\n maxPossibleAmount: 0n,\n isMaxAmount: false,\n isCapped: false,\n impact: {\n currentApy: 0,\n newApy: 0,\n impact: 0,\n impactBps: 0,\n isPartial: false,\n withdrawableAmount: '0',\n markets: [],\n },\n }\n }\n return findMaxWithdrawalAmount(result.markets, result.idleAssets, maxAmount, maxImpactBps, {\n precision: options?.precision,\n includeMarkets: options?.includeMarkets,\n constraint: options?.constraint,\n })\n}\n","/**\n * RPC URL-based convenience functions.\n * These wrap the viem-based functions so consumers don't need to create a PublicClient.\n */\nimport { createPublicClient, defineChain, http } from 'viem'\n\nimport { getMorphoBlueAddress } from './addresses.js'\nimport { computeDepositImpact as computeDepositImpactViem } from './deposit-impact.js'\nimport { fetchVaultApyViem, fetchVaultMarketsViem } from './fetch.js'\nimport { findMaxDeposit as findMaxDepositViem, findMaxWithdrawal as findMaxWithdrawalViem } from './find-max-impact.js'\nimport type {\n DepositImpactResult,\n FindMaxConstraint,\n FindMaxDepositResult,\n FindMaxWithdrawalResult,\n VaultApyResult,\n VaultFetchResult,\n WithdrawalImpactResult,\n} from './types.js'\nimport { computeWithdrawalImpact as computeWithdrawalImpactViem } from './withdrawal-impact.js'\n\nconst MULTICALL3 = '0xcA11bde05977b3631167028862bE2a173976CA11' as const\n\nfunction makeClient(rpcUrl: string, chainId: number) {\n return createPublicClient({\n transport: http(rpcUrl),\n chain: defineChain({\n id: chainId,\n name: `Chain ${chainId}`,\n nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },\n rpcUrls: { default: { http: [rpcUrl] } },\n contracts: { multicall3: { address: MULTICALL3 } },\n }),\n })\n}\n\nexport async function fetchVaultMarkets(\n rpcUrl: string,\n chainId: number,\n vaultAddress: string,\n morphoAddress: string,\n): Promise<VaultFetchResult> {\n return fetchVaultMarketsViem(makeClient(rpcUrl, chainId), vaultAddress, morphoAddress)\n}\n\nexport async function fetchVaultApy(\n rpcUrl: string,\n chainId: number,\n vaultAddress: string,\n options?: { morphoAddress?: string; includeMarkets?: boolean },\n): Promise<VaultApyResult | null> {\n const morpho = options?.morphoAddress ?? getMorphoBlueAddress(chainId)\n return fetchVaultApyViem(makeClient(rpcUrl, chainId), vaultAddress, morpho, {\n includeMarkets: options?.includeMarkets,\n })\n}\n\nexport async function computeDepositImpactRpc(\n rpcUrl: string,\n chainId: number,\n vaultAddress: string,\n depositAmount: bigint,\n options?: { morphoAddress?: string; includeMarkets?: boolean },\n): Promise<DepositImpactResult> {\n return computeDepositImpactViem(makeClient(rpcUrl, chainId), chainId, vaultAddress, depositAmount, options)\n}\n\nexport async function computeWithdrawalImpactRpc(\n rpcUrl: string,\n chainId: number,\n vaultAddress: string,\n withdrawAmount: bigint,\n options?: { morphoAddress?: string; includeMarkets?: boolean },\n): Promise<WithdrawalImpactResult> {\n return computeWithdrawalImpactViem(makeClient(rpcUrl, chainId), chainId, vaultAddress, withdrawAmount, options)\n}\n\nexport async function findMaxDepositRpc(\n rpcUrl: string,\n chainId: number,\n vaultAddress: string,\n maxAmount: bigint,\n maxImpactBps: number,\n options?: { precision?: bigint; morphoAddress?: string; includeMarkets?: boolean; constraint?: FindMaxConstraint },\n): Promise<FindMaxDepositResult> {\n return findMaxDepositViem(makeClient(rpcUrl, chainId), chainId, vaultAddress, maxAmount, maxImpactBps, options)\n}\n\nexport async function findMaxWithdrawalRpc(\n rpcUrl: string,\n chainId: number,\n vaultAddress: string,\n maxAmount: bigint,\n maxImpactBps: number,\n options?: { precision?: bigint; morphoAddress?: string; includeMarkets?: boolean; constraint?: FindMaxConstraint },\n): Promise<FindMaxWithdrawalResult> {\n return findMaxWithdrawalViem(makeClient(rpcUrl, chainId), chainId, vaultAddress, maxAmount, maxImpactBps, options)\n}\n"]}
@@ -0,0 +1,150 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/math.ts
2
+ var TARGET_UTIL = 0.9;
3
+ var STEEPNESS = 4;
4
+ var WAD = 1e18;
5
+ var SECONDS_PER_YEAR = 365 * 24 * 3600;
6
+ function _error(util) {
7
+ if (util > TARGET_UTIL) {
8
+ return (util - TARGET_UTIL) / (1 - TARGET_UTIL);
9
+ }
10
+ return (util - TARGET_UTIL) / TARGET_UTIL;
11
+ }
12
+ function _curveMultiplier(util) {
13
+ const err = _error(util);
14
+ if (util <= TARGET_UTIL) {
15
+ return (1 - 1 / STEEPNESS) * err + 1;
16
+ }
17
+ return (STEEPNESS - 1) * err + 1;
18
+ }
19
+ function estimateMarketApy(depositAmt, totalSupply, totalBorrows, fee, rateAtTarget) {
20
+ const supply = totalSupply + depositAmt;
21
+ if (supply <= 0 || rateAtTarget <= 0) {
22
+ return { supplyApy: 0, borrowApy: 0 };
23
+ }
24
+ let util = Math.min(totalBorrows / supply, 0.9999);
25
+ if (util < 1e-4) util = 0;
26
+ const ratePerSec = rateAtTarget / WAD;
27
+ const borrowRate = ratePerSec * _curveMultiplier(util);
28
+ const borrowApy = Math.max(0, Math.min(Math.exp(borrowRate * SECONDS_PER_YEAR) - 1, 8));
29
+ const supplyApy = Math.max(0, Math.min(borrowApy * util * (1 - fee / WAD), 8));
30
+ return { supplyApy, borrowApy };
31
+ }
32
+ function weightedVaultApyDetailed(markets, depositSim = {}, withdrawalSim = {}) {
33
+ if (markets.length === 0) return { apy: 0, markets: [] };
34
+ let weightedSum = 0;
35
+ let totalWeight = 0;
36
+ const suspiciousMarkets = markets.filter((m) => m.rateAtTarget === 0n && m.totalBorrowAssets > 0n);
37
+ if (suspiciousMarkets.length > 0) {
38
+ console.warn(
39
+ `[morpho-apy] ${suspiciousMarkets.length} market(s) have rateAtTarget=0 but non-zero borrows \u2014 IRM may not implement rateAtTarget(). APY may be underestimated.`
40
+ );
41
+ }
42
+ const details = [];
43
+ const weights = [];
44
+ for (const m of markets) {
45
+ const scale = Math.pow(10, m.decimals);
46
+ let simSupply = depositSim[m.marketId] ? m.totalSupplyAssets + depositSim[m.marketId] : m.totalSupplyAssets;
47
+ const wSim = _nullishCoalesce(withdrawalSim[m.marketId], () => ( 0n));
48
+ simSupply = simSupply - wSim;
49
+ const simVaultSupply = m.vaultSupplyAssets - wSim;
50
+ const supply = Number(simSupply) / scale;
51
+ const borrows = Number(m.totalBorrowAssets) / scale;
52
+ const fee = Number(m.fee);
53
+ const rate = Number(m.rateAtTarget);
54
+ const { supplyApy, borrowApy } = estimateMarketApy(0, supply, borrows, fee, rate);
55
+ const weight = Math.max(0, Number(simVaultSupply) / scale);
56
+ const utilization = supply > 0 ? Math.min(borrows / supply, 1) : 0;
57
+ details.push({
58
+ marketId: m.marketId,
59
+ name: m.name,
60
+ supplyApy,
61
+ borrowApy,
62
+ utilization,
63
+ allocationPct: 0,
64
+ // filled after loop
65
+ vaultSupplyAssets: simVaultSupply
66
+ });
67
+ weights.push(weight);
68
+ if (weight <= 0) continue;
69
+ weightedSum += supplyApy * weight;
70
+ totalWeight += weight;
71
+ }
72
+ if (totalWeight <= 0) {
73
+ throw new Error(
74
+ `[morpho-apy] Vault has zero supply position across all ${markets.length} market(s). Check vault address or wait for funds to be deployed.`
75
+ );
76
+ }
77
+ for (let i = 0; i < details.length; i++) {
78
+ details[i].allocationPct = weights[i] / totalWeight;
79
+ }
80
+ return { apy: weightedSum / totalWeight, markets: details };
81
+ }
82
+ function weightedVaultApy(markets, depositSim = {}, withdrawalSim = {}) {
83
+ return weightedVaultApyDetailed(markets, depositSim, withdrawalSim).apy;
84
+ }
85
+ function simulateDeposit(markets, depositAmount) {
86
+ const sim = {};
87
+ let remaining = depositAmount;
88
+ for (const m of markets) {
89
+ if (!m.inSupplyQueue) continue;
90
+ if (remaining === 0n) break;
91
+ const available = m.cap > m.vaultSupplyAssets ? m.cap - m.vaultSupplyAssets : 0n;
92
+ if (available === 0n) continue;
93
+ const fill = remaining < available ? remaining : available;
94
+ sim[m.marketId] = fill;
95
+ remaining -= fill;
96
+ }
97
+ return sim;
98
+ }
99
+ function simulateWithdrawal(markets, withdrawAmount, idleAssets) {
100
+ const sim = {};
101
+ let remaining = withdrawAmount;
102
+ if (idleAssets > 0n) {
103
+ const fromIdle = remaining < idleAssets ? remaining : idleAssets;
104
+ remaining -= fromIdle;
105
+ }
106
+ const withdrawMarkets = markets.filter((m) => m.inWithdrawQueue && m.withdrawQueueIndex >= 0).sort((a, b) => a.withdrawQueueIndex - b.withdrawQueueIndex);
107
+ for (const m of withdrawMarkets) {
108
+ if (remaining === 0n) break;
109
+ const marketLiquidity = m.totalSupplyAssets > m.totalBorrowAssets ? m.totalSupplyAssets - m.totalBorrowAssets : 0n;
110
+ const available = m.vaultSupplyAssets < marketLiquidity ? m.vaultSupplyAssets : marketLiquidity;
111
+ if (available <= 0n) continue;
112
+ const take = remaining < available ? remaining : available;
113
+ sim[m.marketId] = take;
114
+ remaining -= take;
115
+ }
116
+ return { sim, withdrawable: withdrawAmount - remaining, remaining };
117
+ }
118
+ function mergeMarketDetails(current, simulated) {
119
+ return current.map((c, i) => {
120
+ const s = simulated[i];
121
+ return {
122
+ marketId: c.marketId,
123
+ name: c.name,
124
+ current: {
125
+ supplyApy: c.supplyApy,
126
+ borrowApy: c.borrowApy,
127
+ utilization: c.utilization,
128
+ allocationPct: c.allocationPct,
129
+ vaultSupplyAssets: c.vaultSupplyAssets
130
+ },
131
+ simulated: s ? {
132
+ supplyApy: s.supplyApy,
133
+ borrowApy: s.borrowApy,
134
+ utilization: s.utilization,
135
+ allocationPct: s.allocationPct,
136
+ vaultSupplyAssets: s.vaultSupplyAssets
137
+ } : { supplyApy: 0, borrowApy: 0, utilization: 0, allocationPct: 0, vaultSupplyAssets: 0n }
138
+ };
139
+ });
140
+ }
141
+
142
+
143
+
144
+
145
+
146
+
147
+
148
+
149
+ exports.estimateMarketApy = estimateMarketApy; exports.weightedVaultApyDetailed = weightedVaultApyDetailed; exports.weightedVaultApy = weightedVaultApy; exports.simulateDeposit = simulateDeposit; exports.simulateWithdrawal = simulateWithdrawal; exports.mergeMarketDetails = mergeMarketDetails;
150
+ //# sourceMappingURL=chunk-37KGZP4O.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Volumes/origin/morpho-utils/dist/chunk-37KGZP4O.cjs","../src/math.ts"],"names":[],"mappings":"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","file":"/Volumes/origin/morpho-utils/dist/chunk-37KGZP4O.cjs","sourcesContent":[null,"/**\n * Pure APY math for Morpho Blue / MetaMorpho vaults.\n * No external dependencies — fully unit-testable.\n */\nimport type { MarketApyDetail, MarketForApy, MarketImpactDetail, VaultApyDetailed } from './types.js'\n\nexport type { MarketApyDetail, MarketForApy, MarketImpactDetail, VaultApyDetailed } from './types.js'\n\nconst TARGET_UTIL = 0.9\nconst STEEPNESS = 4\nconst WAD = 1e18\nconst SECONDS_PER_YEAR = 365 * 24 * 3600 // 365-day year, no leap year — matches Morpho convention\n\n/** Normalized distance from target utilization. Range: [-1, +1]. */\nfunction _error(util: number): number {\n if (util > TARGET_UTIL) {\n return (util - TARGET_UTIL) / (1 - TARGET_UTIL)\n }\n return (util - TARGET_UTIL) / TARGET_UTIL\n}\n\n/** IRM rate multiplier at a given utilization. Always positive. */\nfunction _curveMultiplier(util: number): number {\n const err = _error(util)\n if (util <= TARGET_UTIL) {\n return (1 - 1 / STEEPNESS) * err + 1 // 0.75 * err + 1\n }\n return (STEEPNESS - 1) * err + 1 // 3 * err + 1\n}\n\n/**\n * Compute supply and borrow APY for a single Morpho Blue market.\n *\n * @param depositAmt - Extra supply to simulate (0 for current rate). In token units (float).\n * @param totalSupply - Current total supply assets. In token units (float).\n * @param totalBorrows - Current total borrow assets. In token units (float).\n * @param fee - Protocol fee, WAD-scaled (raw bigint converted to number before passing).\n * @param rateAtTarget - Per-second borrow rate at 90% utilisation, WAD-scaled (raw int256 as number).\n */\nexport function estimateMarketApy(\n depositAmt: number,\n totalSupply: number,\n totalBorrows: number,\n fee: number,\n rateAtTarget: number,\n): { supplyApy: number; borrowApy: number } {\n const supply = totalSupply + depositAmt\n if (supply <= 0 || rateAtTarget <= 0) {\n return { supplyApy: 0, borrowApy: 0 }\n }\n\n let util = Math.min(totalBorrows / supply, 0.9999) // clamp to avoid division by zero\n if (util < 0.0001) util = 0\n\n const ratePerSec = rateAtTarget / WAD\n const borrowRate = ratePerSec * _curveMultiplier(util)\n const borrowApy = Math.max(0, Math.min(Math.exp(borrowRate * SECONDS_PER_YEAR) - 1, 8.0)) // continuous compounding, clamped to [0, 800%]\n const supplyApy = Math.max(0, Math.min(borrowApy * util * (1 - fee / WAD), 8.0))\n\n return { supplyApy, borrowApy }\n}\n\n/**\n * Compute the position-weighted vault APY across all markets,\n * returning per-market details (supplyApy, borrowApy, utilization, allocation).\n *\n * @param markets - All markets (both supply + withdraw queues).\n * @param depositSim - Optional map of { marketId -> extra bigint supply } for deposit simulation.\n * @param withdrawalSim - Optional map of { marketId -> bigint withdrawn } for withdrawal simulation.\n */\nexport function weightedVaultApyDetailed(\n markets: MarketForApy[],\n depositSim: Record<string, bigint> = {},\n withdrawalSim: Record<string, bigint> = {},\n): VaultApyDetailed {\n if (markets.length === 0) return { apy: 0, markets: [] }\n\n let weightedSum = 0\n let totalWeight = 0\n\n const suspiciousMarkets = markets.filter((m) => m.rateAtTarget === 0n && m.totalBorrowAssets > 0n)\n if (suspiciousMarkets.length > 0) {\n console.warn(\n `[morpho-apy] ${suspiciousMarkets.length} market(s) have rateAtTarget=0 but non-zero borrows — ` +\n `IRM may not implement rateAtTarget(). APY may be underestimated.`,\n )\n }\n\n const details: MarketApyDetail[] = []\n const weights: number[] = []\n\n for (const m of markets) {\n const scale = Math.pow(10, m.decimals)\n\n // Apply deposit simulation: increase totalSupplyAssets for target markets\n let simSupply = depositSim[m.marketId] ? m.totalSupplyAssets + depositSim[m.marketId] : m.totalSupplyAssets\n\n // Apply withdrawal simulation: decrease both totalSupplyAssets and vaultSupplyAssets\n const wSim = withdrawalSim[m.marketId] ?? 0n\n simSupply = simSupply - wSim\n const simVaultSupply = m.vaultSupplyAssets - wSim\n\n const supply = Number(simSupply) / scale\n const borrows = Number(m.totalBorrowAssets) / scale\n const fee = Number(m.fee) // stays WAD-scaled; /WAD done inside estimateMarketApy\n const rate = Number(m.rateAtTarget) // stays WAD-scaled\n\n const { supplyApy, borrowApy } = estimateMarketApy(0, supply, borrows, fee, rate)\n const weight = Math.max(0, Number(simVaultSupply) / scale)\n const utilization = supply > 0 ? Math.min(borrows / supply, 1) : 0\n\n details.push({\n marketId: m.marketId,\n name: m.name,\n supplyApy,\n borrowApy,\n utilization,\n allocationPct: 0, // filled after loop\n vaultSupplyAssets: simVaultSupply,\n })\n weights.push(weight)\n\n if (weight <= 0) continue\n\n weightedSum += supplyApy * weight\n totalWeight += weight\n }\n\n if (totalWeight <= 0) {\n throw new Error(\n `[morpho-apy] Vault has zero supply position across all ${markets.length} market(s). ` +\n `Check vault address or wait for funds to be deployed.`,\n )\n }\n\n // Fill in allocationPct\n for (let i = 0; i < details.length; i++) {\n details[i].allocationPct = weights[i] / totalWeight\n }\n\n return { apy: weightedSum / totalWeight, markets: details }\n}\n\n/**\n * Compute the position-weighted vault APY across all markets.\n *\n * @param markets - All markets (both supply + withdraw queues).\n * @param depositSim - Optional map of { marketId -> extra bigint supply } for deposit simulation.\n * @param withdrawalSim - Optional map of { marketId -> bigint withdrawn } for withdrawal simulation.\n */\nexport function weightedVaultApy(\n markets: MarketForApy[],\n depositSim: Record<string, bigint> = {},\n withdrawalSim: Record<string, bigint> = {},\n): number {\n return weightedVaultApyDetailed(markets, depositSim, withdrawalSim).apy\n}\n\n/**\n * Simulate how a deposit flows through the supply queue and build a depositSim map.\n *\n * Deposits fill each supply-queue market up to its cap, then spill to the next.\n * Returns a Record<marketId, bigint> representing extra supply per market.\n */\nexport function simulateDeposit(markets: MarketForApy[], depositAmount: bigint): Record<string, bigint> {\n const sim: Record<string, bigint> = {}\n let remaining = depositAmount\n\n for (const m of markets) {\n if (!m.inSupplyQueue) continue\n if (remaining === 0n) break\n\n // How much more can this market absorb (vault cap - current vault supply)?\n const available = m.cap > m.vaultSupplyAssets ? m.cap - m.vaultSupplyAssets : 0n\n if (available === 0n) continue\n\n const fill = remaining < available ? remaining : available\n sim[m.marketId] = fill\n remaining -= fill\n }\n\n return sim\n}\n\n/**\n * Simulate how a withdrawal flows through the withdraw queue.\n *\n * Idle assets are consumed first (no market APY impact), then each withdraw-queue\n * market is drained up to min(vaultSupplyAssets, available liquidity).\n * Returns positive values representing amounts removed per market.\n */\nexport function simulateWithdrawal(\n markets: MarketForApy[],\n withdrawAmount: bigint,\n idleAssets: bigint,\n): { sim: Record<string, bigint>; withdrawable: bigint; remaining: bigint } {\n const sim: Record<string, bigint> = {}\n let remaining = withdrawAmount\n\n // 1. Consume idle assets first (no market impact)\n if (idleAssets > 0n) {\n const fromIdle = remaining < idleAssets ? remaining : idleAssets\n remaining -= fromIdle\n }\n\n // 2. Iterate withdraw queue in order\n const withdrawMarkets = markets\n .filter((m) => m.inWithdrawQueue && m.withdrawQueueIndex >= 0)\n .sort((a, b) => a.withdrawQueueIndex - b.withdrawQueueIndex)\n\n for (const m of withdrawMarkets) {\n if (remaining === 0n) break\n\n const marketLiquidity = m.totalSupplyAssets > m.totalBorrowAssets ? m.totalSupplyAssets - m.totalBorrowAssets : 0n\n const available = m.vaultSupplyAssets < marketLiquidity ? m.vaultSupplyAssets : marketLiquidity\n if (available <= 0n) continue\n\n const take = remaining < available ? remaining : available\n sim[m.marketId] = take\n remaining -= take\n }\n\n return { sim, withdrawable: withdrawAmount - remaining, remaining }\n}\n\n/**\n * Merge two MarketApyDetail arrays (current vs simulated) into a single\n * array of MarketImpactDetail with nested `current` and `simulated` snapshots.\n */\nexport function mergeMarketDetails(current: MarketApyDetail[], simulated: MarketApyDetail[]): MarketImpactDetail[] {\n return current.map((c, i) => {\n const s = simulated[i]\n return {\n marketId: c.marketId,\n name: c.name,\n current: {\n supplyApy: c.supplyApy,\n borrowApy: c.borrowApy,\n utilization: c.utilization,\n allocationPct: c.allocationPct,\n vaultSupplyAssets: c.vaultSupplyAssets,\n },\n simulated: s\n ? {\n supplyApy: s.supplyApy,\n borrowApy: s.borrowApy,\n utilization: s.utilization,\n allocationPct: s.allocationPct,\n vaultSupplyAssets: s.vaultSupplyAssets,\n }\n : { supplyApy: 0, borrowApy: 0, utilization: 0, allocationPct: 0, vaultSupplyAssets: 0n },\n }\n })\n}\n"]}
@@ -0,0 +1,150 @@
1
+ // src/math.ts
2
+ var TARGET_UTIL = 0.9;
3
+ var STEEPNESS = 4;
4
+ var WAD = 1e18;
5
+ var SECONDS_PER_YEAR = 365 * 24 * 3600;
6
+ function _error(util) {
7
+ if (util > TARGET_UTIL) {
8
+ return (util - TARGET_UTIL) / (1 - TARGET_UTIL);
9
+ }
10
+ return (util - TARGET_UTIL) / TARGET_UTIL;
11
+ }
12
+ function _curveMultiplier(util) {
13
+ const err = _error(util);
14
+ if (util <= TARGET_UTIL) {
15
+ return (1 - 1 / STEEPNESS) * err + 1;
16
+ }
17
+ return (STEEPNESS - 1) * err + 1;
18
+ }
19
+ function estimateMarketApy(depositAmt, totalSupply, totalBorrows, fee, rateAtTarget) {
20
+ const supply = totalSupply + depositAmt;
21
+ if (supply <= 0 || rateAtTarget <= 0) {
22
+ return { supplyApy: 0, borrowApy: 0 };
23
+ }
24
+ let util = Math.min(totalBorrows / supply, 0.9999);
25
+ if (util < 1e-4) util = 0;
26
+ const ratePerSec = rateAtTarget / WAD;
27
+ const borrowRate = ratePerSec * _curveMultiplier(util);
28
+ const borrowApy = Math.max(0, Math.min(Math.exp(borrowRate * SECONDS_PER_YEAR) - 1, 8));
29
+ const supplyApy = Math.max(0, Math.min(borrowApy * util * (1 - fee / WAD), 8));
30
+ return { supplyApy, borrowApy };
31
+ }
32
+ function weightedVaultApyDetailed(markets, depositSim = {}, withdrawalSim = {}) {
33
+ if (markets.length === 0) return { apy: 0, markets: [] };
34
+ let weightedSum = 0;
35
+ let totalWeight = 0;
36
+ const suspiciousMarkets = markets.filter((m) => m.rateAtTarget === 0n && m.totalBorrowAssets > 0n);
37
+ if (suspiciousMarkets.length > 0) {
38
+ console.warn(
39
+ `[morpho-apy] ${suspiciousMarkets.length} market(s) have rateAtTarget=0 but non-zero borrows \u2014 IRM may not implement rateAtTarget(). APY may be underestimated.`
40
+ );
41
+ }
42
+ const details = [];
43
+ const weights = [];
44
+ for (const m of markets) {
45
+ const scale = Math.pow(10, m.decimals);
46
+ let simSupply = depositSim[m.marketId] ? m.totalSupplyAssets + depositSim[m.marketId] : m.totalSupplyAssets;
47
+ const wSim = withdrawalSim[m.marketId] ?? 0n;
48
+ simSupply = simSupply - wSim;
49
+ const simVaultSupply = m.vaultSupplyAssets - wSim;
50
+ const supply = Number(simSupply) / scale;
51
+ const borrows = Number(m.totalBorrowAssets) / scale;
52
+ const fee = Number(m.fee);
53
+ const rate = Number(m.rateAtTarget);
54
+ const { supplyApy, borrowApy } = estimateMarketApy(0, supply, borrows, fee, rate);
55
+ const weight = Math.max(0, Number(simVaultSupply) / scale);
56
+ const utilization = supply > 0 ? Math.min(borrows / supply, 1) : 0;
57
+ details.push({
58
+ marketId: m.marketId,
59
+ name: m.name,
60
+ supplyApy,
61
+ borrowApy,
62
+ utilization,
63
+ allocationPct: 0,
64
+ // filled after loop
65
+ vaultSupplyAssets: simVaultSupply
66
+ });
67
+ weights.push(weight);
68
+ if (weight <= 0) continue;
69
+ weightedSum += supplyApy * weight;
70
+ totalWeight += weight;
71
+ }
72
+ if (totalWeight <= 0) {
73
+ throw new Error(
74
+ `[morpho-apy] Vault has zero supply position across all ${markets.length} market(s). Check vault address or wait for funds to be deployed.`
75
+ );
76
+ }
77
+ for (let i = 0; i < details.length; i++) {
78
+ details[i].allocationPct = weights[i] / totalWeight;
79
+ }
80
+ return { apy: weightedSum / totalWeight, markets: details };
81
+ }
82
+ function weightedVaultApy(markets, depositSim = {}, withdrawalSim = {}) {
83
+ return weightedVaultApyDetailed(markets, depositSim, withdrawalSim).apy;
84
+ }
85
+ function simulateDeposit(markets, depositAmount) {
86
+ const sim = {};
87
+ let remaining = depositAmount;
88
+ for (const m of markets) {
89
+ if (!m.inSupplyQueue) continue;
90
+ if (remaining === 0n) break;
91
+ const available = m.cap > m.vaultSupplyAssets ? m.cap - m.vaultSupplyAssets : 0n;
92
+ if (available === 0n) continue;
93
+ const fill = remaining < available ? remaining : available;
94
+ sim[m.marketId] = fill;
95
+ remaining -= fill;
96
+ }
97
+ return sim;
98
+ }
99
+ function simulateWithdrawal(markets, withdrawAmount, idleAssets) {
100
+ const sim = {};
101
+ let remaining = withdrawAmount;
102
+ if (idleAssets > 0n) {
103
+ const fromIdle = remaining < idleAssets ? remaining : idleAssets;
104
+ remaining -= fromIdle;
105
+ }
106
+ const withdrawMarkets = markets.filter((m) => m.inWithdrawQueue && m.withdrawQueueIndex >= 0).sort((a, b) => a.withdrawQueueIndex - b.withdrawQueueIndex);
107
+ for (const m of withdrawMarkets) {
108
+ if (remaining === 0n) break;
109
+ const marketLiquidity = m.totalSupplyAssets > m.totalBorrowAssets ? m.totalSupplyAssets - m.totalBorrowAssets : 0n;
110
+ const available = m.vaultSupplyAssets < marketLiquidity ? m.vaultSupplyAssets : marketLiquidity;
111
+ if (available <= 0n) continue;
112
+ const take = remaining < available ? remaining : available;
113
+ sim[m.marketId] = take;
114
+ remaining -= take;
115
+ }
116
+ return { sim, withdrawable: withdrawAmount - remaining, remaining };
117
+ }
118
+ function mergeMarketDetails(current, simulated) {
119
+ return current.map((c, i) => {
120
+ const s = simulated[i];
121
+ return {
122
+ marketId: c.marketId,
123
+ name: c.name,
124
+ current: {
125
+ supplyApy: c.supplyApy,
126
+ borrowApy: c.borrowApy,
127
+ utilization: c.utilization,
128
+ allocationPct: c.allocationPct,
129
+ vaultSupplyAssets: c.vaultSupplyAssets
130
+ },
131
+ simulated: s ? {
132
+ supplyApy: s.supplyApy,
133
+ borrowApy: s.borrowApy,
134
+ utilization: s.utilization,
135
+ allocationPct: s.allocationPct,
136
+ vaultSupplyAssets: s.vaultSupplyAssets
137
+ } : { supplyApy: 0, borrowApy: 0, utilization: 0, allocationPct: 0, vaultSupplyAssets: 0n }
138
+ };
139
+ });
140
+ }
141
+
142
+ export {
143
+ estimateMarketApy,
144
+ weightedVaultApyDetailed,
145
+ weightedVaultApy,
146
+ simulateDeposit,
147
+ simulateWithdrawal,
148
+ mergeMarketDetails
149
+ };
150
+ //# sourceMappingURL=chunk-K2ZKPGSF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/math.ts"],"sourcesContent":["/**\n * Pure APY math for Morpho Blue / MetaMorpho vaults.\n * No external dependencies — fully unit-testable.\n */\nimport type { MarketApyDetail, MarketForApy, MarketImpactDetail, VaultApyDetailed } from './types.js'\n\nexport type { MarketApyDetail, MarketForApy, MarketImpactDetail, VaultApyDetailed } from './types.js'\n\nconst TARGET_UTIL = 0.9\nconst STEEPNESS = 4\nconst WAD = 1e18\nconst SECONDS_PER_YEAR = 365 * 24 * 3600 // 365-day year, no leap year — matches Morpho convention\n\n/** Normalized distance from target utilization. Range: [-1, +1]. */\nfunction _error(util: number): number {\n if (util > TARGET_UTIL) {\n return (util - TARGET_UTIL) / (1 - TARGET_UTIL)\n }\n return (util - TARGET_UTIL) / TARGET_UTIL\n}\n\n/** IRM rate multiplier at a given utilization. Always positive. */\nfunction _curveMultiplier(util: number): number {\n const err = _error(util)\n if (util <= TARGET_UTIL) {\n return (1 - 1 / STEEPNESS) * err + 1 // 0.75 * err + 1\n }\n return (STEEPNESS - 1) * err + 1 // 3 * err + 1\n}\n\n/**\n * Compute supply and borrow APY for a single Morpho Blue market.\n *\n * @param depositAmt - Extra supply to simulate (0 for current rate). In token units (float).\n * @param totalSupply - Current total supply assets. In token units (float).\n * @param totalBorrows - Current total borrow assets. In token units (float).\n * @param fee - Protocol fee, WAD-scaled (raw bigint converted to number before passing).\n * @param rateAtTarget - Per-second borrow rate at 90% utilisation, WAD-scaled (raw int256 as number).\n */\nexport function estimateMarketApy(\n depositAmt: number,\n totalSupply: number,\n totalBorrows: number,\n fee: number,\n rateAtTarget: number,\n): { supplyApy: number; borrowApy: number } {\n const supply = totalSupply + depositAmt\n if (supply <= 0 || rateAtTarget <= 0) {\n return { supplyApy: 0, borrowApy: 0 }\n }\n\n let util = Math.min(totalBorrows / supply, 0.9999) // clamp to avoid division by zero\n if (util < 0.0001) util = 0\n\n const ratePerSec = rateAtTarget / WAD\n const borrowRate = ratePerSec * _curveMultiplier(util)\n const borrowApy = Math.max(0, Math.min(Math.exp(borrowRate * SECONDS_PER_YEAR) - 1, 8.0)) // continuous compounding, clamped to [0, 800%]\n const supplyApy = Math.max(0, Math.min(borrowApy * util * (1 - fee / WAD), 8.0))\n\n return { supplyApy, borrowApy }\n}\n\n/**\n * Compute the position-weighted vault APY across all markets,\n * returning per-market details (supplyApy, borrowApy, utilization, allocation).\n *\n * @param markets - All markets (both supply + withdraw queues).\n * @param depositSim - Optional map of { marketId -> extra bigint supply } for deposit simulation.\n * @param withdrawalSim - Optional map of { marketId -> bigint withdrawn } for withdrawal simulation.\n */\nexport function weightedVaultApyDetailed(\n markets: MarketForApy[],\n depositSim: Record<string, bigint> = {},\n withdrawalSim: Record<string, bigint> = {},\n): VaultApyDetailed {\n if (markets.length === 0) return { apy: 0, markets: [] }\n\n let weightedSum = 0\n let totalWeight = 0\n\n const suspiciousMarkets = markets.filter((m) => m.rateAtTarget === 0n && m.totalBorrowAssets > 0n)\n if (suspiciousMarkets.length > 0) {\n console.warn(\n `[morpho-apy] ${suspiciousMarkets.length} market(s) have rateAtTarget=0 but non-zero borrows — ` +\n `IRM may not implement rateAtTarget(). APY may be underestimated.`,\n )\n }\n\n const details: MarketApyDetail[] = []\n const weights: number[] = []\n\n for (const m of markets) {\n const scale = Math.pow(10, m.decimals)\n\n // Apply deposit simulation: increase totalSupplyAssets for target markets\n let simSupply = depositSim[m.marketId] ? m.totalSupplyAssets + depositSim[m.marketId] : m.totalSupplyAssets\n\n // Apply withdrawal simulation: decrease both totalSupplyAssets and vaultSupplyAssets\n const wSim = withdrawalSim[m.marketId] ?? 0n\n simSupply = simSupply - wSim\n const simVaultSupply = m.vaultSupplyAssets - wSim\n\n const supply = Number(simSupply) / scale\n const borrows = Number(m.totalBorrowAssets) / scale\n const fee = Number(m.fee) // stays WAD-scaled; /WAD done inside estimateMarketApy\n const rate = Number(m.rateAtTarget) // stays WAD-scaled\n\n const { supplyApy, borrowApy } = estimateMarketApy(0, supply, borrows, fee, rate)\n const weight = Math.max(0, Number(simVaultSupply) / scale)\n const utilization = supply > 0 ? Math.min(borrows / supply, 1) : 0\n\n details.push({\n marketId: m.marketId,\n name: m.name,\n supplyApy,\n borrowApy,\n utilization,\n allocationPct: 0, // filled after loop\n vaultSupplyAssets: simVaultSupply,\n })\n weights.push(weight)\n\n if (weight <= 0) continue\n\n weightedSum += supplyApy * weight\n totalWeight += weight\n }\n\n if (totalWeight <= 0) {\n throw new Error(\n `[morpho-apy] Vault has zero supply position across all ${markets.length} market(s). ` +\n `Check vault address or wait for funds to be deployed.`,\n )\n }\n\n // Fill in allocationPct\n for (let i = 0; i < details.length; i++) {\n details[i].allocationPct = weights[i] / totalWeight\n }\n\n return { apy: weightedSum / totalWeight, markets: details }\n}\n\n/**\n * Compute the position-weighted vault APY across all markets.\n *\n * @param markets - All markets (both supply + withdraw queues).\n * @param depositSim - Optional map of { marketId -> extra bigint supply } for deposit simulation.\n * @param withdrawalSim - Optional map of { marketId -> bigint withdrawn } for withdrawal simulation.\n */\nexport function weightedVaultApy(\n markets: MarketForApy[],\n depositSim: Record<string, bigint> = {},\n withdrawalSim: Record<string, bigint> = {},\n): number {\n return weightedVaultApyDetailed(markets, depositSim, withdrawalSim).apy\n}\n\n/**\n * Simulate how a deposit flows through the supply queue and build a depositSim map.\n *\n * Deposits fill each supply-queue market up to its cap, then spill to the next.\n * Returns a Record<marketId, bigint> representing extra supply per market.\n */\nexport function simulateDeposit(markets: MarketForApy[], depositAmount: bigint): Record<string, bigint> {\n const sim: Record<string, bigint> = {}\n let remaining = depositAmount\n\n for (const m of markets) {\n if (!m.inSupplyQueue) continue\n if (remaining === 0n) break\n\n // How much more can this market absorb (vault cap - current vault supply)?\n const available = m.cap > m.vaultSupplyAssets ? m.cap - m.vaultSupplyAssets : 0n\n if (available === 0n) continue\n\n const fill = remaining < available ? remaining : available\n sim[m.marketId] = fill\n remaining -= fill\n }\n\n return sim\n}\n\n/**\n * Simulate how a withdrawal flows through the withdraw queue.\n *\n * Idle assets are consumed first (no market APY impact), then each withdraw-queue\n * market is drained up to min(vaultSupplyAssets, available liquidity).\n * Returns positive values representing amounts removed per market.\n */\nexport function simulateWithdrawal(\n markets: MarketForApy[],\n withdrawAmount: bigint,\n idleAssets: bigint,\n): { sim: Record<string, bigint>; withdrawable: bigint; remaining: bigint } {\n const sim: Record<string, bigint> = {}\n let remaining = withdrawAmount\n\n // 1. Consume idle assets first (no market impact)\n if (idleAssets > 0n) {\n const fromIdle = remaining < idleAssets ? remaining : idleAssets\n remaining -= fromIdle\n }\n\n // 2. Iterate withdraw queue in order\n const withdrawMarkets = markets\n .filter((m) => m.inWithdrawQueue && m.withdrawQueueIndex >= 0)\n .sort((a, b) => a.withdrawQueueIndex - b.withdrawQueueIndex)\n\n for (const m of withdrawMarkets) {\n if (remaining === 0n) break\n\n const marketLiquidity = m.totalSupplyAssets > m.totalBorrowAssets ? m.totalSupplyAssets - m.totalBorrowAssets : 0n\n const available = m.vaultSupplyAssets < marketLiquidity ? m.vaultSupplyAssets : marketLiquidity\n if (available <= 0n) continue\n\n const take = remaining < available ? remaining : available\n sim[m.marketId] = take\n remaining -= take\n }\n\n return { sim, withdrawable: withdrawAmount - remaining, remaining }\n}\n\n/**\n * Merge two MarketApyDetail arrays (current vs simulated) into a single\n * array of MarketImpactDetail with nested `current` and `simulated` snapshots.\n */\nexport function mergeMarketDetails(current: MarketApyDetail[], simulated: MarketApyDetail[]): MarketImpactDetail[] {\n return current.map((c, i) => {\n const s = simulated[i]\n return {\n marketId: c.marketId,\n name: c.name,\n current: {\n supplyApy: c.supplyApy,\n borrowApy: c.borrowApy,\n utilization: c.utilization,\n allocationPct: c.allocationPct,\n vaultSupplyAssets: c.vaultSupplyAssets,\n },\n simulated: s\n ? {\n supplyApy: s.supplyApy,\n borrowApy: s.borrowApy,\n utilization: s.utilization,\n allocationPct: s.allocationPct,\n vaultSupplyAssets: s.vaultSupplyAssets,\n }\n : { supplyApy: 0, borrowApy: 0, utilization: 0, allocationPct: 0, vaultSupplyAssets: 0n },\n }\n })\n}\n"],"mappings":"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","names":[]}