diff --git a/src/entities/permit2Helper/index.ts b/src/entities/permit2Helper/index.ts index e4ab041e..670d1604 100644 --- a/src/entities/permit2Helper/index.ts +++ b/src/entities/permit2Helper/index.ts @@ -288,7 +288,7 @@ export class Permit2Helper { } } -const signPermit2 = async ( +export const signPermit2 = async ( client: Client & WalletActions, owner: Address | Account, spender: Address, @@ -320,7 +320,7 @@ const signPermit2 = async ( return { batch, signature }; }; -const getDetails = async ( +export const getDetails = async ( client: Client & PublicActions, token: Address, owner: Address | Account, diff --git a/test/anvil/anvil-global-setup.ts b/test/anvil/anvil-global-setup.ts index dc1506be..e30d747a 100644 --- a/test/anvil/anvil-global-setup.ts +++ b/test/anvil/anvil-global-setup.ts @@ -28,6 +28,7 @@ type NetworksWithFork = Extract< | 'HYPEREVM' | 'PLASMA' | 'X_LAYER' + | 'BASE' >; const ANVIL_PORTS: Record = { @@ -46,6 +47,7 @@ const ANVIL_PORTS: Record = { HYPEREVM: 9745, PLASMA: 9845, X_LAYER: 9945, + BASE: 10045, }; export const ANVIL_NETWORKS: Record = { @@ -134,6 +136,12 @@ export const ANVIL_NETWORKS: Record = { port: ANVIL_PORTS.X_LAYER, forkBlockNumber: 43138155n, }, + BASE: { + rpcEnv: 'BASE_RPC_URL', + fallBackRpc: 'https://base.drpc.org', + port: ANVIL_PORTS.BASE, + forkBlockNumber: 38940000n, + }, }; function getAnvilOptions( @@ -162,6 +170,8 @@ function getAnvilOptions( forkUrl, port, forkBlockNumber, + mnemonic: + 'you twelve word test phrase boat cat like this example dog car', // mnemonic for deterministic accounts - should not have delegated accounts }; } diff --git a/test/entities/swaps/v2/swap.integration.test.ts b/test/entities/swaps/v2/swap.integration.test.ts new file mode 100644 index 00000000..0750ba72 --- /dev/null +++ b/test/entities/swaps/v2/swap.integration.test.ts @@ -0,0 +1,259 @@ +// pnpm test test/entities/swaps/v2/swap.integration.test.ts +import { config } from 'dotenv'; +config(); +import { TestActions, Hex } from 'viem'; +import { SwapKind, PublicWalletClient, VAULT_V2 } from '@/index'; + +import { stopAnvilFork } from 'test/anvil/anvil-global-setup'; +import { + setupForkAndClientV2, + setupV2Approval, +} from 'test/lib/utils/swapTestFixture'; +import { + TEST_CONSTANTS_V2, + testsV2, + allTestsHaveSavedDataV2, +} from './swapTestConfig'; +import { loadSwapTestData, saveSwapTestData } from 'test/lib/utils'; +import { runSwapTest } from 'test/lib/utils/swapTestRunner'; +import { join, dirname, basename } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +// Get the directory of the current test file +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const swapTestDataPath = join( + __dirname, + TEST_CONSTANTS_V2.SWAP_TEST_DATA_FILENAME, +); +const jobId = + basename(__filename) + .split('') + .reduce((sum, char) => sum + char.charCodeAt(0), 0) % 10000; + +// Load existing test data (if file exists) +const savedSwapTestData = loadSwapTestData(swapTestDataPath); + +// Data collection for swap test call data (nested structure) +const swapTestData: Record = {}; + +for (const test of testsV2) { + describe.sequential(test.name, () => { + let snapshot: Hex | undefined; + let fork: { rpcUrl: string } | undefined; + let client: (PublicWalletClient & TestActions) | undefined; + const testAddress = TEST_CONSTANTS_V2.ANVIL_TEST_ADDRESS; + const contractToCall = VAULT_V2[test.chainId]; + + beforeAll(async () => { + // Only run fork/client setup if at least one test doesn't have saved data + if (!allTestsHaveSavedDataV2(test, savedSwapTestData)) { + const setup = await setupForkAndClientV2( + test, + jobId, + testAddress, + ); + fork = setup.fork; + client = setup.client; + } + }); + + if (test.isNative === 'input') { + describe.sequential('native input', () => { + it('should handle GivenIn swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenIn, + wethIsEth: true, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS_V2.slippage, + deadline: TEST_CONSTANTS_V2.deadline, + testName: test.name, + context: 'native input', + subContext: undefined, + outputTest: + test.outputTest || + TEST_CONSTANTS_V2.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + + it('should handle GivenOut swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenOut, + wethIsEth: true, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS_V2.slippage, + deadline: TEST_CONSTANTS_V2.deadline, + testName: test.name, + context: 'native input', + subContext: undefined, + outputTest: + test.outputTest || + TEST_CONSTANTS_V2.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + }); + } + + describe.sequential('token swap', () => { + beforeAll(async () => { + // Only run if fork/client were initialized + if (client && fork) { + snapshot = await setupV2Approval( + client, + testAddress, + test.path, + contractToCall, + TEST_CONSTANTS_V2.BALANCE_MULTIPLIER, + ); + } + }); + + beforeEach(async () => { + // Only run if fork/client were initialized + if (client && fork && snapshot) { + await client.revert({ + id: snapshot, + }); + snapshot = await client.snapshot(); + } + }); + + if (test.isNative === 'output') { + describe.sequential('native output', () => { + it('should handle GivenIn swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenIn, + wethIsEth: true, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS_V2.slippage, + deadline: TEST_CONSTANTS_V2.deadline, + testName: test.name, + context: 'native output', + subContext: undefined, + outputTest: + test.outputTest || + TEST_CONSTANTS_V2.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + + it('should handle GivenOut swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenOut, + wethIsEth: true, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS_V2.slippage, + deadline: TEST_CONSTANTS_V2.deadline, + testName: test.name, + context: 'native output', + subContext: undefined, + outputTest: + test.outputTest || + TEST_CONSTANTS_V2.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + }); + } + + describe.sequential('token swap', () => { + it('should handle GivenIn swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenIn, + wethIsEth: false, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS_V2.slippage, + deadline: TEST_CONSTANTS_V2.deadline, + testName: test.name, + context: 'token swap', + subContext: undefined, + outputTest: + test.outputTest || + TEST_CONSTANTS_V2.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + + it('should handle GivenOut swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenOut, + wethIsEth: false, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS_V2.slippage, + deadline: TEST_CONSTANTS_V2.deadline, + testName: test.name, + context: 'token swap', + subContext: undefined, + outputTest: + test.outputTest || + TEST_CONSTANTS_V2.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + }); + }); + + afterAll(async () => { + // Only stop fork if it was started + if (fork) { + console.log('stopFork', test.name); + await stopAnvilFork(test.anvilNetwork, jobId); + } + }); + }); +} + +// Write swap test data to JSON file after all tests complete +afterAll(async () => { + await saveSwapTestData(swapTestDataPath, savedSwapTestData, swapTestData); +}); diff --git a/test/entities/swaps/v2/swapTestConfig.ts b/test/entities/swaps/v2/swapTestConfig.ts new file mode 100644 index 00000000..544aff48 --- /dev/null +++ b/test/entities/swaps/v2/swapTestConfig.ts @@ -0,0 +1,148 @@ +import { ChainId, Path, Slippage } from '@/index'; +import { ANVIL_NETWORKS, NetworkSetup } from 'test/anvil/anvil-global-setup'; +import { TOKENS } from 'test/lib/utils/addresses'; +import { hasSavedTestData } from 'test/lib/utils/swapTestDataHelpers'; + +// Test configuration constants for V2 +export const TEST_CONSTANTS_V2 = { + ANVIL_TEST_ADDRESS: '0x831eFb058FEdCd16Cd6b9174206DFe452dDCe8C3', // address from mnemonic "you twelve word test phrase boat cat like this example dog car" + BALANCE_MULTIPLIER: 10n, // For setting token balances + slippage: Slippage.fromPercentage('0.1'), + deadline: 999999999999999999n, + SWAP_TEST_DATA_FILENAME: 'swapTestData.json', + defaultOutputTest: { + testExactOutAmount: true, + percentage: 0, + }, +} as const; + +export type NativePosition = 'input' | 'output' | 'none'; + +export type TestV2 = { + name: string; + chainId: ChainId; + anvilNetwork: NetworkSetup; + path: Path; + isNative: NativePosition; + blockNumber?: bigint; + outputTest?: { + testExactOutAmount: boolean; + percentage: number; + }; +}; + +export const testsV2: TestV2[] = [ + { + name: 'Single Swap: BAL[swap]WETH', + chainId: ChainId.MAINNET, + anvilNetwork: ANVIL_NETWORKS.MAINNET, + path: { + protocolVersion: 2, + tokens: [ + { + address: TOKENS[ChainId.MAINNET].BAL.address, + decimals: TOKENS[ChainId.MAINNET].BAL.decimals, + }, + { + address: TOKENS[ChainId.MAINNET].WETH.address, + decimals: TOKENS[ChainId.MAINNET].WETH.decimals, + }, + ], + pools: [ + '0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014', + ], + inputAmountRaw: 100000000000n, + outputAmountRaw: 100000n, + }, + isNative: 'output', + }, + { + name: 'Single Swap: WETH[swap]BAL', + chainId: ChainId.MAINNET, + anvilNetwork: ANVIL_NETWORKS.MAINNET, + path: { + protocolVersion: 2, + tokens: [ + { + address: TOKENS[ChainId.MAINNET].WETH.address, + decimals: TOKENS[ChainId.MAINNET].WETH.decimals, + }, + { + address: TOKENS[ChainId.MAINNET].BAL.address, + decimals: TOKENS[ChainId.MAINNET].BAL.decimals, + }, + ], + pools: [ + '0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014', + ], + inputAmountRaw: 10000000000n, + outputAmountRaw: 1000000000000n, + }, + isNative: 'input', + }, +]; + +/** + * Checks if all tests for a given V2 test configuration have valid saved data. + * Valid saved data must be an object with both 'queryOutput' and 'call' properties. + * Checks the nested structure: testName > context > swapKind + * Always checks "token swap" context, plus conditionally checks native contexts based on isNative value. + * @param test - The V2 test configuration + * @param savedData - Nested record of saved test data + * @returns True if all tests have valid saved data, false otherwise + */ +export function allTestsHaveSavedDataV2( + test: Pick, + savedData: Record, +): boolean { + const testData = savedData[test.name]; + if (!testData || typeof testData !== 'object') { + return false; + } + + const testDataObj = testData as Record; + + // Always check "token swap" context + const tokenSwapData = testDataObj['token swap']; + if ( + !tokenSwapData || + typeof tokenSwapData !== 'object' || + !hasSavedTestData((tokenSwapData as Record).GivenIn) || + !hasSavedTestData((tokenSwapData as Record).GivenOut) + ) { + return false; + } + + // Additionally check native contexts based on isNative value + if (test.isNative === 'input') { + const nativeInputData = testDataObj['native input']; + if ( + !nativeInputData || + typeof nativeInputData !== 'object' || + !hasSavedTestData( + (nativeInputData as Record).GivenIn, + ) || + !hasSavedTestData( + (nativeInputData as Record).GivenOut, + ) + ) { + return false; + } + } else if (test.isNative === 'output') { + const nativeOutputData = testDataObj['native output']; + if ( + !nativeOutputData || + typeof nativeOutputData !== 'object' || + !hasSavedTestData( + (nativeOutputData as Record).GivenIn, + ) || + !hasSavedTestData( + (nativeOutputData as Record).GivenOut, + ) + ) { + return false; + } + } + + return true; +} diff --git a/test/entities/swaps/v2/swapTestData.json b/test/entities/swaps/v2/swapTestData.json new file mode 100644 index 00000000..8531cb77 --- /dev/null +++ b/test/entities/swaps/v2/swapTestData.json @@ -0,0 +1,366 @@ +{ + "Single Swap: BAL[swap]WETH": { + "native output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "amountIn": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "100000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "44772212", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "44772212" + } + }, + "call": { + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "callData": "0x52bbbe2900000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002aa7c8f0000000000000000000000000000000000000000000000000de0b6b3a763ffff5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000174876e80000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "44727439", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "44727439" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "amountOut": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "100000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000" + }, + "expectedAmountIn": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "187960564531", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "187960564531" + } + }, + "call": { + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "callData": "0x52bbbe2900000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002bce86a8270000000000000000000000000000000000000000000000000de0b6b3a763ffff5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000140000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "188148525095", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "188148525095" + } + } + } + }, + "token swap": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "amountIn": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "100000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "44772212", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "44772212" + } + }, + "call": { + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "callData": "0x52bbbe2900000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002aa7c8f0000000000000000000000000000000000000000000000000de0b6b3a763ffff5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000174876e80000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "44727439", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "44727439" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "amountOut": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "100000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000" + }, + "expectedAmountIn": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "187960564531", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "187960564531" + } + }, + "call": { + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "callData": "0x52bbbe2900000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002bce86a8270000000000000000000000000000000000000000000000000de0b6b3a763ffff5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000140000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "188148525095", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "188148525095" + } + } + } + } + }, + "Single Swap: WETH[swap]BAL": { + "native input": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "amountIn": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "10000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "11540010705792", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "11540010705792" + } + }, + "call": { + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "callData": "0x52bbbe2900000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7c2e668cae0000000000000000000000000000000000000000000000000de0b6b3a763ffff5c6ee304399dbdb9c8ef030ab642b10820db8f5600020000000000000000001400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d00000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000", + "value": "10000000000", + "minAmountOut": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "11528470695086", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "11528470695086" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "amountOut": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "1000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "1000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "892585871", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "892585871" + } + }, + "call": { + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "callData": "0x52bbbe2900000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000354166380000000000000000000000000000000000000000000000000de0b6b3a763ffff5c6ee304399dbdb9c8ef030ab642b10820db8f5600020000000000000000001400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d000000000000000000000000000000000000000000000000000000e8d4a5100000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000", + "value": "893478456", + "maxAmountIn": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "893478456", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "893478456" + } + } + } + }, + "token swap": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "amountIn": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "10000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "11540010705785", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "11540010705785" + } + }, + "call": { + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "callData": "0x52bbbe2900000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7c2e668ca70000000000000000000000000000000000000000000000000de0b6b3a763ffff5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d00000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "11528470695079", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "11528470695079" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "amountOut": { + "token": { + "chainId": 1, + "address": "0xba100000625a3754423978a60c9317c58a424e3d", + "decimals": 18 + }, + "amount": "1000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "1000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "892585871", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "892585871" + } + }, + "call": { + "to": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "callData": "0x52bbbe2900000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000831efb058fedcd16cd6b9174206dfe452ddce8c3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000354166380000000000000000000000000000000000000000000000000de0b6b3a763ffff5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000140000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000ba100000625a3754423978a60c9317c58a424e3d000000000000000000000000000000000000000000000000000000e8d4a5100000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 1, + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "decimals": 18 + }, + "amount": "893478456", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "893478456" + } + } + } + } + } +} diff --git a/test/entities/swaps/v2/swapV2.integration.test.ts b/test/entities/swaps/v2/swapV2.integration.test.ts deleted file mode 100644 index ab2dd53d..00000000 --- a/test/entities/swaps/v2/swapV2.integration.test.ts +++ /dev/null @@ -1,209 +0,0 @@ -// pnpm test -- swapV2.integration.test.ts -import { config } from 'dotenv'; -config(); -import { - Address, - createTestClient, - http, - parseEther, - publicActions, - walletActions, - TestActions, - Hex, -} from 'viem'; -import { - CHAINS, - ChainId, - SwapKind, - Swap, - VAULT_V2, - Path, - PublicWalletClient, -} from '@/index'; - -import { ANVIL_NETWORKS, startFork } from 'test/anvil/anvil-global-setup'; -import { - assertSwapExactIn, - assertSwapExactOut, - forkSetup, - TOKENS, -} from 'test/lib/utils'; - -const protocolVersion = 2; -const chainId = ChainId.MAINNET; - -const BAL = TOKENS[chainId].BAL; -const WETH = TOKENS[chainId].WETH; -const vault = VAULT_V2[chainId]; - -describe('SwapV2', () => { - let rpcUrl: string; - let client: PublicWalletClient & TestActions; - let testAddress: Address; - let snapshot: Hex; - - const pathBalWeth: Path = { - protocolVersion: 2, - tokens: [ - { - address: TOKENS[chainId].BAL.address, - decimals: TOKENS[chainId].BAL.decimals, - }, - { - address: TOKENS[chainId].WETH.address, - decimals: TOKENS[chainId].WETH.decimals, - }, - ], - pools: [ - '0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014', - ], - inputAmountRaw: 100000000000n, - outputAmountRaw: 100000000000n, - }; - - beforeAll(async () => { - ({ rpcUrl } = await startFork(ANVIL_NETWORKS.MAINNET)); - - client = createTestClient({ - mode: 'anvil', - chain: CHAINS[chainId], - transport: http(rpcUrl), - }) - .extend(publicActions) - .extend(walletActions); - - testAddress = (await client.getAddresses())[0]; - - await forkSetup( - client, - testAddress, - [WETH.address, BAL.address], - [WETH.slot as number, BAL.slot as number], - [parseEther('100'), parseEther('100')], - undefined, - protocolVersion, - ); - - snapshot = await client.snapshot(); - }); - - beforeEach(async () => { - await client.revert({ - id: snapshot, - }); - snapshot = await client.snapshot(); - }); - - describe('swap should be executed correcly', () => { - describe('wethIsEth: false', () => { - const wethIsEth = false; - const swapParams = { - chainId, - paths: [pathBalWeth], - }; - test('GivenIn', async () => { - const swap = new Swap({ - ...swapParams, - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: vault, - client, - rpcUrl, - chainId, - swap, - wethIsEth, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - ...swapParams, - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: vault, - client, - rpcUrl, - chainId, - swap, - wethIsEth, - }); - }); - }); - describe('wethIsEth: true', () => { - const wethIsEth = true; - describe('eth out', async () => { - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [pathBalWeth], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: vault, - client, - rpcUrl, - chainId, - swap, - wethIsEth, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [pathBalWeth], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: vault, - client, - rpcUrl, - chainId, - swap, - wethIsEth, - }); - }); - }); - describe('eth in', () => { - test('GivenIn', async () => { - const pathWethBal = { - ...pathBalWeth, - tokens: [...pathBalWeth.tokens].reverse(), - }; - const swap = new Swap({ - chainId, - paths: [pathWethBal], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: vault, - client, - rpcUrl, - chainId, - swap, - wethIsEth, - }); - }); - test('GivenOut', async () => { - const pathWethBal = { - ...pathBalWeth, - tokens: [...pathBalWeth.tokens].reverse(), - }; - const swap = new Swap({ - chainId, - paths: [pathWethBal], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: vault, - client, - rpcUrl, - chainId, - swap, - wethIsEth, - }); - }); - }); - }); - }); -}); diff --git a/test/entities/swaps/v3/swap.integration.test.ts b/test/entities/swaps/v3/swap.integration.test.ts new file mode 100644 index 00000000..e381e9d1 --- /dev/null +++ b/test/entities/swaps/v3/swap.integration.test.ts @@ -0,0 +1,397 @@ +// pnpm test ./test/entities/swaps/v3/swap.integration.test.ts +import { config } from 'dotenv'; +config(); +import { TestActions, Hex } from 'viem'; +import { + SwapKind, + PublicWalletClient, + AddressProvider, + Permit2, +} from '@/index'; + +import { stopAnvilFork } from 'test/anvil/anvil-global-setup'; +import { + setupForkAndClientV3, + setupPermit2Approval, + setupPermit2Signature, +} from 'test/lib/utils/swapTestFixture'; +import { TEST_CONSTANTS, tests } from './swapTestConfig'; +import { + loadSwapTestData, + saveSwapTestData, + allTestsHaveSavedData, +} from 'test/lib/utils'; +import { + runSwapTest, + runSwapTestWithSignature, +} from 'test/lib/utils/swapTestRunner'; +import { join, dirname, basename } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +// Get the directory of the current test file +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const swapTestDataPath = join( + __dirname, + TEST_CONSTANTS.SWAP_TEST_DATA_FILENAME, +); +const jobId = + basename(__filename) + .split('') + .reduce((sum, char) => sum + char.charCodeAt(0), 0) % 10000; + +// Load existing test data (if file exists) +const savedSwapTestData = loadSwapTestData(swapTestDataPath); + +// Data collection for swap test call data (nested structure) +const swapTestData: Record = {}; + +for (const test of tests) { + describe.sequential(test.name, () => { + let snapshotPreApprove: Hex | undefined; + let fork: { rpcUrl: string } | undefined; + let client: (PublicWalletClient & TestActions) | undefined; + const testAddress = TEST_CONSTANTS.ANVIL_TEST_ADDRESS; + const contractToCall = + test.path.pools.length > 1 + ? AddressProvider.BatchRouter(test.chainId) + : AddressProvider.Router(test.chainId); + + beforeAll(async () => { + // Only run fork/client setup if at least one test doesn't have saved data + if (!allTestsHaveSavedData(test, savedSwapTestData)) { + const setup = await setupForkAndClientV3( + test, + jobId, + testAddress, + ); + fork = setup.fork; + client = setup.client; + snapshotPreApprove = setup.snapshotPreApprove; + } + }); + if (test.isNative === 'input') { + describe.sequential('native input', () => { + it('should handle GivenIn swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenIn, + wethIsEth: true, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS.slippage, + deadline: TEST_CONSTANTS.deadline, + testName: test.name, + context: 'native input', + subContext: undefined, + outputTest: + test.outputTest || + TEST_CONSTANTS.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + it('should handle GivenOut swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenOut, + wethIsEth: true, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS.slippage, + deadline: TEST_CONSTANTS.deadline, + testName: test.name, + context: 'native input', + subContext: undefined, + outputTest: + test.outputTest || + TEST_CONSTANTS.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + }); + } + + describe.sequential('permit2 signature approval', () => { + let permit2: Permit2; + let snapShotPermit2: Hex; + beforeAll(async () => { + // Only run if fork/client were initialized + if (client && fork) { + const { permit2: permit2Sig, snapshot } = + await setupPermit2Signature( + client, + testAddress, + test.path, + contractToCall, + TEST_CONSTANTS.BALANCE_MULTIPLIER, + ); + permit2 = permit2Sig; + snapShotPermit2 = snapshot; + } + }); + beforeEach(async () => { + // Only run if fork/client were initialized + if (client && fork) { + // signatures consume the nonce so we need to reset snapshot after each sig test + await client.revert({ + id: snapShotPermit2, + }); + snapShotPermit2 = await client.snapshot(); + } + }); + + if (test.isNative === 'output') { + describe.sequential('native output', () => { + it('should handle GivenIn swap', async () => { + await runSwapTestWithSignature( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenIn, + wethIsEth: true, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS.slippage, + deadline: TEST_CONSTANTS.deadline, + testName: test.name, + context: 'permit2 signature approval', + subContext: 'native output', + outputTest: + test.outputTest || + TEST_CONSTANTS.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + permit2, + ); + }); + it('should handle GivenOut swap', async () => { + await runSwapTestWithSignature( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenOut, + wethIsEth: true, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS.slippage, + deadline: TEST_CONSTANTS.deadline, + testName: test.name, + context: 'permit2 signature approval', + subContext: 'native output', + outputTest: + test.outputTest || + TEST_CONSTANTS.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + permit2, + ); + }); + }); + } + + describe.sequential('token output', () => { + it('should handle GivenIn swap', async () => { + await runSwapTestWithSignature( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenIn, + wethIsEth: false, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS.slippage, + deadline: TEST_CONSTANTS.deadline, + testName: test.name, + context: 'permit2 signature approval', + subContext: 'token output', + outputTest: + test.outputTest || + TEST_CONSTANTS.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + permit2, + ); + }); + + it('should handle GivenOut swap', async () => { + await runSwapTestWithSignature( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenOut, + wethIsEth: false, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS.slippage, + deadline: TEST_CONSTANTS.deadline, + testName: test.name, + context: 'permit2 signature approval', + subContext: 'token output', + outputTest: + test.outputTest || + TEST_CONSTANTS.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + permit2, + ); + }); + }); + }); + describe.sequential('permit2 direct approval', () => { + beforeAll(async () => { + // Only run if fork/client were initialized + if (client && fork && snapshotPreApprove) { + snapshotPreApprove = await setupPermit2Approval( + client, + testAddress, + test.path, + contractToCall, + snapshotPreApprove, + TEST_CONSTANTS.BALANCE_MULTIPLIER, + ); + } + }); + + if (test.isNative === 'output') { + describe.sequential('native output', () => { + it('should handle GivenIn swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenIn, + wethIsEth: true, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS.slippage, + deadline: TEST_CONSTANTS.deadline, + testName: test.name, + context: 'permit2 direct approval', + subContext: 'native output', + outputTest: + test.outputTest || + TEST_CONSTANTS.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + it('should handle GivenOut swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenOut, + wethIsEth: true, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS.slippage, + deadline: TEST_CONSTANTS.deadline, + testName: test.name, + context: 'permit2 direct approval', + subContext: 'native output', + outputTest: + test.outputTest || + TEST_CONSTANTS.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + }); + } + + describe.sequential('token output', () => { + it('should handle GivenIn swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenIn, + wethIsEth: false, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS.slippage, + deadline: TEST_CONSTANTS.deadline, + testName: test.name, + context: 'permit2 direct approval', + subContext: 'token output', + outputTest: + test.outputTest || + TEST_CONSTANTS.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + + it('should handle GivenOut swap', async () => { + await runSwapTest( + { + chainId: test.chainId, + path: test.path, + swapKind: SwapKind.GivenOut, + wethIsEth: false, + fork, + contractToCall, + client, + testAddress, + slippage: TEST_CONSTANTS.slippage, + deadline: TEST_CONSTANTS.deadline, + testName: test.name, + context: 'permit2 direct approval', + subContext: 'token output', + outputTest: + test.outputTest || + TEST_CONSTANTS.defaultOutputTest, + }, + savedSwapTestData, + swapTestData, + ); + }); + }); + }); + afterAll(async () => { + // Only stop fork if it was started + if (fork) { + console.log('stopFork', test.name); + await stopAnvilFork(test.anvilNetwork, jobId); + } + }); + }); +} + +// Write swap test data to JSON file after all tests complete +afterAll(async () => { + await saveSwapTestData(swapTestDataPath, savedSwapTestData, swapTestData); +}); diff --git a/test/entities/swaps/v3/swapTestConfig.ts b/test/entities/swaps/v3/swapTestConfig.ts new file mode 100644 index 00000000..88dcc8ae --- /dev/null +++ b/test/entities/swaps/v3/swapTestConfig.ts @@ -0,0 +1,236 @@ +import { ChainId, Path, Slippage } from '@/index'; +import { ANVIL_NETWORKS, NetworkSetup } from 'test/anvil/anvil-global-setup'; +import { POOLS, TOKENS } from 'test/lib/utils/addresses'; + +// Test configuration constants +export const TEST_CONSTANTS = { + ANVIL_TEST_ADDRESS: '0x831eFb058FEdCd16Cd6b9174206DFe452dDCe8C3', // address from mnemonic "you twelve word test phrase boat cat like this example dog car" + BALANCE_MULTIPLIER: 10n, // For setting token balances + slippage: Slippage.fromPercentage('0.1'), + deadline: 999999999999999999n, + SWAP_TEST_DATA_FILENAME: 'swapTestData.json', + defaultOutputTest: { + testExactOutAmount: true, + percentage: 0, + }, +} as const; + +export type NativePosition = 'input' | 'output' | 'none'; + +export type Test = { + name: string; + chainId: ChainId; + anvilNetwork: NetworkSetup; + path: Path; + isNative: NativePosition; + blockNumber?: bigint; + outputTest?: { + testExactOutAmount: boolean; + percentage: number; + }; +}; + +export const tests: Test[] = [ + { + name: 'Single Swap: WETH[swap]USDC', + chainId: ChainId.BASE, + anvilNetwork: ANVIL_NETWORKS.BASE, + path: { + protocolVersion: 3, + tokens: [ + { + address: TOKENS[ChainId.BASE].WETH.address, + decimals: TOKENS[ChainId.BASE].WETH.decimals, + }, + { + address: TOKENS[ChainId.BASE].USDC.address, + decimals: TOKENS[ChainId.BASE].USDC.decimals, + }, + ], + pools: ['0x7b4c560f33a71a9f7a500af3c4c65b46fbbafdb7'], // https://balancer.fi/pools/base/v3/0x7b4c560f33a71a9f7a500af3c4c65b46fbbafdb7 + inputAmountRaw: 10000000000000000n, + outputAmountRaw: 100000000n, + }, + isNative: 'input', + }, + { + name: 'Single Swap: USDC[swap]WETH', + chainId: ChainId.BASE, + anvilNetwork: ANVIL_NETWORKS.BASE, + path: { + protocolVersion: 3, + tokens: [ + { + address: TOKENS[ChainId.BASE].USDC.address, + decimals: TOKENS[ChainId.BASE].USDC.decimals, + }, + { + address: TOKENS[ChainId.BASE].WETH.address, + decimals: TOKENS[ChainId.BASE].WETH.decimals, + }, + ], + pools: ['0x7b4c560f33a71a9f7a500af3c4c65b46fbbafdb7'], + inputAmountRaw: 1000000000n, + outputAmountRaw: 100000000000000000n, + }, + isNative: 'output', + }, + { + name: 'Multihop Swap: WETH[swap]USDC[swap]EURC', + chainId: ChainId.BASE, + anvilNetwork: ANVIL_NETWORKS.BASE, + path: { + protocolVersion: 3, + tokens: [ + { + address: TOKENS[ChainId.BASE].WETH.address, + decimals: TOKENS[ChainId.BASE].WETH.decimals, + }, + { + address: TOKENS[ChainId.BASE].USDC.address, + decimals: TOKENS[ChainId.BASE].USDC.decimals, + }, + { + address: TOKENS[ChainId.BASE].EURC.address, + decimals: TOKENS[ChainId.BASE].EURC.decimals, + }, + ], + pools: [ + '0x7b4c560f33a71a9f7a500af3c4c65b46fbbafdb7', + '0x608382d1627c1f2f939c87d14fdb62d5bcbf561f', + ], + inputAmountRaw: 10000000000000000n, + outputAmountRaw: 100000000n, + }, + isNative: 'input', + }, + { + name: 'Multihop Swap: EURC[swap]USDC[swap]WETH', + chainId: ChainId.BASE, + anvilNetwork: ANVIL_NETWORKS.BASE, + path: { + protocolVersion: 3, + tokens: [ + { + address: TOKENS[ChainId.BASE].EURC.address, + decimals: TOKENS[ChainId.BASE].EURC.decimals, + }, + { + address: TOKENS[ChainId.BASE].USDC.address, + decimals: TOKENS[ChainId.BASE].USDC.decimals, + }, + { + address: TOKENS[ChainId.BASE].WETH.address, + decimals: TOKENS[ChainId.BASE].WETH.decimals, + }, + ], + pools: [ + '0x608382d1627c1f2f939c87d14fdb62d5bcbf561f', + '0x7b4c560f33a71a9f7a500af3c4c65b46fbbafdb7', + ], + inputAmountRaw: 100000000n, + outputAmountRaw: 10000000000000000n, + }, + isNative: 'output', + }, + { + name: 'Multihop Swap With Exit: WETH[swap]BPT[Exit]USDC', + chainId: ChainId.SEPOLIA, + anvilNetwork: ANVIL_NETWORKS.SEPOLIA, + path: { + protocolVersion: 3, + tokens: [ + { + address: TOKENS[ChainId.SEPOLIA].WETH.address, + decimals: TOKENS[ChainId.SEPOLIA].WETH.decimals, + }, + { + address: POOLS[ChainId.SEPOLIA].MOCK_USDC_DAI_POOL.address, + decimals: + POOLS[ChainId.SEPOLIA].MOCK_USDC_DAI_POOL.decimals, + }, + { + address: TOKENS[ChainId.SEPOLIA].USDC_AAVE.address, + decimals: TOKENS[ChainId.SEPOLIA].USDC_AAVE.decimals, + }, + ], + pools: [ + POOLS[ChainId.SEPOLIA].MOCK_NESTED_POOL.id, + POOLS[ChainId.SEPOLIA].MOCK_USDC_DAI_POOL.id, + ], + inputAmountRaw: 100000000000000n, + outputAmountRaw: 600000n, + }, + isNative: 'input', + }, + { + name: 'Multihop Swap With Join: USDC[join]BPT[swap]WETH', + chainId: ChainId.SEPOLIA, + anvilNetwork: ANVIL_NETWORKS.SEPOLIA, + path: { + protocolVersion: 3, + tokens: [ + { + address: TOKENS[ChainId.SEPOLIA].USDC_AAVE.address, + decimals: TOKENS[ChainId.SEPOLIA].USDC_AAVE.decimals, + }, + { + address: POOLS[ChainId.SEPOLIA].MOCK_USDC_DAI_POOL.address, + decimals: + POOLS[ChainId.SEPOLIA].MOCK_USDC_DAI_POOL.decimals, + }, + { + address: TOKENS[ChainId.SEPOLIA].WETH.address, + decimals: TOKENS[ChainId.SEPOLIA].WETH.decimals, + }, + ], + pools: [ + POOLS[ChainId.SEPOLIA].MOCK_USDC_DAI_POOL.id, + POOLS[ChainId.SEPOLIA].MOCK_NESTED_POOL.id, + ], + inputAmountRaw: 600000n, + outputAmountRaw: 100000000000000n, + }, + isNative: 'output', + }, + { + name: 'Swap With Buffers: USDC[wrap]waEthUSDC[swap]waEthLidoGHO[unwrap]GHO', + chainId: ChainId.MAINNET, + anvilNetwork: ANVIL_NETWORKS.MAINNET, + path: { + protocolVersion: 3, + tokens: [ + { + address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC + decimals: 6, + }, + { + address: '0xd4fa2d31b7968e448877f69a96de69f5de8cd23e', // waEthUSDC + decimals: 6, + }, + { + address: '0xc71ea051a5f82c67adcf634c36ffe6334793d24c', // waEthLidoGHO + decimals: 18, + }, + { + address: '0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f', // GHO + decimals: 18, + }, + ], + pools: [ + '0xd4fa2d31b7968e448877f69a96de69f5de8cd23e', // waEthUSDC (ERC4626) + '0x85b2b559bc2d21104c4defdd6efca8a20343361d', // Pool + '0xc71ea051a5f82c67adcf634c36ffe6334793d24c', // waEthLidoGHO (ERC4626), + ], + isBuffer: [true, false, true], + inputAmountRaw: 10000000000n, + outputAmountRaw: 100000000000000000000n, + }, + isNative: 'none', + blockNumber: 24017736n, + outputTest: { + testExactOutAmount: false, + percentage: 0.001, + }, + }, +]; diff --git a/test/entities/swaps/v3/swapTestData.json b/test/entities/swaps/v3/swapTestData.json new file mode 100644 index 00000000..33ce4878 --- /dev/null +++ b/test/entities/swaps/v3/swapTestData.json @@ -0,0 +1,2446 @@ +{ + "Single Swap: WETH[swap]USDC": { + "native input": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "10000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "27910757", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "27910757000000000000" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x750283bc0000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb70000000000000000000000004200000000000000000000000000000000000006000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000001a9755e0000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000", + "value": "10000000000000000", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "27882846", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "27882846000000000000" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "100000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100000000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "36196306603632216", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "36196306603632216" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x94e86ef80000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb70000000000000000000000004200000000000000000000000000000000000006000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000080b944f949b4c80000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000", + "value": "36232502910235848", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "36232502910235848", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "36232502910235848" + } + } + } + }, + "permit2 signature approval": { + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "10000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "27346989", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "27346989000000000000" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000003f170631ed9821ca51a59d996ab095162438dc10ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000004200000000000000000000000000000000000006000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041414a1447b1d4e66a9eddd883415657072bf51acf2639f75104484a2afcc0753355545dc6223c3d8464ed037b79962560303869f91baa5b768ac540036df17f7a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000124750283bc0000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb70000000000000000000000004200000000000000000000000000000000000006000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000001a0dd5a0000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "27319642", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "27319642000000000000" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x4200000000000000000000000000000000000006", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x414a1447b1d4e66a9eddd883415657072bf51acf2639f75104484a2afcc0753355545dc6223c3d8464ed037b79962560303869f91baa5b768ac540036df17f7a1b" + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "100000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100000000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "36782051712834578", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "36782051712834578" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000003f170631ed9821ca51a59d996ab095162438dc10ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000004200000000000000000000000000000000000006000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041414a1447b1d4e66a9eddd883415657072bf51acf2639f75104484a2afcc0753355545dc6223c3d8464ed037b79962560303869f91baa5b768ac540036df17f7a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000012494e86ef80000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb70000000000000000000000004200000000000000000000000000000000000006000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000082ce88c3947b540000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "36818833764547412", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "36818833764547412" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x4200000000000000000000000000000000000006", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x414a1447b1d4e66a9eddd883415657072bf51acf2639f75104484a2afcc0753355545dc6223c3d8464ed037b79962560303869f91baa5b768ac540036df17f7a1b" + } + } + } + }, + "permit2 direct approval": { + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "10000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "27910757", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "27910757000000000000" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x750283bc0000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb70000000000000000000000004200000000000000000000000000000000000006000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000001a9755e0000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "27882846", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "27882846000000000000" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "100000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100000000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "36196306603632216", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "36196306603632216" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x94e86ef80000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb70000000000000000000000004200000000000000000000000000000000000006000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000080b944f949b4c80000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "36232502910235848", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "36232502910235848" + } + } + } + } + } + }, + "Single Swap: USDC[swap]WETH": { + "permit2 signature approval": { + "native output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "1000000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "1000000000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "331115889255098973", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "331115889255098973" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000003f170631ed9821ca51a59d996ab095162438dc10ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176500c2eb58c5129827e8304dbfb6eb4c3164031744b8e51faf197e4db5d653c0ca140b5faa6031f0d4e2887613fa21e04290682e2e21cb6a16eee635604f23a1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000124750283bc0000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000004200000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000004972effb19447a20000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "330784773365843874", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "330784773365843874" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x76500c2eb58c5129827e8304dbfb6eb4c3164031744b8e51faf197e4db5d653c0ca140b5faa6031f0d4e2887613fa21e04290682e2e21cb6a16eee635604f23a1c" + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "100000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "286143408", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "286143408000000000000" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000003f170631ed9821ca51a59d996ab095162438dc10ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176500c2eb58c5129827e8304dbfb6eb4c3164031744b8e51faf197e4db5d653c0ca140b5faa6031f0d4e2887613fa21e04290682e2e21cb6a16eee635604f23a1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000012494e86ef80000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000004200000000000000000000000000000000000006000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000000000001112916f0000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "286429551", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "286429551000000000000" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x76500c2eb58c5129827e8304dbfb6eb4c3164031744b8e51faf197e4db5d653c0ca140b5faa6031f0d4e2887613fa21e04290682e2e21cb6a16eee635604f23a1c" + } + } + }, + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "1000000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "1000000000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "331115889255098973", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "331115889255098973" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000003f170631ed9821ca51a59d996ab095162438dc10ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176500c2eb58c5129827e8304dbfb6eb4c3164031744b8e51faf197e4db5d653c0ca140b5faa6031f0d4e2887613fa21e04290682e2e21cb6a16eee635604f23a1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000124750283bc0000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000004200000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000004972effb19447a20000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "330784773365843874", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "330784773365843874" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x76500c2eb58c5129827e8304dbfb6eb4c3164031744b8e51faf197e4db5d653c0ca140b5faa6031f0d4e2887613fa21e04290682e2e21cb6a16eee635604f23a1c" + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "100000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "286143408", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "286143408000000000000" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000003f170631ed9821ca51a59d996ab095162438dc10ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004176500c2eb58c5129827e8304dbfb6eb4c3164031744b8e51faf197e4db5d653c0ca140b5faa6031f0d4e2887613fa21e04290682e2e21cb6a16eee635604f23a1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000012494e86ef80000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000004200000000000000000000000000000000000006000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000000000001112916f0000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "286429551", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "286429551000000000000" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x76500c2eb58c5129827e8304dbfb6eb4c3164031744b8e51faf197e4db5d653c0ca140b5faa6031f0d4e2887613fa21e04290682e2e21cb6a16eee635604f23a1c" + } + } + } + }, + "permit2 direct approval": { + "native output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "1000000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "1000000000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "331115889255098973", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "331115889255098973" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x750283bc0000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000004200000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000004972effb19447a20000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "330784773365843874", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "330784773365843874" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "100000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "334014320", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "334014320000000000000" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x94e86ef80000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000004200000000000000000000000000000000000006000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000000000000013edc02e0000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "334348334", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "334348334000000000000" + } + } + } + }, + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "1000000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "1000000000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "272624076217920941", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "272624076217920941" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x750283bc0000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000004200000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000003c79633e6f7cf6c0000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "272351452141703020", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "272351452141703020" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "100000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "403791060", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "403791060000000000000" + } + }, + "call": { + "to": "0x3f170631ed9821Ca51A59D996aB095162438DC10", + "callData": "0x94e86ef80000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000004200000000000000000000000000000000000006000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000181786230000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "decimals": 6 + }, + "amount": "404194851", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "404194851000000000000" + } + } + } + } + } + }, + "Multihop Swap: WETH[swap]USDC[swap]EURC": { + "native input": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["24016376"], + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "10000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "24016376", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "24016376000000000000" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000042000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000016e182700000000000000000000000000000000000000000000000000000000000000020000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f00000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb4200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "10000000000000000", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "23992359", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "23992359000000000000" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["42120778391056420"], + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "100000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100000000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "42120778391056420", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "42120778391056420" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x8eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000420000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000095caeef3b20e340000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000000000020000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f00000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb4200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "42162899169447476", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "42162899169447476", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "42162899169447476" + } + } + } + }, + "permit2 signature approval": { + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["23469866"], + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "10000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "23469866", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "23469866000000000000" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000085a80afee867adf27b50bdb7b76da70f1e853062ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000004200000000000000000000000000000000000006000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041ee548e8e79765064a5c037f5e169d7f07ae3705e04d17a96d8aee80dd7b92c123b89944caaa35919f38aa89f3d82a6256c50dfbb8b046220becba4fba3c95c521b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000244286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000042000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000165c37c00000000000000000000000000000000000000000000000000000000000000020000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f00000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "23446396", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "23446396000000000000" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x4200000000000000000000000000000000000006", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0xee548e8e79765064a5c037f5e169d7f07ae3705e04d17a96d8aee80dd7b92c123b89944caaa35919f38aa89f3d82a6256c50dfbb8b046220becba4fba3c95c521b" + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["42915394418564706"], + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "100000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100000000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "42915394418564706", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "42915394418564706" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000085a80afee867adf27b50bdb7b76da70f1e853062ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000004200000000000000000000000000000000000006000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041ee548e8e79765064a5c037f5e169d7f07ae3705e04d17a96d8aee80dd7b92c123b89944caaa35919f38aa89f3d82a6256c50dfbb8b046220becba4fba3c95c521b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002448eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000004200000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000989e5aec8dd5e60000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000000000020000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f00000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "42958309812983270", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "42958309812983270" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x4200000000000000000000000000000000000006", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0xee548e8e79765064a5c037f5e169d7f07ae3705e04d17a96d8aee80dd7b92c123b89944caaa35919f38aa89f3d82a6256c50dfbb8b046220becba4fba3c95c521b" + } + } + } + }, + "permit2 direct approval": { + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["24016376"], + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "10000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "24016376", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "24016376000000000000" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000042000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000016e182700000000000000000000000000000000000000000000000000000000000000020000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f00000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb4200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "23992359", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "23992359000000000000" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["42120778391056420"], + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "100000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100000000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "42120778391056420", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "42120778391056420" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x8eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000420000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000095caeef3b20e340000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000000000020000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f00000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb4200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "42162899169447476", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "42162899169447476" + } + } + } + } + } + }, + "Multihop Swap: EURC[swap]USDC[swap]WETH": { + "permit2 signature approval": { + "native output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["41102074809553470"], + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "100000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100000000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "41102074809553470", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "41102074809553470" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000085a80afee867adf27b50bdb7b76da70f1e853062ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb42000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412b6b97ddd1b692dc5f87ddd84ddb9dbb95b7f229a59b1fd8d5a8d5e9ae714f1101aa58823f521be098b554885bcf0a96e4faec6426454e5f87a967cb5e8283ef1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000244286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb4200000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000091e0bcb5fc856c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb700000000000000000000000042000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "41060972734743916", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "41060972734743916" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x2b6b97ddd1b692dc5f87ddd84ddb9dbb95b7f229a59b1fd8d5a8d5e9ae714f1101aa58823f521be098b554885bcf0a96e4faec6426454e5f87a967cb5e8283ef1b" + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["24160779"], + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "10000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "24160779", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "24160779000000000000" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000085a80afee867adf27b50bdb7b76da70f1e853062ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb42000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412b6b97ddd1b692dc5f87ddd84ddb9dbb95b7f229a59b1fd8d5a8d5e9ae714f1101aa58823f521be098b554885bcf0a96e4faec6426454e5f87a967cb5e8283ef1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002448eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb420000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000171086b000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb700000000000000000000000042000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "24184939", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "24184939000000000000" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x2b6b97ddd1b692dc5f87ddd84ddb9dbb95b7f229a59b1fd8d5a8d5e9ae714f1101aa58823f521be098b554885bcf0a96e4faec6426454e5f87a967cb5e8283ef1b" + } + } + }, + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["41102074809553470"], + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "100000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100000000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "41102074809553470", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "41102074809553470" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000085a80afee867adf27b50bdb7b76da70f1e853062ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb42000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412b6b97ddd1b692dc5f87ddd84ddb9dbb95b7f229a59b1fd8d5a8d5e9ae714f1101aa58823f521be098b554885bcf0a96e4faec6426454e5f87a967cb5e8283ef1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000244286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb4200000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000091e0bcb5fc856c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb700000000000000000000000042000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "41060972734743916", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "41060972734743916" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x2b6b97ddd1b692dc5f87ddd84ddb9dbb95b7f229a59b1fd8d5a8d5e9ae714f1101aa58823f521be098b554885bcf0a96e4faec6426454e5f87a967cb5e8283ef1b" + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["24160779"], + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "10000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "24160779", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "24160779000000000000" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000085a80afee867adf27b50bdb7b76da70f1e853062ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb42000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412b6b97ddd1b692dc5f87ddd84ddb9dbb95b7f229a59b1fd8d5a8d5e9ae714f1101aa58823f521be098b554885bcf0a96e4faec6426454e5f87a967cb5e8283ef1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002448eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb420000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000171086b000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb700000000000000000000000042000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "24184939", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "24184939000000000000" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x2b6b97ddd1b692dc5f87ddd84ddb9dbb95b7f229a59b1fd8d5a8d5e9ae714f1101aa58823f521be098b554885bcf0a96e4faec6426454e5f87a967cb5e8283ef1b" + } + } + } + }, + "permit2 direct approval": { + "native output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["41102074809553470"], + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "100000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100000000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "41102074809553470", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "41102074809553470" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb4200000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000000091e0bcb5fc856c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000420000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "41060972734743916", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "41060972734743916" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["24609406"], + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "10000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "24609406", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "24609406000000000000" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x8eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb420000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000177e29f000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000420000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "24634015", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "24634015000000000000" + } + } + } + }, + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["40176740744878721"], + "amountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "100000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100000000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "40176740744878721", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "40176740744878721" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb4200000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000008e97fe07f89bd20000000000000000000000000000000000000000000000000000000000000002000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000420000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "40136564004133842", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "40136564004133842" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "pathAmounts": ["25174229"], + "amountOut": { + "token": { + "chainId": 8453, + "address": "0x4200000000000000000000000000000000000006", + "decimals": 18 + }, + "amount": "10000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "10000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "25174229", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "25174229000000000000" + } + }, + "call": { + "to": "0x85a80afee867aDf27B50BdB7b76DA70f1E853062", + "callData": "0x8eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000060a3e35cc302bfa44cb288bc5a4f316fdb1adb420000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000180832b000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000608382d1627c1f2f939c87d14fdb62d5bcbf561f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b4c560f33a71a9f7a500af3c4c65b46fbbafdb7000000000000000000000000420000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 8453, + "address": "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", + "decimals": 6 + }, + "amount": "25199403", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "25199403000000000000" + } + } + } + } + } + }, + "Multihop Swap With Exit: WETH[swap]BPT[Exit]USDC": { + "native input": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["576500"], + "amountIn": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "576500", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "576500000000000000" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f9000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000000000000000000000000000000000000008c9b30000000000000000000000000000000000000000000000000000000000000002000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e00000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "100000000000000", + "minAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "575923", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "575923000000000000" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["104118574098812"], + "amountOut": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "600000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "600000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "104118574098812", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "104118574098812" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x8eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f9000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000005eca3c93058e00000000000000000000000000000000000000000000000000000000000927c00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e00000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "104222692672910", + "maxAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "104222692672910", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "104222692672910" + } + } + } + }, + "permit2 signature approval": { + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["576061"], + "amountIn": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "576061", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "576061000000000000" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c85b652685567c1b074e8c0d4389f83a2e458b1cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f9000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004107e43d48e64b987e9f0af38aec2912e155c0db6b7169320e34d73c18f9b8356b19d93f529a455b576d4f07f6ed9081a668ada1e2d9b28d89bfcc6455b7dca6d91b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000244286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f9000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000000000000000000000000000000000000008c7fc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e00000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "575484", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "575484000000000000" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x07e43d48e64b987e9f0af38aec2912e155c0db6b7169320e34d73c18f9b8356b19d93f529a455b576d4f07f6ed9081a668ada1e2d9b28d89bfcc6455b7dca6d91b" + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["104159047509227"], + "amountOut": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "600000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "600000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "104159047509227", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "104159047509227" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c85b652685567c1b074e8c0d4389f83a2e458b1cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f9000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004107e43d48e64b987e9f0af38aec2912e155c0db6b7169320e34d73c18f9b8356b19d93f529a455b576d4f07f6ed9081a668ada1e2d9b28d89bfcc6455b7dca6d91b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002448eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f9000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000005ed3ab63d44000000000000000000000000000000000000000000000000000000000000927c00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e00000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "104263206556736", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "104263206556736" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x07e43d48e64b987e9f0af38aec2912e155c0db6b7169320e34d73c18f9b8356b19d93f529a455b576d4f07f6ed9081a668ada1e2d9b28d89bfcc6455b7dca6d91b" + } + } + } + }, + "permit2 direct approval": { + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["576500"], + "amountIn": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "576500", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "576500000000000000" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f9000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000000000000000000000000000000000000008c9b30000000000000000000000000000000000000000000000000000000000000002000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e00000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "575923", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "575923000000000000" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["104118574098812"], + "amountOut": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "600000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "600000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "104118574098812", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "104118574098812" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x8eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f9000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000005eca3c93058e00000000000000000000000000000000000000000000000000000000000927c00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e00000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "104222692672910", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "104222692672910" + } + } + } + } + } + }, + "Multihop Swap With Join: USDC[join]BPT[swap]WETH": { + "permit2 signature approval": { + "native output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["100949709114218"], + "amountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "600000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "600000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100949709114218", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100949709114218" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c85b652685567c1b074e8c0d4389f83a2e458b1cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004114a2208ce79dbcf0f73cb4224d2fb27b4ff9479e2856fe44bfcad019b90a803721f09cbe2bcda4f59f79ff8f7c34cbf1a7f9486fbb7d4457e19e85cb57a0f3f71c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000244286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000927c000000000000000000000000000000000000000000000000000005bb8ae7afa2f000000000000000000000000000000000000000000000000000000000000000200000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100848759405103", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100848759405103" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x14a2208ce79dbcf0f73cb4224d2fb27b4ff9479e2856fe44bfcad019b90a803721f09cbe2bcda4f59f79ff8f7c34cbf1a7f9486fbb7d4457e19e85cb57a0f3f71c" + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["594370"], + "amountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "594370", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "594370000000000000" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c85b652685567c1b074e8c0d4389f83a2e458b1cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004114a2208ce79dbcf0f73cb4224d2fb27b4ff9479e2856fe44bfcad019b90a803721f09cbe2bcda4f59f79ff8f7c34cbf1a7f9486fbb7d4457e19e85cb57a0f3f71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002448eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c80000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000009141400000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "594964", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "594964000000000000" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x14a2208ce79dbcf0f73cb4224d2fb27b4ff9479e2856fe44bfcad019b90a803721f09cbe2bcda4f59f79ff8f7c34cbf1a7f9486fbb7d4457e19e85cb57a0f3f71c" + } + } + }, + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["100949709114218"], + "amountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "600000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "600000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100949709114218", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100949709114218" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c85b652685567c1b074e8c0d4389f83a2e458b1cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004114a2208ce79dbcf0f73cb4224d2fb27b4ff9479e2856fe44bfcad019b90a803721f09cbe2bcda4f59f79ff8f7c34cbf1a7f9486fbb7d4457e19e85cb57a0f3f71c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000244286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000927c000000000000000000000000000000000000000000000000000005bb8ae7afa2f000000000000000000000000000000000000000000000000000000000000000200000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100848759405103", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100848759405103" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x14a2208ce79dbcf0f73cb4224d2fb27b4ff9479e2856fe44bfcad019b90a803721f09cbe2bcda4f59f79ff8f7c34cbf1a7f9486fbb7d4457e19e85cb57a0f3f71c" + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["594370"], + "amountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "594370", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "594370000000000000" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c85b652685567c1b074e8c0d4389f83a2e458b1cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004114a2208ce79dbcf0f73cb4224d2fb27b4ff9479e2856fe44bfcad019b90a803721f09cbe2bcda4f59f79ff8f7c34cbf1a7f9486fbb7d4457e19e85cb57a0f3f71c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002448eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c80000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000009141400000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "594964", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "594964000000000000" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0x94a9D9AC8a22534E3FaCa9F4e7F2E2cf85d5E4C8", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x14a2208ce79dbcf0f73cb4224d2fb27b4ff9479e2856fe44bfcad019b90a803721f09cbe2bcda4f59f79ff8f7c34cbf1a7f9486fbb7d4457e19e85cb57a0f3f71c" + } + } + } + }, + "permit2 direct approval": { + "native output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["100949709114218"], + "amountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "600000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "600000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100949709114218", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100949709114218" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000927c000000000000000000000000000000000000000000000000000005bb8ae7afa2f000000000000000000000000000000000000000000000000000000000000000200000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100848759405103", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100848759405103" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["594597"], + "amountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "594597", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "594597000000000000" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x8eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000914f700000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "595191", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "595191000000000000" + } + } + } + }, + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["100872970306657"], + "amountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "600000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "600000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100872970306657", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100872970306657" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000927c000000000000000000000000000000000000000000000000000005ba6d510a41e000000000000000000000000000000000000000000000000000000000000000200000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100772097336350", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100772097336350" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "pathAmounts": ["595049"], + "amountOut": { + "token": { + "chainId": 11155111, + "address": "0x7b79995e5f793a07bc00c21412e50ecae098e7f9", + "decimals": 18 + }, + "amount": "100000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "595049", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "595049000000000000" + } + }, + "call": { + "to": "0xC85b652685567C1B074e8c0D4389f83a2E458b1C", + "callData": "0x8eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000094a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000916bc00000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c400000000000000000000000086fde41ff01b35846eb2f27868fb2938addd44c40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bfdbdb4d5b8e00bade87cf12ed58e6152f25ac3e0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 11155111, + "address": "0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8", + "decimals": 6 + }, + "amount": "595644", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "595644000000000000" + } + } + } + } + } + }, + "Swap With Buffers: USDC[wrap]waEthUSDC[swap]waEthLidoGHO[unwrap]GHO": { + "permit2 signature approval": { + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", + "pathAmounts": ["9999530198927941607705"], + "amountIn": { + "token": { + "chainId": 1, + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "decimals": 6 + }, + "amount": "10000000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "10000000000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 1, + "address": "0x40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f", + "decimals": 18 + }, + "amount": "9999530198927941607705", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "9999530198927941607705" + } + }, + "call": { + "to": "0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000136f1efcc3f8f88516b9e94110d56fdbfb1778d1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412916dafc5c43306388c6fcb45dd7f4f22951698b24a9f52e4e6766ee5b2e5e4e5a7097aa3667fcf04802180ae8f037fc8a93afa5c99eac41c38b4032f83e71cf1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002a4286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000021d889640683f3881310000000000000000000000000000000000000000000000000000000000000003000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e000000000000000000000000000000000000000000000000000000000000000100000000000000000000000085b2b559bc2d21104c4defdd6efca8a20343361d000000000000000000000000c71ea051a5f82c67adcf634c36ffe6334793d24c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c71ea051a5f82c67adcf634c36ffe6334793d24c00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 1, + "address": "0x40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f", + "decimals": 18 + }, + "amount": "9989530668729013666097", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "9989530668729013666097" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x2916dafc5c43306388c6fcb45dd7f4f22951698b24a9f52e4e6766ee5b2e5e4e5a7097aa3667fcf04802180ae8f037fc8a93afa5c99eac41c38b4032f83e71cf1b" + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", + "pathAmounts": ["100004670"], + "amountOut": { + "token": { + "chainId": 1, + "address": "0x40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f", + "decimals": 18 + }, + "amount": "100000000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 1, + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "decimals": 6 + }, + "amount": "100004670", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100004670000000000000" + } + }, + "call": { + "to": "0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", + "callData": "0x19c6989f00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000136f1efcc3f8f88516b9e94110d56fdbfb1778d1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000ffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412916dafc5c43306388c6fcb45dd7f4f22951698b24a9f52e4e6766ee5b2e5e4e5a7097aa3667fcf04802180ae8f037fc8a93afa5c99eac41c38b4032f83e71cf1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002a48eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000005f779e20000000000000000000000000000000000000000000000056bc75e2d631000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e000000000000000000000000000000000000000000000000000000000000000100000000000000000000000085b2b559bc2d21104c4defdd6efca8a20343361d000000000000000000000000c71ea051a5f82c67adcf634c36ffe6334793d24c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c71ea051a5f82c67adcf634c36ffe6334793d24c00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 1, + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "decimals": 6 + }, + "amount": "100104674", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100104674000000000000" + } + }, + "permit2": { + "batch": { + "details": [ + { + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": 281474976710655, + "nonce": 0 + } + ], + "spender": "0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", + "sigDeadline": "115792089237316195423570985008687907853269984665640564039457584007913129639935" + }, + "signature": "0x2916dafc5c43306388c6fcb45dd7f4f22951698b24a9f52e4e6766ee5b2e5e4e5a7097aa3667fcf04802180ae8f037fc8a93afa5c99eac41c38b4032f83e71cf1b" + } + } + } + }, + "permit2 direct approval": { + "token output": { + "GivenIn": { + "queryOutput": { + "swapKind": 0, + "to": "0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", + "pathAmounts": ["9999530198927941607705"], + "amountIn": { + "token": { + "chainId": 1, + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "decimals": 6 + }, + "amount": "10000000000", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "10000000000000000000000" + }, + "expectedAmountOut": { + "token": { + "chainId": 1, + "address": "0x40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f", + "decimals": 18 + }, + "amount": "9999530198927941607705", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "9999530198927941607705" + } + }, + "call": { + "to": "0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", + "callData": "0x286f580d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000021d889640683f3881310000000000000000000000000000000000000000000000000000000000000003000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e000000000000000000000000000000000000000000000000000000000000000100000000000000000000000085b2b559bc2d21104c4defdd6efca8a20343361d000000000000000000000000c71ea051a5f82c67adcf634c36ffe6334793d24c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c71ea051a5f82c67adcf634c36ffe6334793d24c00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "minAmountOut": { + "token": { + "chainId": 1, + "address": "0x40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f", + "decimals": 18 + }, + "amount": "9989530668729013666097", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "9989530668729013666097" + } + } + }, + "GivenOut": { + "queryOutput": { + "swapKind": 1, + "to": "0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", + "pathAmounts": ["100004734"], + "amountOut": { + "token": { + "chainId": 1, + "address": "0x40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f", + "decimals": 18 + }, + "amount": "100000000000000000000", + "scalar": "1", + "decimalScale": "1000000000000000000", + "scale18": "100000000000000000000" + }, + "expectedAmountIn": { + "token": { + "chainId": 1, + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "decimals": 6 + }, + "amount": "100004734", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100004734000000000000" + } + }, + "call": { + "to": "0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1", + "callData": "0x8eb1b65e00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000de0b6b3a763ffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000005f77a220000000000000000000000000000000000000000000000056bc75e2d631000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e000000000000000000000000000000000000000000000000000000000000000100000000000000000000000085b2b559bc2d21104c4defdd6efca8a20343361d000000000000000000000000c71ea051a5f82c67adcf634c36ffe6334793d24c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c71ea051a5f82c67adcf634c36ffe6334793d24c00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", + "value": "0", + "maxAmountIn": { + "token": { + "chainId": 1, + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "decimals": 6 + }, + "amount": "100104738", + "scalar": "1000000000000", + "decimalScale": "1000000", + "scale18": "100104738000000000000" + } + } + } + } + } + } +} diff --git a/test/entities/swaps/v3/swapV3.integration.test.ts b/test/entities/swaps/v3/swapV3.integration.test.ts deleted file mode 100644 index 7a5eaad7..00000000 --- a/test/entities/swaps/v3/swapV3.integration.test.ts +++ /dev/null @@ -1,851 +0,0 @@ -// pnpm test -- swapV3.integration.test.ts -import { config } from 'dotenv'; -config(); -import { - Address, - createTestClient, - http, - parseEther, - publicActions, - walletActions, - TestActions, - Hex, -} from 'viem'; -import { - CHAINS, - ChainId, - SwapKind, - Swap, - PERMIT2, - PublicWalletClient, -} from '@/index'; -import { Path } from '@/entities/swap/paths/types'; -import { AddressProvider } from '@/entities/inputValidator/utils/addressProvider'; - -import { - approveSpenderOnTokens, - approveTokens, - setTokenBalances, -} from 'test/lib/utils/helper'; -import { ANVIL_NETWORKS, startFork } from 'test/anvil/anvil-global-setup'; -import { POOLS, TOKENS } from 'test/lib/utils/addresses'; -import { - assertSwapExactIn, - assertSwapExactOut, -} from 'test/lib/utils/swapHelpers'; - -const protocolVersion = 3; -const chainId = ChainId.SEPOLIA; - -const BAL = TOKENS[chainId].BAL; -const WETH = TOKENS[chainId].WETH; -const USDC = TOKENS[chainId].USDC_AAVE; -const DAI = TOKENS[chainId].DAI_AAVE; -const USDT = TOKENS[chainId].USDT_AAVE; -const USDC_DAI_BPT = POOLS[chainId].MOCK_USDC_DAI_POOL; -const boosted_pool = POOLS[chainId].MOCK_BOOSTED_POOL; -const stataUSDC = TOKENS[chainId].stataUSDC; -const stataUSDT = TOKENS[chainId].stataUSDT; - -describe('SwapV3', () => { - let client: PublicWalletClient & TestActions; - let testAddress: Address; - let rpcUrl: string; - let snapshot: Hex; - let pathBalWeth: Path; - let pathMultiSwap: Path; - let pathUsdcWethMulti: Path; - let pathWithExit: Path; - let pathUsdcWethJoin: Path; - let tokens: Address[]; - - beforeAll(async () => { - // weth [swap] bal - pathBalWeth = { - protocolVersion, - tokens: [ - { - address: BAL.address, - decimals: BAL.decimals, - }, - { - address: WETH.address, - decimals: WETH.decimals, - }, - ], - pools: [POOLS[chainId].MOCK_WETH_BAL_POOL.id], - inputAmountRaw: 100000000000n, - outputAmountRaw: 100000000000n, - }; - - // weth [swap] bal [swap] dai [swap] usdc - pathMultiSwap = { - protocolVersion, - tokens: [ - { - address: WETH.address, - decimals: WETH.decimals, - }, - { - address: BAL.address, - decimals: BAL.decimals, - }, - { - address: DAI.address, - decimals: DAI.decimals, - }, - { - address: USDC.address, - decimals: USDC.decimals, - }, - ], - pools: [ - POOLS[chainId].MOCK_WETH_BAL_POOL.id, - POOLS[chainId].MOCK_BAL_DAI_POOL.id, - POOLS[chainId].MOCK_USDC_DAI_POOL.id, - ], - inputAmountRaw: 100000000000000n, - outputAmountRaw: 2000000n, - }; - - // usdc [swap] dai [swap] bal [swap] weth - pathUsdcWethMulti = { - ...pathMultiSwap, - tokens: [...pathMultiSwap.tokens].reverse(), - pools: [...pathMultiSwap.pools].reverse(), - inputAmountRaw: 100000n, - outputAmountRaw: 40000000000000n, - }; - - // weth [swap] bpt [exit] usdc - pathWithExit = { - protocolVersion, - tokens: [ - { - address: WETH.address, - decimals: WETH.decimals, - }, - { - address: USDC_DAI_BPT.address, - decimals: USDC_DAI_BPT.decimals, - }, - { - address: USDC.address, - decimals: USDC.decimals, - }, - ], - pools: [ - POOLS[chainId].MOCK_NESTED_POOL.id, - POOLS[chainId].MOCK_USDC_DAI_POOL.id, - ], - inputAmountRaw: 100000000000000n, - outputAmountRaw: 6000000n, - }; - - // usdc [join] bpt [swap] weth - pathUsdcWethJoin = { - ...pathWithExit, - tokens: [...pathWithExit.tokens].reverse(), - pools: [...pathWithExit.pools].reverse(), - inputAmountRaw: 6000000n, - outputAmountRaw: 600000000000000n, - }; - - const fork = await startFork(ANVIL_NETWORKS.SEPOLIA); - rpcUrl = fork.rpcUrl; - client = createTestClient({ - mode: 'anvil', - chain: CHAINS[chainId], - transport: http(rpcUrl), - }) - .extend(publicActions) - .extend(walletActions); - - testAddress = (await client.getAddresses())[0]; - - tokens = [WETH.address, BAL.address, USDC.address]; - - await setTokenBalances( - client, - testAddress, - tokens, - [WETH.slot, BAL.slot, USDC.slot] as number[], - [parseEther('100'), parseEther('100'), 100000000000n], - ); - - await approveSpenderOnTokens( - client, - testAddress, - tokens, - PERMIT2[chainId], - ); - - // Uses Special RPC methods to revert state back to same snapshot for each test - // https://github.com/trufflesuite/ganache-cli-archive/blob/master/README.md - snapshot = await client.snapshot(); - }); - - beforeEach(async () => { - await client.revert({ - id: snapshot, - }); - snapshot = await client.snapshot(); - }); - - describe('permit2 direct approval', () => { - beforeEach(async () => { - await approveTokens(client, testAddress, tokens, protocolVersion); - }); - describe('single swap', () => { - describe('swap should be executed correctly', () => { - describe('wethIsEth: false', () => { - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [pathBalWeth], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: AddressProvider.Router(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: false, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [pathBalWeth], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: AddressProvider.Router(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: false, - }); - }); - }); - describe('wethIsEth: true', () => { - describe('eth out', async () => { - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [pathBalWeth], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: AddressProvider.Router(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [pathBalWeth], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: AddressProvider.Router(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - }); - }); - }); - describe('eth in', () => { - test('GivenIn', async () => { - const pathWethBal = { - ...pathBalWeth, - tokens: [...pathBalWeth.tokens].reverse(), - }; - const swap = new Swap({ - chainId, - paths: [pathWethBal], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: AddressProvider.Router(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - }); - }); - test('GivenOut', async () => { - const pathWethBal = { - ...pathBalWeth, - tokens: [...pathBalWeth.tokens].reverse(), - }; - const swap = new Swap({ - chainId, - paths: [pathWethBal], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: AddressProvider.Router(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - }); - }); - }); - }); - }); - }); - - describe('multi-hop swap', () => { - describe('swap should be executed correctly', () => { - describe('path with swaps only', () => { - describe('wethIsEth: false', () => { - const wethIsEth = false; - test('GivenIn', async () => { - await assertSwapExactIn({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap: new Swap({ - chainId, - paths: [pathMultiSwap], - swapKind: SwapKind.GivenIn, - }), - wethIsEth, - }); - }); - test('GivenOut', async () => { - await assertSwapExactOut({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap: new Swap({ - chainId, - paths: [pathMultiSwap], - swapKind: SwapKind.GivenOut, - }), - wethIsEth, - }); - }); - }); - describe('wethIsEth: true', () => { - const wethIsEth = true; - describe('eth in', async () => { - test('GivenIn', async () => { - await assertSwapExactIn({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap: new Swap({ - chainId, - paths: [pathMultiSwap], - swapKind: SwapKind.GivenIn, - }), - wethIsEth, - }); - }); - test('GivenOut', async () => { - await assertSwapExactOut({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap: new Swap({ - chainId, - paths: [pathMultiSwap], - swapKind: SwapKind.GivenOut, - }), - wethIsEth, - }); - }); - }); - describe('eth out', () => { - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [pathUsdcWethMulti], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [pathUsdcWethMulti], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth, - }); - }); - }); - }); - }); - describe('paths with exit/join', () => { - describe('wethIsEth: false', () => { - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [pathMultiSwap, pathWithExit], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: false, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [pathMultiSwap, pathWithExit], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: false, - }); - }); - }); - describe('wethIsEth: true', () => { - describe('eth in', async () => { - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [pathMultiSwap, pathWithExit], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [pathMultiSwap, pathWithExit], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - }); - }); - }); - describe('eth out', () => { - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [ - pathUsdcWethMulti, - pathUsdcWethJoin, - ], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [ - pathUsdcWethMulti, - pathUsdcWethJoin, - ], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - }); - }); - }); - }); - }); - }); - }); - }); - - describe('permit2 signatures', () => { - const usePermit2Signatures = true; - describe('single swap', () => { - describe('swap should be executed correctly', () => { - describe('wethIsEth: false', () => { - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [pathBalWeth], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: AddressProvider.Router(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: false, - usePermit2Signatures, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [pathBalWeth], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: AddressProvider.Router(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: false, - usePermit2Signatures, - }); - }); - }); - describe('wethIsEth: true', () => { - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [pathBalWeth], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: AddressProvider.Router(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - usePermit2Signatures, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [pathBalWeth], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: AddressProvider.Router(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - usePermit2Signatures, - }); - }); - }); - }); - }); - - describe('multi-hop swap', () => { - describe('swap should be executed correctly', () => { - describe('path with swaps only', () => { - describe('wethIsEth: false', () => { - test('GivenIn', async () => { - await assertSwapExactIn({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap: new Swap({ - chainId, - paths: [pathMultiSwap], - swapKind: SwapKind.GivenIn, - }), - wethIsEth: false, - usePermit2Signatures, - }); - }); - test('GivenOut', async () => { - await assertSwapExactOut({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap: new Swap({ - chainId, - paths: [pathMultiSwap], - swapKind: SwapKind.GivenOut, - }), - wethIsEth: false, - usePermit2Signatures, - }); - }); - }); - describe('wethIsEth: true', () => { - test('GivenIn', async () => { - await assertSwapExactIn({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap: new Swap({ - chainId, - paths: [pathMultiSwap], - swapKind: SwapKind.GivenIn, - }), - wethIsEth: true, - usePermit2Signatures, - }); - }); - test('GivenOut', async () => { - await assertSwapExactOut({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap: new Swap({ - chainId, - paths: [pathMultiSwap], - swapKind: SwapKind.GivenOut, - }), - wethIsEth: true, - usePermit2Signatures, - }); - }); - }); - }); - describe('paths with exit/join', () => { - describe('wethIsEth: false', () => { - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [pathMultiSwap, pathWithExit], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: false, - usePermit2Signatures, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [pathMultiSwap, pathWithExit], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: false, - usePermit2Signatures, - }); - }); - }); - describe('wethIsEth: true', () => { - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [pathMultiSwap, pathWithExit], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - usePermit2Signatures, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [pathMultiSwap, pathWithExit], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: - AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: true, - usePermit2Signatures, - }); - }); - }); - }); - }); - }); - }); - - describe('boosted', () => { - describe('multi-hop swap', () => { - // USDC[wrap]aUSDC[swap]aUSDT[unwrap]USDT - const pathWithBuffers = { - protocolVersion: 3, - tokens: [ - { - address: USDC.address, - decimals: USDC.decimals, - }, - { - address: stataUSDC.address, - decimals: stataUSDC.decimals, - }, - { - address: stataUSDT.address, - decimals: stataUSDT.decimals, - }, - { - address: USDT.address, - decimals: USDT.decimals, - }, - ], - pools: [ - stataUSDC.address, - boosted_pool.address, - stataUSDT.address, - ], - isBuffer: [true, false, true], - }; - - describe('swap should be executed correctly', () => { - beforeEach(async () => { - await approveTokens( - client, - testAddress, - tokens, - protocolVersion, - ); - }); - test('GivenIn', async () => { - const swap = new Swap({ - chainId, - paths: [ - { - ...pathWithBuffers, - inputAmountRaw: 100000000n, - outputAmountRaw: 0n, - } as Path, - ], - swapKind: SwapKind.GivenIn, - }); - // Buffers can have a small difference due to rates so we don't check for 100% match between result and query - await assertSwapExactIn({ - contractToCall: AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: false, - outputTest: { - testExactOutAmount: false, - percentage: 0.001, - }, - }); - }); - test('GivenOut', async () => { - const swap = new Swap({ - chainId, - paths: [ - { - ...pathWithBuffers, - inputAmountRaw: 0n, - outputAmountRaw: 10000000n, - } as Path, - ], - swapKind: SwapKind.GivenOut, - }); - await assertSwapExactOut({ - contractToCall: AddressProvider.BatchRouter(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: false, - inputTest: { - testExactInAmount: false, - percentage: 0.001, - }, - }); - }); - }); - }); - }); -}); diff --git a/test/lib/utils/addresses.ts b/test/lib/utils/addresses.ts index 579b6d22..b77e234f 100644 --- a/test/lib/utils/addresses.ts +++ b/test/lib/utils/addresses.ts @@ -242,6 +242,21 @@ export const TOKENS: Record> = { decimals: 18, }, }, + [ChainId.BASE]: { + WETH: { + address: '0x4200000000000000000000000000000000000006', + decimals: 18, + }, + USDC: { + address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', + decimals: 6, + slot: 9, + }, + EURC: { + address: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42', + decimals: 6, + }, + }, }; export type TestPool = TestToken & { id: Hex; type: PoolType }; diff --git a/test/lib/utils/index.ts b/test/lib/utils/index.ts index 5820b2b0..372f4ac9 100644 --- a/test/lib/utils/index.ts +++ b/test/lib/utils/index.ts @@ -11,5 +11,9 @@ export * from './relayerHelper'; export * from './removeLiquidityHelper'; export * from './removeLiquidityRecoveryHelper'; export * from './swapHelpers'; +export * from './swapTestDataHelpers'; +export * from './swapTestRunner'; +export * from './swapAssertHelpers'; +export * from './swapTestFixture'; export * from './types'; export * from './addLiquidityBoostedHelper'; diff --git a/test/lib/utils/swapAssertHelpers.ts b/test/lib/utils/swapAssertHelpers.ts new file mode 100644 index 00000000..990ddfcc --- /dev/null +++ b/test/lib/utils/swapAssertHelpers.ts @@ -0,0 +1,80 @@ +import { Address, TestActions } from 'viem'; +import { + Swap, + ChainId, + SwapKind, + SwapBuildOutputExactIn, + SwapBuildOutputExactOut, + ExactInQueryOutput, + ExactOutQueryOutput, + PublicWalletClient, +} from '@/index'; +import { expect } from 'vitest'; +import { assertResultExactIn, assertResultExactOut } from './swapHelpers'; + +export async function assertSwapResultWithForkTest({ + swap, + chainId, + contractToCall, + client, + testAddress, + call, + queryOutput, + swapKind, + wethIsEth, + outputTest, +}: { + swap: Swap; + chainId: ChainId; + contractToCall: Address; + client?: PublicWalletClient & TestActions; + testAddress: Address; + call: SwapBuildOutputExactIn | SwapBuildOutputExactOut; + queryOutput: ExactInQueryOutput | ExactOutQueryOutput; + swapKind: SwapKind; + wethIsEth: boolean; + outputTest: { + testExactOutAmount: boolean; + percentage: number; + }; +}): Promise { + // Run full integration assertions - client must be available + if (!client) { + throw new Error( + 'Cannot run integration assertions: client not initialized and no saved test data available', + ); + } + if (swapKind === SwapKind.GivenIn) { + await assertResultExactIn({ + wethIsEth, + swap, + chainId, + contractToCall, + client, + testAddress, + call: call as SwapBuildOutputExactIn, + outputTest, + exactInQueryOutput: queryOutput as ExactInQueryOutput, + }); + } else { + await assertResultExactOut({ + wethIsEth, + swap, + chainId, + contractToCall, + client, + testAddress, + call: call as SwapBuildOutputExactOut, + exactOutQueryOutput: queryOutput as ExactOutQueryOutput, + }); + } +} + +export function assertSwapResultWithSavedData( + builtCall: SwapBuildOutputExactIn | SwapBuildOutputExactOut, + savedData: { call: { to: Address; callData: string; value: string } }, +) { + expect(builtCall.callData).to.deep.equal(savedData.call.callData); + expect(builtCall.to).to.equal(savedData.call.to); + expect(builtCall.value).to.equal(BigInt(savedData.call.value)); +} diff --git a/test/lib/utils/swapBuildHelpers.ts b/test/lib/utils/swapBuildHelpers.ts new file mode 100644 index 00000000..3a8d9510 --- /dev/null +++ b/test/lib/utils/swapBuildHelpers.ts @@ -0,0 +1,100 @@ +import { + Swap, + Slippage, + ExactInQueryOutput, + ExactOutQueryOutput, + SwapBuildOutputExactIn, + SwapBuildOutputExactOut, + Permit2, +} from '@/index'; +import { Address } from 'viem'; +import { serializeCallData } from './swapTestDataHelpers'; + +/** + * Builds swap call data and serializes it for comparison/saving. + * @param swap - The Swap instance + * @param queryOutput - The query output to build the call from + * @param slippage - Slippage tolerance + * @param deadline - Transaction deadline + * @param wethIsEth - Whether WETH should be treated as native ETH + * @param sender - Optional sender address (required for V2 swaps) + * @param recipient - Optional recipient address (required for V2 swaps) + * @returns The built call and its serialized form + */ +export function buildAndSerializeCall( + swap: Swap, + queryOutput: ExactInQueryOutput | ExactOutQueryOutput, + slippage: Slippage, + deadline: bigint, + wethIsEth: boolean, + sender?: Address, + recipient?: Address, +): { + call: SwapBuildOutputExactIn | SwapBuildOutputExactOut; + serializedCall: unknown; +} { + const baseInput = { + slippage, + deadline, + queryOutput, + wethIsEth, + }; + + // V2 swaps require sender and recipient + if (swap.protocolVersion === 2) { + if (!sender || !recipient) { + throw new Error( + 'V2 swaps require sender and recipient addresses to be provided', + ); + } + const call = swap.buildCall({ + ...baseInput, + sender, + recipient, + }); + const serializedCall = serializeCallData(call); + return { call, serializedCall }; + } + + const call = swap.buildCall(baseInput); + + const serializedCall = serializeCallData(call); + + return { call, serializedCall }; +} + +/** + * Builds swap call data with Permit2 and serializes it for comparison/saving. + * @param swap - The Swap instance + * @param queryOutput - The query output to build the call from + * @param slippage - Slippage tolerance + * @param deadline - Transaction deadline + * @param wethIsEth - Whether WETH should be treated as native ETH + * @param permit2 - The Permit2 signature + * @returns The built call and its serialized form + */ +export function buildAndSerializeCallWithPermit2( + swap: Swap, + queryOutput: ExactInQueryOutput | ExactOutQueryOutput, + slippage: Slippage, + deadline: bigint, + wethIsEth: boolean, + permit2: Permit2, +): { + call: SwapBuildOutputExactIn | SwapBuildOutputExactOut; + serializedCall: unknown; +} { + const call = swap.buildCallWithPermit2( + { + slippage, + deadline, + queryOutput, + wethIsEth, + }, + permit2, + ); + + const serializedCall = serializeCallData(call); + + return { call, serializedCall }; +} diff --git a/test/lib/utils/swapHelpers.ts b/test/lib/utils/swapHelpers.ts index 2c08c853..4c4e28f1 100644 --- a/test/lib/utils/swapHelpers.ts +++ b/test/lib/utils/swapHelpers.ts @@ -1,16 +1,15 @@ import { Address, TestActions } from 'viem'; import { ChainId, - Slippage, Swap, ZERO_ADDRESS, SwapBuildOutputExactOut, NATIVE_ASSETS, SwapBuildOutputExactIn, - SwapBuildCallInput, SwapKind, - Permit2Helper, PublicWalletClient, + ExactOutQueryOutput, + ExactInQueryOutput, } from '../../../src'; import { sendTransactionGetBalances } from '../../lib/utils/helper'; @@ -29,69 +28,33 @@ export function areBigIntsWithinPercent( return difference <= tolerance; } -export async function assertSwapExactIn({ +export async function assertResultExactIn({ + wethIsEth, + swap, + chainId, contractToCall, client, - rpcUrl, - chainId, - swap, - wethIsEth, - usePermit2Signatures = false, - outputTest = { - testExactOutAmount: true, - percentage: 0, - }, + testAddress, + call, + outputTest, + exactInQueryOutput, }: { + wethIsEth: boolean; + swap: Swap; + chainId: ChainId; contractToCall: Address; client: PublicWalletClient & TestActions; - rpcUrl: string; - chainId: ChainId; - swap: Swap; - wethIsEth: boolean; - usePermit2Signatures?: boolean; - outputTest?: { + testAddress: Address; + call: SwapBuildOutputExactIn; + outputTest: { testExactOutAmount: boolean; percentage: number; }; + exactInQueryOutput: ExactInQueryOutput; }) { - const testAddress = (await client.getAddresses())[0]; - const slippage = Slippage.fromPercentage('0.1'); - const deadline = 999999999999999999n; - - const expected = await swap.query(rpcUrl); - if (expected.swapKind !== SwapKind.GivenIn) throw Error('Expected GivenIn'); - expect(expected.expectedAmountOut.amount > 0n).to.be.true; - - let buildCallInput: SwapBuildCallInput = { - slippage, - deadline, - queryOutput: expected, - wethIsEth, - }; - - if (swap.protocolVersion === 2) { - buildCallInput = { - ...buildCallInput, - sender: testAddress, - recipient: testAddress, - }; - } - - let call: SwapBuildOutputExactIn; - if (usePermit2Signatures) { - const permit2 = await Permit2Helper.signSwapApproval({ - ...buildCallInput, - client, - owner: testAddress, - }); - - call = swap.buildCallWithPermit2( - buildCallInput, - permit2, - ) as SwapBuildOutputExactIn; - } else { - call = swap.buildCall(buildCallInput) as SwapBuildOutputExactIn; - } + if (exactInQueryOutput.swapKind !== SwapKind.GivenIn) + throw Error('Expected GivenIn'); + expect(exactInQueryOutput.expectedAmountOut.amount > 0n).to.be.true; const isEthInput = wethIsEth && @@ -122,7 +85,7 @@ export async function assertSwapExactIn({ swap.outputAmount.token.isSameAddress(NATIVE_ASSETS[chainId].wrapped); let expectedEthDelta = 0n; let expectedTokenInDelta = swap.inputAmount.amount; - let expectedTokenOutDelta = expected.expectedAmountOut.amount; + let expectedTokenOutDelta = exactInQueryOutput.expectedAmountOut.amount; if (isEthInput) { // Should send eth instead of tokenIn (weth) expectedEthDelta = swap.inputAmount.amount; @@ -130,7 +93,7 @@ export async function assertSwapExactIn({ } if (isEthOutput) { // should receive eth instead of tokenOut (weth) - expectedEthDelta = expected.expectedAmountOut.amount; + expectedEthDelta = exactInQueryOutput.expectedAmountOut.amount; expectedTokenOutDelta = 0n; } @@ -155,70 +118,28 @@ export async function assertSwapExactIn({ } } -export async function assertSwapExactOut({ +export async function assertResultExactOut({ + wethIsEth, + swap, + chainId, contractToCall, client, - rpcUrl, - chainId, - swap, - wethIsEth, - usePermit2Signatures = false, - inputTest = { - testExactInAmount: true, - percentage: 0, - }, + testAddress, + call, + exactOutQueryOutput, }: { + wethIsEth: boolean; + swap: Swap; + chainId: ChainId; contractToCall: Address; client: PublicWalletClient & TestActions; - rpcUrl: string; - chainId: ChainId; - swap: Swap; - wethIsEth: boolean; - usePermit2Signatures?: boolean; - inputTest?: { - testExactInAmount: boolean; - percentage: number; - }; + testAddress: Address; + call: SwapBuildOutputExactOut; + exactOutQueryOutput: ExactOutQueryOutput; }) { - const testAddress = (await client.getAddresses())[0]; - const slippage = Slippage.fromPercentage('0.1'); - const deadline = 999999999999999999n; - - const expected = await swap.query(rpcUrl); - if (expected.swapKind !== SwapKind.GivenOut) + if (exactOutQueryOutput.swapKind !== SwapKind.GivenOut) throw Error('Expected GivenOut'); - - let buildCallInput: SwapBuildCallInput = { - slippage, - deadline, - queryOutput: expected, - wethIsEth, - }; - - if (swap.protocolVersion === 2) { - buildCallInput = { - ...buildCallInput, - sender: testAddress, - recipient: testAddress, - }; - } - expect(expected.expectedAmountIn.amount > 0n).to.be.true; - - let call: SwapBuildOutputExactOut; - if (usePermit2Signatures) { - const permit2 = await Permit2Helper.signSwapApproval({ - ...buildCallInput, - client, - owner: testAddress, - }); - - call = swap.buildCallWithPermit2( - buildCallInput, - permit2, - ) as SwapBuildOutputExactOut; - } else { - call = swap.buildCall(buildCallInput) as SwapBuildOutputExactOut; - } + expect(exactOutQueryOutput.expectedAmountIn.amount > 0n).to.be.true; const isEthInput = wethIsEth && @@ -250,11 +171,11 @@ export async function assertSwapExactOut({ wethIsEth && swap.outputAmount.token.isSameAddress(NATIVE_ASSETS[chainId].wrapped); let expectedEthDelta = 0n; - let expectedTokenInDelta = expected.expectedAmountIn.amount; + let expectedTokenInDelta = exactOutQueryOutput.expectedAmountIn.amount; let expectedTokenOutDelta = swap.outputAmount.amount; if (isEthInput) { // Should send eth instead of tokenIn (weth) - expectedEthDelta = expected.expectedAmountIn.amount; + expectedEthDelta = exactOutQueryOutput.expectedAmountIn.amount; expectedTokenInDelta = 0n; } if (isEthOutput) { @@ -263,23 +184,9 @@ export async function assertSwapExactOut({ expectedTokenOutDelta = 0n; } - if (inputTest.testExactInAmount) - expect(balanceDeltas).to.deep.eq([ - expectedEthDelta, - expectedTokenInDelta, - expectedTokenOutDelta, - ]); - else { - // Here we check that output diff is within an acceptable tolerance. - // !!! This should only be used in the case of buffers as all other cases can be equal - expect(balanceDeltas[0]).to.eq(expectedEthDelta); - expect(balanceDeltas[2]).to.eq(expectedTokenOutDelta); - expect( - areBigIntsWithinPercent( - balanceDeltas[1], - expectedTokenInDelta, - inputTest.percentage, - ), - ).toBe(true); - } + expect(balanceDeltas).to.deep.eq([ + expectedEthDelta, + expectedTokenInDelta, + expectedTokenOutDelta, + ]); } diff --git a/test/lib/utils/swapQueryHelpers.ts b/test/lib/utils/swapQueryHelpers.ts new file mode 100644 index 00000000..ab5bb2ab --- /dev/null +++ b/test/lib/utils/swapQueryHelpers.ts @@ -0,0 +1,56 @@ +import { + Swap, + SwapKind, + ExactInQueryOutput, + ExactOutQueryOutput, +} from '@/index'; +import { + deserializeQueryOutput, + hasSavedTestData, +} from './swapTestDataHelpers'; + +/** + * Loads query output from saved test data or by querying the swap. + * If saved data exists, it uses that. Otherwise, it queries fresh data from the fork. + * @param savedData - Saved test data (may be undefined) + * @param swap - The Swap instance to query if no saved data exists + * @param fork - Fork RPC URL (required if no saved data) + * @param expectedSwapKind - The expected swap kind to validate against + * @returns The query output matching the expected swap kind + * @throws Error if fork is not available when needed, or if swap kind doesn't match + */ +export async function loadQueryOutput< + T extends ExactInQueryOutput | ExactOutQueryOutput, +>( + savedData: unknown, + swap: Swap, + fork: { rpcUrl: string } | undefined, + expectedSwapKind: SwapKind, +): Promise { + const hasSavedData = hasSavedTestData(savedData); + + if (hasSavedData) { + // Use saved query output (skip swap.query() call) + const savedQueryOutput = savedData.queryOutput; + const deserialized = deserializeQueryOutput(savedQueryOutput); + if (deserialized.swapKind !== expectedSwapKind) { + throw new Error( + `Saved query output swap kind mismatch: expected ${expectedSwapKind === SwapKind.GivenIn ? 'GivenIn' : 'GivenOut'}, got ${deserialized.swapKind === SwapKind.GivenIn ? 'GivenIn' : 'GivenOut'}`, + ); + } + return deserialized as T; + } + // Query fresh data - fork must be available + if (!fork) { + throw new Error( + 'Cannot query swap: fork not initialized and no saved test data available', + ); + } + const queryResult = await swap.query(fork.rpcUrl); + if (queryResult.swapKind !== expectedSwapKind) { + throw new Error( + `Query result swap kind mismatch: expected ${expectedSwapKind === SwapKind.GivenIn ? 'GivenIn' : 'GivenOut'}, got ${queryResult.swapKind === SwapKind.GivenIn ? 'GivenIn' : 'GivenOut'}`, + ); + } + return queryResult as T; +} diff --git a/test/lib/utils/swapTestDataAccess.ts b/test/lib/utils/swapTestDataAccess.ts new file mode 100644 index 00000000..73b7fa51 --- /dev/null +++ b/test/lib/utils/swapTestDataAccess.ts @@ -0,0 +1,103 @@ +import { SwapKind, Permit2 } from '@/index'; +import { serializePermit2 } from './swapTestDataHelpers'; + +/** + * Type for the setTestData function used to save test data. + */ +export type SetTestDataFunction = typeof setTestData; + +/** + * Gets test data from the nested structure. + * @param savedData - The saved test data (nested structure) + * @param testName - Name of the test case + * @param context - Test context (e.g., 'native input', 'permit2 direct approval') + * @param subContext - Optional sub-context (e.g., 'native output', 'token output') + * @param swapKind - The swap kind being tested + * @returns The test data if found, undefined otherwise + */ +export function getTestData( + savedData: Record, + testName: string, + context: string, + subContext: string | undefined, + swapKind: SwapKind, +): unknown { + const testData = savedData[testName]; + if (!testData || typeof testData !== 'object') { + return undefined; + } + + const testDataObj = testData as Record; + const contextData = testDataObj[context]; + if (!contextData || typeof contextData !== 'object') { + return undefined; + } + + const contextDataObj = contextData as Record; + + // If subContext is provided, navigate to it + if (subContext) { + const subContextData = contextDataObj[subContext]; + if (!subContextData || typeof subContextData !== 'object') { + return undefined; + } + const subContextDataObj = subContextData as Record; + const swapKindKey = + swapKind === SwapKind.GivenIn ? 'GivenIn' : 'GivenOut'; + return subContextDataObj[swapKindKey]; + } + + // No subContext, swapKind is directly under context + const swapKindKey = swapKind === SwapKind.GivenIn ? 'GivenIn' : 'GivenOut'; + return contextDataObj[swapKindKey]; +} + +/** + * Sets test data in the nested structure. + * @param testData - The test data object to update + * @param testName - Name of the test case + * @param context - Test context (e.g., 'native input', 'permit2 direct approval') + * @param subContext - Optional sub-context (e.g., 'native output', 'token output') + * @param swapKind - The swap kind being tested + * @param data - The data to save (queryOutput, call, and optional permit2) + * @param permit2 - Optional Permit2 to save (only for "permit2 signature approval" tests) + */ +export function setTestData( + testData: Record, + testName: string, + context: string, + subContext: string | undefined, + swapKind: SwapKind, + data: { queryOutput: unknown; call: unknown }, + permit2?: Permit2, +): void { + // Include permit2 in data if provided + const dataToSave = permit2 + ? { ...data, permit2: serializePermit2(permit2) } + : data; + + if (!testData[testName]) { + testData[testName] = {}; + } + const testDataObj = testData[testName] as Record; + + if (!testDataObj[context]) { + testDataObj[context] = {}; + } + const contextDataObj = testDataObj[context] as Record; + + const swapKindKey = swapKind === SwapKind.GivenIn ? 'GivenIn' : 'GivenOut'; + + if (subContext) { + if (!contextDataObj[subContext]) { + contextDataObj[subContext] = {}; + } + const subContextDataObj = contextDataObj[subContext] as Record< + string, + unknown + >; + subContextDataObj[swapKindKey] = dataToSave; + } else { + contextDataObj[swapKindKey] = dataToSave; + } +} diff --git a/test/lib/utils/swapTestDataHelpers.ts b/test/lib/utils/swapTestDataHelpers.ts new file mode 100644 index 00000000..95f4d307 --- /dev/null +++ b/test/lib/utils/swapTestDataHelpers.ts @@ -0,0 +1,752 @@ +import { Address, Hex } from 'viem'; +import { readFileSync } from 'node:fs'; +import { writeFile } from 'node:fs/promises'; +import { TokenAmount } from '@/entities/tokenAmount'; +import { Token } from '@/entities/token'; +import { + SwapKind, + ExactInQueryOutput, + ExactOutQueryOutput, + SwapBuildOutputExactIn, + SwapBuildOutputExactOut, + Permit2, +} from '@/index'; + +// JSON serialization utility +export const serializeTokenAmount = (tokenAmount: TokenAmount) => { + return { + token: { + chainId: tokenAmount.token.chainId, + address: tokenAmount.token.address, + decimals: tokenAmount.token.decimals, + ...(tokenAmount.token.symbol !== undefined && { + symbol: tokenAmount.token.symbol, + }), + ...(tokenAmount.token.name !== undefined && { + name: tokenAmount.token.name, + }), + ...('wrapped' in tokenAmount.token && + tokenAmount.token.wrapped !== undefined && { + wrapped: tokenAmount.token.wrapped, + }), + }, + amount: tokenAmount.amount.toString(), + scalar: tokenAmount.scalar.toString(), + decimalScale: tokenAmount.decimalScale.toString(), + scale18: tokenAmount.scale18.toString(), + }; +}; + +/** + * Deserializes a TokenAmount from JSON. + * Validates the structure and data before creating the TokenAmount instance. + * @param serialized - The serialized TokenAmount data + * @returns A TokenAmount instance + * @throws Error if the data structure is invalid or validation fails + */ +export const deserializeTokenAmount = (serialized: unknown): TokenAmount => { + if (typeof serialized !== 'object' || serialized === null) { + throw new Error( + `Invalid serialized TokenAmount: expected object, got ${typeof serialized}`, + ); + } + + if (!('token' in serialized)) { + throw new Error( + 'Invalid serialized TokenAmount: missing required field "token"', + ); + } + if (!('amount' in serialized)) { + throw new Error( + 'Invalid serialized TokenAmount: missing required field "amount"', + ); + } + + const data = serialized as { + token: { + chainId: number; + address: Address; + decimals: number; + symbol?: string; + name?: string; + wrapped?: Address; + }; + amount: string; + scalar?: string; + decimalScale?: string; + scale18?: string; + }; + + // Validate token structure + if ( + typeof data.token !== 'object' || + data.token === null || + typeof data.token.chainId !== 'number' || + typeof data.token.address !== 'string' || + typeof data.token.decimals !== 'number' || + (data.token.wrapped !== undefined && + typeof data.token.wrapped !== 'string') + ) { + throw new Error( + 'Invalid serialized TokenAmount: token object is malformed or missing required fields (chainId, address, decimals)', + ); + } + + // Validate amount + if (typeof data.amount !== 'string') { + throw new Error( + `Invalid serialized TokenAmount: amount must be a string, got ${typeof data.amount}`, + ); + } + + let amountBigInt: bigint; + try { + amountBigInt = BigInt(data.amount); + } catch { + throw new Error( + `Invalid serialized TokenAmount: amount "${data.amount}" cannot be converted to BigInt`, + ); + } + + // Validate amount is non-negative + if (amountBigInt < 0n) { + throw new Error( + `Invalid serialized TokenAmount: amount cannot be negative, got ${data.amount}`, + ); + } + + // Validate address format (basic check - should be hex string starting with 0x) + if (!/^0x[a-fA-F0-9]{40}$/.test(data.token.address)) { + throw new Error( + `Invalid serialized TokenAmount: token address "${data.token.address}" is not a valid Ethereum address`, + ); + } + if ( + data.token.wrapped !== undefined && + !/^0x[a-fA-F0-9]{40}$/.test(data.token.wrapped) + ) { + throw new Error( + `Invalid serialized TokenAmount: wrapped address "${data.token.wrapped}" is not a valid Ethereum address`, + ); + } + + // Validate decimals + if (data.token.decimals < 0 || data.token.decimals > 255) { + throw new Error( + `Invalid serialized TokenAmount: decimals must be between 0 and 255, got ${data.token.decimals}`, + ); + } + + const token = new Token( + data.token.chainId, + data.token.address, + data.token.decimals, + data.token.symbol, + data.token.name, + ); + return TokenAmount.fromRawAmount(token, amountBigInt); +}; + +/** + * Deserializes a QueryOutput (ExactIn or ExactOut) from JSON. + * Validates the structure and required fields based on swap kind. + * @param serialized - The serialized QueryOutput data + * @returns An ExactInQueryOutput or ExactOutQueryOutput + * @throws Error if the data structure is invalid or required fields are missing + */ +export const deserializeQueryOutput = ( + serialized: unknown, +): ExactInQueryOutput | ExactOutQueryOutput => { + if (typeof serialized !== 'object' || serialized === null) { + throw new Error( + `Invalid serialized QueryOutput: expected object, got ${typeof serialized}`, + ); + } + + if (!('swapKind' in serialized)) { + throw new Error( + 'Invalid serialized QueryOutput: missing required field "swapKind"', + ); + } + + const data = serialized as { + swapKind: number; + to?: Address; + pathAmounts?: string[]; + amountIn?: unknown; + expectedAmountOut?: unknown; + amountOut?: unknown; + expectedAmountIn?: unknown; + }; + + // Validate swapKind + if ( + data.swapKind !== SwapKind.GivenIn && + data.swapKind !== SwapKind.GivenOut + ) { + throw new Error( + `Invalid serialized QueryOutput: swapKind must be ${SwapKind.GivenIn} (GivenIn) or ${SwapKind.GivenOut} (GivenOut), got ${data.swapKind}`, + ); + } + + // Validate 'to' field + if (!('to' in data) || typeof data.to !== 'string') { + throw new Error( + 'Invalid serialized QueryOutput: missing or invalid "to" field (must be a valid address string)', + ); + } + if (!/^0x[a-fA-F0-9]{40}$/.test(data.to)) { + throw new Error( + `Invalid serialized QueryOutput: "to" address "${data.to}" is not a valid Ethereum address`, + ); + } + + // Validate pathAmounts if present + let pathAmounts: bigint[] | undefined; + if (data.pathAmounts !== undefined) { + if (!Array.isArray(data.pathAmounts)) { + throw new Error( + `Invalid serialized QueryOutput: pathAmounts must be an array, got ${typeof data.pathAmounts}`, + ); + } + try { + pathAmounts = data.pathAmounts.map((amt) => { + if (typeof amt !== 'string') { + throw new Error( + `Invalid serialized QueryOutput: pathAmounts must contain string values, got ${typeof amt}`, + ); + } + const bigIntAmt = BigInt(amt); + if (bigIntAmt < 0n) { + throw new Error( + `Invalid serialized QueryOutput: pathAmounts cannot contain negative values, got ${amt}`, + ); + } + return bigIntAmt; + }); + } catch (error) { + if (error instanceof Error) { + throw error; + } + throw new Error( + `Invalid serialized QueryOutput: pathAmounts contains invalid values: ${error}`, + ); + } + } + + const base = { + swapKind: data.swapKind as SwapKind, + to: data.to, + pathAmounts, + }; + + if (data.swapKind === SwapKind.GivenIn) { + if (!('amountIn' in data) || data.amountIn === undefined) { + throw new Error( + 'Invalid ExactInQueryOutput: missing required field "amountIn"', + ); + } + if ( + !('expectedAmountOut' in data) || + data.expectedAmountOut === undefined + ) { + throw new Error( + 'Invalid ExactInQueryOutput: missing required field "expectedAmountOut"', + ); + } + return { + ...base, + swapKind: SwapKind.GivenIn, + amountIn: deserializeTokenAmount(data.amountIn), + expectedAmountOut: deserializeTokenAmount(data.expectedAmountOut), + } as ExactInQueryOutput; + } + + // GivenOut case + if (!('amountOut' in data) || data.amountOut === undefined) { + throw new Error( + 'Invalid ExactOutQueryOutput: missing required field "amountOut"', + ); + } + if (!('expectedAmountIn' in data) || data.expectedAmountIn === undefined) { + throw new Error( + 'Invalid ExactOutQueryOutput: missing required field "expectedAmountIn"', + ); + } + return { + ...base, + swapKind: SwapKind.GivenOut, + amountOut: deserializeTokenAmount(data.amountOut), + expectedAmountIn: deserializeTokenAmount(data.expectedAmountIn), + } as ExactOutQueryOutput; +}; + +export function serializeQueryOutput( + queryOutput: ExactInQueryOutput | ExactOutQueryOutput, +): unknown { + const base = { + swapKind: queryOutput.swapKind, + to: queryOutput.to, + pathAmounts: queryOutput.pathAmounts?.map((amt) => amt.toString()), + }; + + if (queryOutput.swapKind === SwapKind.GivenIn) { + return { + ...base, + amountIn: serializeTokenAmount(queryOutput.amountIn), + expectedAmountOut: serializeTokenAmount( + queryOutput.expectedAmountOut, + ), + }; + } + return { + ...base, + amountOut: serializeTokenAmount(queryOutput.amountOut), + expectedAmountIn: serializeTokenAmount(queryOutput.expectedAmountIn), + }; +} + +export function serializeCallData( + call: SwapBuildOutputExactIn | SwapBuildOutputExactOut, +): unknown { + const base = { + to: call.to, + callData: call.callData, + value: call.value.toString(), + }; + + if ('minAmountOut' in call) { + return { + ...base, + minAmountOut: serializeTokenAmount(call.minAmountOut), + }; + } + return { + ...base, + maxAmountIn: serializeTokenAmount(call.maxAmountIn), + }; +} + +/** + * Serializes a Permit2 object to JSON-serializable format. + * @param permit2 - The Permit2 object to serialize + * @returns Serialized Permit2 data + */ +export function serializePermit2(permit2: Permit2): unknown { + return { + batch: { + details: permit2.batch.details.map((detail) => ({ + token: detail.token, + amount: detail.amount.toString(), + expiration: detail.expiration, + nonce: detail.nonce, + })), + spender: permit2.batch.spender, + sigDeadline: permit2.batch.sigDeadline.toString(), + }, + signature: permit2.signature, + }; +} + +/** + * Deserializes a Permit2 object from JSON. + * Validates the structure and data before creating the Permit2 instance. + * @param serialized - The serialized Permit2 data + * @returns A Permit2 instance + * @throws Error if the data structure is invalid or validation fails + */ +export function deserializePermit2(serialized: unknown): Permit2 { + if (typeof serialized !== 'object' || serialized === null) { + throw new Error( + `Invalid serialized Permit2: expected object, got ${typeof serialized}`, + ); + } + + const data = serialized as { + batch?: { + details?: unknown[]; + spender?: Address; + sigDeadline?: string; + }; + signature?: Hex; + }; + + if (!data.batch || typeof data.batch !== 'object') { + throw new Error( + 'Invalid serialized Permit2: missing or invalid "batch" field', + ); + } + + if (!Array.isArray(data.batch.details)) { + throw new Error( + 'Invalid serialized Permit2: batch.details must be an array', + ); + } + + if (!data.batch.spender || typeof data.batch.spender !== 'string') { + throw new Error( + 'Invalid serialized Permit2: batch.spender must be a valid address string', + ); + } + + if (!/^0x[a-fA-F0-9]{40}$/.test(data.batch.spender)) { + throw new Error( + `Invalid serialized Permit2: batch.spender "${data.batch.spender}" is not a valid Ethereum address`, + ); + } + + if (!data.batch.sigDeadline || typeof data.batch.sigDeadline !== 'string') { + throw new Error( + 'Invalid serialized Permit2: batch.sigDeadline must be a string', + ); + } + + let sigDeadlineBigInt: bigint; + try { + sigDeadlineBigInt = BigInt(data.batch.sigDeadline); + } catch { + throw new Error( + `Invalid serialized Permit2: batch.sigDeadline "${data.batch.sigDeadline}" cannot be converted to BigInt`, + ); + } + + if (sigDeadlineBigInt < 0n) { + throw new Error( + `Invalid serialized Permit2: batch.sigDeadline cannot be negative, got ${data.batch.sigDeadline}`, + ); + } + + if (!data.signature || typeof data.signature !== 'string') { + throw new Error( + 'Invalid serialized Permit2: signature must be a valid hex string', + ); + } + + // Validate signature is a hex string + if (!/^0x[a-fA-F0-9]+$/.test(data.signature)) { + throw new Error( + `Invalid serialized Permit2: signature "${data.signature}" is not a valid hex string`, + ); + } + + // Deserialize details array + const details = data.batch.details.map((detail, index) => { + if (typeof detail !== 'object' || detail === null) { + throw new Error( + `Invalid serialized Permit2: batch.details[${index}] must be an object`, + ); + } + + const detailData = detail as { + token?: Address; + amount?: string; + expiration?: number; + nonce?: number; + }; + + if (!detailData.token || typeof detailData.token !== 'string') { + throw new Error( + `Invalid serialized Permit2: batch.details[${index}].token must be a valid address string`, + ); + } + + if (!/^0x[a-fA-F0-9]{40}$/.test(detailData.token)) { + throw new Error( + `Invalid serialized Permit2: batch.details[${index}].token "${detailData.token}" is not a valid Ethereum address`, + ); + } + + if (!detailData.amount || typeof detailData.amount !== 'string') { + throw new Error( + `Invalid serialized Permit2: batch.details[${index}].amount must be a string`, + ); + } + + let amountBigInt: bigint; + try { + amountBigInt = BigInt(detailData.amount); + } catch { + throw new Error( + `Invalid serialized Permit2: batch.details[${index}].amount "${detailData.amount}" cannot be converted to BigInt`, + ); + } + + if (amountBigInt < 0n) { + throw new Error( + `Invalid serialized Permit2: batch.details[${index}].amount cannot be negative, got ${detailData.amount}`, + ); + } + + if ( + typeof detailData.expiration !== 'number' || + detailData.expiration < 0 + ) { + throw new Error( + `Invalid serialized Permit2: batch.details[${index}].expiration must be a non-negative number, got ${detailData.expiration}`, + ); + } + + if (typeof detailData.nonce !== 'number' || detailData.nonce < 0) { + throw new Error( + `Invalid serialized Permit2: batch.details[${index}].nonce must be a non-negative number, got ${detailData.nonce}`, + ); + } + + return { + token: detailData.token, + amount: amountBigInt, + expiration: detailData.expiration, + nonce: detailData.nonce, + }; + }); + + return { + batch: { + details, + spender: data.batch.spender, + sigDeadline: sigDeadlineBigInt, + }, + signature: data.signature, + }; +} + +/** + * Loads swap test data from a JSON file. + * Returns an empty object if the file doesn't exist or can't be read. + * @param filePath - Path to the JSON file + * @returns Parsed JSON data as a record, or empty object on error + */ +export function loadSwapTestData(filePath: string): Record { + try { + const fileContent = readFileSync(filePath, 'utf-8'); + return JSON.parse(fileContent); + } catch { + // File doesn't exist or can't be read - treat as empty object + return {}; + } +} + +/** + * Deep merges two objects, preserving nested structure. + * @param target - Target object to merge into + * @param source - Source object to merge from + * @returns Merged object + */ +function deepMerge( + target: Record, + source: Record, +): Record { + const result = { ...target }; + for (const key in source) { + if ( + source[key] && + typeof source[key] === 'object' && + !Array.isArray(source[key]) && + target[key] && + typeof target[key] === 'object' && + !Array.isArray(target[key]) + ) { + result[key] = deepMerge( + target[key] as Record, + source[key] as Record, + ); + } else { + result[key] = source[key]; + } + } + return result; +} + +/** + * Saves swap test data to a JSON file. + * Deep merges existingData with newData (existingData takes precedence for conflicts). + * Logs errors but doesn't throw. + * @param filePath - Path to the JSON file + * @param existingData - Existing test data to preserve + * @param newData - New test data to add (nested structure) + */ +export async function saveSwapTestData( + filePath: string, + existingData: Record, + newData: Record, +): Promise { + try { + // Deep merge saved data with new test data (preserves existing, adds new) + const mergedData = deepMerge(existingData, newData); + + // Write the merged data to file + await writeFile(filePath, JSON.stringify(mergedData, null, 2), 'utf-8'); + console.log(`Swap test data written to ${filePath}`); + } catch (error) { + console.error('Failed to write swap test data:', error); + // Don't throw - we don't want to fail tests if file write fails + } +} + +/** + * Type representing saved swap test data with serialized query output and call data. + * permit2 is optional and only present for "permit2 signature approval" tests. + */ +export type SavedSwapTestData = { + queryOutput: unknown; + call: { + to: Address; + callData: string; // Hex string in JSON + value: string; // Serialized as string in JSON + }; + permit2?: unknown; +}; + +/** + * Type guard to check if data is valid saved swap test data. + * Valid saved data must be an object with both 'queryOutput' and 'call' properties. + * The 'call' property must be an object with 'to', 'callData', and 'value' properties. + * 'permit2' is optional and only present for "permit2 signature approval" tests. + * @param data - Data to check + * @returns True if data is valid SavedSwapTestData, false otherwise + */ +export function hasSavedTestData(data: unknown): data is SavedSwapTestData { + if (data === undefined || data === null || typeof data !== 'object') { + return false; + } + + const obj = data as Record; + + // Check top-level structure + if (!('queryOutput' in obj) || !('call' in obj)) { + return false; + } + + // Check that call is an object with required properties + const call = obj.call; + if ( + typeof call !== 'object' || + call === null || + !('to' in call) || + !('callData' in call) || + !('value' in call) + ) { + return false; + } + + return true; +} + +/** + * Type for test configuration used to check saved data. + */ +type TestConfig = { + name: string; + isNative: 'input' | 'output' | 'none'; +}; + +/** + * Checks if all tests for a given test configuration have valid saved data. + * Valid saved data must be an object with both 'queryOutput' and 'call' properties. + * Checks the nested structure: testName > context > subContext > swapKind + * @param test - The test configuration + * @param savedData - Nested record of saved test data + * @returns True if all tests have valid saved data, false otherwise + */ +export function allTestsHaveSavedData( + test: TestConfig, + savedData: Record, +): boolean { + const testData = savedData[test.name]; + if (!testData || typeof testData !== 'object') { + return false; + } + + const testDataObj = testData as Record; + + // Check native input tests (if applicable) + if (test.isNative === 'input') { + const nativeInput = testDataObj['native input']; + if ( + !nativeInput || + typeof nativeInput !== 'object' || + !hasSavedTestData( + (nativeInput as Record).GivenIn, + ) || + !hasSavedTestData((nativeInput as Record).GivenOut) + ) { + return false; + } + } + + // Check permit2 direct approval tests + const permit2 = testDataObj['permit2 direct approval']; + if (!permit2 || typeof permit2 !== 'object') { + return false; + } + const permit2Obj = permit2 as Record; + + // Check native output tests (if applicable) + if (test.isNative === 'output') { + const nativeOutput = permit2Obj['native output']; + if ( + !nativeOutput || + typeof nativeOutput !== 'object' || + !hasSavedTestData( + (nativeOutput as Record).GivenIn, + ) || + !hasSavedTestData( + (nativeOutput as Record).GivenOut, + ) + ) { + return false; + } + } + + // Check token output tests (always present) + const tokenOutput = permit2Obj['token output']; + if ( + !tokenOutput || + typeof tokenOutput !== 'object' || + !hasSavedTestData((tokenOutput as Record).GivenIn) || + !hasSavedTestData((tokenOutput as Record).GivenOut) + ) { + return false; + } + + // Check permit2 signature approval tests + const permit2Signature = testDataObj['permit2 signature approval']; + if (!permit2Signature || typeof permit2Signature !== 'object') { + return false; + } + const permit2SignatureObj = permit2Signature as Record; + + // Check native output tests (if applicable) + if (test.isNative === 'output') { + const nativeOutput = permit2SignatureObj['native output']; + if ( + !nativeOutput || + typeof nativeOutput !== 'object' || + !hasSavedTestData( + (nativeOutput as Record).GivenIn, + ) || + !hasSavedTestData( + (nativeOutput as Record).GivenOut, + ) + ) { + return false; + } + } + + // Check token output tests (always present) + const tokenOutputSignature = permit2SignatureObj['token output']; + if ( + !tokenOutputSignature || + typeof tokenOutputSignature !== 'object' || + !hasSavedTestData( + (tokenOutputSignature as Record).GivenIn, + ) || + !hasSavedTestData( + (tokenOutputSignature as Record).GivenOut, + ) + ) { + return false; + } + + return true; +} diff --git a/test/lib/utils/swapTestFixture.ts b/test/lib/utils/swapTestFixture.ts new file mode 100644 index 00000000..46205d2c --- /dev/null +++ b/test/lib/utils/swapTestFixture.ts @@ -0,0 +1,301 @@ +import { Address, Hex, TestActions } from 'viem'; +import { createTestClient, http, publicActions, walletActions } from 'viem'; +import { + CHAINS, + ChainId, + Path, + PERMIT2, + MAX_UINT256, + PublicWalletClient, + PermitDetails, + getDetails, + signPermit2, + Permit2, +} from '@/index'; +import { startFork } from '../../anvil/anvil-global-setup'; +import { + approveSpenderOnTokens, + findTokenBalanceSlot, + setTokenBalances, + approveSpenderOnPermit2, +} from './helper'; +import type { Test } from '../../entities/swaps/v3/swapTestConfig'; +import type { TestV2 } from '../../entities/swaps/v2/swapTestConfig'; +import { NetworkSetup } from '../../anvil/anvil-global-setup'; + +/** + * Base type constraint for test configurations that can be used with setupForkAndClientBase. + */ +type TestConfigBase = { + chainId: ChainId; + anvilNetwork: NetworkSetup; + blockNumber?: bigint; + path: Path; +}; + +/** + * Base function for setting up fork and test client. + * Handles common setup logic shared between V2 and V3 tests. + * @param test - The test configuration (Test or TestV2) + * @param jobId - Job ID for fork management + * @param testAddress - The expected test address to validate + * @param setupApprovals - Optional function to run approval setup before snapshot + * @returns Fork RPC URL, test client, and pre-approval snapshot + */ +async function setupForkAndClientBase( + test: T, + jobId: number, + testAddress: Address, + setupApprovals?: ( + client: PublicWalletClient & TestActions, + test: T, + testAddress: Address, + ) => Promise, +): Promise<{ + fork: { rpcUrl: string }; + client: PublicWalletClient & TestActions; + snapshotPreApprove: Hex; +}> { + const fork = await startFork(test.anvilNetwork, jobId, test.blockNumber); + const client = createTestClient({ + mode: 'anvil', + chain: CHAINS[test.chainId], + transport: http(fork.rpcUrl), + }) + .extend(publicActions) + .extend(walletActions); + + const testAddressCheck = (await client.getAddresses())[0]; + if (testAddressCheck !== testAddress) { + throw Error('Test address mismatch'); + } + + // Run optional approval setup (e.g., Permit2 for V3) + if (setupApprovals) { + await setupApprovals(client, test, testAddress); + } + + // Uses Special RPC methods to revert state back to same snapshot for each test + // https://github.com/trufflesuite/ganache-cli-archive/blob/master/README.md + const snapshotPreApprove = await client.snapshot(); + + return { fork, client, snapshotPreApprove }; +} + +/** + * Sets up the fork and test client for integration tests. + * Configures token approvals for Permit2 and creates a snapshot for test isolation. + * @param test - The test configuration + * @param jobId - Job ID for fork management + * @param testAddress - The test address to use for approvals + * @returns Fork RPC URL, test client, and pre-approval snapshot + */ +export async function setupForkAndClientV3( + test: Test, + jobId: number, + testAddress: Address, +): Promise<{ + fork: { rpcUrl: string }; + client: PublicWalletClient & TestActions; + snapshotPreApprove: Hex; +}> { + return setupForkAndClientBase( + test, + jobId, + testAddress, + async (client, test, testAddress) => { + // First step of permit2 flow - user approves Permit2 contract to spend input token (this is needed for direct or signature approval) + await approveSpenderOnTokens( + client, + testAddress, + [test.path.tokens[0].address], + PERMIT2[test.chainId], + [MAX_UINT256], + ); + }, + ); +} + +/** + * Sets up Permit2 approval for the router. + * Reverts to pre-approval snapshot, sets token balances, and approves router via Permit2. + * @param client - The test client + * @param testAddress - Address of the test account + * @param path - The swap path + * @param routerAddress - Address of the router contract + * @param snapshotPreApprove - Snapshot ID before permit2 approval + * @param balanceMultiplier - Multiplier for setting token balances + * @returns New snapshot ID after permit2 approval setup + */ +export async function setupPermit2Approval( + client: PublicWalletClient & TestActions, + testAddress: Address, + path: Path, + routerAddress: Address, + snapshotPreApprove: Hex, + balanceMultiplier: bigint, +): Promise { + // Revert to pre-approval snapshot + await client.revert({ + id: snapshotPreApprove, + }); + const newSnapshot = await client.snapshot(); + + const slot = await findTokenBalanceSlot( + client, + testAddress, + path.tokens[0].address, + ); + + await setTokenBalances( + client, + testAddress, + [path.tokens[0].address], + [slot], + [path.inputAmountRaw * balanceMultiplier], + ); + + // Second step of permit2 flow - user Permit2 approves router to spend input token + await approveSpenderOnPermit2( + client, + testAddress, + path.tokens[0].address, + routerAddress, + ); + + return newSnapshot; +} + +/** + * Sets up Permit2 signature approval for the router. + * Sets token balances, approves router via Permit2, builds permit details, and signs. + * @param client - The test client + * @param testAddress - Address of the test account + * @param path - The swap path + * @param routerAddress - Address of the router contract + * @param balanceMultiplier - Multiplier for setting token balances + * @returns Permit2 signature and snapshot ID after setup + */ +export async function setupPermit2Signature( + client: PublicWalletClient & TestActions, + testAddress: Address, + path: Path, + routerAddress: Address, + balanceMultiplier: bigint, +): Promise<{ + permit2: Permit2; + snapshot: Hex; +}> { + const slot = await findTokenBalanceSlot( + client, + testAddress, + path.tokens[0].address, + ); + + await setTokenBalances( + client, + testAddress, + [path.tokens[0].address], + [slot], + [path.inputAmountRaw * balanceMultiplier], + ); + + await approveSpenderOnPermit2( + client, + testAddress, + path.tokens[0].address, + routerAddress, + ); + + // build permit details + const details: PermitDetails[] = [ + await getDetails( + client, + path.tokens[0].address, + testAddress, + routerAddress, + ), + ]; + + // sign permit2 + const permit2 = await signPermit2( + client, + testAddress, + routerAddress, + details, + ); + + const snapshot = await client.snapshot(); + + return { permit2, snapshot }; +} + +/** + * Sets up the fork and test client for V2 integration tests. + * Configures the test client and creates a snapshot for test isolation. + * @param test - The V2 test configuration + * @param jobId - Job ID for fork management + * @param testAddress - The test address to use for validation + * @returns Fork RPC URL, test client, and pre-approval snapshot + */ +export async function setupForkAndClientV2( + test: TestV2, + jobId: number, + testAddress: Address, +): Promise<{ + fork: { rpcUrl: string }; + client: PublicWalletClient & TestActions; + snapshotPreApprove: Hex; +}> { + return setupForkAndClientBase( + test, + jobId, + testAddress, + // No approval setup needed for V2 + ); +} + +/** + * Sets up V2 approval for the vault. + * Reverts to pre-approval snapshot, sets token balance for input token, and approves VAULT_V2. + * @param client - The test client + * @param testAddress - Address of the test account + * @param path - The swap path + * @param vaultAddress - Address of the VAULT_V2 contract + * @param balanceMultiplier - Multiplier for setting token balances + * @returns New snapshot ID after approval setup + */ +export async function setupV2Approval( + client: PublicWalletClient & TestActions, + testAddress: Address, + path: Path, + vaultAddress: Address, + balanceMultiplier: bigint, +): Promise { + const slot = await findTokenBalanceSlot( + client, + testAddress, + path.tokens[0].address, + ); + + await setTokenBalances( + client, + testAddress, + [path.tokens[0].address], + [slot], + [path.inputAmountRaw * balanceMultiplier], + ); + + // Approve VAULT_V2 to spend input token directly (V2 doesn't use Permit2) + await approveSpenderOnTokens( + client, + testAddress, + [path.tokens[0].address], + vaultAddress, + [MAX_UINT256], + ); + + const snapshot = await client.snapshot(); + + return snapshot; +} diff --git a/test/lib/utils/swapTestRunner.ts b/test/lib/utils/swapTestRunner.ts new file mode 100644 index 00000000..8da14792 --- /dev/null +++ b/test/lib/utils/swapTestRunner.ts @@ -0,0 +1,226 @@ +import { Address, TestActions } from 'viem'; +import { + ChainId, + Path, + SwapKind, + Swap, + Slippage, + ExactInQueryOutput, + ExactOutQueryOutput, + PublicWalletClient, + Permit2, +} from '@/index'; +import { loadQueryOutput } from './swapQueryHelpers'; +import { + buildAndSerializeCall, + buildAndSerializeCallWithPermit2, +} from './swapBuildHelpers'; +import { + assertSwapResultWithForkTest, + assertSwapResultWithSavedData, +} from './swapAssertHelpers'; +import { getTestData, setTestData } from './swapTestDataAccess'; +import { + hasSavedTestData, + deserializePermit2, + serializeQueryOutput, +} from './swapTestDataHelpers'; + +/** + * Configuration for running a swap test. + */ +export type TestSwapConfig = { + chainId: ChainId; + path: Path; + swapKind: SwapKind; + wethIsEth: boolean; + fork?: { rpcUrl: string }; + contractToCall: Address; + client?: PublicWalletClient & TestActions; + testAddress: Address; + slippage: Slippage; + deadline: bigint; + testName: string; + context: string; + subContext?: string; + outputTest: { + testExactOutAmount: boolean; + percentage: number; + }; +}; + +/** + * Core swap test execution logic shared between regular and permit2 tests. + * @param config - Test configuration + * @param savedSwapTestData - Saved test data from file + * @param swapTestData - Test data object to update with new results + * @param permit2ToUse - Optional Permit2 signature to use for building the call + */ +async function executeSwapTestCore( + config: TestSwapConfig, + savedSwapTestData: Record, + swapTestData: Record, + permit2ToUse?: Permit2, +): Promise { + const { + chainId, + path, + swapKind, + wethIsEth, + fork, + contractToCall, + client, + testAddress, + slippage, + deadline, + testName, + context, + subContext, + outputTest, + } = config; + + const swap = new Swap({ + chainId, + paths: [path], + swapKind, + }); + + const savedData = getTestData( + savedSwapTestData, + testName, + context, + subContext, + swapKind, + ); + + // Load query output (from saved data or by querying) + const queryOutput = + swapKind === SwapKind.GivenIn + ? await loadQueryOutput( + savedData, + swap, + fork, + SwapKind.GivenIn, + ) + : await loadQueryOutput( + savedData, + swap, + fork, + SwapKind.GivenOut, + ); + + // Build and serialize call (use permit2 variant if permit2 is provided) + // V2 swaps require sender and recipient, V3 swaps don't + const { call, serializedCall } = permit2ToUse + ? buildAndSerializeCallWithPermit2( + swap, + queryOutput, + slippage, + deadline, + wethIsEth, + permit2ToUse, + ) + : buildAndSerializeCall( + swap, + queryOutput, + slippage, + deadline, + wethIsEth, + swap.protocolVersion === 2 ? testAddress : undefined, + swap.protocolVersion === 2 ? testAddress : undefined, + ); + + if (hasSavedTestData(savedData)) { + assertSwapResultWithSavedData(call, savedData); + return; + } + + // Assert or compare results + await assertSwapResultWithForkTest({ + swap, + chainId, + contractToCall, + client, + testAddress, + call, + queryOutput, + swapKind, + wethIsEth, + outputTest, + }); + + // Save both query output and call data for new tests + // Include permit2 if context is "permit2 signature approval" + setTestData( + swapTestData, + testName, + context, + subContext, + swapKind, + { + queryOutput: serializeQueryOutput(queryOutput), + call: serializedCall, + }, + context === 'permit2 signature approval' ? permit2ToUse : undefined, + ); +} + +/** + * Executes a swap test by loading query output, building call data, and asserting results. + * Can use saved test data for faster execution or run full integration tests. + * @param config - Test configuration + * @param savedSwapTestData - Saved test data from file + * @param swapTestData - Test data object to update with new results + */ +export async function runSwapTest( + config: TestSwapConfig, + savedSwapTestData: Record, + swapTestData: Record, +): Promise { + return executeSwapTestCore(config, savedSwapTestData, swapTestData); +} + +/** + * Executes a swap test with Permit2 signature by loading query output, building call data, and asserting results. + * Can use saved test data for faster execution or run full integration tests. + * @param config - Test configuration + * @param savedSwapTestData - Saved test data from file + * @param swapTestData - Test data object to update with new results + * @param permit2 - Optional Permit2 signature. Required when building new calls, optional when using saved data. + */ +export async function runSwapTestWithSignature( + config: TestSwapConfig, + savedSwapTestData: Record, + swapTestData: Record, + permit2?: Permit2, +): Promise { + const { testName, context, subContext, swapKind } = config; + + const savedData = getTestData( + savedSwapTestData, + testName, + context, + subContext, + swapKind, + ); + + // Load permit2 from saved data if we have saved data but no permit2 parameter + let permit2ToUse = permit2; + if (!permit2 && hasSavedTestData(savedData) && savedData.permit2) { + permit2ToUse = deserializePermit2(savedData.permit2); + } + + // If we don't have saved data, permit2 is required + if (!permit2ToUse) { + throw new Error( + 'Cannot build call with permit2: permit2 is required when no saved test data is available', + ); + } + + return executeSwapTestCore( + config, + savedSwapTestData, + swapTestData, + permit2ToUse, + ); +} diff --git a/test/validateAllNetworks.test.ts b/test/validateAllNetworks.test.ts index d00a42e7..355f2f13 100644 --- a/test/validateAllNetworks.test.ts +++ b/test/validateAllNetworks.test.ts @@ -26,12 +26,13 @@ import { setTokenBalances, } from 'test/lib/utils/helper'; import { POOLS, TOKENS, TestToken, TestPool } from 'test/lib/utils/addresses'; -import { assertSwapExactIn } from 'test/lib/utils/swapHelpers'; import { ANVIL_NETWORKS, startFork, NetworkSetup, } from 'test/anvil/anvil-global-setup'; +import { runSwapTest } from 'test/lib/utils/swapTestRunner'; +import { TEST_CONSTANTS } from 'test/entities/swaps/v3/swapTestConfig'; const protocolVersion = 3; @@ -208,19 +209,27 @@ describe('validateAllNetworks', () => { protocolVersion, ); - const swap = new Swap({ - chainId, - paths: [swapPath], - swapKind: SwapKind.GivenIn, - }); - await assertSwapExactIn({ - contractToCall: AddressProvider.Router(chainId), - client, - rpcUrl, - chainId, - swap, - wethIsEth: false, - }); + // Use runSwapTest without saving results + // Pass empty objects so data isn't persisted + await runSwapTest( + { + chainId, + path: swapPath, + swapKind: SwapKind.GivenIn, + wethIsEth: false, + fork: { rpcUrl }, + contractToCall: AddressProvider.Router(chainId), + client, + testAddress, + slippage: TEST_CONSTANTS.slippage, + deadline: TEST_CONSTANTS.deadline, + testName: `validateAllNetworks-${chainId}`, + context: 'network validation', + outputTest: TEST_CONSTANTS.defaultOutputTest, + }, + {}, // Empty savedSwapTestData - always run fresh + {}, // Empty swapTestData - don't save results + ); }); }); });