UNPKG

@catalabs/catalyst-sdk

Version:
819 lines 42.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.depositWithGas = depositWithGas; exports.depositWithGasViaPermit = depositWithGasViaPermit; exports.withdrawWithGas = withdrawWithGas; exports.withdrawWithGasViaPermit = withdrawWithGasViaPermit; exports.swapByRoute = swapByRoute; exports.swapByRouteViaPermit = swapByRouteViaPermit; exports.depositWithLiquiditySwaps = depositWithLiquiditySwaps; exports.prepareDepositWithLiquiditySwaps = prepareDepositWithLiquiditySwaps; exports.withdrawWithLiquiditySwap = withdrawWithLiquiditySwap; exports.prepareWithdrawWithLiquiditySwap = prepareWithdrawWithLiquiditySwap; exports.prepareWithdrawSamePercentageWithLiquiditySwap = prepareWithdrawSamePercentageWithLiquiditySwap; const catalyst_chain_lists_1 = require("@catalabs/catalyst-chain-lists"); const math_1 = require("../math"); const math_utils_1 = require("../math/math.utils"); const utils_1 = require("../utils"); const router_utils_1 = require("./router.utils"); function depositWithGas(vault, tokens, minOut, transferFroms = [[], []]) { const depositRouterArguments = new router_utils_1.RouterArguments(); depositRouterArguments.wrapGas(); const [transferFromTokens, transferFromAmounts] = transferFroms; for (let i = 0; i < transferFromTokens.length; i++) { const tkn = transferFromTokens[i]; const amount = transferFromAmounts[i]; depositRouterArguments.transferFrom(tkn, amount); } const balances = tokens.map((_t) => router_utils_1.RouterArguments.BALANCE_THIS); depositRouterArguments.deposit(vault, tokens, balances, minOut); depositRouterArguments.sweep(vault, router_utils_1.RouterArguments.MSG_SENDER); return depositRouterArguments.getParams(false); } function depositWithGasViaPermit(vault, tokens, minOut, transferFroms = [[], []], owner, permitBatchData) { const depositRouterArguments = new router_utils_1.RouterArguments(); depositRouterArguments.wrapGas(); const [transferFromTokens, transferFromAmounts] = transferFroms; const assets = []; for (let i = 0; i < transferFromTokens.length; i++) { assets.push({ token: transferFromTokens[i], amount: transferFromAmounts[i], }); } depositRouterArguments.transferWithOptionalPermitBatch(assets, owner, permitBatchData); const balances = tokens.map((_t) => router_utils_1.RouterArguments.BALANCE_THIS); depositRouterArguments.deposit(vault, tokens, balances, minOut); depositRouterArguments.sweep(vault, router_utils_1.RouterArguments.MSG_SENDER); return depositRouterArguments.getParams(false); } function withdrawWithGas(vault, vaultTokenAmount, tokens, minOuts, gasToken = '') { const withdrawRouterArguments = new router_utils_1.RouterArguments({ WGAS: gasToken }); withdrawRouterArguments.transferFrom(vault, vaultTokenAmount); withdrawRouterArguments.withdrawEqual(vault, vaultTokenAmount, minOuts); for (const token of tokens) { if (token === gasToken) { withdrawRouterArguments.unwrapGas(router_utils_1.RouterArguments.MSG_SENDER); } else { withdrawRouterArguments.sweep(token, router_utils_1.RouterArguments.MSG_SENDER); } } return withdrawRouterArguments.getParams(); } function withdrawWithGasViaPermit(vault, vaultTokenAmount, tokens, minOuts, gasToken = '', permitData) { const withdrawRouterArguments = new router_utils_1.RouterArguments({ WGAS: gasToken }); withdrawRouterArguments.transferWithOptionalPermit({ token: vault, amount: vaultTokenAmount, }, permitData); withdrawRouterArguments.withdrawEqual(vault, vaultTokenAmount, minOuts); for (const token of tokens) { if (token === gasToken) { withdrawRouterArguments.unwrapGas(router_utils_1.RouterArguments.MSG_SENDER); } else { withdrawRouterArguments.sweep(token, router_utils_1.RouterArguments.MSG_SENDER); } } return withdrawRouterArguments.getParams(); } function swapByRoute(args) { const { toAccount, amount, route, minOut, toAssetIndex, channelId, fromChainId, toChainId, messageVerifyGasCost, priceOfDeliveryGas, priceOfAckGas, refundGasTo = '', } = args; const deadline = BigInt((0, utils_1.toDeadline)(14 * 24 * 60 * utils_1.ONE_MIN_MS)); let { fromAsset, toAsset, underwritingIncentive } = args; if (underwritingIncentive === undefined) { underwritingIncentive = 0n; } const fromChainGasToken = (0, catalyst_chain_lists_1.getChainGasToken)(fromChainId); const [routeHost, routeCross, routeTarget] = router_utils_1.RouterArguments.splitRoute(fromAsset, route); let gasFrom, gasTo = false; if (fromAsset === utils_1.GAS_TOKEN_IDENTIFIER) { fromAsset = fromChainGasToken; gasFrom = true; } if (toAsset === utils_1.GAS_TOKEN_IDENTIFIER) { toAsset = (0, catalyst_chain_lists_1.getChainGasToken)(toChainId); gasTo = true; } const routerArgsHost = new router_utils_1.RouterArguments({ WGAS: fromChainGasToken }); const routerArgsTarget = new router_utils_1.RouterArguments({ WGAS: fromChainGasToken }); if (route[0].length === 0 && route[1].length === 0) { if (gasFrom) { routerArgsHost.wrapGas(toAccount); } else if (gasTo) { routerArgsHost.transferFrom(fromAsset, amount); routerArgsHost.unwrapGas(toAccount); } else { throw new Error('No route but not wrapping gas?'); } } else if (gasFrom) { routerArgsHost.wrapGas(router_utils_1.RouterArguments.ADDRESS_THIS, amount); } else { routerArgsHost.transferFrom(fromAsset, amount); } if (routeHost['routeDetails'][0].length !== 0) { routerArgsHost.localroute(routeHost.fromAsset, routeHost.routeDetails, routeCross.routeDetails[0].length === 0 ? minOut : 0n); if (routeCross.routeDetails[0].length === 0) { if (gasTo) { routerArgsHost.unwrapGas(router_utils_1.RouterArguments.MSG_SENDER); } else { routerArgsHost.sweep(toAsset, router_utils_1.RouterArguments.MSG_SENDER); } } } let routingIncentive = { maxGasDelivery: 0n, maxGasAck: 0n, refundGasTo: refundGasTo, priceOfDeliveryGas: 0n, priceOfAckGas: 0n, targetDelta: 0n, messageVerifyGasCost: 0n, }; let estimatedRefund = 0n; if (routeCross.fromAsset !== '' && routeTarget.fromAsset !== '') { let targetRoutingCalldata = ''; if (routeTarget['routeDetails'][0].length !== 0) { routerArgsTarget.localroute(routeTarget['fromAsset'], routeTarget['routeDetails'], minOut); targetRoutingCalldata = routerArgsTarget.getCalldata(); } if (gasTo) { routerArgsTarget.unwrapGas(toAccount); } else { routerArgsTarget.sweep(toAsset, toAccount); } targetRoutingCalldata = routerArgsTarget.getCalldata(); if (refundGasTo === '') { throw Error('refundGasTo cannot be "" or unset for cross-chain swaps'); } const maxGasDelivery = routerArgsTarget.getGasCostEstimate({ additionalMargin: 0.2, remote: true, }); estimatedRefund = (maxGasDelivery * 2n) / 12n; routingIncentive = { maxGasDelivery: maxGasDelivery, maxGasAck: router_utils_1.gasCostTable['ACK'], refundGasTo: refundGasTo, priceOfDeliveryGas: priceOfDeliveryGas, priceOfAckGas: priceOfAckGas, targetDelta: 0n, messageVerifyGasCost, }; const hostVault = routeCross['routeDetails'][0][0]; const targetVault = routeCross['routeDetails'][0][routeCross['routeDetails'][0].length - 1]; routerArgsHost.sendAsset(routeCross['fromAsset'] === utils_1.GAS_TOKEN_IDENTIFIER ? (0, catalyst_chain_lists_1.getChainGasToken)(fromChainId) : routeCross['fromAsset'], toAssetIndex, hostVault, targetVault, channelId, minOut, router_utils_1.RouterArguments.ROUTER, router_utils_1.RouterArguments.BALANCE_THIS, routingIncentive, deadline, underwritingIncentive, targetRoutingCalldata); } const toCallParameters = routerArgsHost.getParams(); return { executionInstructions: { commands: toCallParameters[0], inputs: toCallParameters[1], gas: { estimatedGasUsedOnLocal: routerArgsHost.getGasCostEstimate(), estimatedGasUsedOnRemote: routingIncentive.maxGasDelivery, estimatedGasUsedOnLocalAck: routingIncentive.maxGasAck, estimatedRoutingPayment: router_utils_1.RouterArguments.getIncentiveCost(routingIncentive), estimatedRefundOnAck: estimatedRefund, }, }, }; } function swapByRouteViaPermit(args) { const { toAccount, amount, route, minOut, toAssetIndex, channelId, fromChainId, toChainId, messageVerifyGasCost, priceOfDeliveryGas, priceOfAckGas, refundGasTo = '', permitData, } = args; const deadline = BigInt((0, utils_1.toDeadline)(14 * 24 * 60 * utils_1.ONE_MIN_MS)); let { fromAsset, toAsset, underwritingIncentive } = args; if (underwritingIncentive === undefined) { underwritingIncentive = 0n; } const fromChainGasToken = (0, catalyst_chain_lists_1.getChainGasToken)(fromChainId); const [routeHost, routeCross, routeTarget] = router_utils_1.RouterArguments.splitRoute(fromAsset, route); let gasFrom, gasTo = false; if (fromAsset === utils_1.GAS_TOKEN_IDENTIFIER) { fromAsset = fromChainGasToken; gasFrom = true; } if (toAsset === utils_1.GAS_TOKEN_IDENTIFIER) { toAsset = (0, catalyst_chain_lists_1.getChainGasToken)(toChainId); gasTo = true; } const routerArgsHost = new router_utils_1.RouterArguments({ WGAS: fromChainGasToken }); const routerArgsTarget = new router_utils_1.RouterArguments({ WGAS: fromChainGasToken }); if (route[0].length === 0 && route[1].length === 0) { if (gasFrom) { routerArgsHost.wrapGas(toAccount); } else if (gasTo) { routerArgsHost.transferWithOptionalPermit({ token: fromAsset, amount, }, permitData); routerArgsHost.unwrapGas(toAccount); } else { throw new Error('No route but not wrapping gas?'); } } else if (gasFrom) { routerArgsHost.wrapGas(router_utils_1.RouterArguments.ADDRESS_THIS, amount); } else { routerArgsHost.transferWithOptionalPermit({ token: fromAsset, amount, }, permitData); } if (routeHost['routeDetails'][0].length !== 0) { routerArgsHost.localroute(routeHost.fromAsset, routeHost.routeDetails, routeCross.routeDetails[0].length === 0 ? minOut : 0n); if (routeCross.routeDetails[0].length === 0) { if (gasTo) { routerArgsHost.unwrapGas(router_utils_1.RouterArguments.MSG_SENDER); } else { routerArgsHost.sweep(toAsset, router_utils_1.RouterArguments.MSG_SENDER); } } } let routingIncentive = { maxGasDelivery: 0n, maxGasAck: 0n, refundGasTo: refundGasTo, priceOfDeliveryGas: 0n, priceOfAckGas: 0n, targetDelta: 0n, messageVerifyGasCost, }; let estimatedRefund = 0n; if (routeCross.fromAsset !== '' && routeTarget.fromAsset !== '') { let targetRoutingCalldata = ''; if (routeTarget['routeDetails'][0].length !== 0) { routerArgsTarget.localroute(routeTarget['fromAsset'], routeTarget['routeDetails'], minOut); targetRoutingCalldata = routerArgsTarget.getCalldata(); } if (gasTo) { routerArgsTarget.unwrapGas(toAccount); } else { routerArgsTarget.sweep(toAsset, toAccount); } targetRoutingCalldata = routerArgsTarget.getCalldata(); if (refundGasTo === '') { throw Error('refundGasTo cannot be "" or unset for cross-chain swaps'); } const maxGasDelivery = routerArgsTarget.getGasCostEstimate({ additionalMargin: 0.2, remote: true, }); estimatedRefund = (maxGasDelivery * 2n) / 12n; routingIncentive = { maxGasDelivery: maxGasDelivery, maxGasAck: router_utils_1.gasCostTable['ACK'], refundGasTo: refundGasTo, priceOfDeliveryGas: priceOfDeliveryGas, priceOfAckGas: priceOfAckGas, targetDelta: 0n, messageVerifyGasCost, }; const hostVault = routeCross['routeDetails'][0][0]; const targetVault = routeCross['routeDetails'][0][routeCross['routeDetails'][0].length - 1]; routerArgsHost.sendAsset(routeCross['fromAsset'] === utils_1.GAS_TOKEN_IDENTIFIER ? (0, catalyst_chain_lists_1.getChainGasToken)(fromChainId) : routeCross['fromAsset'], toAssetIndex, hostVault, targetVault, channelId, minOut, router_utils_1.RouterArguments.ROUTER, router_utils_1.RouterArguments.BALANCE_THIS, routingIncentive, deadline, underwritingIncentive, targetRoutingCalldata); } const toCallParameters = routerArgsHost.getParams(); return { executionInstructions: { commands: toCallParameters[0], inputs: toCallParameters[1], gas: { estimatedGasUsedOnLocal: routerArgsHost.getGasCostEstimate(), estimatedGasUsedOnRemote: routingIncentive.maxGasDelivery, estimatedGasUsedOnLocalAck: routingIncentive.maxGasAck, estimatedRoutingPayment: router_utils_1.RouterArguments.getIncentiveCost(routingIncentive), estimatedRefundOnAck: estimatedRefund, }, }, }; } function depositWithLiquiditySwaps(userDeposits, chains, vaults, vaultAddresses, assetsAddresses, userAddresses, messageVerifyGasCosts, priceOfDeliveryGas, priceOfAckGas, refundGasTo, slippage = math_1.WAD / 100n) { if (chains.length !== vaults.length) { throw new Error('Different length chains and vaults'); } const { vaultTokenSwaps: allLiquiditySwaps } = (0, math_1.findOptimalLiquiditySwaps)(vaults, userDeposits); const gasUsages = []; const routerArgs = []; for (let i = 0; i < chains.length; ++i) { const chain = chains[i]; const vault = vaults[i]; const vaultAddress = vaultAddresses[i]; const userDeposit = userDeposits[i]; const vaultAssets = assetsAddresses[i]; const chainSpecificLiquiditySwaps = allLiquiditySwaps.filter((ls) => ls.from === i); const chainArgs = new router_utils_1.RouterArguments({ WGAS: (0, catalyst_chain_lists_1.getChainGasToken)(chain.chainId), }); for (let assetIndex = 0; assetIndex < userDeposit.length; ++assetIndex) { chainArgs.transferFrom(vaultAssets[assetIndex], userDeposit[assetIndex]); } const estimatedOut = (0, math_1.depositMixed)(vault, userDeposit); chainArgs.deposit(vaultAddress, vaultAssets, userDeposit, (estimatedOut * (math_1.WAD - slippage)) / math_1.WAD); const routingIncentives = []; for (let j = 0; j < chainSpecificLiquiditySwaps.length; ++j) { const liquiditySwap = chainSpecificLiquiditySwaps[j]; const toChain = chains[liquiditySwap.to]; const toVaultAddress = vaultAddresses[liquiditySwap.to]; const deliveryGasPrice = priceOfDeliveryGas[liquiditySwap.from][liquiditySwap.to]; const ackGasPrice = priceOfAckGas[liquiditySwap.from]; const targetUserAddress = userAddresses[liquiditySwap.to]; const messageVerifyGasCost = messageVerifyGasCosts[liquiditySwap.from][liquiditySwap.to]; const amount = liquiditySwap.vaultTokensSent; const routingIncentive = { maxGasDelivery: router_utils_1.gasCostTable['RECEIVE'] + router_utils_1.gasCostTable['SENDLIQUIDITY'], maxGasAck: router_utils_1.gasCostTable['ACK'], refundGasTo: refundGasTo, priceOfDeliveryGas: deliveryGasPrice, priceOfAckGas: ackGasPrice, targetDelta: 0n, messageVerifyGasCost, }; routingIncentives.push(routingIncentive); const gasTokenAmount = chainSpecificLiquiditySwaps.length - 1 === j ? router_utils_1.RouterArguments.BALANCE_THIS : router_utils_1.RouterArguments.getIncentiveCost(routingIncentive); const deadline = BigInt((0, utils_1.toDeadline)(14 * 24 * 60 * utils_1.ONE_MIN_MS)); chainArgs.liquiditySwap(vaultAddress, toVaultAddress, toChain.channelId, [0n, 0n], targetUserAddress, gasTokenAmount, routingIncentive, amount, deadline); } chainArgs.sweep(vaultAddress, router_utils_1.RouterArguments.MSG_SENDER); gasUsages.push({ estimatedGasUsedOnRemote: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => ri.maxGasDelivery)), estimatedGasUsedOnLocalAck: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => ri.maxGasAck)), estimatedRoutingPayment: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => router_utils_1.RouterArguments.getIncentiveCost(ri))), }); routerArgs.push(chainArgs); } return routerArgs.map((ra, rai) => { const estimatedGasUsedOnLocal = ra.getGasCostEstimate(); const toCallParameters = ra.getParams(); const gasUsage = gasUsages[rai]; const estimatedRefund = (gasUsage.estimatedGasUsedOnRemote * 2n) / 12n; return { executionInstructions: { commands: toCallParameters[0], inputs: toCallParameters[1], gas: { ...gasUsage, estimatedGasUsedOnLocal: estimatedGasUsedOnLocal, estimatedRefundOnAck: estimatedRefund, }, }, }; }); } function prepareDepositWithLiquiditySwaps(userDeposits, chains, vaults, vaultAddresses, assetsAddresses, userAddresses, messageVerifyGasCosts, priceOfDeliveryGas, priceOfAckGas, refundGasTo, slippage = math_1.WAD / 100n, wrapGasValues = []) { if (chains.length !== vaults.length) { throw new Error('Different length chains and vaults'); } const { vaultTokenSwaps: allLiquiditySwaps } = (0, math_1.findOptimalLiquiditySwaps)(vaults, userDeposits); const gasUsages = []; const routerArgs = []; for (let i = 0; i < chains.length; ++i) { const chain = chains[i]; const vault = vaults[i]; const vaultAddress = vaultAddresses[i]; const userDeposit = userDeposits[i]; const vaultAssets = assetsAddresses[i]; const chainSpecificLiquiditySwaps = allLiquiditySwaps.filter((ls) => ls.from === i); const chainArgs = new router_utils_1.RouterArguments({ WGAS: (0, catalyst_chain_lists_1.getChainGasToken)(chain.chainId), }); const wrapGasAmount = wrapGasValues[i]; if (wrapGasAmount) { chainArgs.wrapGas(router_utils_1.RouterArguments.ADDRESS_THIS, wrapGasAmount); } const estimatedOut = (0, math_1.depositMixed)(vault, userDeposit); chainArgs.deposit(vaultAddress, vaultAssets, userDeposit, (estimatedOut * (math_1.WAD - slippage)) / math_1.WAD); const routingIncentives = []; for (let j = 0; j < chainSpecificLiquiditySwaps.length; ++j) { const liquiditySwap = chainSpecificLiquiditySwaps[j]; const toChain = chains[liquiditySwap.to]; const toVaultAddress = vaultAddresses[liquiditySwap.to]; const deliveryGasPrice = priceOfDeliveryGas[liquiditySwap.from][liquiditySwap.to]; const ackGasPrice = priceOfAckGas[liquiditySwap.from]; const targetUserAddress = userAddresses[liquiditySwap.to]; const messageVerifyGasCost = messageVerifyGasCosts[liquiditySwap.from][liquiditySwap.to]; const amount = liquiditySwap.vaultTokensSent; const routingIncentive = { maxGasDelivery: router_utils_1.gasCostTable['RECEIVE'] + router_utils_1.gasCostTable['SENDLIQUIDITY'], maxGasAck: router_utils_1.gasCostTable['ACK'], refundGasTo: refundGasTo, priceOfDeliveryGas: deliveryGasPrice, priceOfAckGas: ackGasPrice, targetDelta: 0n, messageVerifyGasCost, }; routingIncentives.push(routingIncentive); const gasTokenAmount = chainSpecificLiquiditySwaps.length - 1 === j ? router_utils_1.RouterArguments.BALANCE_THIS : router_utils_1.RouterArguments.getIncentiveCost(routingIncentive); const deadline = BigInt((0, utils_1.toDeadline)(14 * 24 * 60 * utils_1.ONE_MIN_MS)); chainArgs.liquiditySwap(vaultAddress, toVaultAddress, toChain.channelId, [0n, 0n], targetUserAddress, gasTokenAmount, routingIncentive, amount, deadline); } chainArgs.sweep(vaultAddress, router_utils_1.RouterArguments.MSG_SENDER); gasUsages.push({ estimatedGasUsedOnRemote: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => ri.maxGasDelivery)), estimatedGasUsedOnLocalAck: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => ri.maxGasAck)), estimatedRoutingPayment: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => router_utils_1.RouterArguments.getIncentiveCost(ri))), }); routerArgs.push(chainArgs); } return routerArgs.map((chainArgs, chainArgsIndex) => { const gasUsage = gasUsages[chainArgsIndex]; return { routerArgs: chainArgs, gasUsage, transferDetails: userDeposits[chainArgsIndex].map((amount, assetIndex) => ({ token: assetsAddresses[chainArgsIndex][assetIndex], amount, })), }; }); } function withdrawWithLiquiditySwap(userVaultTokens, userWithdrawals, chains, vaults, vaultAddresses, assetsAddresses, userAddresses, messageVerifyGasCosts, priceOfDeliveryGas, priceOfAckGas, refundGasTo, routerAddresses, unwrapGas = [], withdrawRatios = undefined) { if (chains.length !== vaults.length) { throw new Error('Different length chains and vaults'); } const { vaultTokenSwaps: allLiquiditySwaps, boughtUnits } = (0, math_1.findOptimalWithdrawLiquiditySwaps)(vaults, userVaultTokens, userWithdrawals); const gasUsages = []; const routerArgs = []; for (let i = 0; i < chains.length; ++i) { const chain = chains[i]; const vaultAddress = vaultAddresses[i]; const vaultAssets = assetsAddresses[i]; const chainSpecificLiquiditySwaps = allLiquiditySwaps.filter((ls) => ls.from === i); const chainArgs = new router_utils_1.RouterArguments({ WGAS: (0, catalyst_chain_lists_1.getChainGasToken)(chain.chainId), }); const routingIncentives = []; let vaultTokensToCollect = 0n; for (const liquiditySwap of chainSpecificLiquiditySwaps) { vaultTokensToCollect = vaultTokensToCollect + liquiditySwap.vaultTokens; } if (vaultTokensToCollect === 0n) { routerArgs.push(undefined); gasUsages.push({ estimatedGasUsedOnRemote: 0n, estimatedGasUsedOnLocalAck: 0n, estimatedRoutingPayment: 0n, }); continue; } chainArgs.transferFrom(vaultAddress, vaultTokensToCollect); const vaultUnits = boughtUnits[i]; let allUnits = (0, math_utils_1.bigNumberSum)(vaultUnits); const withdrawRatio = vaultUnits.map((unitsForToken, i) => { if (allUnits === 0n) { return i === 0 ? math_1.WAD : 0n; } const percentage = (unitsForToken * math_1.WAD) / allUnits; allUnits = allUnits - unitsForToken; return percentage; }); chainSpecificLiquiditySwaps.sort((a, b) => { return Number(a.to === i) - Number(b.to === i); }); for (let j = 0; j < chainSpecificLiquiditySwaps.length; ++j) { const liquiditySwap = chainSpecificLiquiditySwaps[j]; const toChain = chains[liquiditySwap.to]; if (i === liquiditySwap.to) { chainArgs.withdrawMixed(vaultAddress, router_utils_1.RouterArguments.BALANCE_THIS, withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio, [0n, 0n, 0n]); if (unwrapGas[liquiditySwap.to]) { chainArgs.unwrapGas(router_utils_1.RouterArguments.MSG_SENDER); } for (let withdrawRatioIndex = 0; withdrawRatioIndex < withdrawRatio.length; ++withdrawRatioIndex) { if ((withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio)[withdrawRatioIndex] > 0n) { chainArgs.sweep(vaultAssets[withdrawRatioIndex], router_utils_1.RouterArguments.MSG_SENDER); } } continue; } const toVaultAssets = assetsAddresses[liquiditySwap.to]; const toVaultAddress = vaultAddresses[liquiditySwap.to]; const deliveryGasPrice = priceOfDeliveryGas[liquiditySwap.from][liquiditySwap.to]; const ackGasPrice = priceOfAckGas[liquiditySwap.from]; const targetUserAddress = userAddresses[liquiditySwap.to]; const messageVerifyGasCost = messageVerifyGasCosts[liquiditySwap.from][liquiditySwap.to]; const amount = liquiditySwap.vaultTokens; const remoteChainArgs = new router_utils_1.RouterArguments({ WGAS: (0, catalyst_chain_lists_1.getChainGasToken)(chain.chainId), }); remoteChainArgs.withdrawMixed(vaultAddress, router_utils_1.RouterArguments.BALANCE_THIS, withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio, [0n, 0n, 0n]); if (unwrapGas[liquiditySwap.to]) { remoteChainArgs.unwrapGas(targetUserAddress); } for (let withdrawRatioIndex = 0; withdrawRatioIndex < withdrawRatio.length; ++withdrawRatioIndex) { if ((withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio)[withdrawRatioIndex] > 0n) { remoteChainArgs.sweep(toVaultAssets[withdrawRatioIndex], targetUserAddress); } } const routingIncentive = { maxGasDelivery: router_utils_1.gasCostTable['SENDLIQUIDITY'] + remoteChainArgs.getGasCostEstimate({ remote: true }), maxGasAck: router_utils_1.gasCostTable['ACK'], refundGasTo: refundGasTo, priceOfDeliveryGas: deliveryGasPrice, priceOfAckGas: ackGasPrice, targetDelta: 0n, messageVerifyGasCost, }; routingIncentives.push(routingIncentive); const gasTokenAmount = chainSpecificLiquiditySwaps.length - 1 === j ? router_utils_1.RouterArguments.BALANCE_THIS : router_utils_1.RouterArguments.getIncentiveCost(routingIncentive); const targetRoutingCalldata = remoteChainArgs.getCalldata(); const deadline = BigInt((0, utils_1.toDeadline)(14 * 24 * 60 * utils_1.ONE_MIN_MS)); chainArgs.liquiditySwap(vaultAddress, toVaultAddress, toChain.channelId, [0n, 0n], typeof routerAddresses === 'string' ? routerAddresses : routerAddresses[liquiditySwap.to], gasTokenAmount, routingIncentive, amount, deadline, targetRoutingCalldata); } gasUsages.push({ estimatedGasUsedOnRemote: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => ri.maxGasDelivery)), estimatedGasUsedOnLocalAck: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => ri.maxGasAck)), estimatedRoutingPayment: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => router_utils_1.RouterArguments.getIncentiveCost(ri))), }); routerArgs.push(chainArgs); } return routerArgs.map((ra, rai) => { if (ra) { const estimatedGasUsedOnLocal = ra.getGasCostEstimate(); const toCallParameters = ra.getParams(); const gasUsage = gasUsages[rai]; const estimatedRefund = (gasUsage.estimatedGasUsedOnRemote * 2n) / 12n; return { executionInstructions: { commands: toCallParameters[0], inputs: toCallParameters[1], gas: { ...gasUsage, estimatedGasUsedOnLocal: estimatedGasUsedOnLocal, estimatedRefundOnAck: estimatedRefund, }, }, }; } else { return { executionInstructions: undefined, }; } }); } function prepareWithdrawWithLiquiditySwap(userVaultTokens, userWithdrawals, chains, vaults, vaultAddresses, assetsAddresses, userAddresses, messageVerifyGasCosts, priceOfDeliveryGas, priceOfAckGas, refundGasTo, routerAddresses, unwrapGas = [], withdrawRatios = undefined) { if (chains.length !== vaults.length) { throw new Error('Different length chains and vaults'); } const { vaultTokenSwaps: allLiquiditySwaps, boughtUnits } = (0, math_1.findOptimalWithdrawLiquiditySwaps)(vaults, userVaultTokens, userWithdrawals); const gasUsages = []; const routerArgs = []; const transferDetailsArray = []; for (let i = 0; i < chains.length; ++i) { const chain = chains[i]; const vaultAddress = vaultAddresses[i]; const vaultAssets = assetsAddresses[i]; const chainSpecificLiquiditySwaps = allLiquiditySwaps.filter((ls) => ls.from === i); const chainArgs = new router_utils_1.RouterArguments({ WGAS: (0, catalyst_chain_lists_1.getChainGasToken)(chain.chainId), }); const routingIncentives = []; let vaultTokensToCollect = 0n; for (const liquiditySwap of chainSpecificLiquiditySwaps) { vaultTokensToCollect = vaultTokensToCollect + liquiditySwap.vaultTokens; } transferDetailsArray.push({ token: vaultAddress, amount: vaultTokensToCollect, }); if (vaultTokensToCollect === 0n) { routerArgs.push(undefined); gasUsages.push({ estimatedGasUsedOnRemote: 0n, estimatedGasUsedOnLocalAck: 0n, estimatedRoutingPayment: 0n, }); continue; } const vaultUnits = boughtUnits[i]; let allUnits = (0, math_utils_1.bigNumberSum)(vaultUnits); const withdrawRatio = vaultUnits.map((unitsForToken, i) => { if (allUnits === 0n) { return i === 0 ? math_1.WAD : 0n; } const percentage = (unitsForToken * math_1.WAD) / allUnits; allUnits = allUnits - unitsForToken; return percentage; }); chainSpecificLiquiditySwaps.sort((a, b) => { return Number(a.to === i) - Number(b.to === i); }); for (let j = 0; j < chainSpecificLiquiditySwaps.length; ++j) { const liquiditySwap = chainSpecificLiquiditySwaps[j]; const toChain = chains[liquiditySwap.to]; if (i === liquiditySwap.to) { chainArgs.withdrawMixed(vaultAddress, router_utils_1.RouterArguments.BALANCE_THIS, withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio, [0n, 0n, 0n]); if (unwrapGas[liquiditySwap.to]) { chainArgs.unwrapGas(router_utils_1.RouterArguments.MSG_SENDER); } for (let withdrawRatioIndex = 0; withdrawRatioIndex < withdrawRatio.length; ++withdrawRatioIndex) { if ((withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio)[withdrawRatioIndex] > 0n) { chainArgs.sweep(vaultAssets[withdrawRatioIndex], router_utils_1.RouterArguments.MSG_SENDER); } } continue; } const toVaultAssets = assetsAddresses[liquiditySwap.to]; const toVaultAddress = vaultAddresses[liquiditySwap.to]; const deliveryGasPrice = priceOfDeliveryGas[liquiditySwap.from][liquiditySwap.to]; const ackGasPrice = priceOfAckGas[liquiditySwap.from]; const targetUserAddress = userAddresses[liquiditySwap.to]; const messageVerifyGasCost = messageVerifyGasCosts[liquiditySwap.from][liquiditySwap.to]; const amount = liquiditySwap.vaultTokens; const remoteChainArgs = new router_utils_1.RouterArguments({ WGAS: (0, catalyst_chain_lists_1.getChainGasToken)(chain.chainId), }); remoteChainArgs.withdrawMixed(vaultAddress, router_utils_1.RouterArguments.BALANCE_THIS, withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio, [0n, 0n, 0n]); if (unwrapGas[liquiditySwap.to]) { remoteChainArgs.unwrapGas(targetUserAddress); } for (let withdrawRatioIndex = 0; withdrawRatioIndex < withdrawRatio.length; ++withdrawRatioIndex) { if ((withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio)[withdrawRatioIndex] > 0n) { remoteChainArgs.sweep(toVaultAssets[withdrawRatioIndex], targetUserAddress); } } const routingIncentive = { maxGasDelivery: router_utils_1.gasCostTable['SENDLIQUIDITY'] + remoteChainArgs.getGasCostEstimate({ remote: true }), maxGasAck: router_utils_1.gasCostTable['ACK'], refundGasTo: refundGasTo, priceOfDeliveryGas: deliveryGasPrice, priceOfAckGas: ackGasPrice, targetDelta: 0n, messageVerifyGasCost, }; routingIncentives.push(routingIncentive); const gasTokenAmount = chainSpecificLiquiditySwaps.length - 1 === j ? router_utils_1.RouterArguments.BALANCE_THIS : router_utils_1.RouterArguments.getIncentiveCost(routingIncentive); const targetRoutingCalldata = remoteChainArgs.getCalldata(); const deadline = BigInt((0, utils_1.toDeadline)(14 * 24 * 60 * utils_1.ONE_MIN_MS)); chainArgs.liquiditySwap(vaultAddress, toVaultAddress, toChain.channelId, [0n, 0n], typeof routerAddresses === 'string' ? routerAddresses : routerAddresses[liquiditySwap.to], gasTokenAmount, routingIncentive, amount, deadline, targetRoutingCalldata); } gasUsages.push({ estimatedGasUsedOnRemote: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => ri.maxGasDelivery)), estimatedGasUsedOnLocalAck: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => ri.maxGasAck)), estimatedRoutingPayment: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => router_utils_1.RouterArguments.getIncentiveCost(ri))), }); routerArgs.push(chainArgs); } return routerArgs.map((chainArgs, chainArgsIndex) => { const gasUsage = gasUsages[chainArgsIndex]; return { routerArgs: chainArgs, gasUsage, transferDetails: transferDetailsArray[chainArgsIndex], }; }); } function prepareWithdrawSamePercentageWithLiquiditySwap(userVaultTokens, percentage, targetVaultIndex, targetAssetIndex, chains, vaults, vaultAddresses, assetsAddresses, userAddresses, messageVerifyGasCosts, priceOfDeliveryGas, priceOfAckGas, refundGasTo, routerAddresses, unwrapGas = [], withdrawRatios = undefined) { if (chains.length !== vaults.length) { throw new Error('Different length chains and vaults'); } const { vaultTokenSwaps: allLiquiditySwaps } = (0, math_1.findMeExpectedWithdrawnUnits)(vaults, userVaultTokens, percentage, targetVaultIndex); const gasUsages = []; const routerArgs = []; const transferDetailsArray = []; for (let i = 0; i < chains.length; ++i) { const chain = chains[i]; const vaultAddress = vaultAddresses[i]; const vaultAssets = assetsAddresses[i]; const chainSpecificLiquiditySwaps = allLiquiditySwaps.filter((ls) => ls.from === i); const chainArgs = new router_utils_1.RouterArguments({ WGAS: (0, catalyst_chain_lists_1.getChainGasToken)(chain.chainId), }); const routingIncentives = []; let vaultTokensToCollect = 0n; for (const liquiditySwap of chainSpecificLiquiditySwaps) { vaultTokensToCollect = vaultTokensToCollect + liquiditySwap.vaultTokens; } transferDetailsArray.push({ token: vaultAddress, amount: vaultTokensToCollect, }); if (vaultTokensToCollect === 0n) { routerArgs.push(undefined); gasUsages.push({ estimatedGasUsedOnRemote: 0n, estimatedGasUsedOnLocalAck: 0n, estimatedRoutingPayment: 0n, }); continue; } const withdrawRatio = vaults[i].balances.map((_, l) => { if (i !== targetVaultIndex) { if (l === 0) { return math_1.WAD; } else { return 0n; } } if (l === targetAssetIndex) { return math_1.WAD; } else { return 0n; } }); chainSpecificLiquiditySwaps.sort((a, b) => { return Number(a.to === i) - Number(b.to === i); }); for (let j = 0; j < chainSpecificLiquiditySwaps.length; ++j) { const liquiditySwap = chainSpecificLiquiditySwaps[j]; const toChain = chains[liquiditySwap.to]; if (i === liquiditySwap.to) { chainArgs.withdrawMixed(vaultAddress, router_utils_1.RouterArguments.BALANCE_THIS, withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio, [0n, 0n, 0n]); if (unwrapGas[liquiditySwap.to]) { chainArgs.unwrapGas(router_utils_1.RouterArguments.MSG_SENDER); } for (let withdrawRatioIndex = 0; withdrawRatioIndex < withdrawRatio.length; ++withdrawRatioIndex) { if ((withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio)[withdrawRatioIndex] > 0n) { chainArgs.sweep(vaultAssets[withdrawRatioIndex], router_utils_1.RouterArguments.MSG_SENDER); } } continue; } const toVaultAssets = assetsAddresses[liquiditySwap.to]; const toVaultAddress = vaultAddresses[liquiditySwap.to]; const deliveryGasPrice = priceOfDeliveryGas[liquiditySwap.from][liquiditySwap.to]; const ackGasPrice = priceOfAckGas[liquiditySwap.from]; const targetUserAddress = userAddresses[liquiditySwap.to]; const messageVerifyGasCost = messageVerifyGasCosts[liquiditySwap.from][liquiditySwap.to]; const amount = liquiditySwap.vaultTokens; const remoteChainArgs = new router_utils_1.RouterArguments({ WGAS: (0, catalyst_chain_lists_1.getChainGasToken)(chain.chainId), }); remoteChainArgs.withdrawMixed(vaultAddress, router_utils_1.RouterArguments.BALANCE_THIS, withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio, [0n, 0n, 0n]); if (unwrapGas[liquiditySwap.to]) { remoteChainArgs.unwrapGas(targetUserAddress); } for (let withdrawRatioIndex = 0; withdrawRatioIndex < withdrawRatio.length; ++withdrawRatioIndex) { if ((withdrawRatios ? withdrawRatios[liquiditySwap.to] : withdrawRatio)[withdrawRatioIndex] > 0n) { remoteChainArgs.sweep(toVaultAssets[withdrawRatioIndex], targetUserAddress); } } const routingIncentive = { maxGasDelivery: router_utils_1.gasCostTable['SENDLIQUIDITY'] + remoteChainArgs.getGasCostEstimate({ remote: true }), maxGasAck: router_utils_1.gasCostTable['ACK'], refundGasTo: refundGasTo, priceOfDeliveryGas: deliveryGasPrice, priceOfAckGas: ackGasPrice, targetDelta: 0n, messageVerifyGasCost, }; routingIncentives.push(routingIncentive); const gasTokenAmount = chainSpecificLiquiditySwaps.length - 1 === j ? router_utils_1.RouterArguments.BALANCE_THIS : router_utils_1.RouterArguments.getIncentiveCost(routingIncentive); const targetRoutingCalldata = remoteChainArgs.getCalldata(); const deadline = BigInt((0, utils_1.toDeadline)(14 * 24 * 60 * utils_1.ONE_MIN_MS)); chainArgs.liquiditySwap(vaultAddress, toVaultAddress, toChain.channelId, [0n, 0n], typeof routerAddresses === 'string' ? routerAddresses : routerAddresses[liquiditySwap.to], gasTokenAmount, routingIncentive, amount, deadline, targetRoutingCalldata); } gasUsages.push({ estimatedGasUsedOnRemote: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => ri.maxGasDelivery)), estimatedGasUsedOnLocalAck: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => ri.maxGasAck)), estimatedRoutingPayment: (0, math_utils_1.bigNumberSum)(routingIncentives.map((ri) => router_utils_1.RouterArguments.getIncentiveCost(ri))), }); routerArgs.push(chainArgs); } return routerArgs.map((chainArgs, chainArgsIndex) => { const gasUsage = gasUsages[chainArgsIndex]; return { routerArgs: chainArgs, gasUsage, transferDetails: transferDetailsArray[chainArgsIndex], }; }); } //# sourceMappingURL=router.macro.js.map