From 744f5674e1e67d07dad0679758cc4aa13874a74f Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 4 Oct 2024 11:12:44 +0100 Subject: [PATCH 01/66] chore: Adding Sepolia to configs so we can test against deployments. --- src/config.ts | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ src/constants.ts | 1 + 2 files changed, 95 insertions(+) diff --git a/src/config.ts b/src/config.ts index f8b2a02fd..53220628b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -417,6 +417,100 @@ const baseConfigs: { [network: number]: BaseConfig } = { rpcPollingBlocksBackToTriggerUpdate: 3, forceRpcFallbackDexs: [], }, + [Network.SEPOLIA]: { + network: Network.SEPOLIA, + networkName: 'Sepolia', + isTestnet: false, + nativeTokenName: 'Ether', + nativeTokenSymbol: 'ETH', + wrappedNativeTokenAddress: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + hasEIP1559: true, + augustusAddress: '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57', + augustusRFQAddress: '0xe92b586627ccA7a83dC919cc7127196d70f55a06', + tokenTransferProxyAddress: '0x216b4b4ba9f3e719726886d34a177484278bfcae', + multicallV2Address: '0xcA11bde05977b3631167028862bE2a173976CA11', + privateHttpProvider: process.env.HTTP_PROVIDER_11155111, + augustusV6Address: '0x6a000f20005980200259b80c5102003040001068', + executorsAddresses: { + Executor01: '0xa600910B670804230E00A100000D28000AE005C0', + Executor02: '0x3800091020a00290f20606b000000000E38c33Ef', + Executor03: '0x20004f017a0bC0050bc004d9C500a7A089800000', + }, + adapterAddresses: { + Adapter01: '0x9bE264469eF954c139Da4A45Cf76CbCC5e3A6A73', + Adapter02: '0xFC2Ba6E830a04C25e207B8214b26d8C713F6881F', + Adapter03: '0xBAEeb4540f59d30E567a5B563CC0c4587eDd9366', + Adapter04: '0x369A2FDb910d432f0a07381a5E3d27572c876713', + Adapter05: '0x3329dfa55A40B450952FBE0203167Ae6908E656d', + Adapter06: '0xAeb7B3688a658C3f3B1AEd94d69b7b8045D64B57', + BuyAdapter: '0x84bEF12C9931cE12662cc9F2366b6a5029E4BD29', + BuyAdapter02: '0x2299568c3299e7420033deA9009233FF89F5C485', + }, + uniswapV2ExchangeRouterAddress: + '0xF9234CB08edb93c0d4a4d4c70cC3FfD070e78e07', + rpcPollingMaxAllowedStateDelayInBlocks: 0, + rpcPollingBlocksBackToTriggerUpdate: 0, + swaapV2AuthToken: process.env.API_KEY_SWAAP_V2_AUTH_TOKEN || '', + hashFlowAuthToken: process.env.API_KEY_HASHFLOW_AUTH_TOKEN || '', + idleDaoAuthToken: process.env.API_KEY_IDLEDAO_AUTH_TOKEN || '', + hashFlowDisabledMMs: + process.env[`HASHFLOW_DISABLED_MMS_1`]?.split(',') || [], + uniswapV3EventLoggingSampleRate: 0, + rfqConfigs: { + DummyParaSwapPool: { + maker: process.env.TEST_ADDRESS!, + tokensConfig: { + reqParams: { + url: `http://localhost:${PORT_TEST_SERVER}/tokens`, + method: 'GET', + }, + secret: { + domain: 'paraswap-test', + accessKey: 'access', + secretKey: 'secret', + }, + intervalMs: 1000 * 60 * 60 * 10, // every 10 minutes + dataTTLS: 1000 * 60 * 60 * 11, // ttl 11 minutes + }, + pairsConfig: { + reqParams: { + url: `http://localhost:${PORT_TEST_SERVER}/pairs`, + method: 'GET', + }, + secret: { + domain: 'paraswap-test', + accessKey: 'access', + secretKey: 'secret', + }, + intervalMs: 1000 * 60 * 60 * 10, // every 10 minutes + dataTTLS: 1000 * 60 * 60 * 11, // ttl 11 minutes + }, + rateConfig: { + reqParams: { + url: `http://localhost:${PORT_TEST_SERVER}/prices`, + method: 'GET', + }, + secret: { + domain: 'paraswap-test', + accessKey: 'access', + secretKey: 'secret', + }, + intervalMs: 1000 * 60 * 60 * 1, // every 1 minute + dataTTLS: 1000 * 60 * 60 * 1, // ttl 1 minute + }, + firmRateConfig: { + url: `http://localhost:${PORT_TEST_SERVER}/firm`, + method: 'POST', + secret: { + domain: 'paraswap-test', + accessKey: 'access', + secretKey: 'secret', + }, + }, + }, + }, + forceRpcFallbackDexs: [], + }, }; // Should not be used, except by internal test code diff --git a/src/constants.ts b/src/constants.ts index 68d570746..bc3ee69f1 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -41,6 +41,7 @@ export enum Network { ARBITRUM = 42161, OPTIMISM = 10, BASE = 8453, + SEPOLIA = 11155111, } export const SUBGRAPH_TIMEOUT = 20 * 1000; From 4200f9ddd75a353856adac1cdd24e64ecafa27f1 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 4 Oct 2024 11:15:22 +0100 Subject: [PATCH 02/66] chore: Initial test templates and adding V3 to dex. --- src/dex/balancer-v3/balancer-v3-e2e.test.ts | 155 +++++++++++ .../balancer-v3-integration.test.ts | 251 ++++++++++++++++++ src/dex/index.ts | 2 + 3 files changed, 408 insertions(+) create mode 100644 src/dex/balancer-v3/balancer-v3-e2e.test.ts create mode 100644 src/dex/balancer-v3/balancer-v3-integration.test.ts diff --git a/src/dex/balancer-v3/balancer-v3-e2e.test.ts b/src/dex/balancer-v3/balancer-v3-e2e.test.ts new file mode 100644 index 000000000..16156ea5a --- /dev/null +++ b/src/dex/balancer-v3/balancer-v3-e2e.test.ts @@ -0,0 +1,155 @@ +/* eslint-disable no-console */ +import dotenv from 'dotenv'; +dotenv.config(); + +import { testE2E } from '../../../tests/utils-e2e'; +import { + Tokens, + Holders, + NativeTokenSymbols, +} from '../../../tests/constants-e2e'; +import { Network, ContractMethod, SwapSide } from '../../constants'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { generateConfig } from '../../config'; + +/* + README + ====== + + This test script should add e2e tests for BalancerV3. The tests + should cover as many cases as possible. Most of the DEXes follow + the following test structure: + - DexName + - ForkName + Network + - ContractMethod + - ETH -> Token swap + - Token -> ETH swap + - Token -> Token swap + + The template already enumerates the basic structure which involves + testing simpleSwap, multiSwap, megaSwap contract methods for + ETH <> TOKEN and TOKEN <> TOKEN swaps. You should replace tokenA and + tokenB with any two highly liquid tokens on BalancerV3 for the tests + to work. If the tokens that you would like to use are not defined in + Tokens or Holders map, you can update the './tests/constants-e2e' + + Other than the standard cases that are already added by the template + it is highly recommended to add test cases which could be specific + to testing BalancerV3 (Eg. Tests based on poolType, special tokens, + etc). + + You can run this individual test script by running: + `npx jest src/dex//-e2e.test.ts` + + e2e tests use the Tenderly fork api. Please add the following to your + .env file: + TENDERLY_TOKEN=Find this under Account>Settings>Authorization. + TENDERLY_ACCOUNT_ID=Your Tenderly account name. + TENDERLY_PROJECT=Name of a Tenderly project you have created in your + dashboard. + + (This comment should be removed from the final implementation) +*/ + +function testForNetwork( + network: Network, + dexKey: string, + tokenASymbol: string, + tokenBSymbol: string, + tokenAAmount: string, + tokenBAmount: string, + nativeTokenAmount: string, +) { + const provider = new StaticJsonRpcProvider( + generateConfig(network).privateHttpProvider, + network, + ); + const tokens = Tokens[network]; + const holders = Holders[network]; + const nativeTokenSymbol = NativeTokenSymbols[network]; + + // TODO: Add any direct swap contractMethod name if it exists + const sideToContractMethods = new Map([ + [SwapSide.SELL, [ContractMethod.swapExactAmountIn]], + // TODO: If buy is not supported remove the buy contract methods + [SwapSide.BUY, [ContractMethod.swapExactAmountOut]], + ]); + + describe(`${network}`, () => { + sideToContractMethods.forEach((contractMethods, side) => + describe(`${side}`, () => { + contractMethods.forEach((contractMethod: ContractMethod) => { + describe(`${contractMethod}`, () => { + it(`${nativeTokenSymbol} -> ${tokenASymbol}`, async () => { + await testE2E( + tokens[nativeTokenSymbol], + tokens[tokenASymbol], + holders[nativeTokenSymbol], + side === SwapSide.SELL ? nativeTokenAmount : tokenAAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it(`${tokenASymbol} -> ${nativeTokenSymbol}`, async () => { + await testE2E( + tokens[tokenASymbol], + tokens[nativeTokenSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : nativeTokenAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it(`${tokenASymbol} -> ${tokenBSymbol}`, async () => { + await testE2E( + tokens[tokenASymbol], + tokens[tokenBSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : tokenBAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + }); + }); + }), + ); + }); +} + +describe('BalancerV3 E2E', () => { + const dexKey = 'BalancerV3'; + + describe('Mainnet', () => { + const network = Network.MAINNET; + + // TODO: Modify the tokenASymbol, tokenBSymbol, tokenAAmount; + const tokenASymbol: string = 'tokenASymbol'; + const tokenBSymbol: string = 'tokenBSymbol'; + + const tokenAAmount: string = 'tokenAAmount'; + const tokenBAmount: string = 'tokenBAmount'; + const nativeTokenAmount = '1000000000000000000'; + + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + nativeTokenAmount, + ); + + // TODO: Add any additional test cases required to test BalancerV3 + }); +}); diff --git a/src/dex/balancer-v3/balancer-v3-integration.test.ts b/src/dex/balancer-v3/balancer-v3-integration.test.ts new file mode 100644 index 000000000..b025b2de8 --- /dev/null +++ b/src/dex/balancer-v3/balancer-v3-integration.test.ts @@ -0,0 +1,251 @@ +/* eslint-disable no-console */ +import dotenv from 'dotenv'; +dotenv.config(); + +import { Interface, Result } from '@ethersproject/abi'; +import { DummyDexHelper } from '../../dex-helper/index'; +import { Network, SwapSide } from '../../constants'; +import { BI_POWS } from '../../bigint-constants'; +import { BalancerV3 } from './balancer-v3'; +import { + checkPoolPrices, + checkPoolsLiquidity, + checkConstantPoolPrices, +} from '../../../tests/utils'; +import { Tokens } from '../../../tests/constants-e2e'; + +/* + README + ====== + + This test script adds tests for BalancerV3 general integration + with the DEX interface. The test cases below are example tests. + It is recommended to add tests which cover BalancerV3 specific + logic. + + You can run this individual test script by running: + `npx jest src/dex//-integration.test.ts` + + (This comment should be removed from the final implementation) +*/ + +function getReaderCalldata( + exchangeAddress: string, + readerIface: Interface, + amounts: bigint[], + funcName: string, + // TODO: Put here additional arguments you need +) { + return amounts.map(amount => ({ + target: exchangeAddress, + callData: readerIface.encodeFunctionData(funcName, [ + // TODO: Put here additional arguments to encode them + amount, + ]), + })); +} + +function decodeReaderResult( + results: Result, + readerIface: Interface, + funcName: string, +) { + // TODO: Adapt this function for your needs + return results.map(result => { + const parsed = readerIface.decodeFunctionResult(funcName, result); + return BigInt(parsed[0]._hex); + }); +} + +async function checkOnChainPricing( + balancerV3: BalancerV3, + funcName: string, + blockNumber: number, + prices: bigint[], + amounts: bigint[], +) { + const exchangeAddress = ''; // TODO: Put here the real exchange address + + // TODO: Replace dummy interface with the real one + // Normally you can get it from balancerV3.Iface or from eventPool. + // It depends on your implementation + const readerIface = new Interface(''); + + const readerCallData = getReaderCalldata( + exchangeAddress, + readerIface, + amounts.slice(1), + funcName, + ); + const readerResult = ( + await balancerV3.dexHelper.multiContract.methods + .aggregate(readerCallData) + .call({}, blockNumber) + ).returnData; + + const expectedPrices = [0n].concat( + decodeReaderResult(readerResult, readerIface, funcName), + ); + + expect(prices).toEqual(expectedPrices); +} + +async function testPricingOnNetwork( + balancerV3: BalancerV3, + network: Network, + dexKey: string, + blockNumber: number, + srcTokenSymbol: string, + destTokenSymbol: string, + side: SwapSide, + amounts: bigint[], + funcNameToCheck: string, +) { + const networkTokens = Tokens[network]; + + const pools = await balancerV3.getPoolIdentifiers( + networkTokens[srcTokenSymbol], + networkTokens[destTokenSymbol], + side, + blockNumber, + ); + console.log( + `${srcTokenSymbol} <> ${destTokenSymbol} Pool Identifiers: `, + pools, + ); + + expect(pools.length).toBeGreaterThan(0); + + const poolPrices = await balancerV3.getPricesVolume( + networkTokens[srcTokenSymbol], + networkTokens[destTokenSymbol], + amounts, + side, + blockNumber, + pools, + ); + console.log( + `${srcTokenSymbol} <> ${destTokenSymbol} Pool Prices: `, + poolPrices, + ); + + expect(poolPrices).not.toBeNull(); + if (balancerV3.hasConstantPriceLargeAmounts) { + checkConstantPoolPrices(poolPrices!, amounts, dexKey); + } else { + checkPoolPrices(poolPrices!, amounts, side, dexKey); + } + + // Check if onchain pricing equals to calculated ones + await checkOnChainPricing( + balancerV3, + funcNameToCheck, + blockNumber, + poolPrices![0].prices, + amounts, + ); +} + +describe('BalancerV3', function () { + const dexKey = 'BalancerV3'; + let blockNumber: number; + let balancerV3: BalancerV3; + + describe('Mainnet', () => { + const network = Network.MAINNET; + const dexHelper = new DummyDexHelper(network); + + const tokens = Tokens[network]; + + // TODO: Put here token Symbol to check against + // Don't forget to update relevant tokens in constant-e2e.ts + const srcTokenSymbol = 'srcTokenSymbol'; + const destTokenSymbol = 'destTokenSymbol'; + + const amountsForSell = [ + 0n, + 1n * BI_POWS[tokens[srcTokenSymbol].decimals], + 2n * BI_POWS[tokens[srcTokenSymbol].decimals], + 3n * BI_POWS[tokens[srcTokenSymbol].decimals], + 4n * BI_POWS[tokens[srcTokenSymbol].decimals], + 5n * BI_POWS[tokens[srcTokenSymbol].decimals], + 6n * BI_POWS[tokens[srcTokenSymbol].decimals], + 7n * BI_POWS[tokens[srcTokenSymbol].decimals], + 8n * BI_POWS[tokens[srcTokenSymbol].decimals], + 9n * BI_POWS[tokens[srcTokenSymbol].decimals], + 10n * BI_POWS[tokens[srcTokenSymbol].decimals], + ]; + + const amountsForBuy = [ + 0n, + 1n * BI_POWS[tokens[destTokenSymbol].decimals], + 2n * BI_POWS[tokens[destTokenSymbol].decimals], + 3n * BI_POWS[tokens[destTokenSymbol].decimals], + 4n * BI_POWS[tokens[destTokenSymbol].decimals], + 5n * BI_POWS[tokens[destTokenSymbol].decimals], + 6n * BI_POWS[tokens[destTokenSymbol].decimals], + 7n * BI_POWS[tokens[destTokenSymbol].decimals], + 8n * BI_POWS[tokens[destTokenSymbol].decimals], + 9n * BI_POWS[tokens[destTokenSymbol].decimals], + 10n * BI_POWS[tokens[destTokenSymbol].decimals], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + balancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (balancerV3.initializePricing) { + await balancerV3.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.SELL, + amountsForSell, + '', // TODO: Put here proper function name to check pricing + ); + }); + + it('getPoolIdentifiers and getPricesVolume BUY', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.BUY, + amountsForBuy, + '', // TODO: Put here proper function name to check pricing + ); + }); + + it('getTopPoolsForToken', async function () { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (newBalancerV3.updatePoolState) { + await newBalancerV3.updatePoolState(); + } + const poolLiquidity = await newBalancerV3.getTopPoolsForToken( + tokens[srcTokenSymbol].address, + 10, + ); + console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); + + if (!newBalancerV3.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity( + poolLiquidity, + Tokens[network][srcTokenSymbol].address, + dexKey, + ); + } + }); + }); +}); diff --git a/src/dex/index.ts b/src/dex/index.ts index 67f63d401..011a1928f 100644 --- a/src/dex/index.ts +++ b/src/dex/index.ts @@ -89,6 +89,7 @@ import { FxProtocolRusd } from './fx-protocol-rusd/fx-protocol-rusd'; import { AaveGsm } from './aave-gsm/aave-gsm'; import { LitePsm } from './lite-psm/lite-psm'; import { StkGHO } from './stkgho/stkgho'; +import { BalancerV3 } from './balancer-v3/balancer-v3'; const LegacyDexes = [ CurveV2, @@ -114,6 +115,7 @@ const Dexes = [ Swerve, BalancerV1, BalancerV2, + BalancerV3, UniswapV2, UniswapV3, Algebra, From a422a9e7fd13cd7e6db6b8bb8dc559e80b41a87d Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 4 Oct 2024 14:35:28 +0100 Subject: [PATCH 03/66] feat: Initial implementation. Pool loading with onchain state. Balance change event handling and test. --- src/dex/balancer-v3/abi/vaultExtension.V3.ts | 1800 +++++++++++++++++ .../balancer-v3/balancer-v3-events.test.ts | 128 ++ src/dex/balancer-v3/balancer-v3-pool.ts | 143 ++ src/dex/balancer-v3/balancer-v3.ts | 174 ++ src/dex/balancer-v3/config.ts | 28 + src/dex/balancer-v3/getOnChainState.ts | 304 +++ src/dex/balancer-v3/getPoolsApi.ts | 96 + src/dex/balancer-v3/types.ts | 54 + 8 files changed, 2727 insertions(+) create mode 100644 src/dex/balancer-v3/abi/vaultExtension.V3.ts create mode 100644 src/dex/balancer-v3/balancer-v3-events.test.ts create mode 100644 src/dex/balancer-v3/balancer-v3-pool.ts create mode 100644 src/dex/balancer-v3/balancer-v3.ts create mode 100644 src/dex/balancer-v3/config.ts create mode 100644 src/dex/balancer-v3/getOnChainState.ts create mode 100644 src/dex/balancer-v3/getPoolsApi.ts create mode 100644 src/dex/balancer-v3/types.ts diff --git a/src/dex/balancer-v3/abi/vaultExtension.V3.ts b/src/dex/balancer-v3/abi/vaultExtension.V3.ts new file mode 100644 index 000000000..3440ad461 --- /dev/null +++ b/src/dex/balancer-v3/abi/vaultExtension.V3.ts @@ -0,0 +1,1800 @@ +export const vaultExtensionAbi_V3 = [ + { + inputs: [ + { + internalType: 'contract IVault', + name: 'mainVault', + type: 'address', + }, + { + internalType: 'contract IVaultAdmin', + name: 'vaultAdmin', + type: 'address', + }, + ], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [{ internalType: 'address', name: 'target', type: 'address' }], + name: 'AddressEmptyCode', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'account', type: 'address' }], + name: 'AddressInsufficientBalance', + type: 'error', + }, + { inputs: [], name: 'AfterAddLiquidityHookFailed', type: 'error' }, + { inputs: [], name: 'AfterInitializeHookFailed', type: 'error' }, + { inputs: [], name: 'AfterRemoveLiquidityHookFailed', type: 'error' }, + { inputs: [], name: 'AfterSwapHookFailed', type: 'error' }, + { inputs: [], name: 'AmountGivenZero', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, + { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + ], + name: 'AmountInAboveMax', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + ], + name: 'AmountOutBelowMin', + type: 'error', + }, + { inputs: [], name: 'BalanceNotSettled', type: 'error' }, + { inputs: [], name: 'BalanceOverflow', type: 'error' }, + { inputs: [], name: 'BeforeAddLiquidityHookFailed', type: 'error' }, + { inputs: [], name: 'BeforeInitializeHookFailed', type: 'error' }, + { inputs: [], name: 'BeforeRemoveLiquidityHookFailed', type: 'error' }, + { inputs: [], name: 'BeforeSwapHookFailed', type: 'error' }, + { + inputs: [ + { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, + { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + ], + name: 'BptAmountInAboveMax', + type: 'error', + }, + { + inputs: [ + { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + ], + name: 'BptAmountOutBelowMin', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'BufferAlreadyInitialized', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'BufferNotInitialized', + type: 'error', + }, + { inputs: [], name: 'BufferSharesInvalidOwner', type: 'error' }, + { inputs: [], name: 'BufferSharesInvalidReceiver', type: 'error' }, + { + inputs: [ + { internalType: 'uint256', name: 'totalSupply', type: 'uint256' }, + ], + name: 'BufferTotalSupplyTooLow', + type: 'error', + }, + { inputs: [], name: 'CannotReceiveEth', type: 'error' }, + { inputs: [], name: 'CannotSwapSameToken', type: 'error' }, + { inputs: [], name: 'CodecOverflow', type: 'error' }, + { inputs: [], name: 'DoesNotSupportAddLiquidityCustom', type: 'error' }, + { inputs: [], name: 'DoesNotSupportDonation', type: 'error' }, + { inputs: [], name: 'DoesNotSupportRemoveLiquidityCustom', type: 'error' }, + { inputs: [], name: 'DoesNotSupportUnbalancedLiquidity', type: 'error' }, + { inputs: [], name: 'DynamicSwapFeeHookFailed', type: 'error' }, + { + inputs: [ + { internalType: 'address', name: 'spender', type: 'address' }, + { internalType: 'uint256', name: 'allowance', type: 'uint256' }, + { internalType: 'uint256', name: 'needed', type: 'uint256' }, + ], + name: 'ERC20InsufficientAllowance', + type: 'error', + }, + { + inputs: [ + { internalType: 'address', name: 'sender', type: 'address' }, + { internalType: 'uint256', name: 'balance', type: 'uint256' }, + { internalType: 'uint256', name: 'needed', type: 'uint256' }, + ], + name: 'ERC20InsufficientBalance', + type: 'error', + }, + { + inputs: [ + { internalType: 'address', name: 'approver', type: 'address' }, + ], + name: 'ERC20InvalidApprover', + type: 'error', + }, + { + inputs: [ + { internalType: 'address', name: 'receiver', type: 'address' }, + ], + name: 'ERC20InvalidReceiver', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], + name: 'ERC20InvalidSender', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'spender', type: 'address' }], + name: 'ERC20InvalidSpender', + type: 'error', + }, + { inputs: [], name: 'ErrorSelectorNotFound', type: 'error' }, + { inputs: [], name: 'FailedInnerCall', type: 'error' }, + { inputs: [], name: 'FeePrecisionTooHigh', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, + { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + ], + name: 'HookAdjustedAmountInAboveMax', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + ], + name: 'HookAdjustedAmountOutBelowMin', + type: 'error', + }, + { + inputs: [ + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'uint256', name: 'limit', type: 'uint256' }, + ], + name: 'HookAdjustedSwapLimit', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'poolHooksContract', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'poolFactory', type: 'address' }, + ], + name: 'HookRegistrationFailed', + type: 'error', + }, + { inputs: [], name: 'InputLengthMismatch', type: 'error' }, + { inputs: [], name: 'InvalidAddLiquidityKind', type: 'error' }, + { inputs: [], name: 'InvalidRemoveLiquidityKind', type: 'error' }, + { inputs: [], name: 'InvalidToken', type: 'error' }, + { inputs: [], name: 'InvalidTokenConfiguration', type: 'error' }, + { inputs: [], name: 'InvalidTokenType', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'InvalidUnderlyingToken', + type: 'error', + }, + { inputs: [], name: 'MaxTokens', type: 'error' }, + { inputs: [], name: 'MinTokens', type: 'error' }, + { inputs: [], name: 'NotEnoughBufferShares', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'expectedUnderlyingAmount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'actualUnderlyingAmount', + type: 'uint256', + }, + ], + name: 'NotEnoughUnderlying', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'expectedWrappedAmount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'actualWrappedAmount', + type: 'uint256', + }, + ], + name: 'NotEnoughWrapped', + type: 'error', + }, + { inputs: [], name: 'NotStaticCall', type: 'error' }, + { inputs: [], name: 'NotVaultDelegateCall', type: 'error' }, + { inputs: [], name: 'OutOfBounds', type: 'error' }, + { inputs: [], name: 'PauseBufferPeriodDurationTooLarge', type: 'error' }, + { inputs: [], name: 'PercentageAboveMax', type: 'error' }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolAlreadyInitialized', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolAlreadyRegistered', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolInRecoveryMode', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolNotInRecoveryMode', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolNotInitialized', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolNotPaused', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolNotRegistered', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolPauseWindowExpired', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolPaused', + type: 'error', + }, + { + inputs: [ + { internalType: 'uint256', name: 'totalSupply', type: 'uint256' }, + ], + name: 'PoolTotalSupplyTooLow', + type: 'error', + }, + { inputs: [], name: 'ProtocolFeesExceedTotalCollected', type: 'error' }, + { inputs: [], name: 'QueriesDisabled', type: 'error' }, + { inputs: [], name: 'QuoteResultSpoofed', type: 'error' }, + { inputs: [], name: 'ReentrancyGuardReentrantCall', type: 'error' }, + { + inputs: [{ internalType: 'bytes', name: 'result', type: 'bytes' }], + name: 'Result', + type: 'error', + }, + { inputs: [], name: 'RouterNotTrusted', type: 'error' }, + { + inputs: [{ internalType: 'uint256', name: 'value', type: 'uint256' }], + name: 'SafeCastOverflowedUintToInt', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], + name: 'SenderIsNotVault', + type: 'error', + }, + { inputs: [], name: 'SwapFeePercentageTooHigh', type: 'error' }, + { inputs: [], name: 'SwapFeePercentageTooLow', type: 'error' }, + { + inputs: [ + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'uint256', name: 'limit', type: 'uint256' }, + ], + name: 'SwapLimit', + type: 'error', + }, + { + inputs: [ + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'TokenAlreadyRegistered', + type: 'error', + }, + { + inputs: [ + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'TokenNotRegistered', + type: 'error', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'expectedToken', type: 'address' }, + { internalType: 'address', name: 'actualToken', type: 'address' }, + ], + name: 'TokensMismatch', + type: 'error', + }, + { inputs: [], name: 'TokensNotSorted', type: 'error' }, + { inputs: [], name: 'TradeAmountTooSmall', type: 'error' }, + { inputs: [], name: 'VaultBuffersArePaused', type: 'error' }, + { inputs: [], name: 'VaultIsNotUnlocked', type: 'error' }, + { inputs: [], name: 'VaultNotPaused', type: 'error' }, + { inputs: [], name: 'VaultPauseWindowDurationTooLarge', type: 'error' }, + { inputs: [], name: 'VaultPauseWindowExpired', type: 'error' }, + { inputs: [], name: 'VaultPaused', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'WrapAmountTooSmall', + type: 'error', + }, + { inputs: [], name: 'WrongProtocolFeeControllerDeployment', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'address', + name: 'underlyingToken', + type: 'address', + }, + ], + name: 'WrongUnderlyingToken', + type: 'error', + }, + { inputs: [], name: 'WrongVaultAdminDeployment', type: 'error' }, + { inputs: [], name: 'WrongVaultExtensionDeployment', type: 'error' }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'owner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + ], + name: 'Approval', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IAuthorizer', + name: 'newAuthorizer', + type: 'address', + }, + ], + name: 'AuthorizerChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'burnedShares', + type: 'uint256', + }, + ], + name: 'BufferSharesBurned', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'issuedShares', + type: 'uint256', + }, + ], + name: 'BufferSharesMinted', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountUnderlying', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountWrapped', + type: 'uint256', + }, + ], + name: 'LiquidityAddedToBuffer', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountUnderlying', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountWrapped', + type: 'uint256', + }, + ], + name: 'LiquidityRemovedFromBuffer', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'liquidityProvider', + type: 'address', + }, + { + indexed: false, + internalType: 'int256[]', + name: 'deltas', + type: 'int256[]', + }, + ], + name: 'PoolBalanceChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolInitialized', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: false, + internalType: 'bool', + name: 'paused', + type: 'bool', + }, + ], + name: 'PoolPausedStateChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: false, + internalType: 'bool', + name: 'recoveryMode', + type: 'bool', + }, + ], + name: 'PoolRecoveryModeStateChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'factory', + type: 'address', + }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, + { + internalType: 'enum TokenType', + name: 'tokenType', + type: 'uint8', + }, + { + internalType: 'contract IRateProvider', + name: 'rateProvider', + type: 'address', + }, + { + internalType: 'bool', + name: 'paysYieldFees', + type: 'bool', + }, + ], + indexed: false, + internalType: 'struct TokenConfig[]', + name: 'tokenConfig', + type: 'tuple[]', + }, + { + indexed: false, + internalType: 'uint256', + name: 'swapFeePercentage', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint32', + name: 'pauseWindowEndTime', + type: 'uint32', + }, + { + components: [ + { + internalType: 'address', + name: 'pauseManager', + type: 'address', + }, + { + internalType: 'address', + name: 'swapFeeManager', + type: 'address', + }, + { + internalType: 'address', + name: 'poolCreator', + type: 'address', + }, + ], + indexed: false, + internalType: 'struct PoolRoleAccounts', + name: 'roleAccounts', + type: 'tuple', + }, + { + components: [ + { + internalType: 'bool', + name: 'enableHookAdjustedAmounts', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeInitialize', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterInitialize', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallComputeDynamicSwapFee', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeSwap', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterSwap', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeAddLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterAddLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeRemoveLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterRemoveLiquidity', + type: 'bool', + }, + { + internalType: 'address', + name: 'hooksContract', + type: 'address', + }, + ], + indexed: false, + internalType: 'struct HooksConfig', + name: 'hooksConfig', + type: 'tuple', + }, + { + components: [ + { + internalType: 'bool', + name: 'disableUnbalancedLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableAddLiquidityCustom', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableRemoveLiquidityCustom', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableDonation', + type: 'bool', + }, + ], + indexed: false, + internalType: 'struct LiquidityManagement', + name: 'liquidityManagement', + type: 'tuple', + }, + ], + name: 'PoolRegistered', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IProtocolFeeController', + name: 'newProtocolFeeController', + type: 'address', + }, + ], + name: 'ProtocolFeeControllerChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: true, + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + indexed: true, + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountIn', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountOut', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'swapFeePercentage', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'swapFeeAmount', + type: 'uint256', + }, + { + indexed: false, + internalType: 'contract IERC20', + name: 'swapFeeToken', + type: 'address', + }, + ], + name: 'Swap', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'swapFeePercentage', + type: 'uint256', + }, + ], + name: 'SwapFeePercentageChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + ], + name: 'Transfer', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: true, + internalType: 'contract IERC20', + name: 'underlyingToken', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'burnedShares', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'withdrawnUnderlying', + type: 'uint256', + }, + ], + name: 'Unwrap', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'bool', + name: 'paused', + type: 'bool', + }, + ], + name: 'VaultBuffersPausedStateChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'bool', + name: 'paused', + type: 'bool', + }, + ], + name: 'VaultPausedStateChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [], + name: 'VaultQueriesDisabled', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC20', + name: 'underlyingToken', + type: 'address', + }, + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'depositedUnderlying', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'mintedShares', + type: 'uint256', + }, + ], + name: 'Wrap', + type: 'event', + }, + { stateMutability: 'payable', type: 'fallback' }, + { + inputs: [ + { internalType: 'address', name: 'token', type: 'address' }, + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'address', name: 'spender', type: 'address' }, + ], + name: 'allowance', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'address', name: 'spender', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'approve', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'token', type: 'address' }, + { internalType: 'address', name: 'account', type: 'address' }, + ], + name: 'balanceOf', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + components: [ + { + internalType: 'enum SwapKind', + name: 'kind', + type: 'uint8', + }, + { + internalType: 'uint256', + name: 'amountGivenScaled18', + type: 'uint256', + }, + { + internalType: 'uint256[]', + name: 'balancesScaled18', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'indexIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'indexOut', + type: 'uint256', + }, + { + internalType: 'address', + name: 'router', + type: 'address', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct PoolSwapParams', + name: 'swapParams', + type: 'tuple', + }, + ], + name: 'computeDynamicSwapFeePercentage', + outputs: [ + { + internalType: 'uint256', + name: 'dynamicSwapFeePercentage', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'getAggregateSwapFeeAmount', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'getAggregateYieldFeeAmount', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getBptRate', + outputs: [{ internalType: 'uint256', name: 'rate', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getCurrentLiveBalances', + outputs: [ + { + internalType: 'uint256[]', + name: 'balancesLiveScaled18', + type: 'uint256[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getHooksConfig', + outputs: [ + { + components: [ + { + internalType: 'bool', + name: 'enableHookAdjustedAmounts', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeInitialize', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterInitialize', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallComputeDynamicSwapFee', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeSwap', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterSwap', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeAddLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterAddLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeRemoveLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterRemoveLiquidity', + type: 'bool', + }, + { + internalType: 'address', + name: 'hooksContract', + type: 'address', + }, + ], + internalType: 'struct HooksConfig', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getNonzeroDeltaCount', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolConfig', + outputs: [ + { + components: [ + { + components: [ + { + internalType: 'bool', + name: 'disableUnbalancedLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableAddLiquidityCustom', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableRemoveLiquidityCustom', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableDonation', + type: 'bool', + }, + ], + internalType: 'struct LiquidityManagement', + name: 'liquidityManagement', + type: 'tuple', + }, + { + internalType: 'uint256', + name: 'staticSwapFeePercentage', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'aggregateSwapFeePercentage', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'aggregateYieldFeePercentage', + type: 'uint256', + }, + { + internalType: 'uint40', + name: 'tokenDecimalDiffs', + type: 'uint40', + }, + { + internalType: 'uint32', + name: 'pauseWindowEndTime', + type: 'uint32', + }, + { + internalType: 'bool', + name: 'isPoolRegistered', + type: 'bool', + }, + { + internalType: 'bool', + name: 'isPoolInitialized', + type: 'bool', + }, + { + internalType: 'bool', + name: 'isPoolPaused', + type: 'bool', + }, + { + internalType: 'bool', + name: 'isPoolInRecoveryMode', + type: 'bool', + }, + ], + internalType: 'struct PoolConfig', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolData', + outputs: [ + { + components: [ + { + internalType: 'PoolConfigBits', + name: 'poolConfigBits', + type: 'bytes32', + }, + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + { + components: [ + { + internalType: 'enum TokenType', + name: 'tokenType', + type: 'uint8', + }, + { + internalType: 'contract IRateProvider', + name: 'rateProvider', + type: 'address', + }, + { + internalType: 'bool', + name: 'paysYieldFees', + type: 'bool', + }, + ], + internalType: 'struct TokenInfo[]', + name: 'tokenInfo', + type: 'tuple[]', + }, + { + internalType: 'uint256[]', + name: 'balancesRaw', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'balancesLiveScaled18', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'tokenRates', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'decimalScalingFactors', + type: 'uint256[]', + }, + ], + internalType: 'struct PoolData', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolPausedState', + outputs: [ + { internalType: 'bool', name: '', type: 'bool' }, + { internalType: 'uint32', name: '', type: 'uint32' }, + { internalType: 'uint32', name: '', type: 'uint32' }, + { internalType: 'address', name: '', type: 'address' }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolRoleAccounts', + outputs: [ + { + components: [ + { + internalType: 'address', + name: 'pauseManager', + type: 'address', + }, + { + internalType: 'address', + name: 'swapFeeManager', + type: 'address', + }, + { + internalType: 'address', + name: 'poolCreator', + type: 'address', + }, + ], + internalType: 'struct PoolRoleAccounts', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolTokenInfo', + outputs: [ + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + { + components: [ + { + internalType: 'enum TokenType', + name: 'tokenType', + type: 'uint8', + }, + { + internalType: 'contract IRateProvider', + name: 'rateProvider', + type: 'address', + }, + { + internalType: 'bool', + name: 'paysYieldFees', + type: 'bool', + }, + ], + internalType: 'struct TokenInfo[]', + name: 'tokenInfo', + type: 'tuple[]', + }, + { + internalType: 'uint256[]', + name: 'balancesRaw', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'lastBalancesLiveScaled18', + type: 'uint256[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolTokenRates', + outputs: [ + { + internalType: 'uint256[]', + name: 'decimalScalingFactors', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'tokenRates', + type: 'uint256[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolTokens', + outputs: [ + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getProtocolFeeController', + outputs: [ + { + internalType: 'contract IProtocolFeeController', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'getReservesOf', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getStaticSwapFeePercentage', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'getTokenDelta', + outputs: [{ internalType: 'int256', name: '', type: 'int256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getVaultAdmin', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'exactAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'initialize', + outputs: [ + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'isPoolInRecoveryMode', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'isPoolInitialized', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'isPoolPaused', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'isPoolRegistered', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'isQueryDisabled', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'isUnlocked', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes', name: 'data', type: 'bytes' }], + name: 'quote', + outputs: [{ internalType: 'bytes', name: 'result', type: 'bytes' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes', name: 'data', type: 'bytes' }], + name: 'quoteAndRevert', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'reentrancyGuardEntered', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, + { + internalType: 'enum TokenType', + name: 'tokenType', + type: 'uint8', + }, + { + internalType: 'contract IRateProvider', + name: 'rateProvider', + type: 'address', + }, + { + internalType: 'bool', + name: 'paysYieldFees', + type: 'bool', + }, + ], + internalType: 'struct TokenConfig[]', + name: 'tokenConfig', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'swapFeePercentage', + type: 'uint256', + }, + { + internalType: 'uint32', + name: 'pauseWindowEndTime', + type: 'uint32', + }, + { internalType: 'bool', name: 'protocolFeeExempt', type: 'bool' }, + { + components: [ + { + internalType: 'address', + name: 'pauseManager', + type: 'address', + }, + { + internalType: 'address', + name: 'swapFeeManager', + type: 'address', + }, + { + internalType: 'address', + name: 'poolCreator', + type: 'address', + }, + ], + internalType: 'struct PoolRoleAccounts', + name: 'roleAccounts', + type: 'tuple', + }, + { + internalType: 'address', + name: 'poolHooksContract', + type: 'address', + }, + { + components: [ + { + internalType: 'bool', + name: 'disableUnbalancedLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableAddLiquidityCustom', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableRemoveLiquidityCustom', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableDonation', + type: 'bool', + }, + ], + internalType: 'struct LiquidityManagement', + name: 'liquidityManagement', + type: 'tuple', + }, + ], + name: 'registerPool', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'from', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + ], + name: 'removeLiquidityRecovery', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOutRaw', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'token', type: 'address' }], + name: 'totalSupply', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'transfer', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'spender', type: 'address' }, + { internalType: 'address', name: 'from', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'transferFrom', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'vault', + outputs: [ + { internalType: 'contract IVault', name: '', type: 'address' }, + ], + stateMutability: 'view', + type: 'function', + }, + { stateMutability: 'payable', type: 'receive' }, +] as const; diff --git a/src/dex/balancer-v3/balancer-v3-events.test.ts b/src/dex/balancer-v3/balancer-v3-events.test.ts new file mode 100644 index 000000000..b8eb2e777 --- /dev/null +++ b/src/dex/balancer-v3/balancer-v3-events.test.ts @@ -0,0 +1,128 @@ +/* eslint-disable no-console */ +import dotenv from 'dotenv'; +dotenv.config(); + +import { BalancerV3EventPool } from './balancer-v3-pool'; +import { Network } from '../../constants'; +import { Address } from '../../types'; +import { DummyDexHelper } from '../../dex-helper/index'; +import { testEventSubscriber } from '../../../tests/utils-events'; +import { PoolStateMap } from './types'; +import { BalancerV3Config } from './config'; +import _ from 'lodash'; + +/* + README + ====== + + This test script adds unit tests for BalancerV3 event based + system. This is done by fetching the state on-chain before the + event block, manually pushing the block logs to the event-subscriber, + comparing the local state with on-chain state. + + Most of the logic for testing is abstracted by `testEventSubscriber`. + You need to do two things to make the tests work: + + 1. Fetch the block numbers where certain events were released. You + can modify the `./scripts/fetch-event-blocknumber.ts` to get the + block numbers for different events. Make sure to get sufficient + number of blockNumbers to cover all possible cases for the event + mutations. + + 2. Complete the implementation for fetchPoolState function. The + function should fetch the on-chain state of the event subscriber + using just the blocknumber. + + The template tests only include the test for a single event + subscriber. There can be cases where multiple event subscribers + exist for a single DEX. In such cases additional tests should be + added. + + You can run this individual test script by running: + `npx jest src/dex/balancer-v3/balancer-v3-events.test.ts` + + (This comment should be removed from the final implementation) +*/ + +jest.setTimeout(50 * 1000); + +async function fetchPoolState( + balancerV3Pools: BalancerV3EventPool, + blockNumber: number, + poolAddress: string, +): Promise { + const pools = await balancerV3Pools.generateState(blockNumber); + // Filter to pool of interest + return Object.entries(_.cloneDeep(pools) as PoolStateMap) + .filter(([address]) => { + return address === poolAddress; + }) + .reduce((acc, [address, pool]) => { + acc[address] = pool; + return acc; + }, {} as PoolStateMap); +} + +// eventName -> blockNumbers +type EventMappings = Record; +type EventData = { blockNumbers: number[]; poolAddress: string[] }; + +describe('BalancerV3 EventPool', function () { + const dexKey = 'BalancerV3'; + const network = Network.SEPOLIA; + const dexHelper = new DummyDexHelper(network); + const logger = dexHelper.getLogger(dexKey); + let balancerV3Pool: BalancerV3EventPool; + + // vault -> EventMappings + const eventsToTest: Record = { + [BalancerV3Config.BalancerV3[network].vaultAddress]: { + // 6806714: + // - https://eth-sepolia.blockscout.com/tx/0x831ef55d8c697f5e603174373e3fbe388def01944a3f73b4c90e6f1775d6e49f?tab=logs + // - has swap for pool : 0x3e8b62395aea51c3d7bdfeb8cde7d4a272c34750 + PoolBalanceChanged: { + blockNumbers: [6806714], + poolAddress: ['0x3e8b62395aea51c3d7bdfeb8cde7d4a272c34750'], + }, + }, + }; + + beforeEach(async () => { + balancerV3Pool = new BalancerV3EventPool( + dexKey, + network, + dexHelper, + logger, + ); + }); + + Object.entries(eventsToTest).forEach( + ([vaultAddress, events]: [string, EventMappings]) => { + describe(`Events for Vault: ${vaultAddress}`, () => { + Object.entries(events).forEach( + ([eventName, eventData]: [string, EventData]) => { + describe(`${eventName}`, () => { + eventData.blockNumbers.forEach((blockNumber: number, i) => { + it(`Pool: ${eventData.poolAddress[i]} State after ${blockNumber}`, async function () { + await testEventSubscriber( + balancerV3Pool, + balancerV3Pool.addressesSubscribed, + (_blockNumber: number) => + fetchPoolState( + balancerV3Pool, + _blockNumber, + eventData.poolAddress[i], + ), + blockNumber, + `${dexKey}_${vaultAddress}`, + dexHelper.provider, + ); + }); + }); + }); + }, + ); + }); + }, + ); +}); diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts new file mode 100644 index 000000000..bca32ed78 --- /dev/null +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -0,0 +1,143 @@ +import _ from 'lodash'; +import { Interface } from '@ethersproject/abi'; +import { DeepReadonly } from 'ts-essentials'; +import { Log, Logger } from '../../types'; +import { catchParseLogError } from '../../utils'; +import { StatefulEventSubscriber } from '../../stateful-event-subscriber'; +import { IDexHelper } from '../../dex-helper/idex-helper'; +import { PoolStateMap } from './types'; +import { getPoolsApi } from './getPoolsApi'; +import { vaultExtensionAbi_V3 } from './abi/vaultExtension.V3'; +import { getOnChainState } from './getOnChainState'; +import { BalancerV3Config } from './config'; + +export class BalancerV3EventPool extends StatefulEventSubscriber { + handlers: { + [event: string]: ( + event: any, + state: DeepReadonly, + log: Readonly, + ) => DeepReadonly | null; + } = {}; + + logDecoder: (log: Log) => any; + + addressesSubscribed: string[]; + + interfaces: { + [name: string]: Interface; + }; + + constructor( + readonly parentName: string, + protected network: number, + protected dexHelper: IDexHelper, + logger: Logger, + ) { + super( + parentName, + BalancerV3Config.BalancerV3[network].vaultAddress, + dexHelper, + logger, + ); + + this.interfaces = { + ['VAULT']: new Interface(vaultExtensionAbi_V3), + ['STABLE']: new Interface([ + 'function getAmplificationParameter() external view returns (uint256 value, bool isUpdating, uint256 precision)', + ]), + }; + + this.logDecoder = (log: Log) => this.interfaces['VAULT'].parseLog(log); + this.addressesSubscribed = [ + BalancerV3Config.BalancerV3[network].vaultAddress, + ]; + + // Add handlers + this.handlers['PoolBalanceChanged'] = + this.poolBalanceChangedEvent.bind(this); + } + + /** + * The function is called every time any of the subscribed + * addresses release log. The function accepts the current + * state, updates the state according to the log, and returns + * the updated state. + * @param state - Current state of event subscriber + * @param log - Log released by one of the subscribed addresses + * @returns Updates state of the event subscriber after the log + */ + protected processLog( + state: DeepReadonly, + log: Readonly, + ): DeepReadonly | null { + try { + const event = this.logDecoder(log); + if (event.name in this.handlers) { + return this.handlers[event.name](event, state, log); + } + } catch (e) { + catchParseLogError(e, this.logger); + } + + return null; + } + + /** + * The function generates state using on-chain calls. This + * function is called to regenerate state if the event based + * system fails to fetch events and the local state is no + * more correct. + * @param blockNumber - Blocknumber for which the state should + * should be generated + * @returns state of the event subscriber at blocknumber + */ + async generateState( + blockNumber: number, + ): Promise> { + const block = await this.dexHelper.provider.getBlock(blockNumber); + const apiPoolStateMap = await getPoolsApi(this.network, block.timestamp); + const allOnChainPools = await getOnChainState( + this.network, + apiPoolStateMap, + this.dexHelper, + this.interfaces, + blockNumber, + ); + + // Filter out all pools with hooks and paused pools + const filteredPools = Object.entries(allOnChainPools) + .filter(([address, pool]) => { + return !(pool.hasHook || pool.isPoolPaused); + }) + .reduce((acc, [address, pool]) => { + acc[address] = pool; + return acc; + }, {} as PoolStateMap); + + return filteredPools; + } + + poolBalanceChangedEvent( + event: any, + state: DeepReadonly, + log: Readonly, + ): DeepReadonly | null { + const poolAddress = event.args.pool.toLowerCase(); + // Vault will send events from any pools, some of which are not officially supported by Balancer + if (!state[poolAddress]) { + return null; + } + const newState = _.cloneDeep(state) as PoolStateMap; + for ( + let i = 0; + i < newState[poolAddress].balancesLiveScaled18.length; + i++ + ) { + newState[poolAddress].balancesLiveScaled18[i] += BigInt( + event.args.deltas[i], + ); + } + return newState; + } +} diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts new file mode 100644 index 000000000..d49fafe6e --- /dev/null +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -0,0 +1,174 @@ +import { AsyncOrSync, DeepReadonly } from 'ts-essentials'; +import { + Token, + Address, + ExchangePrices, + PoolPrices, + AdapterExchangeParam, + SimpleExchangeParam, + PoolLiquidity, + Logger, +} from '../../types'; +import { SwapSide, Network } from '../../constants'; +import * as CALLDATA_GAS_COST from '../../calldata-gas-cost'; +import { getDexKeysWithNetwork } from '../../utils'; +import { IDex } from '../../dex/idex'; +import { IDexHelper } from '../../dex-helper/idex-helper'; +import { BalancerV3Data, PoolStateMap } from './types'; +import { SimpleExchange } from '../simple-exchange'; +import { BalancerV3Config, Adapters } from './config'; +import { BalancerV3EventPool } from './balancer-v3-pool'; + +export class BalancerV3 extends SimpleExchange implements IDex { + protected eventPools: BalancerV3EventPool; + + readonly hasConstantPriceLargeAmounts = false; + // TODO: set true here if protocols works only with wrapped asset + readonly needWrapNative = true; + + readonly isFeeOnTransferSupported = false; + + public static dexKeysWithNetwork: { key: string; networks: Network[] }[] = + getDexKeysWithNetwork(BalancerV3Config); + + logger: Logger; + + constructor( + readonly network: Network, + readonly dexKey: string, + readonly dexHelper: IDexHelper, + protected adapters = Adapters[network] || {}, + ) { + super(dexHelper, dexKey); + this.logger = dexHelper.getLogger(dexKey); + this.eventPools = new BalancerV3EventPool( + dexKey, + network, + dexHelper, + this.logger, + ); + } + + // Initialize pricing is called once in the start of + // pricing service. It is intended to setup the integration + // for pricing requests. It is optional for a DEX to + // implement this function + async initializePricing(blockNumber: number) { + await this.eventPools.initialize(blockNumber); + } + + // Returns the list of contract adapters (name and index) + // for a buy/sell. Return null if there are no adapters. + getAdapters(side: SwapSide): { name: string; index: number }[] | null { + return this.adapters[side] ? this.adapters[side] : null; + } + + // Returns list of pool identifiers that can be used + // for a given swap. poolIdentifiers must be unique + // across DEXes. It is recommended to use + // ${dexKey}_${poolAddress} as a poolIdentifier + async getPoolIdentifiers( + srcToken: Token, + destToken: Token, + side: SwapSide, + blockNumber: number, + ): Promise { + // const _from = this.dexHelper.config.wrapETH(from); + // const _to = this.dexHelper.config.wrapETH(to); + const poolState = this.eventPools.getState(blockNumber); + if (poolState === null) return []; + return this.findPoolAddressesWithTokens( + poolState, + srcToken.address, + destToken.address, + ); + } + + findPoolAddressesWithTokens( + pools: DeepReadonly, + tokenA: string, + tokenB: string, + ): string[] { + return Object.entries(pools) + .filter(([, poolState]) => { + return ( + poolState.tokens.includes(tokenA) && poolState.tokens.includes(tokenB) + ); + }) + .map(([address]) => address); + } + + // Returns pool prices for amounts. + // If limitPools is defined only pools in limitPools + // should be used. If limitPools is undefined then + // any pools can be used. + async getPricesVolume( + srcToken: Token, + destToken: Token, + amounts: bigint[], + side: SwapSide, + blockNumber: number, + limitPools?: string[], + ): Promise> { + // TODO: complete me! + return null; + } + + // Returns estimated gas cost of calldata for this DEX in multiSwap + getCalldataGasCost( + poolPrices: PoolPrices, + ): number | number[] { + // TODO: update if there is any payload in getAdapterParam + return CALLDATA_GAS_COST.DEX_NO_PAYLOAD; + } + + // Encode params required by the exchange adapter + // V5: Used for multiSwap, buy & megaSwap + // V6: Not used, can be left blank + // Hint: abiCoder.encodeParameter() could be useful + getAdapterParam( + srcToken: string, + destToken: string, + srcAmount: string, + destAmount: string, + data: BalancerV3Data, + side: SwapSide, + ): AdapterExchangeParam { + // TODO: complete me! + const { exchange } = data; + + // Encode here the payload for adapter + const payload = ''; + + return { + targetExchange: exchange, + payload, + networkFee: '0', + }; + } + + // This is called once before getTopPoolsForToken is + // called for multiple tokens. This can be helpful to + // update common state required for calculating + // getTopPoolsForToken. It is optional for a DEX + // to implement this + async updatePoolState(): Promise { + // TODO: complete me! + } + + // Returns list of top pools based on liquidity. Max + // limit number pools should be returned. + async getTopPoolsForToken( + tokenAddress: Address, + limit: number, + ): Promise { + //TODO: complete me! + return []; + } + + // This is optional function in case if your implementation has acquired any resources + // you need to release for graceful shutdown. For example, it may be any interval timer + releaseResources(): AsyncOrSync { + // TODO: complete me! + } +} diff --git a/src/dex/balancer-v3/config.ts b/src/dex/balancer-v3/config.ts new file mode 100644 index 000000000..4cee9db9e --- /dev/null +++ b/src/dex/balancer-v3/config.ts @@ -0,0 +1,28 @@ +import { DexParams } from './types'; +import { DexConfigMap, AdapterMappings } from '../../types'; +import { Network, SwapSide } from '../../constants'; + +// These map to the Balancer API poolType. Only Balancer supported pools will be added +export enum SUPPORTED_POOLS { + WEIGHTED = 'WEIGHTED', + STABLE = 'STABLE', +} + +// Balancer API - aggregatorSpecific query serves all useful static pool data +export const apiUrl = 'https://test-api-v3.balancer.fi/'; + +// TODO Full config added after V3 release +export const BalancerV3Config: DexConfigMap = { + BalancerV3: { + [Network.SEPOLIA]: { + vaultAddress: '0x0EF1c156a7986F394d90eD1bEeA6483Cc435F542', + apiNetworkName: 'SEPOLIA', + }, + }, +}; + +export const Adapters: Record = { + // TODO: add adapters for each chain + // This is an example to copy + [Network.MAINNET]: { [SwapSide.SELL]: [{ name: '', index: 0 }] }, +}; diff --git a/src/dex/balancer-v3/getOnChainState.ts b/src/dex/balancer-v3/getOnChainState.ts new file mode 100644 index 000000000..465ce4364 --- /dev/null +++ b/src/dex/balancer-v3/getOnChainState.ts @@ -0,0 +1,304 @@ +import _ from 'lodash'; +import { + ImmutablePoolStateMap, + CommonMutableState, + PoolStateMap, + StableMutableState, +} from './types'; +import { BalancerV3Config } from './config'; +import { Interface, Result } from '@ethersproject/abi'; +import { IDexHelper } from '../../dex-helper'; + +interface callData { + target: string; + callData: string; +} + +// Encoding & Decoding for onchain calls to fetch mutable pool data +// Each supported pool type should have its own specific calls if needed +const poolOnChain: Record< + string, + { + count: number; + encode: ( + network: number, + contractInterface: Interface, + address: string, + ) => callData[]; + decode: ( + contractInterface: Interface, + poolAddress: string, + data: any, + startIndex: number, + ) => {} | CommonMutableState | StableMutableState; + } +> = { + ['COMMON']: { + count: 6, + ['encode']: ( + network: number, + contractInterface: Interface, + address: string, + ): callData[] => { + return [ + { + target: BalancerV3Config.BalancerV3[network].vaultAddress, + callData: contractInterface.encodeFunctionData('getPoolTokenRates', [ + address, + ]), + }, + { + target: BalancerV3Config.BalancerV3[network].vaultAddress, + callData: contractInterface.encodeFunctionData( + 'getCurrentLiveBalances', + [address], + ), + }, + { + target: BalancerV3Config.BalancerV3[network].vaultAddress, + callData: contractInterface.encodeFunctionData('getPoolConfig', [ + address, + ]), + }, + { + target: BalancerV3Config.BalancerV3[network].vaultAddress, + callData: contractInterface.encodeFunctionData('totalSupply', [ + address, + ]), + }, + { + target: BalancerV3Config.BalancerV3[network].vaultAddress, + callData: contractInterface.encodeFunctionData('isPoolPaused', [ + address, + ]), + }, + { + target: BalancerV3Config.BalancerV3[network].vaultAddress, + callData: contractInterface.encodeFunctionData('getHooksConfig', [ + address, + ]), + }, + ]; + }, + ['decode']: ( + contractInterface: Interface, + poolAddress: string, + data: any, + startIndex: number, + ): CommonMutableState => { + const resultTokenRates = decodeThrowError( + contractInterface, + 'getPoolTokenRates', + data[startIndex++], + poolAddress, + ); + if (!resultTokenRates) + throw new Error( + `Failed to get result for getPoolTokenRates for ${poolAddress}`, + ); + const resultLiveBalances = decodeThrowError( + contractInterface, + 'getCurrentLiveBalances', + data[startIndex++], + poolAddress, + ); + if (!resultLiveBalances) + throw new Error( + `Failed to get result for getPoolTokenRates for ${poolAddress}`, + ); + const resultGetPoolConfig = decodeThrowError( + contractInterface, + 'getPoolConfig', + data[startIndex++], + poolAddress, + ); + if (!resultGetPoolConfig) + throw new Error( + `Failed to get result for getPoolConfig for ${poolAddress}`, + ); + const resultTotalSupply = decodeThrowError( + contractInterface, + 'totalSupply', + data[startIndex++], + poolAddress, + ); + if (!resultTotalSupply) + throw new Error( + `Failed to get result for totalSupply for ${poolAddress}`, + ); + const resultIsPoolPaused = decodeThrowError( + contractInterface, + 'isPoolPaused', + data[startIndex++], + poolAddress, + ); + if (!resultIsPoolPaused) + throw new Error( + `Failed to get result for isPoolPaused for ${poolAddress}`, + ); + const resultHooksConfig = decodeThrowError( + contractInterface, + 'getHooksConfig', + data[startIndex++], + poolAddress, + ); + if (!resultHooksConfig) + throw new Error( + `Failed to get result for resultHooksConfig for ${poolAddress}`, + ); + return { + tokenRates: resultTokenRates.tokenRates.map((r: string) => BigInt(r)), + balancesLiveScaled18: resultLiveBalances.balancesLiveScaled18.map( + (b: string) => BigInt(b), + ), + swapFee: BigInt(resultGetPoolConfig[0].staticSwapFeePercentage), + aggregateSwapFee: BigInt( + resultGetPoolConfig[0].aggregateSwapFeePercentage, + ), + totalSupply: BigInt(resultTotalSupply[0]), + scalingFactors: resultTokenRates.decimalScalingFactors.map( + (r: string) => BigInt(r), + ), + isPoolPaused: resultIsPoolPaused[0], + hasHook: + resultHooksConfig[0].hooksContract !== + '0x0000000000000000000000000000000000000000', + }; + }, + }, + ['WEIGHTED']: { + count: 0, + ['encode']: ( + network: number, + contractInterface: Interface, + address: string, + ): callData[] => { + return []; + }, + ['decode']: ( + contractInterface: Interface, + poolAddress: string, + data: any, + startIndex: number, + ) => { + return {}; + }, + }, + ['STABLE']: { + count: 1, + ['encode']: ( + network: number, + contractInterface: Interface, + address: string, + ): callData[] => { + return [ + { + target: address, + callData: contractInterface.encodeFunctionData( + 'getAmplificationParameter', + ), + }, + ]; + }, + ['decode']: ( + contractInterface: Interface, + poolAddress: string, + data: any, + startIndex: number, + ): StableMutableState => { + const resultAmp = decodeThrowError( + contractInterface, + 'getAmplificationParameter', + data[startIndex++], + poolAddress, + ); + if (!resultAmp) + throw new Error( + `Failed to get result for getAmplificationParameter for ${poolAddress}`, + ); + return { + amp: resultAmp[0].toBigInt(), + }; + }, + }, +}; + +export function decodeThrowError( + contractInterface: Interface, + functionName: string, + resultEntry: { success: boolean; returnData: any }, + poolAddress: string, +): Result { + if (!resultEntry.success) + throw new Error(`Failed to execute ${functionName} for ${poolAddress}`); + return contractInterface.decodeFunctionResult( + functionName, + resultEntry.returnData, + ); +} + +// Any data from API will be immutable. Mutable data such as balances, etc will be fetched via onchain/event state. +export async function getOnChainState( + network: number, + immutablePoolStateMap: ImmutablePoolStateMap, + dexHelper: IDexHelper, + interfaces: { + [name: string]: Interface; + }, + blockNumber: number, +): Promise { + const multiCallData = Object.entries(immutablePoolStateMap) + .map(([address, pool]) => { + return [ + ...poolOnChain['COMMON'].encode(network, interfaces['VAULT'], address), + ...poolOnChain[pool.poolType].encode( + network, + interfaces[pool.poolType], + address, + ), + ]; + }) + .flat(); + + // 500 is an arbitrary number chosen based on the blockGasLimit + const slicedMultiCallData = _.chunk(multiCallData, 500); + + const multicallData = ( + await Promise.all( + slicedMultiCallData.map(async _multiCallData => + dexHelper.multiContract.methods + .tryAggregate(false, _multiCallData) + .call({}, blockNumber), + ), + ) + ).flat(); + + let i = 0; + const poolStateMap = Object.fromEntries( + Object.entries(immutablePoolStateMap).map(([address, pool]) => { + const commonMutableData = poolOnChain['COMMON'].decode( + interfaces['VAULT'], + address, + multicallData, + i, + ) as CommonMutableState; + i = i + poolOnChain['COMMON'].count; + const poolMutableData = poolOnChain[pool.poolType].decode( + interfaces[pool.poolType], + address, + multicallData, + i, + ); + i = i + poolOnChain[pool.poolType].count; + return [ + address, + { + ...pool, + ...commonMutableData, + ...poolMutableData, + }, + ]; + }), + ); + return poolStateMap; +} diff --git a/src/dex/balancer-v3/getPoolsApi.ts b/src/dex/balancer-v3/getPoolsApi.ts new file mode 100644 index 000000000..1dd8c4667 --- /dev/null +++ b/src/dex/balancer-v3/getPoolsApi.ts @@ -0,0 +1,96 @@ +import axios from 'axios'; +import { DeepReadonly } from 'ts-essentials'; +import { apiUrl, BalancerV3Config, SUPPORTED_POOLS } from './config'; +import { CommonImmutablePoolState, ImmutablePoolStateMap } from './types'; +import { parseUnits } from 'ethers/lib/utils'; + +interface PoolToken { + address: string; + weight: string | null; +} + +interface Pool { + id: string; + type: string; + poolTokens: PoolToken[]; + factory: string; +} + +interface QueryResponse { + data: { + poolGetAggregatorPools: Pool[]; + }; +} + +function createQuery( + networkId: number, + timestamp: number, + poolTypes: SUPPORTED_POOLS[], +): string { + const poolTypesString = poolTypes.map(type => `${type}`).join(', '); + const networkString = BalancerV3Config.BalancerV3[networkId].apiNetworkName; + return ` + query MyQuery { + poolGetAggregatorPools( + where: {chainIn: ${networkString}, protocolVersionIn: 3, poolTypeIn: [${poolTypesString}], createTime: {lt: ${timestamp}}} + ) { + id + type + poolTokens { + address + weight + } + factory + } + } + `; +} + +function toImmutablePoolStateMap(pools: Pool[]): ImmutablePoolStateMap { + return pools.reduce((map, pool) => { + const immutablePoolState: CommonImmutablePoolState = { + tokens: pool.poolTokens.map(t => t.address), + weights: pool.poolTokens.map(t => + t.weight ? parseUnits(t.weight, 18).toBigInt() : 0n, + ), + poolType: pool.type, + // TODO add scalingFactors once API provides them + // scalingFactors: pool.poolTokens.map(t => parseUnits('1', 18).toBigInt()), + hookType: 'Unsupported', + }; + + map[pool.id] = immutablePoolState; + return map; + }, {} as ImmutablePoolStateMap); +} + +// Any data from API will be immutable. Mutable data such as balances, etc will be fetched via onchain/event state. +export async function getPoolsApi( + network: number, + timestamp: number, +): Promise { + try { + const query = createQuery( + network, + timestamp, + Object.values(SUPPORTED_POOLS), + ); + const response = await axios.post( + apiUrl, + { + query, + }, + { + headers: { + 'Content-Type': 'application/json', + }, + }, + ); + + const pools = response.data.data.poolGetAggregatorPools; + return toImmutablePoolStateMap(pools); + } catch (error) { + console.error('Error executing GraphQL query:', error); + throw error; + } +} diff --git a/src/dex/balancer-v3/types.ts b/src/dex/balancer-v3/types.ts new file mode 100644 index 000000000..771a8feca --- /dev/null +++ b/src/dex/balancer-v3/types.ts @@ -0,0 +1,54 @@ +import { Address } from '../../types'; + +// Immutable data types available on all pools (Available from API) +export type CommonImmutablePoolState = { + poolType: string; + tokens: string[]; + weights: bigint[]; + // TODO re-introduce this once added to API + // scalingFactors: bigint[]; + hookType: string; +}; + +// Mutable data types available on all pools (Available via onchain calls/events) +export interface CommonMutableState { + tokenRates: bigint[]; + balancesLiveScaled18: bigint[]; + swapFee: bigint; + aggregateSwapFee: bigint; + totalSupply: bigint; + isPoolPaused: boolean; + // TODO remove this once API provides it + scalingFactors: bigint[]; + // TODO remove this once API provides it + hasHook: boolean; +} + +type CommonPoolState = CommonImmutablePoolState & CommonMutableState; + +// Stable Pool specific mutable data +export interface StableMutableState { + amp: bigint; +} + +export type PoolStateMap = { + [address: string]: CommonPoolState | (CommonPoolState & StableMutableState); +}; + +export type ImmutablePoolStateMap = { + [address: string]: CommonImmutablePoolState; +}; + +export type BalancerV3Data = { + // TODO: BalancerV3Data is the dex data that is + // returned by the API that can be used for + // tx building. The data structure should be minimal. + // Complete me! + exchange: Address; +}; + +export type DexParams = { + // Used to map network > API Name, e.g. 11155111>SEPOLIA + apiNetworkName: string; + vaultAddress: string; +}; From 3c76dbd076e6ac9dfeaad5fe2b83f6b2e880854e Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Tue, 8 Oct 2024 22:16:18 +0100 Subject: [PATCH 04/66] feat: Add volume/pool pricing using Balancer V3 maths. --- package.json | 1 + src/dex/balancer-v3/balancer-v3-pool.ts | 49 ++++++++- src/dex/balancer-v3/balancer-v3.ts | 134 +++++++++++++++++++++++- src/dex/balancer-v3/getPoolsApi.ts | 4 +- src/dex/balancer-v3/types.ts | 9 +- yarn.lock | 5 + 6 files changed, 195 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 08b0f22d0..bc0dcb7fa 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ }, "dependencies": { "@0x/utils": "^4.5.2", + "@balancer-labs/balancer-maths": "^0.0.12", "@balancer-labs/sor": "4.1.1-beta.4", "@bgd-labs/aave-address-book": "2.21.1", "@ethersproject/abi": "^5.7.0", diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index bca32ed78..cd277b697 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -5,11 +5,12 @@ import { Log, Logger } from '../../types'; import { catchParseLogError } from '../../utils'; import { StatefulEventSubscriber } from '../../stateful-event-subscriber'; import { IDexHelper } from '../../dex-helper/idex-helper'; -import { PoolStateMap } from './types'; +import { PoolState, PoolStateMap } from './types'; import { getPoolsApi } from './getPoolsApi'; import { vaultExtensionAbi_V3 } from './abi/vaultExtension.V3'; import { getOnChainState } from './getOnChainState'; import { BalancerV3Config } from './config'; +import { SwapKind, Vault } from '@balancer-labs/balancer-maths'; export class BalancerV3EventPool extends StatefulEventSubscriber { handlers: { @@ -28,6 +29,8 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { [name: string]: Interface; }; + vault: Vault; + constructor( readonly parentName: string, protected network: number, @@ -56,6 +59,9 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { // Add handlers this.handlers['PoolBalanceChanged'] = this.poolBalanceChangedEvent.bind(this); + + // replicates V3 maths with fees, pool and hook logic + this.vault = new Vault(); } /** @@ -140,4 +146,45 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { } return newState; } + + getMaxSwapAmount( + pool: PoolState, + tokenIn: string, + tokenOut: string, + swapKind: SwapKind, + ): bigint { + const tokenInIndex = pool.tokens.indexOf(tokenIn); + const tokenOutIndex = pool.tokens.indexOf(tokenOut); + // Find the maximum swap amount the pool will support + const maxSwapAmount = this.vault.getMaxSwapAmount( + { + swapKind, + balancesLiveScaled18: pool.balancesLiveScaled18, + tokenRates: pool.tokenRates, + scalingFactors: pool.scalingFactors, + indexIn: tokenInIndex, + indexOut: tokenOutIndex, + }, + pool, + ); + return maxSwapAmount; + } + + getSwapResult( + pool: PoolState, + amountRaw: bigint, + tokenIn: string, + tokenOut: string, + swapKind: SwapKind, + ): bigint { + return this.vault.swap( + { + amountRaw, + tokenIn, + tokenOut, + swapKind, + }, + pool, + ); + } } diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index d49fafe6e..2f2661289 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -11,13 +11,18 @@ import { } from '../../types'; import { SwapSide, Network } from '../../constants'; import * as CALLDATA_GAS_COST from '../../calldata-gas-cost'; -import { getDexKeysWithNetwork } from '../../utils'; +import { getBigIntPow, getDexKeysWithNetwork } from '../../utils'; import { IDex } from '../../dex/idex'; import { IDexHelper } from '../../dex-helper/idex-helper'; -import { BalancerV3Data, PoolStateMap } from './types'; +import { BalancerV3Data, PoolState, PoolStateMap } from './types'; import { SimpleExchange } from '../simple-exchange'; import { BalancerV3Config, Adapters } from './config'; import { BalancerV3EventPool } from './balancer-v3-pool'; +import { SwapKind } from '@balancer-labs/balancer-maths'; + +type DeepMutable = { + -readonly [P in keyof T]: T[P] extends object ? DeepMutable : T[P]; +}; export class BalancerV3 extends SimpleExchange implements IDex { protected eventPools: BalancerV3EventPool; @@ -98,6 +103,30 @@ export class BalancerV3 extends SimpleExchange implements IDex { .map(([address]) => address); } + /** + * Filter pools that have tokens from/to and are in limitPool list + * @param pools + * @param from + * @param to + * @param limitPools + * @returns Array of PoolState + */ + filterPools( + pools: DeepReadonly, + from: string, + to: string, + limitPools?: string[], + ): PoolState[] { + return Object.entries(pools) + .filter(([address, poolState]) => { + const hasRequiredTokens = + poolState.tokens.includes(from) && poolState.tokens.includes(to); + const isAllowedPool = !limitPools || limitPools.includes(address); + return hasRequiredTokens && isAllowedPool; + }) + .map(([_, poolState]) => poolState as DeepMutable); + } + // Returns pool prices for amounts. // If limitPools is defined only pools in limitPools // should be used. If limitPools is undefined then @@ -110,10 +139,109 @@ export class BalancerV3 extends SimpleExchange implements IDex { blockNumber: number, limitPools?: string[], ): Promise> { - // TODO: complete me! + try { + const _from = this.dexHelper.config.wrapETH(srcToken); + const _to = this.dexHelper.config.wrapETH(destToken); + if (_from.address === _to.address) { + return null; + } + + // get up to date pools and state + const allPoolState = this.eventPools.getState(blockNumber); + if (allPoolState === null) { + this.logger.error(`getState returned null`); + return null; + } + + // filter for pools with tokens and to only use limit pools + const allowedPools = this.filterPools( + allPoolState, + _from.address, + _to.address, + limitPools, + ); + + if (!allowedPools.length) return null; + + const swapKind = SwapSide.SELL ? SwapKind.GivenIn : SwapKind.GivenOut; + const tokenIn = _from.address; + const tokenOut = _to.address; + + // Gets the single unit amount based off token decimals, e.g. for USDC its 1e6 + const unitAmount = getBigIntPow( + (side === SwapSide.SELL ? _from : _to).decimals, + ); + + const poolPrices: ExchangePrices = []; + // For each pool we calculate swap result using balancer maths + for (let i = 0; i < allowedPools.length; i++) { + const pool = { + ...allowedPools[i], + // TODO - Remove mapping once maths updated to same poolType convention + poolType: this.mapToPoolType(allowedPools[i].poolType), + }; + + try { + // This is the max amount the pool can swap + const maxSwapAmount = this.eventPools.getMaxSwapAmount( + pool, + tokenIn, + tokenOut, + swapKind, + ); + + let unit = 0n; + if (unitAmount < maxSwapAmount) + unit = this.eventPools.getSwapResult( + pool, + unitAmount, + tokenIn, + tokenOut, + swapKind, + ); + + const exchangePrice: PoolPrices = { + prices: new Array(amounts.length).fill(0n), + unit, + data: { + exchange: this.dexKey, // TODO is this needed? + }, + exchange: this.dexKey, + gasCost: 1, // TODO - this will be updated once final profiles done + poolAddresses: [allowedPools[i].address], + poolIdentifier: `${this.dexKey}_${allowedPools[i].address}`, + }; + + for (let j = 0; j < amounts.length; j++) { + if (amounts[j] < maxSwapAmount) { + // Uses balancer maths to calculate swap + exchangePrice.prices[j] = this.eventPools.getSwapResult( + pool, + amounts[j], + tokenIn, + tokenOut, + swapKind, + ); + } + } + poolPrices.push(exchangePrice); + } catch (err) { + this.logger.error(`error fetching prices for pool`); + this.logger.error(err); + } + } + + return poolPrices; + } catch (err) {} return null; } + private mapToPoolType(apiPoolType: string): string { + if (apiPoolType === 'STABLE') return 'Stable'; + else if (apiPoolType === 'WEIGHTED') return 'Weighted'; + else return apiPoolType; + } + // Returns estimated gas cost of calldata for this DEX in multiSwap getCalldataGasCost( poolPrices: PoolPrices, diff --git a/src/dex/balancer-v3/getPoolsApi.ts b/src/dex/balancer-v3/getPoolsApi.ts index 1dd8c4667..58fd48e8b 100644 --- a/src/dex/balancer-v3/getPoolsApi.ts +++ b/src/dex/balancer-v3/getPoolsApi.ts @@ -49,6 +49,7 @@ function createQuery( function toImmutablePoolStateMap(pools: Pool[]): ImmutablePoolStateMap { return pools.reduce((map, pool) => { const immutablePoolState: CommonImmutablePoolState = { + address: pool.id, tokens: pool.poolTokens.map(t => t.address), weights: pool.poolTokens.map(t => t.weight ? parseUnits(t.weight, 18).toBigInt() : 0n, @@ -56,7 +57,8 @@ function toImmutablePoolStateMap(pools: Pool[]): ImmutablePoolStateMap { poolType: pool.type, // TODO add scalingFactors once API provides them // scalingFactors: pool.poolTokens.map(t => parseUnits('1', 18).toBigInt()), - hookType: 'Unsupported', + // TODO Hook support will be added in future PR + hookType: undefined, }; map[pool.id] = immutablePoolState; diff --git a/src/dex/balancer-v3/types.ts b/src/dex/balancer-v3/types.ts index 771a8feca..d313f4d61 100644 --- a/src/dex/balancer-v3/types.ts +++ b/src/dex/balancer-v3/types.ts @@ -2,12 +2,13 @@ import { Address } from '../../types'; // Immutable data types available on all pools (Available from API) export type CommonImmutablePoolState = { + address: string; poolType: string; tokens: string[]; weights: bigint[]; // TODO re-introduce this once added to API // scalingFactors: bigint[]; - hookType: string; + hookType: string | undefined; }; // Mutable data types available on all pools (Available via onchain calls/events) @@ -26,13 +27,17 @@ export interface CommonMutableState { type CommonPoolState = CommonImmutablePoolState & CommonMutableState; +export type PoolState = + | CommonPoolState + | (CommonPoolState & StableMutableState); + // Stable Pool specific mutable data export interface StableMutableState { amp: bigint; } export type PoolStateMap = { - [address: string]: CommonPoolState | (CommonPoolState & StableMutableState); + [address: string]: PoolState; }; export type ImmutablePoolStateMap = { diff --git a/yarn.lock b/yarn.lock index 75f92a0a7..617be3909 100644 --- a/yarn.lock +++ b/yarn.lock @@ -341,6 +341,11 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@balancer-labs/balancer-maths@^0.0.12": + version "0.0.12" + resolved "https://registry.yarnpkg.com/@balancer-labs/balancer-maths/-/balancer-maths-0.0.12.tgz#2a02a5768c1e81cdce4049dea86c990e83bb9396" + integrity sha512-IjjXyTAhVn/rtfMn9kEvv8gsOLAGg1yXh04zZb3GyYgbV89x08dsCivoLTvqj71cSlsnpbmYvpM9N3DEhVaczQ== + "@balancer-labs/sor@4.1.1-beta.4": version "4.1.1-beta.4" resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.1.1-beta.4.tgz#9369435f8bbc781e9048f33aa496a484631b56e9" From c56892037a8ea7f0b2c027449ced2fc4846fe556 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 10 Oct 2024 10:22:38 +0100 Subject: [PATCH 05/66] feat: Add getDexParam functionality (for single swap only). --- src/config.ts | 2 +- src/dex/balancer-v3/abi/balancerRouter.ts | 1169 +++++++++++++++++++ src/dex/balancer-v3/balancer-v3-e2e.test.ts | 16 +- src/dex/balancer-v3/balancer-v3.ts | 107 +- src/dex/balancer-v3/config.ts | 1 + src/dex/balancer-v3/types.ts | 9 +- src/dex/weth/config.ts | 3 + tests/constants-e2e.ts | 22 + 8 files changed, 1299 insertions(+), 30 deletions(-) create mode 100644 src/dex/balancer-v3/abi/balancerRouter.ts diff --git a/src/config.ts b/src/config.ts index 53220628b..f15bbb8a3 100644 --- a/src/config.ts +++ b/src/config.ts @@ -423,7 +423,7 @@ const baseConfigs: { [network: number]: BaseConfig } = { isTestnet: false, nativeTokenName: 'Ether', nativeTokenSymbol: 'ETH', - wrappedNativeTokenAddress: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + wrappedNativeTokenAddress: '0x7b79995e5f793a07bc00c21412e50ecae098e7f9', hasEIP1559: true, augustusAddress: '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57', augustusRFQAddress: '0xe92b586627ccA7a83dC919cc7127196d70f55a06', diff --git a/src/dex/balancer-v3/abi/balancerRouter.ts b/src/dex/balancer-v3/abi/balancerRouter.ts new file mode 100644 index 000000000..da5ff88c5 --- /dev/null +++ b/src/dex/balancer-v3/abi/balancerRouter.ts @@ -0,0 +1,1169 @@ +export const balancerRouterAbi = [ + { + inputs: [ + { internalType: 'contract IVault', name: 'vault', type: 'address' }, + { internalType: 'contract IWETH', name: 'weth', type: 'address' }, + { + internalType: 'contract IPermit2', + name: 'permit2', + type: 'address', + }, + ], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [{ internalType: 'address', name: 'target', type: 'address' }], + name: 'AddressEmptyCode', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'account', type: 'address' }], + name: 'AddressInsufficientBalance', + type: 'error', + }, + { inputs: [], name: 'EthTransfer', type: 'error' }, + { inputs: [], name: 'FailedInnerCall', type: 'error' }, + { inputs: [], name: 'InsufficientEth', type: 'error' }, + { inputs: [], name: 'ReentrancyGuardReentrantCall', type: 'error' }, + { + inputs: [{ internalType: 'address', name: 'token', type: 'address' }], + name: 'SafeERC20FailedOperation', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], + name: 'SenderIsNotVault', + type: 'error', + }, + { inputs: [], name: 'SwapDeadline', type: 'error' }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'maxAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'addLiquidityCustom', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'maxAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { + internalType: 'enum AddLiquidityKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouterCommon.AddLiquidityHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'addLiquidityHook', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'maxAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'exactBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'addLiquidityProportional', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + { + internalType: 'uint256', + name: 'exactBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'addLiquiditySingleTokenExactOut', + outputs: [ + { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amountUnderlyingRaw', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'amountWrappedRaw', + type: 'uint256', + }, + { internalType: 'address', name: 'sharesOwner', type: 'address' }, + ], + name: 'addLiquidityToBuffer', + outputs: [ + { internalType: 'uint256', name: 'issuedShares', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amountUnderlyingRaw', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'amountWrappedRaw', + type: 'uint256', + }, + { internalType: 'address', name: 'sharesOwner', type: 'address' }, + ], + name: 'addLiquidityToBufferHook', + outputs: [ + { internalType: 'uint256', name: 'issuedShares', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'exactAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'addLiquidityUnbalanced', + outputs: [ + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'donate', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [], + name: 'getSender', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'exactAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'initialize', + outputs: [ + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'exactAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouter.InitializeHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'initializeHook', + outputs: [ + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes[]', name: 'data', type: 'bytes[]' }], + name: 'multicall', + outputs: [ + { internalType: 'bytes[]', name: 'results', type: 'bytes[]' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { internalType: 'address', name: 'token', type: 'address' }, + { internalType: 'address', name: 'owner', type: 'address' }, + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + { internalType: 'uint256', name: 'nonce', type: 'uint256' }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + ], + internalType: 'struct IRouterCommon.PermitApproval[]', + name: 'permitBatch', + type: 'tuple[]', + }, + { + internalType: 'bytes[]', + name: 'permitSignatures', + type: 'bytes[]', + }, + { + components: [ + { + components: [ + { + internalType: 'address', + name: 'token', + type: 'address', + }, + { + internalType: 'uint160', + name: 'amount', + type: 'uint160', + }, + { + internalType: 'uint48', + name: 'expiration', + type: 'uint48', + }, + { + internalType: 'uint48', + name: 'nonce', + type: 'uint48', + }, + ], + internalType: + 'struct IAllowanceTransfer.PermitDetails[]', + name: 'details', + type: 'tuple[]', + }, + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'sigDeadline', + type: 'uint256', + }, + ], + internalType: 'struct IAllowanceTransfer.PermitBatch', + name: 'permit2Batch', + type: 'tuple', + }, + { internalType: 'bytes', name: 'permit2Signature', type: 'bytes' }, + { internalType: 'bytes[]', name: 'multicallData', type: 'bytes[]' }, + ], + name: 'permitBatchAndCall', + outputs: [ + { internalType: 'bytes[]', name: 'results', type: 'bytes[]' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'maxAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryAddLiquidityCustom', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'maxAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { + internalType: 'enum AddLiquidityKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouterCommon.AddLiquidityHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'queryAddLiquidityHook', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryAddLiquidityProportional', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactBptAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryAddLiquiditySingleTokenExactOut', + outputs: [ + { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'exactAmountsIn', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryAddLiquidityUnbalanced', + outputs: [ + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'maxBptAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryRemoveLiquidityCustom', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'maxBptAmountIn', + type: 'uint256', + }, + { + internalType: 'enum RemoveLiquidityKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouterCommon.RemoveLiquidityHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'queryRemoveLiquidityHook', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryRemoveLiquidityProportional', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + ], + name: 'queryRemoveLiquidityRecovery', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'sender', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + ], + name: 'queryRemoveLiquidityRecoveryHook', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryRemoveLiquiditySingleTokenExactIn', + outputs: [ + { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryRemoveLiquiditySingleTokenExactOut', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'enum SwapKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amountGiven', + type: 'uint256', + }, + { internalType: 'uint256', name: 'limit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouter.SwapSingleTokenHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'querySwapHook', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'uint256', name: 'exactAmountIn', type: 'uint256' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'querySwapSingleTokenExactIn', + outputs: [ + { + internalType: 'uint256', + name: 'amountCalculated', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'querySwapSingleTokenExactOut', + outputs: [ + { + internalType: 'uint256', + name: 'amountCalculated', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'maxBptAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'removeLiquidityCustom', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'sharesToRemove', + type: 'uint256', + }, + ], + name: 'removeLiquidityFromBuffer', + outputs: [ + { internalType: 'uint256', name: '', type: 'uint256' }, + { internalType: 'uint256', name: '', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'sharesToRemove', + type: 'uint256', + }, + { internalType: 'address', name: 'sharesOwner', type: 'address' }, + ], + name: 'removeLiquidityFromBufferHook', + outputs: [ + { + internalType: 'uint256', + name: 'removedUnderlyingBalanceRaw', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'removedWrappedBalanceRaw', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'maxBptAmountIn', + type: 'uint256', + }, + { + internalType: 'enum RemoveLiquidityKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouterCommon.RemoveLiquidityHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'removeLiquidityHook', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'removeLiquidityProportional', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + ], + name: 'removeLiquidityRecovery', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'sender', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + ], + name: 'removeLiquidityRecoveryHook', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'removeLiquiditySingleTokenExactIn', + outputs: [ + { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'maxBptAmountIn', + type: 'uint256', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'removeLiquiditySingleTokenExactOut', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'uint256', name: 'exactAmountIn', type: 'uint256' }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'swapSingleTokenExactIn', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'swapSingleTokenExactOut', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'enum SwapKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amountGiven', + type: 'uint256', + }, + { internalType: 'uint256', name: 'limit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouter.SwapSingleTokenHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'swapSingleTokenHook', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { stateMutability: 'payable', type: 'receive' }, +] as const; diff --git a/src/dex/balancer-v3/balancer-v3-e2e.test.ts b/src/dex/balancer-v3/balancer-v3-e2e.test.ts index 16156ea5a..7f1bc76e9 100644 --- a/src/dex/balancer-v3/balancer-v3-e2e.test.ts +++ b/src/dex/balancer-v3/balancer-v3-e2e.test.ts @@ -71,7 +71,6 @@ function testForNetwork( // TODO: Add any direct swap contractMethod name if it exists const sideToContractMethods = new Map([ [SwapSide.SELL, [ContractMethod.swapExactAmountIn]], - // TODO: If buy is not supported remove the buy contract methods [SwapSide.BUY, [ContractMethod.swapExactAmountOut]], ]); @@ -130,15 +129,14 @@ describe('BalancerV3 E2E', () => { const dexKey = 'BalancerV3'; describe('Mainnet', () => { - const network = Network.MAINNET; + const network = Network.SEPOLIA; - // TODO: Modify the tokenASymbol, tokenBSymbol, tokenAAmount; - const tokenASymbol: string = 'tokenASymbol'; - const tokenBSymbol: string = 'tokenBSymbol'; + const tokenASymbol: string = 'bal'; + const tokenBSymbol: string = 'daiAave'; - const tokenAAmount: string = 'tokenAAmount'; - const tokenBAmount: string = 'tokenBAmount'; - const nativeTokenAmount = '1000000000000000000'; + const tokenAAmount: string = '1000000000000000000'; + const tokenBAmount: string = '1000000000000000000'; + const nativeTokenAmount = '100000000000000'; testForNetwork( network, @@ -149,7 +147,5 @@ describe('BalancerV3 E2E', () => { tokenBAmount, nativeTokenAmount, ); - - // TODO: Add any additional test cases required to test BalancerV3 }); }); diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 2f2661289..b98e71ffb 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -8,6 +8,7 @@ import { SimpleExchangeParam, PoolLiquidity, Logger, + DexExchangeParam, } from '../../types'; import { SwapSide, Network } from '../../constants'; import * as CALLDATA_GAS_COST from '../../calldata-gas-cost'; @@ -18,7 +19,14 @@ import { BalancerV3Data, PoolState, PoolStateMap } from './types'; import { SimpleExchange } from '../simple-exchange'; import { BalancerV3Config, Adapters } from './config'; import { BalancerV3EventPool } from './balancer-v3-pool'; +import { NumberAsString } from '@paraswap/core'; import { SwapKind } from '@balancer-labs/balancer-maths'; +import { Interface } from '@ethersproject/abi'; +import { balancerRouterAbi } from './abi/balancerRouter'; +import { extractReturnAmountPosition } from '../../executor/utils'; + +const MAX_UINT256 = + '115792089237316195423570985008687907853269984665640564039457584007913129639935'; type DeepMutable = { -readonly [P in keyof T]: T[P] extends object ? DeepMutable : T[P]; @@ -28,7 +36,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { protected eventPools: BalancerV3EventPool; readonly hasConstantPriceLargeAmounts = false; - // TODO: set true here if protocols works only with wrapped asset + // TODO: vault can handle native readonly needWrapNative = true; readonly isFeeOnTransferSupported = false; @@ -37,6 +45,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { getDexKeysWithNetwork(BalancerV3Config); logger: Logger; + balancerRouter: Interface; constructor( readonly network: Network, @@ -52,6 +61,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { dexHelper, this.logger, ); + this.balancerRouter = new Interface(balancerRouterAbi); } // Initialize pricing is called once in the start of @@ -78,14 +88,14 @@ export class BalancerV3 extends SimpleExchange implements IDex { side: SwapSide, blockNumber: number, ): Promise { - // const _from = this.dexHelper.config.wrapETH(from); - // const _to = this.dexHelper.config.wrapETH(to); + const _from = this.dexHelper.config.wrapETH(srcToken); + const _to = this.dexHelper.config.wrapETH(destToken); const poolState = this.eventPools.getState(blockNumber); if (poolState === null) return []; return this.findPoolAddressesWithTokens( poolState, - srcToken.address, - destToken.address, + _from.address, + _to.address, ); } @@ -163,7 +173,8 @@ export class BalancerV3 extends SimpleExchange implements IDex { if (!allowedPools.length) return null; - const swapKind = SwapSide.SELL ? SwapKind.GivenIn : SwapKind.GivenOut; + const swapKind = + side === SwapSide.SELL ? SwapKind.GivenIn : SwapKind.GivenOut; const tokenIn = _from.address; const tokenOut = _to.address; @@ -200,22 +211,22 @@ export class BalancerV3 extends SimpleExchange implements IDex { swapKind, ); - const exchangePrice: PoolPrices = { + const poolExchangePrice: PoolPrices = { prices: new Array(amounts.length).fill(0n), unit, data: { - exchange: this.dexKey, // TODO is this needed? + poolAddress: pool.address, }, exchange: this.dexKey, gasCost: 1, // TODO - this will be updated once final profiles done - poolAddresses: [allowedPools[i].address], - poolIdentifier: `${this.dexKey}_${allowedPools[i].address}`, + poolAddresses: [pool.address], + poolIdentifier: `${this.dexKey}_${pool.address}`, }; for (let j = 0; j < amounts.length; j++) { if (amounts[j] < maxSwapAmount) { // Uses balancer maths to calculate swap - exchangePrice.prices[j] = this.eventPools.getSwapResult( + poolExchangePrice.prices[j] = this.eventPools.getSwapResult( pool, amounts[j], tokenIn, @@ -224,7 +235,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ); } } - poolPrices.push(exchangePrice); + poolPrices.push(poolExchangePrice); } catch (err) { this.logger.error(`error fetching prices for pool`); this.logger.error(err); @@ -262,19 +273,87 @@ export class BalancerV3 extends SimpleExchange implements IDex { data: BalancerV3Data, side: SwapSide, ): AdapterExchangeParam { + console.log(`!!!!!!!!!!!! getAdapterParam is being hit !!!!!!`); // TODO: complete me! - const { exchange } = data; + const { poolAddress } = data; // Encode here the payload for adapter const payload = ''; return { - targetExchange: exchange, + targetExchange: + BalancerV3Config.BalancerV3[this.network].balancerRouterAddress, payload, networkFee: '0', }; } + getDexParam( + srcToken: Address, + destToken: Address, + srcAmount: NumberAsString, + destAmount: NumberAsString, + recipient: Address, + data: BalancerV3Data, + side: SwapSide, + ): DexExchangeParam { + if (side === SwapSide.SELL) { + const exchangeData = this.balancerRouter.encodeFunctionData( + 'swapSingleTokenExactIn', + [ + data.poolAddress, + srcToken, + destToken, + srcAmount, + '0', // This should be limit for min amount out. Assume this is set elsewhere via Paraswap contract. + MAX_UINT256, + this.needWrapNative, // TODO vault can handle native assets + '0x', + ], + ); + + return { + needWrapNative: this.needWrapNative, + dexFuncHasRecipient: false, + exchangeData, + // This router handles single swaps + targetExchange: + BalancerV3Config.BalancerV3[this.network].balancerRouterAddress, + returnAmountPos: extractReturnAmountPosition( + this.balancerRouter, + 'swapSingleTokenExactIn', + ), + }; + } else { + const exchangeData = this.balancerRouter.encodeFunctionData( + 'swapSingleTokenExactOut', + [ + data.poolAddress, + srcToken, + destToken, + srcAmount, + MAX_UINT256, // This should be limit for max amount in. Assume this is set elsewhere via Paraswap contract. + MAX_UINT256, + this.needWrapNative, // TODO vault can handle native assets + '0x', + ], + ); + + return { + needWrapNative: this.needWrapNative, + dexFuncHasRecipient: false, + exchangeData, + // Single swaps are submitted via Balancer Router + targetExchange: + BalancerV3Config.BalancerV3[this.network].balancerRouterAddress, + returnAmountPos: extractReturnAmountPosition( + this.balancerRouter, + 'swapSingleTokenExactOut', + ), + }; + } + } + // This is called once before getTopPoolsForToken is // called for multiple tokens. This can be helpful to // update common state required for calculating diff --git a/src/dex/balancer-v3/config.ts b/src/dex/balancer-v3/config.ts index 4cee9db9e..525396210 100644 --- a/src/dex/balancer-v3/config.ts +++ b/src/dex/balancer-v3/config.ts @@ -17,6 +17,7 @@ export const BalancerV3Config: DexConfigMap = { [Network.SEPOLIA]: { vaultAddress: '0x0EF1c156a7986F394d90eD1bEeA6483Cc435F542', apiNetworkName: 'SEPOLIA', + balancerRouterAddress: '0xDd10aDF05379D7C0Ee4bC9c72ecc5C01c40E25b8', }, }, }; diff --git a/src/dex/balancer-v3/types.ts b/src/dex/balancer-v3/types.ts index d313f4d61..8b5674e38 100644 --- a/src/dex/balancer-v3/types.ts +++ b/src/dex/balancer-v3/types.ts @@ -45,15 +45,14 @@ export type ImmutablePoolStateMap = { }; export type BalancerV3Data = { - // TODO: BalancerV3Data is the dex data that is - // returned by the API that can be used for - // tx building. The data structure should be minimal. - // Complete me! - exchange: Address; + poolAddress: string; }; export type DexParams = { // Used to map network > API Name, e.g. 11155111>SEPOLIA apiNetworkName: string; vaultAddress: string; + // This router handles single swaps + // https://github.com/balancer/balancer-v3-monorepo/blob/main/pkg/interfaces/contracts/vault/IRouter.sol + balancerRouterAddress: string; }; diff --git a/src/dex/weth/config.ts b/src/dex/weth/config.ts index 653b9133f..4f2ffc62a 100644 --- a/src/dex/weth/config.ts +++ b/src/dex/weth/config.ts @@ -25,6 +25,9 @@ export const WethConfig: DexConfigMap = { [Network.BASE]: { poolGasCost: WethGasCost, }, + [Network.SEPOLIA]: { + poolGasCost: WethGasCost, + }, }, Wbnb: { [Network.BSC]: { diff --git a/tests/constants-e2e.ts b/tests/constants-e2e.ts index c685588ee..1ef7d2229 100644 --- a/tests/constants-e2e.ts +++ b/tests/constants-e2e.ts @@ -1482,6 +1482,21 @@ export const Tokens: { decimals: 6, }, }, + [Network.SEPOLIA]: { + ETH: { address: ETHER_ADDRESS, decimals: 18 }, + WETH: { + address: '0x7b79995e5f793a07bc00c21412e50ecae098e7f9', + decimals: 18, + }, + bal: { + address: `0xb19382073c7a0addbb56ac6af1808fa49e377b75`, + decimals: 18, + }, + daiAave: { + address: `0xff34b3d4aee8ddcd6f9afffb6fe49bd371b8a357`, + decimals: 18, + }, + }, }; export const Holders: { @@ -1831,6 +1846,11 @@ export const Holders: { crvUSD: '0xBbAbDB1385deA5285113581A7024d6DC04131101', cbETH: '0x50e011dD1e2b4906F1534623cD134B30422bb11E', }, + [Network.SEPOLIA]: { + bal: '0xDb4ff41B4C1222c2b1869A67Be115070688989a2', + daiAave: '0xbB0bc84687fFb642fd90a3D12215e7eC16352A49', + WETH: '0x546e37DAA15cdb82fd1a717E5dEEa4AF08D4349A', + }, }; export const SmartTokens = Object.keys(Tokens).reduce((acc, _network) => { @@ -1856,6 +1876,7 @@ export const NativeTokenSymbols: { [network: number]: string } = { [Network.ARBITRUM]: 'ETH', [Network.OPTIMISM]: 'ETH', [Network.BASE]: 'ETH', + [Network.SEPOLIA]: 'ETH', }; export const WrappedNativeTokenSymbols: { [network: number]: string } = { @@ -1867,4 +1888,5 @@ export const WrappedNativeTokenSymbols: { [network: number]: string } = { [Network.ARBITRUM]: 'WETH', [Network.OPTIMISM]: 'WETH', [Network.BASE]: 'WETH', + [Network.SEPOLIA]: 'WETH', }; From 724cb6eb5b91eef2f324e6deaa05e864e663c3c7 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 10 Oct 2024 13:41:18 +0100 Subject: [PATCH 06/66] feat: Add timer to periodically check for new pools and update state. --- src/dex/balancer-v3/balancer-v3-pool.ts | 46 +++++++++++++++++++++++++ src/dex/balancer-v3/balancer-v3.ts | 21 ++++++++++- src/dex/balancer-v3/getOnChainState.ts | 2 +- src/dex/balancer-v3/getPoolsApi.ts | 21 ++++++++--- 4 files changed, 84 insertions(+), 6 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index cd277b697..04fd09317 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -124,6 +124,52 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { return filteredPools; } + async getUpdatedPoolState( + existingPoolState: DeepReadonly, + ): Promise | null> { + // Get all latest pools from API + const apiPoolStateMap = await getPoolsApi(this.network); + + // Filter out pools that already exist in existing state + const newApiPools = Object.entries(apiPoolStateMap).reduce( + (acc, [address, pool]) => { + if (!existingPoolState[address]) { + acc[address] = pool; + } + return acc; + }, + {} as typeof apiPoolStateMap, + ); + + // If no new pools return + if (Object.keys(newApiPools).length === 0) { + return null; + } + + // Only get on-chain state for new pools + const newOnChainPools = await getOnChainState( + this.network, + newApiPools, + this.dexHelper, + this.interfaces, + ); + + // Filter out pools with hooks and paused pools from new state + // TODO this won't be necessary once API has this filter option + const filteredNewPools = Object.entries(newOnChainPools) + .filter(([_, pool]) => !(pool.hasHook || pool.isPoolPaused)) + .reduce((acc, [address, pool]) => { + acc[address] = pool; + return acc; + }, {} as PoolStateMap); + + // Merge existing pools with new pools + return { + ...existingPoolState, + ...filteredNewPools, + }; + } + poolBalanceChangedEvent( event: any, state: DeepReadonly, diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index b98e71ffb..6344adef0 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -27,6 +27,7 @@ import { extractReturnAmountPosition } from '../../executor/utils'; const MAX_UINT256 = '115792089237316195423570985008687907853269984665640564039457584007913129639935'; +const POOL_UPDATE_TTL = 10; type DeepMutable = { -readonly [P in keyof T]: T[P] extends object ? DeepMutable : T[P]; @@ -46,6 +47,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { logger: Logger; balancerRouter: Interface; + updateNewPoolsTimer?: NodeJS.Timer; constructor( readonly network: Network, @@ -70,6 +72,16 @@ export class BalancerV3 extends SimpleExchange implements IDex { // implement this function async initializePricing(blockNumber: number) { await this.eventPools.initialize(blockNumber); + if (!this.updateNewPoolsTimer) { + // This will periodically query API and add any new pools to pool state + this.updateNewPoolsTimer = setInterval(async () => { + try { + await this.updatePoolState(); + } catch (e) { + this.logger.error(`${this.dexKey}: Failed to update pool state:`, e); + } + }, POOL_UPDATE_TTL * 1000); + } } // Returns the list of contract adapters (name and index) @@ -360,7 +372,14 @@ export class BalancerV3 extends SimpleExchange implements IDex { // getTopPoolsForToken. It is optional for a DEX // to implement this async updatePoolState(): Promise { - // TODO: complete me! + const blockNumber = await this.dexHelper.provider.getBlockNumber(); + // We just want the current saved state + const currentState = this.eventPools.getState(1) || {}; + const updatedPoolState = await this.eventPools.getUpdatedPoolState( + currentState, + ); + if (updatedPoolState) + this.eventPools.setState(updatedPoolState, blockNumber); } // Returns list of top pools based on liquidity. Max diff --git a/src/dex/balancer-v3/getOnChainState.ts b/src/dex/balancer-v3/getOnChainState.ts index 465ce4364..28058b3b8 100644 --- a/src/dex/balancer-v3/getOnChainState.ts +++ b/src/dex/balancer-v3/getOnChainState.ts @@ -245,7 +245,7 @@ export async function getOnChainState( interfaces: { [name: string]: Interface; }, - blockNumber: number, + blockNumber?: number, ): Promise { const multiCallData = Object.entries(immutablePoolStateMap) .map(([address, pool]) => { diff --git a/src/dex/balancer-v3/getPoolsApi.ts b/src/dex/balancer-v3/getPoolsApi.ts index 58fd48e8b..83af683be 100644 --- a/src/dex/balancer-v3/getPoolsApi.ts +++ b/src/dex/balancer-v3/getPoolsApi.ts @@ -24,15 +24,28 @@ interface QueryResponse { function createQuery( networkId: number, - timestamp: number, poolTypes: SUPPORTED_POOLS[], + timestamp?: number, ): string { const poolTypesString = poolTypes.map(type => `${type}`).join(', '); const networkString = BalancerV3Config.BalancerV3[networkId].apiNetworkName; + // Build the where clause conditionally + const whereClause = { + chainIn: networkString, + protocolVersionIn: 3, + hasHook: false, + poolTypeIn: `[${poolTypesString}]`, + ...(timestamp && { createTime: `{lt: ${timestamp}}` }), + }; + + // Convert where clause to string, filtering out undefined values + const whereString = Object.entries(whereClause) + .map(([key, value]) => `${key}: ${value}`) + .join(', '); return ` query MyQuery { poolGetAggregatorPools( - where: {chainIn: ${networkString}, protocolVersionIn: 3, poolTypeIn: [${poolTypesString}], createTime: {lt: ${timestamp}}} + where: {${whereString}} ) { id type @@ -69,13 +82,13 @@ function toImmutablePoolStateMap(pools: Pool[]): ImmutablePoolStateMap { // Any data from API will be immutable. Mutable data such as balances, etc will be fetched via onchain/event state. export async function getPoolsApi( network: number, - timestamp: number, + timestamp?: number, ): Promise { try { const query = createQuery( network, - timestamp, Object.values(SUPPORTED_POOLS), + timestamp, ); const response = await axios.post( apiUrl, From 46c2791064ca5db51ce47121a87caa75947e0dd1 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 10 Oct 2024 16:35:49 +0100 Subject: [PATCH 07/66] feat: Add timer to periodically refresh pool token rates and update state. --- src/dex/balancer-v3/balancer-v3-pool.ts | 73 ++++++++++++++++++++++++- src/dex/balancer-v3/balancer-v3.ts | 35 ++++++++---- 2 files changed, 96 insertions(+), 12 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 04fd09317..30b3e2eb0 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -8,7 +8,7 @@ import { IDexHelper } from '../../dex-helper/idex-helper'; import { PoolState, PoolStateMap } from './types'; import { getPoolsApi } from './getPoolsApi'; import { vaultExtensionAbi_V3 } from './abi/vaultExtension.V3'; -import { getOnChainState } from './getOnChainState'; +import { decodeThrowError, getOnChainState } from './getOnChainState'; import { BalancerV3Config } from './config'; import { SwapKind, Vault } from '@balancer-labs/balancer-maths'; @@ -233,4 +233,75 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { pool, ); } + + /** + * Retrieves any new pools via API/multicall and adds to state + */ + async updateStatePools(): Promise { + const blockNumber = await this.dexHelper.provider.getBlockNumber(); + // We just want the current saved state + const currentState = this.getStaleState() || {}; + const updatedPoolState = await this.getUpdatedPoolState(currentState); + if (updatedPoolState) this.setState(updatedPoolState, blockNumber); + } + + /** + * Uses multicall to get onchain token rate for each pool then updates pool state + */ + async updateStatePoolRates(): Promise { + // Get existing state + const poolState = _.cloneDeep(this.getStaleState()) as PoolStateMap; + if (!poolState) return; + + // Fetch onchain pool rates + const poolRates = await this.getPoolRates(Object.keys(poolState)); + + // Update each pools rate + poolRates.forEach(({ poolAddress, tokenRates }, i) => { + poolState[poolAddress].tokenRates = tokenRates; + }); + + // Update state + const blockNumber = await this.dexHelper.provider.getBlockNumber(); + this.setState(poolState, blockNumber); + } + + private async getPoolRates(poolAddresses: string[]) { + // For each pool make the getPoolTokenRates call + const multiCallData = poolAddresses.map(address => { + return { + target: BalancerV3Config.BalancerV3[this.network].vaultAddress, + callData: this.interfaces['VAULT'].encodeFunctionData( + 'getPoolTokenRates', + [address], + ), + }; + }); + // 500 is an arbitrary number chosen based on the blockGasLimit + const slicedMultiCallData = _.chunk(multiCallData, 500); + + // Make the multicall + const multicallData = ( + await Promise.all( + slicedMultiCallData.map(async _multiCallData => + this.dexHelper.multiContract.methods + .tryAggregate(false, _multiCallData) + .call({}), + ), + ) + ).flat(); + + return poolAddresses.map((address, i) => { + const tokenRateResult = decodeThrowError( + this.interfaces['VAULT'], + 'getPoolTokenRates', + multicallData[i], + address, + ); + return { + poolAddress: address, + tokenRates: tokenRateResult.tokenRates.map((r: string) => BigInt(r)), + }; + }); + } } diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 6344adef0..2ce70a410 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -5,7 +5,6 @@ import { ExchangePrices, PoolPrices, AdapterExchangeParam, - SimpleExchangeParam, PoolLiquidity, Logger, DexExchangeParam, @@ -27,7 +26,8 @@ import { extractReturnAmountPosition } from '../../executor/utils'; const MAX_UINT256 = '115792089237316195423570985008687907853269984665640564039457584007913129639935'; -const POOL_UPDATE_TTL = 10; +const POOL_UPDATE_TTL = 5 * 60; // 5mins +const RATE_UPDATE_TTL = 30 * 60; // 30mins type DeepMutable = { -readonly [P in keyof T]: T[P] extends object ? DeepMutable : T[P]; @@ -48,6 +48,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { logger: Logger; balancerRouter: Interface; updateNewPoolsTimer?: NodeJS.Timer; + updateRatesTimer?: NodeJS.Timer; constructor( readonly network: Network, @@ -72,8 +73,9 @@ export class BalancerV3 extends SimpleExchange implements IDex { // implement this function async initializePricing(blockNumber: number) { await this.eventPools.initialize(blockNumber); + + // This will periodically query API and add any new pools to pool state if (!this.updateNewPoolsTimer) { - // This will periodically query API and add any new pools to pool state this.updateNewPoolsTimer = setInterval(async () => { try { await this.updatePoolState(); @@ -82,6 +84,17 @@ export class BalancerV3 extends SimpleExchange implements IDex { } }, POOL_UPDATE_TTL * 1000); } + + // This will periodically refresh tokenRates with onchain state + if (!this.updateRatesTimer) { + this.updateRatesTimer = setInterval(async () => { + try { + await this.updateStatePoolRates(); + } catch (e) { + this.logger.error(`${this.dexKey}: Failed to update pool rates:`, e); + } + }, RATE_UPDATE_TTL * 1000); + } } // Returns the list of contract adapters (name and index) @@ -366,20 +379,20 @@ export class BalancerV3 extends SimpleExchange implements IDex { } } + /** + * Uses multicall to get onchain token rate for each pool then updates pool state + */ + async updateStatePoolRates(): Promise { + await this.eventPools.updateStatePoolRates(); + } + // This is called once before getTopPoolsForToken is // called for multiple tokens. This can be helpful to // update common state required for calculating // getTopPoolsForToken. It is optional for a DEX // to implement this async updatePoolState(): Promise { - const blockNumber = await this.dexHelper.provider.getBlockNumber(); - // We just want the current saved state - const currentState = this.eventPools.getState(1) || {}; - const updatedPoolState = await this.eventPools.getUpdatedPoolState( - currentState, - ); - if (updatedPoolState) - this.eventPools.setState(updatedPoolState, blockNumber); + await this.eventPools.updateStatePools(); } // Returns list of top pools based on liquidity. Max From abf10b00808cc9f1a39968ecff1b9d3b483a5924 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 11 Oct 2024 13:14:32 +0100 Subject: [PATCH 08/66] feat: WIP add amp update handling. Needs SC update to finish. --- src/dex/balancer-v3/balancer-v3-pool.ts | 8 ++++++++ src/dex/balancer-v3/getOnChainState.ts | 6 ++++++ src/dex/balancer-v3/types.ts | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 30b3e2eb0..d72f4cefd 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -223,6 +223,14 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { tokenOut: string, swapKind: SwapKind, ): bigint { + if (pool.poolType === 'Stable' && 'amp' in pool) { + if (pool.ampIsUpdating) { + console.log(`!!!!!!! need to handle this correctly once SC updated`); + /* + Will be able to calculate current amp using pool amp start/stop time & values + */ + } + } return this.vault.swap( { amountRaw, diff --git a/src/dex/balancer-v3/getOnChainState.ts b/src/dex/balancer-v3/getOnChainState.ts index 28058b3b8..85dc3f6a1 100644 --- a/src/dex/balancer-v3/getOnChainState.ts +++ b/src/dex/balancer-v3/getOnChainState.ts @@ -216,8 +216,14 @@ const poolOnChain: Record< throw new Error( `Failed to get result for getAmplificationParameter for ${poolAddress}`, ); + // TODO requested SC to add view to stable pool to get amp update state if it is currently updating return { amp: resultAmp[0].toBigInt(), + ampIsUpdating: !!resultAmp[1], + ampStartTime: 0n, + ampStopTime: 0n, + ampStartValue: 0n, + ampEndValue: 0n, }; }, }, diff --git a/src/dex/balancer-v3/types.ts b/src/dex/balancer-v3/types.ts index 8b5674e38..a032a35b6 100644 --- a/src/dex/balancer-v3/types.ts +++ b/src/dex/balancer-v3/types.ts @@ -34,6 +34,11 @@ export type PoolState = // Stable Pool specific mutable data export interface StableMutableState { amp: bigint; + ampIsUpdating: boolean; + ampStartValue: bigint; + ampEndValue: bigint; + ampStartTime: bigint; + ampStopTime: bigint; } export type PoolStateMap = { From 554bced8c5ed7eec565fb5ef32b15f8f366090d1 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 11 Oct 2024 13:22:26 +0100 Subject: [PATCH 09/66] feat: Add fee events and handling. --- src/dex/balancer-v3/balancer-v3-pool.ts | 38 ++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index d72f4cefd..d8f398f07 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -59,6 +59,10 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { // Add handlers this.handlers['PoolBalanceChanged'] = this.poolBalanceChangedEvent.bind(this); + this.handlers['AggregateSwapFeePercentageChanged'] = + this.poolAggregateSwapFeePercentageEvent.bind(this); + this.handlers['SwapFeePercentageChanged'] = + this.poolSwapFeePercentageChangedEvent.bind(this); // replicates V3 maths with fees, pool and hook logic this.vault = new Vault(); @@ -176,7 +180,7 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { log: Readonly, ): DeepReadonly | null { const poolAddress = event.args.pool.toLowerCase(); - // Vault will send events from any pools, some of which are not officially supported by Balancer + // Vault will send events from all pools, some of which are not officially supported by Balancer if (!state[poolAddress]) { return null; } @@ -193,6 +197,38 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { return newState; } + poolAggregateSwapFeePercentageEvent( + event: any, + state: DeepReadonly, + log: Readonly, + ): DeepReadonly | null { + const poolAddress = event.args.pool.toLowerCase(); + // Vault will send events from all pools, some of which are not officially supported by Balancer + if (!state[poolAddress]) { + return null; + } + const newState = _.cloneDeep(state) as PoolStateMap; + newState[poolAddress].aggregateSwapFee = BigInt( + event.args.aggregateSwapFeePercentage, + ); + return newState; + } + + poolSwapFeePercentageChangedEvent( + event: any, + state: DeepReadonly, + log: Readonly, + ): DeepReadonly | null { + const poolAddress = event.args.pool.toLowerCase(); + // Vault will send events from all pools, some of which are not officially supported by Balancer + if (!state[poolAddress]) { + return null; + } + const newState = _.cloneDeep(state) as PoolStateMap; + newState[poolAddress].swapFee = BigInt(event.args.swapFeePercentage); + return newState; + } + getMaxSwapAmount( pool: PoolState, tokenIn: string, From 2abcd65aec8f132bb17b9cf16a662cc49eede157 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 11 Oct 2024 13:32:21 +0100 Subject: [PATCH 10/66] feat: Add handling for PoolPausedStateChanged event. --- .../balancer-v3/balancer-v3-events.test.ts | 1 + src/dex/balancer-v3/balancer-v3-pool.ts | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/dex/balancer-v3/balancer-v3-events.test.ts b/src/dex/balancer-v3/balancer-v3-events.test.ts index b8eb2e777..3ad42c8d1 100644 --- a/src/dex/balancer-v3/balancer-v3-events.test.ts +++ b/src/dex/balancer-v3/balancer-v3-events.test.ts @@ -75,6 +75,7 @@ describe('BalancerV3 EventPool', function () { let balancerV3Pool: BalancerV3EventPool; // vault -> EventMappings + // TODO once we have a new test deployment add tests for: AggregateSwapFeePercentageChanged, SwapFeePercentageChanged, PoolPausedStateChanged const eventsToTest: Record = { [BalancerV3Config.BalancerV3[network].vaultAddress]: { // 6806714: diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index d8f398f07..2d42e47a9 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -63,6 +63,8 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { this.poolAggregateSwapFeePercentageEvent.bind(this); this.handlers['SwapFeePercentageChanged'] = this.poolSwapFeePercentageChangedEvent.bind(this); + this.handlers['PoolPausedStateChanged'] = + this.poolPausedStateChanged.bind(this); // replicates V3 maths with fees, pool and hook logic this.vault = new Vault(); @@ -229,6 +231,24 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { return newState; } + poolPausedStateChanged( + event: any, + state: DeepReadonly, + log: Readonly, + ): DeepReadonly | null { + // Unpaused pools will be added with correct state during updateStatePools + if (event.args.paused === false) return null; + const poolAddress = event.args.pool.toLowerCase(); + // Vault will send events from all pools, some of which are not officially supported by Balancer + if (!state[poolAddress]) { + return null; + } + // Remove paused pool from state as it can't be swapped against + const newState = _.cloneDeep(state) as PoolStateMap; + delete newState[poolAddress]; + return newState; + } + getMaxSwapAmount( pool: PoolState, tokenIn: string, From ed7bd917f1fb2c782053f9be4daf13a8da27a1a1 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 11 Oct 2024 13:40:13 +0100 Subject: [PATCH 11/66] feat: Implement releaseResources. --- src/dex/balancer-v3/balancer-v3.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 2ce70a410..fbe6fd19c 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -272,6 +272,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { return null; } + // This is a temp helper until we change maths library type to match private mapToPoolType(apiPoolType: string): string { if (apiPoolType === 'STABLE') return 'Stable'; else if (apiPoolType === 'WEIGHTED') return 'Weighted'; @@ -405,9 +406,20 @@ export class BalancerV3 extends SimpleExchange implements IDex { return []; } - // This is optional function in case if your implementation has acquired any resources - // you need to release for graceful shutdown. For example, it may be any interval timer releaseResources(): AsyncOrSync { - // TODO: complete me! + if (this.updateNewPoolsTimer) { + clearInterval(this.updateNewPoolsTimer); + this.updateNewPoolsTimer = undefined; + this.logger.info( + `${this.dexKey}: cleared updateNewPoolsTimer before shutting down`, + ); + } + if (this.updateRatesTimer) { + clearInterval(this.updateRatesTimer); + this.updateRatesTimer = undefined; + this.logger.info( + `${this.dexKey}: cleared updateRatesTimer before shutting down`, + ); + } } } From aaa988c756ed08f5677d2991bfa4fc7fafd3243b Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 11 Oct 2024 14:24:37 +0100 Subject: [PATCH 12/66] feat: Implement getTopPoolsForToken. --- src/dex/balancer-v3/balancer-v3.ts | 23 ++++++- src/dex/balancer-v3/getTopPoolsApi.ts | 88 +++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 src/dex/balancer-v3/getTopPoolsApi.ts diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index fbe6fd19c..287be9e2a 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -23,6 +23,7 @@ import { SwapKind } from '@balancer-labs/balancer-maths'; import { Interface } from '@ethersproject/abi'; import { balancerRouterAbi } from './abi/balancerRouter'; import { extractReturnAmountPosition } from '../../executor/utils'; +import { getTopPoolsApi } from './getTopPoolsApi'; const MAX_UINT256 = '115792089237316195423570985008687907853269984665640564039457584007913129639935'; @@ -400,10 +401,26 @@ export class BalancerV3 extends SimpleExchange implements IDex { // limit number pools should be returned. async getTopPoolsForToken( tokenAddress: Address, - limit: number, + count: number, ): Promise { - //TODO: complete me! - return []; + const poolsWithToken = Object.entries(this.eventPools.getStaleState() || {}) + .filter(([, poolState]) => { + return poolState.tokens.includes(tokenAddress); + }) + .map(([address]) => address); + + const topPools = await getTopPoolsApi(this.network, poolsWithToken, count); + + return topPools.map(pool => { + return { + exchange: this.dexKey, + address: pool.address, + liquidityUSD: parseFloat(pool.dynamicData.totalLiquidity), + connectorTokens: pool.poolTokens.filter( + t => t.address !== tokenAddress, + ), + }; + }); } releaseResources(): AsyncOrSync { diff --git a/src/dex/balancer-v3/getTopPoolsApi.ts b/src/dex/balancer-v3/getTopPoolsApi.ts new file mode 100644 index 000000000..eb3b48aaa --- /dev/null +++ b/src/dex/balancer-v3/getTopPoolsApi.ts @@ -0,0 +1,88 @@ +import axios from 'axios'; +import { apiUrl, BalancerV3Config } from './config'; + +interface PoolToken { + address: string; + decimals: number; +} + +interface Pool { + address: string; + poolTokens: PoolToken[]; + dynamicData: { + totalLiquidity: string; + }; +} + +interface QueryResponse { + data: { + poolGetAggregatorPools: Pool[]; + }; +} + +function createQuery( + networkId: number, + poolsFilter: string[], + count: number, +): string { + const networkString = BalancerV3Config.BalancerV3[networkId].apiNetworkName; + const poolIdString = poolsFilter.map(a => `"${a}"`).join(', '); + // Build the where clause conditionally + const whereClause = { + chainIn: networkString, + protocolVersionIn: 3, + hasHook: false, + idIn: `[${poolIdString}]`, + }; + + // Convert where clause to string, filtering out undefined values + const whereString = Object.entries(whereClause) + .map(([key, value]) => `${key}: ${value}`) + .join(', '); + return ` + query MyQuery { + poolGetAggregatorPools( + where: {${whereString}} + first: ${count} + orderBy: totalLiquidity + orderDirection: desc + ) { + address + poolTokens { + address + decimals + } + dynamicData { + totalLiquidity + } + } + } + `; +} + +export async function getTopPoolsApi( + networkId: number, + poolsFilter: string[], + count: number, +): Promise { + try { + const query = createQuery(networkId, poolsFilter, count); + const response = await axios.post( + apiUrl, + { + query, + }, + { + headers: { + 'Content-Type': 'application/json', + }, + }, + ); + + const pools = response.data.data.poolGetAggregatorPools; + return pools; + } catch (error) { + console.error('Error executing GraphQL query:', error); + throw error; + } +} From 2a36478231d05c5fadc2c0c6dc29a915defb9e42 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 11 Oct 2024 14:25:18 +0100 Subject: [PATCH 13/66] debug: Add run-dex-integration-v3 script. --- scripts/run-dex-integration-v3.ts | 68 +++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 scripts/run-dex-integration-v3.ts diff --git a/scripts/run-dex-integration-v3.ts b/scripts/run-dex-integration-v3.ts new file mode 100644 index 000000000..23ef70b35 --- /dev/null +++ b/scripts/run-dex-integration-v3.ts @@ -0,0 +1,68 @@ +// npx ts-node scripts/run-dex-integration-v3.ts +/* eslint-disable no-console */ +import dotenv from 'dotenv'; +dotenv.config(); + +import { Network, SwapSide } from '../src/constants'; +import { BalancerV3 } from '../src/dex/balancer-v3/balancer-v3'; +import { DummyDexHelper } from '../src/dex-helper/index'; +import { BI_POWS } from '../src/bigint-constants'; + +const stataUSDC = { + address: '0x8a88124522dbbf1e56352ba3de1d9f78c143751e'.toLowerCase(), + decimals: 6, +}; + +const stataDAI = { + address: '0xde46e43f46ff74a23a65ebb0580cbe3dfe684a17'.toLowerCase(), + decimals: 18, +}; + +const bal = { + address: '0xb19382073c7a0addbb56ac6af1808fa49e377b75'.toLowerCase(), + decimals: 18, +}; + +const daiAave = { + address: '0xff34b3d4aee8ddcd6f9afffb6fe49bd371b8a357'.toLowerCase(), + decimals: 18, +}; + +const amounts = [0n, BI_POWS[18], 2000000000000000000n]; + +async function main() { + const dexHelper = new DummyDexHelper(Network.SEPOLIA); + const blocknumber = await dexHelper.web3Provider.eth.getBlockNumber(); + + const balancerV3 = new BalancerV3(Network.SEPOLIA, 'BalancerV3', dexHelper); + + await balancerV3.initializePricing(blocknumber); + + // const from = stataDAI; + // const to = stataUSDC; + const from = bal; + const to = daiAave; + + const pools = await balancerV3.getPoolIdentifiers( + from, + to, + SwapSide.SELL, + blocknumber, + ); + console.log('Pool Identifiers: ', from.address, to.address, pools); + + const prices = await balancerV3.getPricesVolume( + from, + to, + amounts, + SwapSide.SELL, + blocknumber, + pools, + ); + console.log('Pool Prices: ', prices); + + const poolLiquidity = await balancerV3.getTopPoolsForToken(from.address, 10); + console.log('Top Pools:', poolLiquidity); +} + +main(); From 10d170cc6dfe2263093a1a9105f501a4236fc91d Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Mon, 14 Oct 2024 10:01:06 +0100 Subject: [PATCH 14/66] chore: Update to work with deploy9. Add event handling for totalSupply. --- src/dex/balancer-v3/abi/balancerRouter.ts | 2334 +++++------ src/dex/balancer-v3/abi/vaultExtension.V3.ts | 3625 +++++++++-------- .../balancer-v3/balancer-v3-events.test.ts | 8 +- src/dex/balancer-v3/balancer-v3-pool.ts | 1 + src/dex/balancer-v3/config.ts | 4 +- src/dex/balancer-v3/getOnChainState.ts | 2 +- 6 files changed, 3011 insertions(+), 2963 deletions(-) diff --git a/src/dex/balancer-v3/abi/balancerRouter.ts b/src/dex/balancer-v3/abi/balancerRouter.ts index da5ff88c5..c2431342e 100644 --- a/src/dex/balancer-v3/abi/balancerRouter.ts +++ b/src/dex/balancer-v3/abi/balancerRouter.ts @@ -1,1169 +1,1171 @@ export const balancerRouterAbi = [ - { - inputs: [ - { internalType: 'contract IVault', name: 'vault', type: 'address' }, - { internalType: 'contract IWETH', name: 'weth', type: 'address' }, - { - internalType: 'contract IPermit2', - name: 'permit2', + { + inputs: [ + { internalType: 'contract IVault', name: 'vault', type: 'address' }, + { internalType: 'contract IWETH', name: 'weth', type: 'address' }, + { + internalType: 'contract IPermit2', + name: 'permit2', + type: 'address', + }, + ], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [{ internalType: 'address', name: 'target', type: 'address' }], + name: 'AddressEmptyCode', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'account', type: 'address' }], + name: 'AddressInsufficientBalance', + type: 'error', + }, + { inputs: [], name: 'EthTransfer', type: 'error' }, + { inputs: [], name: 'FailedInnerCall', type: 'error' }, + { inputs: [], name: 'InsufficientEth', type: 'error' }, + { inputs: [], name: 'ReentrancyGuardReentrantCall', type: 'error' }, + { + inputs: [ + { internalType: 'uint8', name: 'bits', type: 'uint8' }, + { internalType: 'uint256', name: 'value', type: 'uint256' }, + ], + name: 'SafeCastOverflowedUintDowncast', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'token', type: 'address' }], + name: 'SafeERC20FailedOperation', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], + name: 'SenderIsNotVault', + type: 'error', + }, + { inputs: [], name: 'SwapDeadline', type: 'error' }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'maxAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'addLiquidityCustom', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'maxAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { + internalType: 'enum AddLiquidityKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouterCommon.AddLiquidityHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'addLiquidityHook', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'maxAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'exactBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'addLiquidityProportional', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + { + internalType: 'uint256', + name: 'exactBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'addLiquiditySingleTokenExactOut', + outputs: [{ internalType: 'uint256', name: 'amountIn', type: 'uint256' }], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactSharesToIssue', + type: 'uint256', + }, + ], + name: 'addLiquidityToBuffer', + outputs: [ + { + internalType: 'uint256', + name: 'amountUnderlyingRaw', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'amountWrappedRaw', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactSharesToIssue', + type: 'uint256', + }, + { internalType: 'address', name: 'sharesOwner', type: 'address' }, + ], + name: 'addLiquidityToBufferHook', + outputs: [ + { + internalType: 'uint256', + name: 'amountUnderlyingRaw', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'amountWrappedRaw', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'exactAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'addLiquidityUnbalanced', + outputs: [ + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'donate', + outputs: [], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [], + name: 'getSender', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'exactAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'initialize', + outputs: [ + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amountUnderlyingRaw', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'amountWrappedRaw', + type: 'uint256', + }, + ], + name: 'initializeBuffer', + outputs: [ + { internalType: 'uint256', name: 'issuedShares', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amountUnderlyingRaw', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'amountWrappedRaw', + type: 'uint256', + }, + { internalType: 'address', name: 'sharesOwner', type: 'address' }, + ], + name: 'initializeBufferHook', + outputs: [ + { internalType: 'uint256', name: 'issuedShares', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'exactAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouter.InitializeHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'initializeHook', + outputs: [ + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes[]', name: 'data', type: 'bytes[]' }], + name: 'multicall', + outputs: [{ internalType: 'bytes[]', name: 'results', type: 'bytes[]' }], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { internalType: 'address', name: 'token', type: 'address' }, + { internalType: 'address', name: 'owner', type: 'address' }, + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + { internalType: 'uint256', name: 'nonce', type: 'uint256' }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + ], + internalType: 'struct IRouterCommon.PermitApproval[]', + name: 'permitBatch', + type: 'tuple[]', + }, + { + internalType: 'bytes[]', + name: 'permitSignatures', + type: 'bytes[]', + }, + { + components: [ + { + components: [ + { + internalType: 'address', + name: 'token', type: 'address', - }, - ], - stateMutability: 'nonpayable', - type: 'constructor', - }, - { - inputs: [{ internalType: 'address', name: 'target', type: 'address' }], - name: 'AddressEmptyCode', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'account', type: 'address' }], - name: 'AddressInsufficientBalance', - type: 'error', - }, - { inputs: [], name: 'EthTransfer', type: 'error' }, - { inputs: [], name: 'FailedInnerCall', type: 'error' }, - { inputs: [], name: 'InsufficientEth', type: 'error' }, - { inputs: [], name: 'ReentrancyGuardReentrantCall', type: 'error' }, - { - inputs: [{ internalType: 'address', name: 'token', type: 'address' }], - name: 'SafeERC20FailedOperation', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], - name: 'SenderIsNotVault', - type: 'error', - }, - { inputs: [], name: 'SwapDeadline', type: 'error' }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256[]', - name: 'maxAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'addLiquidityCustom', - outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256[]', - name: 'maxAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { - internalType: 'enum AddLiquidityKind', - name: 'kind', - type: 'uint8', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - internalType: 'struct IRouterCommon.AddLiquidityHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'addLiquidityHook', - outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256[]', - name: 'maxAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'exactBptAmountOut', - type: 'uint256', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'addLiquidityProportional', - outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, - { - internalType: 'uint256', - name: 'exactBptAmountOut', - type: 'uint256', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'addLiquiditySingleTokenExactOut', - outputs: [ - { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amountUnderlyingRaw', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'amountWrappedRaw', - type: 'uint256', - }, - { internalType: 'address', name: 'sharesOwner', type: 'address' }, - ], - name: 'addLiquidityToBuffer', - outputs: [ - { internalType: 'uint256', name: 'issuedShares', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amountUnderlyingRaw', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'amountWrappedRaw', - type: 'uint256', - }, - { internalType: 'address', name: 'sharesOwner', type: 'address' }, - ], - name: 'addLiquidityToBufferHook', - outputs: [ - { internalType: 'uint256', name: 'issuedShares', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256[]', - name: 'exactAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'addLiquidityUnbalanced', - outputs: [ - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'donate', - outputs: [], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [], - name: 'getSender', - outputs: [{ internalType: 'address', name: '', type: 'address' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'exactAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'initialize', - outputs: [ - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'exactAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - internalType: 'struct IRouter.InitializeHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'initializeHook', - outputs: [ - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'bytes[]', name: 'data', type: 'bytes[]' }], - name: 'multicall', - outputs: [ - { internalType: 'bytes[]', name: 'results', type: 'bytes[]' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { internalType: 'address', name: 'token', type: 'address' }, - { internalType: 'address', name: 'owner', type: 'address' }, - { - internalType: 'address', - name: 'spender', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amount', - type: 'uint256', - }, - { internalType: 'uint256', name: 'nonce', type: 'uint256' }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - ], - internalType: 'struct IRouterCommon.PermitApproval[]', - name: 'permitBatch', - type: 'tuple[]', - }, - { - internalType: 'bytes[]', - name: 'permitSignatures', - type: 'bytes[]', - }, - { - components: [ - { - components: [ - { - internalType: 'address', - name: 'token', - type: 'address', - }, - { - internalType: 'uint160', - name: 'amount', - type: 'uint160', - }, - { - internalType: 'uint48', - name: 'expiration', - type: 'uint48', - }, - { - internalType: 'uint48', - name: 'nonce', - type: 'uint48', - }, - ], - internalType: - 'struct IAllowanceTransfer.PermitDetails[]', - name: 'details', - type: 'tuple[]', - }, - { - internalType: 'address', - name: 'spender', - type: 'address', - }, - { - internalType: 'uint256', - name: 'sigDeadline', - type: 'uint256', - }, - ], - internalType: 'struct IAllowanceTransfer.PermitBatch', - name: 'permit2Batch', - type: 'tuple', - }, - { internalType: 'bytes', name: 'permit2Signature', type: 'bytes' }, - { internalType: 'bytes[]', name: 'multicallData', type: 'bytes[]' }, - ], - name: 'permitBatchAndCall', - outputs: [ - { internalType: 'bytes[]', name: 'results', type: 'bytes[]' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256[]', - name: 'maxAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'queryAddLiquidityCustom', - outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256[]', - name: 'maxAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { - internalType: 'enum AddLiquidityKind', - name: 'kind', - type: 'uint8', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - internalType: 'struct IRouterCommon.AddLiquidityHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'queryAddLiquidityHook', - outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256', - name: 'exactBptAmountOut', - type: 'uint256', - }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'queryAddLiquidityProportional', - outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountOut', - type: 'uint256', - }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'queryAddLiquiditySingleTokenExactOut', - outputs: [ - { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256[]', - name: 'exactAmountsIn', - type: 'uint256[]', - }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'queryAddLiquidityUnbalanced', - outputs: [ - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256', - name: 'maxBptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'queryRemoveLiquidityCustom', - outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'maxBptAmountIn', - type: 'uint256', - }, - { - internalType: 'enum RemoveLiquidityKind', - name: 'kind', - type: 'uint8', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - internalType: 'struct IRouterCommon.RemoveLiquidityHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'queryRemoveLiquidityHook', - outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'queryRemoveLiquidityProportional', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - ], - name: 'queryRemoveLiquidityRecovery', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'sender', type: 'address' }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - ], - name: 'queryRemoveLiquidityRecoveryHook', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'queryRemoveLiquiditySingleTokenExactIn', - outputs: [ - { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'queryRemoveLiquiditySingleTokenExactOut', - outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'enum SwapKind', - name: 'kind', - type: 'uint8', - }, - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amountGiven', - type: 'uint256', - }, - { internalType: 'uint256', name: 'limit', type: 'uint256' }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - internalType: 'struct IRouter.SwapSingleTokenHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'querySwapHook', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { internalType: 'uint256', name: 'exactAmountIn', type: 'uint256' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'querySwapSingleTokenExactIn', - outputs: [ - { - internalType: 'uint256', - name: 'amountCalculated', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'querySwapSingleTokenExactOut', - outputs: [ - { - internalType: 'uint256', - name: 'amountCalculated', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256', - name: 'maxBptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'removeLiquidityCustom', - outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - internalType: 'uint256', - name: 'sharesToRemove', - type: 'uint256', - }, - ], - name: 'removeLiquidityFromBuffer', - outputs: [ - { internalType: 'uint256', name: '', type: 'uint256' }, - { internalType: 'uint256', name: '', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - internalType: 'uint256', - name: 'sharesToRemove', - type: 'uint256', - }, - { internalType: 'address', name: 'sharesOwner', type: 'address' }, - ], - name: 'removeLiquidityFromBufferHook', - outputs: [ - { - internalType: 'uint256', - name: 'removedUnderlyingBalanceRaw', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'removedWrappedBalanceRaw', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'maxBptAmountIn', - type: 'uint256', - }, - { - internalType: 'enum RemoveLiquidityKind', - name: 'kind', - type: 'uint8', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - internalType: 'struct IRouterCommon.RemoveLiquidityHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'removeLiquidityHook', - outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'removeLiquidityProportional', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - ], - name: 'removeLiquidityRecovery', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'sender', type: 'address' }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - ], - name: 'removeLiquidityRecoveryHook', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'removeLiquiditySingleTokenExactIn', - outputs: [ - { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'uint256', - name: 'maxBptAmountIn', - type: 'uint256', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'removeLiquiditySingleTokenExactOut', - outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { internalType: 'uint256', name: 'exactAmountIn', type: 'uint256' }, - { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, - { internalType: 'uint256', name: 'deadline', type: 'uint256' }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'swapSingleTokenExactIn', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, - { internalType: 'uint256', name: 'deadline', type: 'uint256' }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'swapSingleTokenExactOut', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'enum SwapKind', - name: 'kind', - type: 'uint8', - }, - { internalType: 'address', name: 'pool', type: 'address' }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amountGiven', - type: 'uint256', - }, - { internalType: 'uint256', name: 'limit', type: 'uint256' }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - internalType: 'struct IRouter.SwapSingleTokenHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'swapSingleTokenHook', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'nonpayable', - type: 'function', - }, - { stateMutability: 'payable', type: 'receive' }, + }, + { + internalType: 'uint160', + name: 'amount', + type: 'uint160', + }, + { + internalType: 'uint48', + name: 'expiration', + type: 'uint48', + }, + { + internalType: 'uint48', + name: 'nonce', + type: 'uint48', + }, + ], + internalType: 'struct IAllowanceTransfer.PermitDetails[]', + name: 'details', + type: 'tuple[]', + }, + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'sigDeadline', + type: 'uint256', + }, + ], + internalType: 'struct IAllowanceTransfer.PermitBatch', + name: 'permit2Batch', + type: 'tuple', + }, + { internalType: 'bytes', name: 'permit2Signature', type: 'bytes' }, + { internalType: 'bytes[]', name: 'multicallData', type: 'bytes[]' }, + ], + name: 'permitBatchAndCall', + outputs: [{ internalType: 'bytes[]', name: 'results', type: 'bytes[]' }], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'maxAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryAddLiquidityCustom', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'maxAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { + internalType: 'enum AddLiquidityKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouterCommon.AddLiquidityHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'queryAddLiquidityHook', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryAddLiquidityProportional', + outputs: [ + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactBptAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryAddLiquiditySingleTokenExactOut', + outputs: [{ internalType: 'uint256', name: 'amountIn', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'exactAmountsIn', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryAddLiquidityUnbalanced', + outputs: [ + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'maxBptAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryRemoveLiquidityCustom', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'maxBptAmountIn', + type: 'uint256', + }, + { + internalType: 'enum RemoveLiquidityKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouterCommon.RemoveLiquidityHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'queryRemoveLiquidityHook', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryRemoveLiquidityProportional', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + ], + name: 'queryRemoveLiquidityRecovery', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'sender', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + ], + name: 'queryRemoveLiquidityRecoveryHook', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryRemoveLiquiditySingleTokenExactIn', + outputs: [{ internalType: 'uint256', name: 'amountOut', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'queryRemoveLiquiditySingleTokenExactOut', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'enum SwapKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amountGiven', + type: 'uint256', + }, + { internalType: 'uint256', name: 'limit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouter.SwapSingleTokenHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'querySwapHook', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'uint256', name: 'exactAmountIn', type: 'uint256' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'querySwapSingleTokenExactIn', + outputs: [ + { + internalType: 'uint256', + name: 'amountCalculated', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'querySwapSingleTokenExactOut', + outputs: [ + { + internalType: 'uint256', + name: 'amountCalculated', + type: 'uint256', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'maxBptAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'removeLiquidityCustom', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'maxBptAmountIn', + type: 'uint256', + }, + { + internalType: 'enum RemoveLiquidityKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouterCommon.RemoveLiquidityHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'removeLiquidityHook', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'removeLiquidityProportional', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + ], + name: 'removeLiquidityRecovery', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'sender', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + ], + name: 'removeLiquidityRecoveryHook', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'removeLiquiditySingleTokenExactIn', + outputs: [{ internalType: 'uint256', name: 'amountOut', type: 'uint256' }], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'uint256', + name: 'maxBptAmountIn', + type: 'uint256', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'removeLiquiditySingleTokenExactOut', + outputs: [ + { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'uint256', name: 'exactAmountIn', type: 'uint256' }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'swapSingleTokenExactIn', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'swapSingleTokenExactOut', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'enum SwapKind', + name: 'kind', + type: 'uint8', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amountGiven', + type: 'uint256', + }, + { internalType: 'uint256', name: 'limit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IRouter.SwapSingleTokenHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'swapSingleTokenHook', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { stateMutability: 'payable', type: 'receive' }, ] as const; diff --git a/src/dex/balancer-v3/abi/vaultExtension.V3.ts b/src/dex/balancer-v3/abi/vaultExtension.V3.ts index 3440ad461..d89a1f347 100644 --- a/src/dex/balancer-v3/abi/vaultExtension.V3.ts +++ b/src/dex/balancer-v3/abi/vaultExtension.V3.ts @@ -1,1800 +1,1847 @@ export const vaultExtensionAbi_V3 = [ - { - inputs: [ - { - internalType: 'contract IVault', - name: 'mainVault', - type: 'address', - }, - { - internalType: 'contract IVaultAdmin', - name: 'vaultAdmin', - type: 'address', - }, - ], - stateMutability: 'nonpayable', - type: 'constructor', - }, - { - inputs: [{ internalType: 'address', name: 'target', type: 'address' }], - name: 'AddressEmptyCode', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'account', type: 'address' }], - name: 'AddressInsufficientBalance', - type: 'error', - }, - { inputs: [], name: 'AfterAddLiquidityHookFailed', type: 'error' }, - { inputs: [], name: 'AfterInitializeHookFailed', type: 'error' }, - { inputs: [], name: 'AfterRemoveLiquidityHookFailed', type: 'error' }, - { inputs: [], name: 'AfterSwapHookFailed', type: 'error' }, - { inputs: [], name: 'AmountGivenZero', type: 'error' }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, - { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, - ], - name: 'AmountInAboveMax', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, - { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, - ], - name: 'AmountOutBelowMin', - type: 'error', - }, - { inputs: [], name: 'BalanceNotSettled', type: 'error' }, - { inputs: [], name: 'BalanceOverflow', type: 'error' }, - { inputs: [], name: 'BeforeAddLiquidityHookFailed', type: 'error' }, - { inputs: [], name: 'BeforeInitializeHookFailed', type: 'error' }, - { inputs: [], name: 'BeforeRemoveLiquidityHookFailed', type: 'error' }, - { inputs: [], name: 'BeforeSwapHookFailed', type: 'error' }, - { - inputs: [ - { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, - { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, - ], - name: 'BptAmountInAboveMax', - type: 'error', - }, - { - inputs: [ - { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, - { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, - ], - name: 'BptAmountOutBelowMin', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - ], - name: 'BufferAlreadyInitialized', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - ], - name: 'BufferNotInitialized', - type: 'error', - }, - { inputs: [], name: 'BufferSharesInvalidOwner', type: 'error' }, - { inputs: [], name: 'BufferSharesInvalidReceiver', type: 'error' }, - { - inputs: [ - { internalType: 'uint256', name: 'totalSupply', type: 'uint256' }, - ], - name: 'BufferTotalSupplyTooLow', - type: 'error', - }, - { inputs: [], name: 'CannotReceiveEth', type: 'error' }, - { inputs: [], name: 'CannotSwapSameToken', type: 'error' }, - { inputs: [], name: 'CodecOverflow', type: 'error' }, - { inputs: [], name: 'DoesNotSupportAddLiquidityCustom', type: 'error' }, - { inputs: [], name: 'DoesNotSupportDonation', type: 'error' }, - { inputs: [], name: 'DoesNotSupportRemoveLiquidityCustom', type: 'error' }, - { inputs: [], name: 'DoesNotSupportUnbalancedLiquidity', type: 'error' }, - { inputs: [], name: 'DynamicSwapFeeHookFailed', type: 'error' }, - { - inputs: [ - { internalType: 'address', name: 'spender', type: 'address' }, - { internalType: 'uint256', name: 'allowance', type: 'uint256' }, - { internalType: 'uint256', name: 'needed', type: 'uint256' }, - ], - name: 'ERC20InsufficientAllowance', - type: 'error', - }, - { - inputs: [ - { internalType: 'address', name: 'sender', type: 'address' }, - { internalType: 'uint256', name: 'balance', type: 'uint256' }, - { internalType: 'uint256', name: 'needed', type: 'uint256' }, - ], - name: 'ERC20InsufficientBalance', - type: 'error', - }, - { - inputs: [ - { internalType: 'address', name: 'approver', type: 'address' }, - ], - name: 'ERC20InvalidApprover', - type: 'error', - }, - { - inputs: [ - { internalType: 'address', name: 'receiver', type: 'address' }, - ], - name: 'ERC20InvalidReceiver', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], - name: 'ERC20InvalidSender', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'spender', type: 'address' }], - name: 'ERC20InvalidSpender', - type: 'error', - }, - { inputs: [], name: 'ErrorSelectorNotFound', type: 'error' }, - { inputs: [], name: 'FailedInnerCall', type: 'error' }, - { inputs: [], name: 'FeePrecisionTooHigh', type: 'error' }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, - { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, - ], - name: 'HookAdjustedAmountInAboveMax', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, - { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, - ], - name: 'HookAdjustedAmountOutBelowMin', - type: 'error', - }, - { - inputs: [ - { internalType: 'uint256', name: 'amount', type: 'uint256' }, - { internalType: 'uint256', name: 'limit', type: 'uint256' }, - ], - name: 'HookAdjustedSwapLimit', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'poolHooksContract', - type: 'address', - }, - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'poolFactory', type: 'address' }, - ], - name: 'HookRegistrationFailed', - type: 'error', - }, - { inputs: [], name: 'InputLengthMismatch', type: 'error' }, - { inputs: [], name: 'InvalidAddLiquidityKind', type: 'error' }, - { inputs: [], name: 'InvalidRemoveLiquidityKind', type: 'error' }, - { inputs: [], name: 'InvalidToken', type: 'error' }, - { inputs: [], name: 'InvalidTokenConfiguration', type: 'error' }, - { inputs: [], name: 'InvalidTokenType', type: 'error' }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - ], - name: 'InvalidUnderlyingToken', - type: 'error', - }, - { inputs: [], name: 'MaxTokens', type: 'error' }, - { inputs: [], name: 'MinTokens', type: 'error' }, - { inputs: [], name: 'NotEnoughBufferShares', type: 'error' }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - internalType: 'uint256', - name: 'expectedUnderlyingAmount', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'actualUnderlyingAmount', - type: 'uint256', - }, - ], - name: 'NotEnoughUnderlying', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - internalType: 'uint256', - name: 'expectedWrappedAmount', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'actualWrappedAmount', - type: 'uint256', - }, - ], - name: 'NotEnoughWrapped', - type: 'error', - }, - { inputs: [], name: 'NotStaticCall', type: 'error' }, - { inputs: [], name: 'NotVaultDelegateCall', type: 'error' }, - { inputs: [], name: 'OutOfBounds', type: 'error' }, - { inputs: [], name: 'PauseBufferPeriodDurationTooLarge', type: 'error' }, - { inputs: [], name: 'PercentageAboveMax', type: 'error' }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolAlreadyInitialized', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolAlreadyRegistered', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolInRecoveryMode', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolNotInRecoveryMode', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolNotInitialized', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolNotPaused', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolNotRegistered', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolPauseWindowExpired', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolPaused', - type: 'error', - }, - { - inputs: [ - { internalType: 'uint256', name: 'totalSupply', type: 'uint256' }, - ], - name: 'PoolTotalSupplyTooLow', - type: 'error', - }, - { inputs: [], name: 'ProtocolFeesExceedTotalCollected', type: 'error' }, - { inputs: [], name: 'QueriesDisabled', type: 'error' }, - { inputs: [], name: 'QuoteResultSpoofed', type: 'error' }, - { inputs: [], name: 'ReentrancyGuardReentrantCall', type: 'error' }, - { - inputs: [{ internalType: 'bytes', name: 'result', type: 'bytes' }], - name: 'Result', - type: 'error', - }, - { inputs: [], name: 'RouterNotTrusted', type: 'error' }, - { - inputs: [{ internalType: 'uint256', name: 'value', type: 'uint256' }], - name: 'SafeCastOverflowedUintToInt', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], - name: 'SenderIsNotVault', - type: 'error', - }, - { inputs: [], name: 'SwapFeePercentageTooHigh', type: 'error' }, - { inputs: [], name: 'SwapFeePercentageTooLow', type: 'error' }, - { - inputs: [ - { internalType: 'uint256', name: 'amount', type: 'uint256' }, - { internalType: 'uint256', name: 'limit', type: 'uint256' }, - ], - name: 'SwapLimit', - type: 'error', - }, - { - inputs: [ - { internalType: 'contract IERC20', name: 'token', type: 'address' }, - ], - name: 'TokenAlreadyRegistered', - type: 'error', - }, - { - inputs: [ - { internalType: 'contract IERC20', name: 'token', type: 'address' }, - ], - name: 'TokenNotRegistered', - type: 'error', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'expectedToken', type: 'address' }, - { internalType: 'address', name: 'actualToken', type: 'address' }, - ], - name: 'TokensMismatch', - type: 'error', - }, - { inputs: [], name: 'TokensNotSorted', type: 'error' }, - { inputs: [], name: 'TradeAmountTooSmall', type: 'error' }, - { inputs: [], name: 'VaultBuffersArePaused', type: 'error' }, - { inputs: [], name: 'VaultIsNotUnlocked', type: 'error' }, - { inputs: [], name: 'VaultNotPaused', type: 'error' }, - { inputs: [], name: 'VaultPauseWindowDurationTooLarge', type: 'error' }, - { inputs: [], name: 'VaultPauseWindowExpired', type: 'error' }, - { inputs: [], name: 'VaultPaused', type: 'error' }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - ], - name: 'WrapAmountTooSmall', - type: 'error', - }, - { inputs: [], name: 'WrongProtocolFeeControllerDeployment', type: 'error' }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - internalType: 'address', - name: 'underlyingToken', - type: 'address', - }, - ], - name: 'WrongUnderlyingToken', - type: 'error', - }, - { inputs: [], name: 'WrongVaultAdminDeployment', type: 'error' }, - { inputs: [], name: 'WrongVaultExtensionDeployment', type: 'error' }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'owner', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'spender', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'value', - type: 'uint256', - }, - ], - name: 'Approval', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IAuthorizer', - name: 'newAuthorizer', - type: 'address', - }, - ], - name: 'AuthorizerChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'from', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'burnedShares', - type: 'uint256', - }, - ], - name: 'BufferSharesBurned', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'to', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'issuedShares', - type: 'uint256', - }, - ], - name: 'BufferSharesMinted', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountUnderlying', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountWrapped', - type: 'uint256', - }, - ], - name: 'LiquidityAddedToBuffer', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountUnderlying', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountWrapped', - type: 'uint256', - }, - ], - name: 'LiquidityRemovedFromBuffer', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'liquidityProvider', - type: 'address', - }, - { - indexed: false, - internalType: 'int256[]', - name: 'deltas', - type: 'int256[]', - }, - ], - name: 'PoolBalanceChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'PoolInitialized', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: false, + { + inputs: [ + { + internalType: 'contract IVault', + name: 'mainVault', + type: 'address', + }, + { + internalType: 'contract IVaultAdmin', + name: 'vaultAdmin', + type: 'address', + }, + ], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [{ internalType: 'address', name: 'target', type: 'address' }], + name: 'AddressEmptyCode', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'account', type: 'address' }], + name: 'AddressInsufficientBalance', + type: 'error', + }, + { inputs: [], name: 'AfterAddLiquidityHookFailed', type: 'error' }, + { inputs: [], name: 'AfterInitializeHookFailed', type: 'error' }, + { inputs: [], name: 'AfterRemoveLiquidityHookFailed', type: 'error' }, + { inputs: [], name: 'AfterSwapHookFailed', type: 'error' }, + { inputs: [], name: 'AmountGivenZero', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, + { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + ], + name: 'AmountInAboveMax', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + ], + name: 'AmountOutBelowMin', + type: 'error', + }, + { inputs: [], name: 'BalanceNotSettled', type: 'error' }, + { inputs: [], name: 'BalanceOverflow', type: 'error' }, + { inputs: [], name: 'BeforeAddLiquidityHookFailed', type: 'error' }, + { inputs: [], name: 'BeforeInitializeHookFailed', type: 'error' }, + { inputs: [], name: 'BeforeRemoveLiquidityHookFailed', type: 'error' }, + { inputs: [], name: 'BeforeSwapHookFailed', type: 'error' }, + { + inputs: [ + { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, + { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + ], + name: 'BptAmountInAboveMax', + type: 'error', + }, + { + inputs: [ + { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + ], + name: 'BptAmountOutBelowMin', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'BufferAlreadyInitialized', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'BufferNotInitialized', + type: 'error', + }, + { inputs: [], name: 'BufferSharesInvalidOwner', type: 'error' }, + { inputs: [], name: 'BufferSharesInvalidReceiver', type: 'error' }, + { + inputs: [{ internalType: 'uint256', name: 'totalSupply', type: 'uint256' }], + name: 'BufferTotalSupplyTooLow', + type: 'error', + }, + { inputs: [], name: 'CannotReceiveEth', type: 'error' }, + { inputs: [], name: 'CannotSwapSameToken', type: 'error' }, + { inputs: [], name: 'CodecOverflow', type: 'error' }, + { inputs: [], name: 'DoesNotSupportAddLiquidityCustom', type: 'error' }, + { inputs: [], name: 'DoesNotSupportDonation', type: 'error' }, + { inputs: [], name: 'DoesNotSupportRemoveLiquidityCustom', type: 'error' }, + { inputs: [], name: 'DoesNotSupportUnbalancedLiquidity', type: 'error' }, + { inputs: [], name: 'DynamicSwapFeeHookFailed', type: 'error' }, + { + inputs: [ + { internalType: 'address', name: 'spender', type: 'address' }, + { internalType: 'uint256', name: 'allowance', type: 'uint256' }, + { internalType: 'uint256', name: 'needed', type: 'uint256' }, + ], + name: 'ERC20InsufficientAllowance', + type: 'error', + }, + { + inputs: [ + { internalType: 'address', name: 'sender', type: 'address' }, + { internalType: 'uint256', name: 'balance', type: 'uint256' }, + { internalType: 'uint256', name: 'needed', type: 'uint256' }, + ], + name: 'ERC20InsufficientBalance', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'approver', type: 'address' }], + name: 'ERC20InvalidApprover', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'receiver', type: 'address' }], + name: 'ERC20InvalidReceiver', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], + name: 'ERC20InvalidSender', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'spender', type: 'address' }], + name: 'ERC20InvalidSpender', + type: 'error', + }, + { inputs: [], name: 'ErrorSelectorNotFound', type: 'error' }, + { inputs: [], name: 'FailedInnerCall', type: 'error' }, + { inputs: [], name: 'FeePrecisionTooHigh', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, + { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + ], + name: 'HookAdjustedAmountInAboveMax', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, + { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + ], + name: 'HookAdjustedAmountOutBelowMin', + type: 'error', + }, + { + inputs: [ + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'uint256', name: 'limit', type: 'uint256' }, + ], + name: 'HookAdjustedSwapLimit', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'poolHooksContract', + type: 'address', + }, + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'poolFactory', type: 'address' }, + ], + name: 'HookRegistrationFailed', + type: 'error', + }, + { inputs: [], name: 'InputLengthMismatch', type: 'error' }, + { inputs: [], name: 'InvalidAddLiquidityKind', type: 'error' }, + { inputs: [], name: 'InvalidRemoveLiquidityKind', type: 'error' }, + { inputs: [], name: 'InvalidToken', type: 'error' }, + { inputs: [], name: 'InvalidTokenConfiguration', type: 'error' }, + { inputs: [], name: 'InvalidTokenType', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'InvalidUnderlyingToken', + type: 'error', + }, + { inputs: [], name: 'MaxTokens', type: 'error' }, + { inputs: [], name: 'MinTokens', type: 'error' }, + { inputs: [], name: 'NotEnoughBufferShares', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'expectedUnderlyingAmount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'actualUnderlyingAmount', + type: 'uint256', + }, + ], + name: 'NotEnoughUnderlying', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'expectedWrappedAmount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'actualWrappedAmount', + type: 'uint256', + }, + ], + name: 'NotEnoughWrapped', + type: 'error', + }, + { inputs: [], name: 'NotStaticCall', type: 'error' }, + { inputs: [], name: 'NotVaultDelegateCall', type: 'error' }, + { inputs: [], name: 'OutOfBounds', type: 'error' }, + { inputs: [], name: 'PauseBufferPeriodDurationTooLarge', type: 'error' }, + { inputs: [], name: 'PercentageAboveMax', type: 'error' }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolAlreadyInitialized', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolAlreadyRegistered', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolInRecoveryMode', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolNotInRecoveryMode', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolNotInitialized', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolNotPaused', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolNotRegistered', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolPauseWindowExpired', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'PoolPaused', + type: 'error', + }, + { + inputs: [{ internalType: 'uint256', name: 'totalSupply', type: 'uint256' }], + name: 'PoolTotalSupplyTooLow', + type: 'error', + }, + { inputs: [], name: 'ProtocolFeesExceedTotalCollected', type: 'error' }, + { inputs: [], name: 'QueriesDisabled', type: 'error' }, + { inputs: [], name: 'QuoteResultSpoofed', type: 'error' }, + { inputs: [], name: 'ReentrancyGuardReentrantCall', type: 'error' }, + { + inputs: [{ internalType: 'bytes', name: 'result', type: 'bytes' }], + name: 'Result', + type: 'error', + }, + { inputs: [], name: 'RouterNotTrusted', type: 'error' }, + { + inputs: [{ internalType: 'uint256', name: 'value', type: 'uint256' }], + name: 'SafeCastOverflowedUintToInt', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], + name: 'SenderIsNotVault', + type: 'error', + }, + { inputs: [], name: 'SwapFeePercentageTooHigh', type: 'error' }, + { inputs: [], name: 'SwapFeePercentageTooLow', type: 'error' }, + { + inputs: [ + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { internalType: 'uint256', name: 'limit', type: 'uint256' }, + ], + name: 'SwapLimit', + type: 'error', + }, + { + inputs: [ + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'TokenAlreadyRegistered', + type: 'error', + }, + { + inputs: [ + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'TokenNotRegistered', + type: 'error', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'expectedToken', type: 'address' }, + { internalType: 'address', name: 'actualToken', type: 'address' }, + ], + name: 'TokensMismatch', + type: 'error', + }, + { inputs: [], name: 'TokensNotSorted', type: 'error' }, + { inputs: [], name: 'TradeAmountTooSmall', type: 'error' }, + { inputs: [], name: 'VaultBuffersArePaused', type: 'error' }, + { inputs: [], name: 'VaultIsNotUnlocked', type: 'error' }, + { inputs: [], name: 'VaultNotPaused', type: 'error' }, + { inputs: [], name: 'VaultPauseWindowDurationTooLarge', type: 'error' }, + { inputs: [], name: 'VaultPauseWindowExpired', type: 'error' }, + { inputs: [], name: 'VaultPaused', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'WrapAmountTooSmall', + type: 'error', + }, + { inputs: [], name: 'WrongProtocolFeeControllerDeployment', type: 'error' }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'address', + name: 'underlyingToken', + type: 'address', + }, + ], + name: 'WrongUnderlyingToken', + type: 'error', + }, + { inputs: [], name: 'WrongVaultAdminDeployment', type: 'error' }, + { inputs: [], name: 'WrongVaultExtensionDeployment', type: 'error' }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'aggregateSwapFeePercentage', + type: 'uint256', + }, + ], + name: 'AggregateSwapFeePercentageChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'aggregateYieldFeePercentage', + type: 'uint256', + }, + ], + name: 'AggregateYieldFeePercentageChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'owner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + ], + name: 'Approval', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IAuthorizer', + name: 'newAuthorizer', + type: 'address', + }, + ], + name: 'AuthorizerChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'burnedShares', + type: 'uint256', + }, + ], + name: 'BufferSharesBurned', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'issuedShares', + type: 'uint256', + }, + ], + name: 'BufferSharesMinted', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountUnderlying', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountWrapped', + type: 'uint256', + }, + ], + name: 'LiquidityAddedToBuffer', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountUnderlying', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountWrapped', + type: 'uint256', + }, + ], + name: 'LiquidityRemovedFromBuffer', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'liquidityProvider', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'totalSupply', + type: 'uint256', + }, + { + indexed: false, + internalType: 'int256[]', + name: 'deltas', + type: 'int256[]', + }, + { + indexed: false, + internalType: 'uint256[]', + name: 'swapFeeAmountsRaw', + type: 'uint256[]', + }, + ], + name: 'PoolBalanceChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolInitialized', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: false, + internalType: 'bool', + name: 'paused', + type: 'bool', + }, + ], + name: 'PoolPausedStateChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: false, + internalType: 'bool', + name: 'recoveryMode', + type: 'bool', + }, + ], + name: 'PoolRecoveryModeStateChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'factory', + type: 'address', + }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, + { + internalType: 'enum TokenType', + name: 'tokenType', + type: 'uint8', + }, + { + internalType: 'contract IRateProvider', + name: 'rateProvider', + type: 'address', + }, + { + internalType: 'bool', + name: 'paysYieldFees', + type: 'bool', + }, + ], + indexed: false, + internalType: 'struct TokenConfig[]', + name: 'tokenConfig', + type: 'tuple[]', + }, + { + indexed: false, + internalType: 'uint256', + name: 'swapFeePercentage', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint32', + name: 'pauseWindowEndTime', + type: 'uint32', + }, + { + components: [ + { + internalType: 'address', + name: 'pauseManager', + type: 'address', + }, + { + internalType: 'address', + name: 'swapFeeManager', + type: 'address', + }, + { + internalType: 'address', + name: 'poolCreator', + type: 'address', + }, + ], + indexed: false, + internalType: 'struct PoolRoleAccounts', + name: 'roleAccounts', + type: 'tuple', + }, + { + components: [ + { + internalType: 'bool', + name: 'enableHookAdjustedAmounts', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeInitialize', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterInitialize', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallComputeDynamicSwapFee', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeSwap', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterSwap', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeAddLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterAddLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeRemoveLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterRemoveLiquidity', + type: 'bool', + }, + { + internalType: 'address', + name: 'hooksContract', + type: 'address', + }, + ], + indexed: false, + internalType: 'struct HooksConfig', + name: 'hooksConfig', + type: 'tuple', + }, + { + components: [ + { + internalType: 'bool', + name: 'disableUnbalancedLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableAddLiquidityCustom', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableRemoveLiquidityCustom', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableDonation', + type: 'bool', + }, + ], + indexed: false, + internalType: 'struct LiquidityManagement', + name: 'liquidityManagement', + type: 'tuple', + }, + ], + name: 'PoolRegistered', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IProtocolFeeController', + name: 'newProtocolFeeController', + type: 'address', + }, + ], + name: 'ProtocolFeeControllerChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: true, + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + indexed: true, + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountIn', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountOut', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'swapFeePercentage', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'swapFeeAmount', + type: 'uint256', + }, + ], + name: 'Swap', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'swapFeePercentage', + type: 'uint256', + }, + ], + name: 'SwapFeePercentageChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'from', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'to', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + ], + name: 'Transfer', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: true, + internalType: 'contract IERC20', + name: 'underlyingToken', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'burnedShares', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'withdrawnUnderlying', + type: 'uint256', + }, + ], + name: 'Unwrap', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'bool', + name: 'paused', + type: 'bool', + }, + ], + name: 'VaultBuffersPausedStateChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'bool', + name: 'paused', + type: 'bool', + }, + ], + name: 'VaultPausedStateChanged', + type: 'event', + }, + { + anonymous: false, + inputs: [], + name: 'VaultQueriesDisabled', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC20', + name: 'underlyingToken', + type: 'address', + }, + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'depositedUnderlying', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'mintedShares', + type: 'uint256', + }, + ], + name: 'Wrap', + type: 'event', + }, + { stateMutability: 'payable', type: 'fallback' }, + { + inputs: [ + { internalType: 'address', name: 'token', type: 'address' }, + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'address', name: 'spender', type: 'address' }, + ], + name: 'allowance', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'address', name: 'spender', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'approve', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'token', type: 'address' }, + { internalType: 'address', name: 'account', type: 'address' }, + ], + name: 'balanceOf', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + components: [ + { + internalType: 'enum SwapKind', + name: 'kind', + type: 'uint8', + }, + { + internalType: 'uint256', + name: 'amountGivenScaled18', + type: 'uint256', + }, + { + internalType: 'uint256[]', + name: 'balancesScaled18', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'indexIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'indexOut', + type: 'uint256', + }, + { + internalType: 'address', + name: 'router', + type: 'address', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct PoolSwapParams', + name: 'swapParams', + type: 'tuple', + }, + ], + name: 'computeDynamicSwapFeePercentage', + outputs: [ + { + internalType: 'uint256', + name: 'dynamicSwapFeePercentage', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'getAggregateSwapFeeAmount', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'getAggregateYieldFeeAmount', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getBptRate', + outputs: [{ internalType: 'uint256', name: 'rate', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getCurrentLiveBalances', + outputs: [ + { + internalType: 'uint256[]', + name: 'balancesLiveScaled18', + type: 'uint256[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getHooksConfig', + outputs: [ + { + components: [ + { + internalType: 'bool', + name: 'enableHookAdjustedAmounts', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeInitialize', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterInitialize', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallComputeDynamicSwapFee', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeSwap', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterSwap', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeAddLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterAddLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallBeforeRemoveLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'shouldCallAfterRemoveLiquidity', + type: 'bool', + }, + { + internalType: 'address', + name: 'hooksContract', + type: 'address', + }, + ], + internalType: 'struct HooksConfig', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getNonzeroDeltaCount', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolConfig', + outputs: [ + { + components: [ + { + components: [ + { internalType: 'bool', - name: 'paused', + name: 'disableUnbalancedLiquidity', type: 'bool', - }, - ], - name: 'PoolPausedStateChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: false, + }, + { internalType: 'bool', - name: 'recoveryMode', + name: 'enableAddLiquidityCustom', type: 'bool', - }, - ], - name: 'PoolRecoveryModeStateChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'factory', - type: 'address', - }, - { - components: [ - { - internalType: 'contract IERC20', - name: 'token', - type: 'address', - }, - { - internalType: 'enum TokenType', - name: 'tokenType', - type: 'uint8', - }, - { - internalType: 'contract IRateProvider', - name: 'rateProvider', - type: 'address', - }, - { - internalType: 'bool', - name: 'paysYieldFees', - type: 'bool', - }, - ], - indexed: false, - internalType: 'struct TokenConfig[]', - name: 'tokenConfig', - type: 'tuple[]', - }, - { - indexed: false, - internalType: 'uint256', - name: 'swapFeePercentage', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint32', - name: 'pauseWindowEndTime', - type: 'uint32', - }, - { - components: [ - { - internalType: 'address', - name: 'pauseManager', - type: 'address', - }, - { - internalType: 'address', - name: 'swapFeeManager', - type: 'address', - }, - { - internalType: 'address', - name: 'poolCreator', - type: 'address', - }, - ], - indexed: false, - internalType: 'struct PoolRoleAccounts', - name: 'roleAccounts', - type: 'tuple', - }, - { - components: [ - { - internalType: 'bool', - name: 'enableHookAdjustedAmounts', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeInitialize', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterInitialize', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallComputeDynamicSwapFee', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeSwap', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterSwap', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeAddLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterAddLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeRemoveLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterRemoveLiquidity', - type: 'bool', - }, - { - internalType: 'address', - name: 'hooksContract', - type: 'address', - }, - ], - indexed: false, - internalType: 'struct HooksConfig', - name: 'hooksConfig', - type: 'tuple', - }, - { - components: [ - { - internalType: 'bool', - name: 'disableUnbalancedLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableAddLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableRemoveLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableDonation', - type: 'bool', - }, - ], - indexed: false, - internalType: 'struct LiquidityManagement', - name: 'liquidityManagement', - type: 'tuple', - }, - ], - name: 'PoolRegistered', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IProtocolFeeController', - name: 'newProtocolFeeController', - type: 'address', - }, - ], - name: 'ProtocolFeeControllerChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: true, - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - indexed: true, - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountIn', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountOut', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'swapFeePercentage', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'swapFeeAmount', - type: 'uint256', - }, - { - indexed: false, - internalType: 'contract IERC20', - name: 'swapFeeToken', - type: 'address', - }, - ], - name: 'Swap', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'swapFeePercentage', - type: 'uint256', - }, - ], - name: 'SwapFeePercentageChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'from', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'to', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'value', - type: 'uint256', - }, - ], - name: 'Transfer', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - indexed: true, - internalType: 'contract IERC20', - name: 'underlyingToken', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'burnedShares', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'withdrawnUnderlying', - type: 'uint256', - }, - ], - name: 'Unwrap', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, + }, + { internalType: 'bool', - name: 'paused', + name: 'enableRemoveLiquidityCustom', type: 'bool', - }, - ], - name: 'VaultBuffersPausedStateChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, + }, + { internalType: 'bool', - name: 'paused', + name: 'enableDonation', type: 'bool', - }, - ], - name: 'VaultPausedStateChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [], - name: 'VaultQueriesDisabled', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC20', - name: 'underlyingToken', - type: 'address', - }, - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', + }, + ], + internalType: 'struct LiquidityManagement', + name: 'liquidityManagement', + type: 'tuple', + }, + { + internalType: 'uint256', + name: 'staticSwapFeePercentage', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'aggregateSwapFeePercentage', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'aggregateYieldFeePercentage', + type: 'uint256', + }, + { + internalType: 'uint40', + name: 'tokenDecimalDiffs', + type: 'uint40', + }, + { + internalType: 'uint32', + name: 'pauseWindowEndTime', + type: 'uint32', + }, + { + internalType: 'bool', + name: 'isPoolRegistered', + type: 'bool', + }, + { + internalType: 'bool', + name: 'isPoolInitialized', + type: 'bool', + }, + { + internalType: 'bool', + name: 'isPoolPaused', + type: 'bool', + }, + { + internalType: 'bool', + name: 'isPoolInRecoveryMode', + type: 'bool', + }, + ], + internalType: 'struct PoolConfig', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolData', + outputs: [ + { + components: [ + { + internalType: 'PoolConfigBits', + name: 'poolConfigBits', + type: 'bytes32', + }, + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + { + components: [ + { + internalType: 'enum TokenType', + name: 'tokenType', + type: 'uint8', + }, + { + internalType: 'contract IRateProvider', + name: 'rateProvider', type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'depositedUnderlying', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'mintedShares', - type: 'uint256', - }, - ], - name: 'Wrap', - type: 'event', - }, - { stateMutability: 'payable', type: 'fallback' }, - { - inputs: [ - { internalType: 'address', name: 'token', type: 'address' }, - { internalType: 'address', name: 'owner', type: 'address' }, - { internalType: 'address', name: 'spender', type: 'address' }, - ], - name: 'allowance', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'owner', type: 'address' }, - { internalType: 'address', name: 'spender', type: 'address' }, - { internalType: 'uint256', name: 'amount', type: 'uint256' }, - ], - name: 'approve', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'token', type: 'address' }, - { internalType: 'address', name: 'account', type: 'address' }, - ], - name: 'balanceOf', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - components: [ - { - internalType: 'enum SwapKind', - name: 'kind', - type: 'uint8', - }, - { - internalType: 'uint256', - name: 'amountGivenScaled18', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'balancesScaled18', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'indexIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'indexOut', - type: 'uint256', - }, - { - internalType: 'address', - name: 'router', - type: 'address', - }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - internalType: 'struct PoolSwapParams', - name: 'swapParams', - type: 'tuple', - }, - ], - name: 'computeDynamicSwapFeePercentage', - outputs: [ - { - internalType: 'uint256', - name: 'dynamicSwapFeePercentage', - type: 'uint256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'contract IERC20', name: 'token', type: 'address' }, - ], - name: 'getAggregateSwapFeeAmount', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'contract IERC20', name: 'token', type: 'address' }, - ], - name: 'getAggregateYieldFeeAmount', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getBptRate', - outputs: [{ internalType: 'uint256', name: 'rate', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getCurrentLiveBalances', - outputs: [ - { - internalType: 'uint256[]', - name: 'balancesLiveScaled18', - type: 'uint256[]', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getHooksConfig', - outputs: [ - { - components: [ - { - internalType: 'bool', - name: 'enableHookAdjustedAmounts', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeInitialize', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterInitialize', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallComputeDynamicSwapFee', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeSwap', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterSwap', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeAddLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterAddLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeRemoveLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterRemoveLiquidity', - type: 'bool', - }, - { - internalType: 'address', - name: 'hooksContract', - type: 'address', - }, - ], - internalType: 'struct HooksConfig', - name: '', - type: 'tuple', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'getNonzeroDeltaCount', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getPoolConfig', - outputs: [ - { - components: [ - { - components: [ - { - internalType: 'bool', - name: 'disableUnbalancedLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableAddLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableRemoveLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableDonation', - type: 'bool', - }, - ], - internalType: 'struct LiquidityManagement', - name: 'liquidityManagement', - type: 'tuple', - }, - { - internalType: 'uint256', - name: 'staticSwapFeePercentage', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'aggregateSwapFeePercentage', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'aggregateYieldFeePercentage', - type: 'uint256', - }, - { - internalType: 'uint40', - name: 'tokenDecimalDiffs', - type: 'uint40', - }, - { - internalType: 'uint32', - name: 'pauseWindowEndTime', - type: 'uint32', - }, - { - internalType: 'bool', - name: 'isPoolRegistered', - type: 'bool', - }, - { - internalType: 'bool', - name: 'isPoolInitialized', - type: 'bool', - }, - { - internalType: 'bool', - name: 'isPoolPaused', - type: 'bool', - }, - { - internalType: 'bool', - name: 'isPoolInRecoveryMode', - type: 'bool', - }, - ], - internalType: 'struct PoolConfig', - name: '', - type: 'tuple', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getPoolData', - outputs: [ - { - components: [ - { - internalType: 'PoolConfigBits', - name: 'poolConfigBits', - type: 'bytes32', - }, - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - { - components: [ - { - internalType: 'enum TokenType', - name: 'tokenType', - type: 'uint8', - }, - { - internalType: 'contract IRateProvider', - name: 'rateProvider', - type: 'address', - }, - { - internalType: 'bool', - name: 'paysYieldFees', - type: 'bool', - }, - ], - internalType: 'struct TokenInfo[]', - name: 'tokenInfo', - type: 'tuple[]', - }, - { - internalType: 'uint256[]', - name: 'balancesRaw', - type: 'uint256[]', - }, - { - internalType: 'uint256[]', - name: 'balancesLiveScaled18', - type: 'uint256[]', - }, - { - internalType: 'uint256[]', - name: 'tokenRates', - type: 'uint256[]', - }, - { - internalType: 'uint256[]', - name: 'decimalScalingFactors', - type: 'uint256[]', - }, - ], - internalType: 'struct PoolData', - name: '', - type: 'tuple', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getPoolPausedState', - outputs: [ - { internalType: 'bool', name: '', type: 'bool' }, - { internalType: 'uint32', name: '', type: 'uint32' }, - { internalType: 'uint32', name: '', type: 'uint32' }, - { internalType: 'address', name: '', type: 'address' }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getPoolRoleAccounts', - outputs: [ - { - components: [ - { - internalType: 'address', - name: 'pauseManager', - type: 'address', - }, - { - internalType: 'address', - name: 'swapFeeManager', - type: 'address', - }, - { - internalType: 'address', - name: 'poolCreator', - type: 'address', - }, - ], - internalType: 'struct PoolRoleAccounts', - name: '', - type: 'tuple', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getPoolTokenInfo', - outputs: [ - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - { - components: [ - { - internalType: 'enum TokenType', - name: 'tokenType', - type: 'uint8', - }, - { - internalType: 'contract IRateProvider', - name: 'rateProvider', - type: 'address', - }, - { - internalType: 'bool', - name: 'paysYieldFees', - type: 'bool', - }, - ], - internalType: 'struct TokenInfo[]', - name: 'tokenInfo', - type: 'tuple[]', - }, - { - internalType: 'uint256[]', - name: 'balancesRaw', - type: 'uint256[]', - }, - { - internalType: 'uint256[]', - name: 'lastBalancesLiveScaled18', - type: 'uint256[]', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getPoolTokenRates', - outputs: [ - { - internalType: 'uint256[]', - name: 'decimalScalingFactors', - type: 'uint256[]', - }, - { - internalType: 'uint256[]', - name: 'tokenRates', - type: 'uint256[]', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getPoolTokens', - outputs: [ - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'getProtocolFeeController', - outputs: [ - { - internalType: 'contract IProtocolFeeController', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'contract IERC20', name: 'token', type: 'address' }, - ], - name: 'getReservesOf', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getStaticSwapFeePercentage', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'contract IERC20', name: 'token', type: 'address' }, - ], - name: 'getTokenDelta', - outputs: [{ internalType: 'int256', name: '', type: 'int256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'getVaultAdmin', - outputs: [{ internalType: 'address', name: '', type: 'address' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'to', type: 'address' }, - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'exactAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'initialize', - outputs: [ - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'isPoolInRecoveryMode', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'isPoolInitialized', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'isPoolPaused', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'isPoolRegistered', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'isQueryDisabled', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'isUnlocked', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'bytes', name: 'data', type: 'bytes' }], - name: 'quote', - outputs: [{ internalType: 'bytes', name: 'result', type: 'bytes' }], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'bytes', name: 'data', type: 'bytes' }], - name: 'quoteAndRevert', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [], - name: 'reentrancyGuardEntered', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { - components: [ - { - internalType: 'contract IERC20', - name: 'token', - type: 'address', - }, - { - internalType: 'enum TokenType', - name: 'tokenType', - type: 'uint8', - }, - { - internalType: 'contract IRateProvider', - name: 'rateProvider', - type: 'address', - }, - { - internalType: 'bool', - name: 'paysYieldFees', - type: 'bool', - }, - ], - internalType: 'struct TokenConfig[]', - name: 'tokenConfig', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'swapFeePercentage', - type: 'uint256', - }, - { - internalType: 'uint32', - name: 'pauseWindowEndTime', - type: 'uint32', - }, - { internalType: 'bool', name: 'protocolFeeExempt', type: 'bool' }, - { - components: [ - { - internalType: 'address', - name: 'pauseManager', - type: 'address', - }, - { - internalType: 'address', - name: 'swapFeeManager', - type: 'address', - }, - { - internalType: 'address', - name: 'poolCreator', - type: 'address', - }, - ], - internalType: 'struct PoolRoleAccounts', - name: 'roleAccounts', - type: 'tuple', - }, - { - internalType: 'address', - name: 'poolHooksContract', - type: 'address', - }, - { - components: [ - { - internalType: 'bool', - name: 'disableUnbalancedLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableAddLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableRemoveLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableDonation', - type: 'bool', - }, - ], - internalType: 'struct LiquidityManagement', - name: 'liquidityManagement', - type: 'tuple', - }, - ], - name: 'registerPool', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'from', type: 'address' }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - ], - name: 'removeLiquidityRecovery', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOutRaw', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'token', type: 'address' }], - name: 'totalSupply', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'owner', type: 'address' }, - { internalType: 'address', name: 'to', type: 'address' }, - { internalType: 'uint256', name: 'amount', type: 'uint256' }, - ], - name: 'transfer', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'spender', type: 'address' }, - { internalType: 'address', name: 'from', type: 'address' }, - { internalType: 'address', name: 'to', type: 'address' }, - { internalType: 'uint256', name: 'amount', type: 'uint256' }, - ], - name: 'transferFrom', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [], - name: 'vault', - outputs: [ - { internalType: 'contract IVault', name: '', type: 'address' }, - ], - stateMutability: 'view', - type: 'function', - }, - { stateMutability: 'payable', type: 'receive' }, + }, + { + internalType: 'bool', + name: 'paysYieldFees', + type: 'bool', + }, + ], + internalType: 'struct TokenInfo[]', + name: 'tokenInfo', + type: 'tuple[]', + }, + { + internalType: 'uint256[]', + name: 'balancesRaw', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'balancesLiveScaled18', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'tokenRates', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'decimalScalingFactors', + type: 'uint256[]', + }, + ], + internalType: 'struct PoolData', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolPausedState', + outputs: [ + { internalType: 'bool', name: '', type: 'bool' }, + { internalType: 'uint32', name: '', type: 'uint32' }, + { internalType: 'uint32', name: '', type: 'uint32' }, + { internalType: 'address', name: '', type: 'address' }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolRoleAccounts', + outputs: [ + { + components: [ + { + internalType: 'address', + name: 'pauseManager', + type: 'address', + }, + { + internalType: 'address', + name: 'swapFeeManager', + type: 'address', + }, + { + internalType: 'address', + name: 'poolCreator', + type: 'address', + }, + ], + internalType: 'struct PoolRoleAccounts', + name: '', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolTokenInfo', + outputs: [ + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + { + components: [ + { + internalType: 'enum TokenType', + name: 'tokenType', + type: 'uint8', + }, + { + internalType: 'contract IRateProvider', + name: 'rateProvider', + type: 'address', + }, + { + internalType: 'bool', + name: 'paysYieldFees', + type: 'bool', + }, + ], + internalType: 'struct TokenInfo[]', + name: 'tokenInfo', + type: 'tuple[]', + }, + { + internalType: 'uint256[]', + name: 'balancesRaw', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'lastBalancesLiveScaled18', + type: 'uint256[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolTokenRates', + outputs: [ + { + internalType: 'uint256[]', + name: 'decimalScalingFactors', + type: 'uint256[]', + }, + { + internalType: 'uint256[]', + name: 'tokenRates', + type: 'uint256[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getPoolTokens', + outputs: [ + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getProtocolFeeController', + outputs: [ + { + internalType: 'contract IProtocolFeeController', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'getReservesOf', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'getStaticSwapFeePercentage', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'contract IERC20', name: 'token', type: 'address' }, + ], + name: 'getTokenDelta', + outputs: [{ internalType: 'int256', name: '', type: 'int256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getVaultAdmin', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { + internalType: 'contract IERC20[]', + name: 'tokens', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'exactAmountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'minBptAmountOut', + type: 'uint256', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'initialize', + outputs: [ + { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'isERC4626BufferInitialized', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'isPoolInRecoveryMode', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'isPoolInitialized', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'isPoolPaused', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + name: 'isPoolRegistered', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'isQueryDisabled', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'isUnlocked', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes', name: 'data', type: 'bytes' }], + name: 'quote', + outputs: [{ internalType: 'bytes', name: 'result', type: 'bytes' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes', name: 'data', type: 'bytes' }], + name: 'quoteAndRevert', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'reentrancyGuardEntered', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, + { + internalType: 'enum TokenType', + name: 'tokenType', + type: 'uint8', + }, + { + internalType: 'contract IRateProvider', + name: 'rateProvider', + type: 'address', + }, + { + internalType: 'bool', + name: 'paysYieldFees', + type: 'bool', + }, + ], + internalType: 'struct TokenConfig[]', + name: 'tokenConfig', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'swapFeePercentage', + type: 'uint256', + }, + { + internalType: 'uint32', + name: 'pauseWindowEndTime', + type: 'uint32', + }, + { internalType: 'bool', name: 'protocolFeeExempt', type: 'bool' }, + { + components: [ + { + internalType: 'address', + name: 'pauseManager', + type: 'address', + }, + { + internalType: 'address', + name: 'swapFeeManager', + type: 'address', + }, + { + internalType: 'address', + name: 'poolCreator', + type: 'address', + }, + ], + internalType: 'struct PoolRoleAccounts', + name: 'roleAccounts', + type: 'tuple', + }, + { + internalType: 'address', + name: 'poolHooksContract', + type: 'address', + }, + { + components: [ + { + internalType: 'bool', + name: 'disableUnbalancedLiquidity', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableAddLiquidityCustom', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableRemoveLiquidityCustom', + type: 'bool', + }, + { + internalType: 'bool', + name: 'enableDonation', + type: 'bool', + }, + ], + internalType: 'struct LiquidityManagement', + name: 'liquidityManagement', + type: 'tuple', + }, + ], + name: 'registerPool', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'pool', type: 'address' }, + { internalType: 'address', name: 'from', type: 'address' }, + { + internalType: 'uint256', + name: 'exactBptAmountIn', + type: 'uint256', + }, + ], + name: 'removeLiquidityRecovery', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsOutRaw', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'token', type: 'address' }], + name: 'totalSupply', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'transfer', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'spender', type: 'address' }, + { internalType: 'address', name: 'from', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'amount', type: 'uint256' }, + ], + name: 'transferFrom', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'vault', + outputs: [{ internalType: 'contract IVault', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { stateMutability: 'payable', type: 'receive' }, ] as const; diff --git a/src/dex/balancer-v3/balancer-v3-events.test.ts b/src/dex/balancer-v3/balancer-v3-events.test.ts index 3ad42c8d1..68fc95733 100644 --- a/src/dex/balancer-v3/balancer-v3-events.test.ts +++ b/src/dex/balancer-v3/balancer-v3-events.test.ts @@ -78,12 +78,10 @@ describe('BalancerV3 EventPool', function () { // TODO once we have a new test deployment add tests for: AggregateSwapFeePercentageChanged, SwapFeePercentageChanged, PoolPausedStateChanged const eventsToTest: Record = { [BalancerV3Config.BalancerV3[network].vaultAddress]: { - // 6806714: - // - https://eth-sepolia.blockscout.com/tx/0x831ef55d8c697f5e603174373e3fbe388def01944a3f73b4c90e6f1775d6e49f?tab=logs - // - has swap for pool : 0x3e8b62395aea51c3d7bdfeb8cde7d4a272c34750 + // - https://eth-sepolia.blockscout.com/tx/0x6c2a7a38fd469779269f11ff8366ef01de0977219972cbe2eaa3c9a0a9a91d1e PoolBalanceChanged: { - blockNumbers: [6806714], - poolAddress: ['0x3e8b62395aea51c3d7bdfeb8cde7d4a272c34750'], + blockNumbers: [6839703], + poolAddress: ['0xd71958aed5e2e835a648ff832a181f7bdabbaf13'], }, }, }; diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 2d42e47a9..4d0d51939 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -196,6 +196,7 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { event.args.deltas[i], ); } + newState[poolAddress].totalSupply = BigInt(event.args.totalSupply); return newState; } diff --git a/src/dex/balancer-v3/config.ts b/src/dex/balancer-v3/config.ts index 525396210..1654100c3 100644 --- a/src/dex/balancer-v3/config.ts +++ b/src/dex/balancer-v3/config.ts @@ -15,9 +15,9 @@ export const apiUrl = 'https://test-api-v3.balancer.fi/'; export const BalancerV3Config: DexConfigMap = { BalancerV3: { [Network.SEPOLIA]: { - vaultAddress: '0x0EF1c156a7986F394d90eD1bEeA6483Cc435F542', + vaultAddress: '0x30AF3689547354f82C70256894B07C9D0f067BB6', apiNetworkName: 'SEPOLIA', - balancerRouterAddress: '0xDd10aDF05379D7C0Ee4bC9c72ecc5C01c40E25b8', + balancerRouterAddress: '0x77eDc69766409C599F06Ef0B551a0990CBfe13A7', }, }, }; diff --git a/src/dex/balancer-v3/getOnChainState.ts b/src/dex/balancer-v3/getOnChainState.ts index 85dc3f6a1..96edcaa6c 100644 --- a/src/dex/balancer-v3/getOnChainState.ts +++ b/src/dex/balancer-v3/getOnChainState.ts @@ -104,7 +104,7 @@ const poolOnChain: Record< ); if (!resultLiveBalances) throw new Error( - `Failed to get result for getPoolTokenRates for ${poolAddress}`, + `Failed to get result for getCurrentLiveBalances for ${poolAddress}`, ); const resultGetPoolConfig = decodeThrowError( contractInterface, From d6e187e3aa2cb639eaae775e964a1ec07696f881 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 17 Oct 2024 11:49:39 +0100 Subject: [PATCH 15/66] feat: Add boosted pool support which needs batchRouter functions. --- package.json | 2 +- scripts/run-dex-integration-v3.ts | 11 +- .../balancer-v3/abi/balancerBatchRouter.ts | 728 ++++++++++++++++++ src/dex/balancer-v3/balancer-v3-e2e.test.ts | 103 ++- src/dex/balancer-v3/balancer-v3-pool.ts | 198 ++++- src/dex/balancer-v3/balancer-v3.ts | 163 +++- src/dex/balancer-v3/config.ts | 1 + src/dex/balancer-v3/getPoolsApi.ts | 13 +- src/dex/balancer-v3/types.ts | 26 +- tests/constants-e2e.ts | 12 + yarn.lock | 8 +- 11 files changed, 1160 insertions(+), 105 deletions(-) create mode 100644 src/dex/balancer-v3/abi/balancerBatchRouter.ts diff --git a/package.json b/package.json index bc0dcb7fa..53165156e 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ }, "dependencies": { "@0x/utils": "^4.5.2", - "@balancer-labs/balancer-maths": "^0.0.12", + "@balancer-labs/balancer-maths": "^0.0.13", "@balancer-labs/sor": "4.1.1-beta.4", "@bgd-labs/aave-address-book": "2.21.1", "@ethersproject/abi": "^5.7.0", diff --git a/scripts/run-dex-integration-v3.ts b/scripts/run-dex-integration-v3.ts index 23ef70b35..17aefb8e9 100644 --- a/scripts/run-dex-integration-v3.ts +++ b/scripts/run-dex-integration-v3.ts @@ -28,7 +28,12 @@ const daiAave = { decimals: 18, }; -const amounts = [0n, BI_POWS[18], 2000000000000000000n]; +const usdcAave = { + address: '0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8'.toLowerCase(), + decimals: 6, +}; + +const amounts = [0n, BI_POWS[19], 20000000000000000000n]; async function main() { const dexHelper = new DummyDexHelper(Network.SEPOLIA); @@ -40,8 +45,8 @@ async function main() { // const from = stataDAI; // const to = stataUSDC; - const from = bal; - const to = daiAave; + const from = daiAave; + const to = usdcAave; const pools = await balancerV3.getPoolIdentifiers( from, diff --git a/src/dex/balancer-v3/abi/balancerBatchRouter.ts b/src/dex/balancer-v3/abi/balancerBatchRouter.ts new file mode 100644 index 000000000..e15c2bc1d --- /dev/null +++ b/src/dex/balancer-v3/abi/balancerBatchRouter.ts @@ -0,0 +1,728 @@ +export const balancerBatchRouterAbi = [ + { + inputs: [ + { internalType: 'contract IVault', name: 'vault', type: 'address' }, + { internalType: 'contract IWETH', name: 'weth', type: 'address' }, + { + internalType: 'contract IPermit2', + name: 'permit2', + type: 'address', + }, + ], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [{ internalType: 'address', name: 'target', type: 'address' }], + name: 'AddressEmptyCode', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'account', type: 'address' }], + name: 'AddressInsufficientBalance', + type: 'error', + }, + { inputs: [], name: 'EthTransfer', type: 'error' }, + { inputs: [], name: 'FailedInnerCall', type: 'error' }, + { inputs: [], name: 'InsufficientEth', type: 'error' }, + { inputs: [], name: 'ReentrancyGuardReentrantCall', type: 'error' }, + { + inputs: [ + { internalType: 'uint8', name: 'bits', type: 'uint8' }, + { internalType: 'uint256', name: 'value', type: 'uint256' }, + ], + name: 'SafeCastOverflowedUintDowncast', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'token', type: 'address' }], + name: 'SafeERC20FailedOperation', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], + name: 'SenderIsNotVault', + type: 'error', + }, + { inputs: [], name: 'SwapDeadline', type: 'error' }, + { inputs: [], name: 'TransientIndexOutOfBounds', type: 'error' }, + { + inputs: [], + name: 'getSender', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes[]', name: 'data', type: 'bytes[]' }], + name: 'multicall', + outputs: [{ internalType: 'bytes[]', name: 'results', type: 'bytes[]' }], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { internalType: 'address', name: 'token', type: 'address' }, + { internalType: 'address', name: 'owner', type: 'address' }, + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + { internalType: 'uint256', name: 'nonce', type: 'uint256' }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + ], + internalType: 'struct IRouterCommon.PermitApproval[]', + name: 'permitBatch', + type: 'tuple[]', + }, + { + internalType: 'bytes[]', + name: 'permitSignatures', + type: 'bytes[]', + }, + { + components: [ + { + components: [ + { + internalType: 'address', + name: 'token', + type: 'address', + }, + { + internalType: 'uint160', + name: 'amount', + type: 'uint160', + }, + { + internalType: 'uint48', + name: 'expiration', + type: 'uint48', + }, + { + internalType: 'uint48', + name: 'nonce', + type: 'uint48', + }, + ], + internalType: 'struct IAllowanceTransfer.PermitDetails[]', + name: 'details', + type: 'tuple[]', + }, + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'sigDeadline', + type: 'uint256', + }, + ], + internalType: 'struct IAllowanceTransfer.PermitBatch', + name: 'permit2Batch', + type: 'tuple', + }, + { internalType: 'bytes', name: 'permit2Signature', type: 'bytes' }, + { internalType: 'bytes[]', name: 'multicallData', type: 'bytes[]' }, + ], + name: 'permitBatchAndCall', + outputs: [{ internalType: 'bytes[]', name: 'results', type: 'bytes[]' }], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + components: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'bool', + name: 'isBuffer', + type: 'bool', + }, + ], + internalType: 'struct IBatchRouter.SwapPathStep[]', + name: 'steps', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'exactAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minAmountOut', + type: 'uint256', + }, + ], + internalType: 'struct IBatchRouter.SwapPathExactAmountIn[]', + name: 'paths', + type: 'tuple[]', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'querySwapExactIn', + outputs: [ + { + internalType: 'uint256[]', + name: 'pathAmountsOut', + type: 'uint256[]', + }, + { internalType: 'address[]', name: 'tokensOut', type: 'address[]' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + components: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'bool', + name: 'isBuffer', + type: 'bool', + }, + ], + internalType: 'struct IBatchRouter.SwapPathStep[]', + name: 'steps', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'exactAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minAmountOut', + type: 'uint256', + }, + ], + internalType: 'struct IBatchRouter.SwapPathExactAmountIn[]', + name: 'paths', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IBatchRouter.SwapExactInHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'querySwapExactInHook', + outputs: [ + { + internalType: 'uint256[]', + name: 'pathAmountsOut', + type: 'uint256[]', + }, + { internalType: 'address[]', name: 'tokensOut', type: 'address[]' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + components: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'bool', + name: 'isBuffer', + type: 'bool', + }, + ], + internalType: 'struct IBatchRouter.SwapPathStep[]', + name: 'steps', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'maxAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + ], + internalType: 'struct IBatchRouter.SwapPathExactAmountOut[]', + name: 'paths', + type: 'tuple[]', + }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'querySwapExactOut', + outputs: [ + { + internalType: 'uint256[]', + name: 'pathAmountsIn', + type: 'uint256[]', + }, + { internalType: 'address[]', name: 'tokensIn', type: 'address[]' }, + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + components: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'bool', + name: 'isBuffer', + type: 'bool', + }, + ], + internalType: 'struct IBatchRouter.SwapPathStep[]', + name: 'steps', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'maxAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + ], + internalType: 'struct IBatchRouter.SwapPathExactAmountOut[]', + name: 'paths', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IBatchRouter.SwapExactOutHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'querySwapExactOutHook', + outputs: [ + { + internalType: 'uint256[]', + name: 'pathAmountsIn', + type: 'uint256[]', + }, + { internalType: 'address[]', name: 'tokensIn', type: 'address[]' }, + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + components: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'bool', + name: 'isBuffer', + type: 'bool', + }, + ], + internalType: 'struct IBatchRouter.SwapPathStep[]', + name: 'steps', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'exactAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minAmountOut', + type: 'uint256', + }, + ], + internalType: 'struct IBatchRouter.SwapPathExactAmountIn[]', + name: 'paths', + type: 'tuple[]', + }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'swapExactIn', + outputs: [ + { + internalType: 'uint256[]', + name: 'pathAmountsOut', + type: 'uint256[]', + }, + { internalType: 'address[]', name: 'tokensOut', type: 'address[]' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + components: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'bool', + name: 'isBuffer', + type: 'bool', + }, + ], + internalType: 'struct IBatchRouter.SwapPathStep[]', + name: 'steps', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'exactAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minAmountOut', + type: 'uint256', + }, + ], + internalType: 'struct IBatchRouter.SwapPathExactAmountIn[]', + name: 'paths', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IBatchRouter.SwapExactInHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'swapExactInHook', + outputs: [ + { + internalType: 'uint256[]', + name: 'pathAmountsOut', + type: 'uint256[]', + }, + { internalType: 'address[]', name: 'tokensOut', type: 'address[]' }, + { + internalType: 'uint256[]', + name: 'amountsOut', + type: 'uint256[]', + }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + components: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'bool', + name: 'isBuffer', + type: 'bool', + }, + ], + internalType: 'struct IBatchRouter.SwapPathStep[]', + name: 'steps', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'maxAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + ], + internalType: 'struct IBatchRouter.SwapPathExactAmountOut[]', + name: 'paths', + type: 'tuple[]', + }, + { internalType: 'uint256', name: 'deadline', type: 'uint256' }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + name: 'swapExactOut', + outputs: [ + { + internalType: 'uint256[]', + name: 'pathAmountsIn', + type: 'uint256[]', + }, + { internalType: 'address[]', name: 'tokensIn', type: 'address[]' }, + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + components: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + components: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'bool', + name: 'isBuffer', + type: 'bool', + }, + ], + internalType: 'struct IBatchRouter.SwapPathStep[]', + name: 'steps', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'maxAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'exactAmountOut', + type: 'uint256', + }, + ], + internalType: 'struct IBatchRouter.SwapPathExactAmountOut[]', + name: 'paths', + type: 'tuple[]', + }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, + { internalType: 'bytes', name: 'userData', type: 'bytes' }, + ], + internalType: 'struct IBatchRouter.SwapExactOutHookParams', + name: 'params', + type: 'tuple', + }, + ], + name: 'swapExactOutHook', + outputs: [ + { + internalType: 'uint256[]', + name: 'pathAmountsIn', + type: 'uint256[]', + }, + { internalType: 'address[]', name: 'tokensIn', type: 'address[]' }, + { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + ], + stateMutability: 'nonpayable', + type: 'function', + }, + { stateMutability: 'payable', type: 'receive' }, +] as const; diff --git a/src/dex/balancer-v3/balancer-v3-e2e.test.ts b/src/dex/balancer-v3/balancer-v3-e2e.test.ts index 7f1bc76e9..250ddf333 100644 --- a/src/dex/balancer-v3/balancer-v3-e2e.test.ts +++ b/src/dex/balancer-v3/balancer-v3-e2e.test.ts @@ -59,6 +59,7 @@ function testForNetwork( tokenAAmount: string, tokenBAmount: string, nativeTokenAmount: string, + testNative: boolean, ) { const provider = new StaticJsonRpcProvider( generateConfig(network).privateHttpProvider, @@ -79,32 +80,34 @@ function testForNetwork( describe(`${side}`, () => { contractMethods.forEach((contractMethod: ContractMethod) => { describe(`${contractMethod}`, () => { - it(`${nativeTokenSymbol} -> ${tokenASymbol}`, async () => { - await testE2E( - tokens[nativeTokenSymbol], - tokens[tokenASymbol], - holders[nativeTokenSymbol], - side === SwapSide.SELL ? nativeTokenAmount : tokenAAmount, - side, - dexKey, - contractMethod, - network, - provider, - ); - }); - it(`${tokenASymbol} -> ${nativeTokenSymbol}`, async () => { - await testE2E( - tokens[tokenASymbol], - tokens[nativeTokenSymbol], - holders[tokenASymbol], - side === SwapSide.SELL ? tokenAAmount : nativeTokenAmount, - side, - dexKey, - contractMethod, - network, - provider, - ); - }); + if (testNative) { + it(`${nativeTokenSymbol} -> ${tokenASymbol}`, async () => { + await testE2E( + tokens[nativeTokenSymbol], + tokens[tokenASymbol], + holders[nativeTokenSymbol], + side === SwapSide.SELL ? nativeTokenAmount : tokenAAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it(`${tokenASymbol} -> ${nativeTokenSymbol}`, async () => { + await testE2E( + tokens[tokenASymbol], + tokens[nativeTokenSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : nativeTokenAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + } it(`${tokenASymbol} -> ${tokenBSymbol}`, async () => { await testE2E( tokens[tokenASymbol], @@ -125,10 +128,11 @@ function testForNetwork( }); } +// TODO - these tests dont currently run without full PS setup on Sepolia describe('BalancerV3 E2E', () => { const dexKey = 'BalancerV3'; - describe('Mainnet', () => { + describe('Mainnet, Weighted Path', () => { const network = Network.SEPOLIA; const tokenASymbol: string = 'bal'; @@ -146,6 +150,51 @@ describe('BalancerV3 E2E', () => { tokenAAmount, tokenBAmount, nativeTokenAmount, + true, + ); + }); + + describe('Mainnet, Stable Path', () => { + const network = Network.SEPOLIA; + + const tokenASymbol: string = 'aUsdcAave'; + const tokenBSymbol: string = 'aDaiAave'; + + const tokenAAmount: string = '10000000'; + const tokenBAmount: string = '1000000000000000000'; + const nativeTokenAmount = '0'; + + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + nativeTokenAmount, + false, + ); + }); + + describe('Mainnet, Boosted Path', () => { + const network = Network.SEPOLIA; + + const tokenASymbol: string = 'usdcAave'; + const tokenBSymbol: string = 'daiAave'; + + const tokenAAmount: string = '10000000'; + const tokenBAmount: string = '1000000000000000000'; + const nativeTokenAmount = '0'; + + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + nativeTokenAmount, + false, ); }); }); diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 4d0d51939..38775d812 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -5,7 +5,7 @@ import { Log, Logger } from '../../types'; import { catchParseLogError } from '../../utils'; import { StatefulEventSubscriber } from '../../stateful-event-subscriber'; import { IDexHelper } from '../../dex-helper/idex-helper'; -import { PoolState, PoolStateMap } from './types'; +import { PoolState, PoolStateMap, Step, TokenInfo } from './types'; import { getPoolsApi } from './getPoolsApi'; import { vaultExtensionAbi_V3 } from './abi/vaultExtension.V3'; import { decodeThrowError, getOnChainState } from './getOnChainState'; @@ -117,10 +117,10 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { blockNumber, ); - // Filter out all pools with hooks and paused pools + // Filter out all paused pools const filteredPools = Object.entries(allOnChainPools) .filter(([address, pool]) => { - return !(pool.hasHook || pool.isPoolPaused); + return !pool.isPoolPaused; }) .reduce((acc, [address, pool]) => { acc[address] = pool; @@ -252,12 +252,10 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { getMaxSwapAmount( pool: PoolState, - tokenIn: string, - tokenOut: string, + tokenIn: TokenInfo, + tokenOut: TokenInfo, swapKind: SwapKind, ): bigint { - const tokenInIndex = pool.tokens.indexOf(tokenIn); - const tokenOutIndex = pool.tokens.indexOf(tokenOut); // Find the maximum swap amount the pool will support const maxSwapAmount = this.vault.getMaxSwapAmount( { @@ -265,38 +263,33 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { balancesLiveScaled18: pool.balancesLiveScaled18, tokenRates: pool.tokenRates, scalingFactors: pool.scalingFactors, - indexIn: tokenInIndex, - indexOut: tokenOutIndex, + indexIn: tokenIn.index, + indexOut: tokenOut.index, }, pool, ); return maxSwapAmount; } - getSwapResult( - pool: PoolState, - amountRaw: bigint, - tokenIn: string, - tokenOut: string, - swapKind: SwapKind, - ): bigint { - if (pool.poolType === 'Stable' && 'amp' in pool) { - if (pool.ampIsUpdating) { - console.log(`!!!!!!! need to handle this correctly once SC updated`); - /* - Will be able to calculate current amp using pool amp start/stop time & values - */ - } + getSwapResult(steps: Step[], amountRaw: bigint, swapKind: SwapKind): bigint { + if (amountRaw === 0n) return 0n; + let amount = amountRaw; + let outputAmountRaw = 0n; + // Simulates the result of a multi-step swap path + for (let i = 0; i < steps.length; i++) { + const step = steps[i]; + outputAmountRaw = this.vault.swap( + { + ...step.swapInput, + amountRaw: amount, + swapKind, + }, + step.poolState, + ); + // Next step uses output from previous step as input + amount = outputAmountRaw; } - return this.vault.swap( - { - amountRaw, - tokenIn, - tokenOut, - swapKind, - }, - pool, - ); + return outputAmountRaw; } /** @@ -369,4 +362,145 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { }; }); } + + // If a token is "boosted" it can be auto wrapped/unwrapped by Vault, e.g. aDAI<>DAI + // mainToken is the actual token the pool would contain, e.g. in a bbausd type setup it would be aDAI/aUSDC/aUSDT + // underlyingToken would be the unwrapped, e.g. DAI/USDC/USDT + // need rate info to calculate wrap/unwrap + getTokenInfo(poolState: PoolState, tokenAddress: string): TokenInfo | null { + // Check in main tokens + let tokenIndex = poolState.tokens.indexOf(tokenAddress); + if (tokenIndex !== -1) { + return { + isBoosted: false, + mainToken: tokenAddress, + underlyingToken: null, + index: tokenIndex, + rate: poolState.tokenRates[tokenIndex], + }; + } + + // Check in underlying tokens if available + if (poolState.tokensUnderlying) { + tokenIndex = poolState.tokensUnderlying.indexOf(tokenAddress); + if (tokenIndex !== -1) { + return { + isBoosted: true, + mainToken: poolState.tokens[tokenIndex], + underlyingToken: tokenAddress, + index: tokenIndex, + rate: poolState.tokenRates[tokenIndex], + }; + } + } + + // Token not found + this.logger.error(`getTokenInfo token not found`); + return null; + } + + /** + * Prepares all the step data required to simulate maths and construct swap transaction. + * Balancer V3 has the concepts of Boosted Pools and ERC4626 Liquidity Buffers. + * These enable highly capital efficient pools and gas efficient swaps. + * To swap via a buffer we must provide the correct ""steps" to the router transaction. + * Wrap: e.g. USDC>aUSDC + * Unwrap: e.g. aUSDC>USDC + * A full swap between USDC>DAI for an example bbausd pool consisting of aDAI/aUSDC/aUSDT would look like: + * USDC[wrap-buffer]aUSDC[swap-pool]aDAI[unwrap-buffer]USDC + * See docs for further info: + * https://docs-v3.balancer.fi/concepts/explore-available-balancer-pools/boosted-pool.html + * https://docs-v3.balancer.fi/concepts/vault/buffer.html + */ + getSteps(pool: PoolState, tokenIn: TokenInfo, tokenOut: TokenInfo): Step[] { + if (tokenIn.isBoosted && tokenOut.isBoosted) { + return [ + // Wrap tokenIn underlying to main token + this.getWrapStep(tokenIn), + // Swap main > main + this.getSwapStep(pool, tokenIn, tokenOut), + // Unwrap tokenOut main to underlying token + this.getUnwrapStep(tokenOut), + ]; + } else if (tokenIn.isBoosted) { + return [ + // Wrap tokenIn underlying to main token + this.getWrapStep(tokenIn), + // Swap main > main + this.getSwapStep(pool, tokenIn, tokenOut), + ]; + } else if (tokenOut.isBoosted) { + return [ + // Swap main > main + this.getSwapStep(pool, tokenIn, tokenOut), + // Unwrap tokenOut main to underlying token + this.getUnwrapStep(tokenOut), + ]; + } else { + return [ + // Swap main > main + this.getSwapStep(pool, tokenIn, tokenOut), + ]; + } + } + + getWrapStep(token: TokenInfo): Step { + if (!token.underlyingToken) + throw new Error( + `Buffer wrap: token has no underlying. ${token.mainToken}`, + ); + // Vault expects pool to be the ERC4626 wrapped token, e.g. aUSDC + return { + pool: token.mainToken, + tokenOut: token.mainToken, + isBuffer: true, + swapInput: { + tokenIn: token.underlyingToken, + tokenOut: token.mainToken, + }, + poolState: { + poolType: 'Buffer', + rate: token.rate, + poolAddress: token.mainToken, + tokens: [token.mainToken, token.underlyingToken], // staticToken & underlying + }, + }; + } + + getUnwrapStep(token: TokenInfo): Step { + if (!token.underlyingToken) + throw new Error( + `Buffer unwrap: token has no underlying. ${token.mainToken}`, + ); + // Vault expects pool to be the ERC4626 wrapped token, e.g. aUSDC + return { + pool: token.mainToken, + tokenOut: token.underlyingToken, + isBuffer: true, + swapInput: { + tokenIn: token.mainToken, + tokenOut: token.underlyingToken, + }, + poolState: { + poolType: 'Buffer', + rate: token.rate, + poolAddress: token.mainToken, + tokens: [token.mainToken, token.underlyingToken], // staticToken & underlying + }, + }; + } + + getSwapStep(pool: PoolState, tokenIn: TokenInfo, tokenOut: TokenInfo): Step { + // A normal swap between two tokens in a pool + return { + pool: pool.address, + tokenOut: tokenOut.mainToken, + isBuffer: false, + swapInput: { + tokenIn: tokenIn.mainToken, + tokenOut: tokenOut.mainToken, + }, + poolState: pool, + }; + } } diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 287be9e2a..0f0142401 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -24,6 +24,7 @@ import { Interface } from '@ethersproject/abi'; import { balancerRouterAbi } from './abi/balancerRouter'; import { extractReturnAmountPosition } from '../../executor/utils'; import { getTopPoolsApi } from './getTopPoolsApi'; +import { balancerBatchRouterAbi } from './abi/balancerBatchRouter'; const MAX_UINT256 = '115792089237316195423570985008687907853269984665640564039457584007913129639935'; @@ -48,6 +49,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { logger: Logger; balancerRouter: Interface; + balancerBatchRouter: Interface; updateNewPoolsTimer?: NodeJS.Timer; updateRatesTimer?: NodeJS.Timer; @@ -66,6 +68,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { this.logger, ); this.balancerRouter = new Interface(balancerRouterAbi); + this.balancerBatchRouter = new Interface(balancerBatchRouterAbi); } // Initialize pricing is called once in the start of @@ -132,9 +135,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ): string[] { return Object.entries(pools) .filter(([, poolState]) => { - return ( - poolState.tokens.includes(tokenA) && poolState.tokens.includes(tokenB) - ); + return this.hasTokens(poolState, [tokenA, tokenB]); }) .map(([address]) => address); } @@ -155,14 +156,20 @@ export class BalancerV3 extends SimpleExchange implements IDex { ): PoolState[] { return Object.entries(pools) .filter(([address, poolState]) => { - const hasRequiredTokens = - poolState.tokens.includes(from) && poolState.tokens.includes(to); + const hasRequiredTokens = this.hasTokens(poolState, [from, to]); const isAllowedPool = !limitPools || limitPools.includes(address); return hasRequiredTokens && isAllowedPool; }) .map(([_, poolState]) => poolState as DeepMutable); } + hasTokens(pool: DeepReadonly, tokens: string[]): boolean { + return tokens.every( + token => + pool.tokens.includes(token) || pool.tokensUnderlying.includes(token), + ); + } + // Returns pool prices for amounts. // If limitPools is defined only pools in limitPools // should be used. If limitPools is undefined then @@ -214,34 +221,34 @@ export class BalancerV3 extends SimpleExchange implements IDex { for (let i = 0; i < allowedPools.length; i++) { const pool = { ...allowedPools[i], - // TODO - Remove mapping once maths updated to same poolType convention - poolType: this.mapToPoolType(allowedPools[i].poolType), }; + const tokenInInfo = this.eventPools.getTokenInfo(pool, tokenIn); + const tokenOutInfo = this.eventPools.getTokenInfo(pool, tokenOut); + if (!tokenInInfo || !tokenOutInfo) { + continue; + } + + const steps = this.eventPools.getSteps(pool, tokenInInfo, tokenOutInfo); + try { // This is the max amount the pool can swap const maxSwapAmount = this.eventPools.getMaxSwapAmount( pool, - tokenIn, - tokenOut, + tokenInInfo, + tokenOutInfo, swapKind, ); let unit = 0n; if (unitAmount < maxSwapAmount) - unit = this.eventPools.getSwapResult( - pool, - unitAmount, - tokenIn, - tokenOut, - swapKind, - ); + unit = this.eventPools.getSwapResult(steps, unitAmount, swapKind); const poolExchangePrice: PoolPrices = { prices: new Array(amounts.length).fill(0n), unit, data: { - poolAddress: pool.address, + steps: steps, }, exchange: this.dexKey, gasCost: 1, // TODO - this will be updated once final profiles done @@ -253,10 +260,8 @@ export class BalancerV3 extends SimpleExchange implements IDex { if (amounts[j] < maxSwapAmount) { // Uses balancer maths to calculate swap poolExchangePrice.prices[j] = this.eventPools.getSwapResult( - pool, + steps, amounts[j], - tokenIn, - tokenOut, swapKind, ); } @@ -273,13 +278,6 @@ export class BalancerV3 extends SimpleExchange implements IDex { return null; } - // This is a temp helper until we change maths library type to match - private mapToPoolType(apiPoolType: string): string { - if (apiPoolType === 'STABLE') return 'Stable'; - else if (apiPoolType === 'WEIGHTED') return 'Weighted'; - else return apiPoolType; - } - // Returns estimated gas cost of calldata for this DEX in multiSwap getCalldataGasCost( poolPrices: PoolPrices, @@ -302,7 +300,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ): AdapterExchangeParam { console.log(`!!!!!!!!!!!! getAdapterParam is being hit !!!!!!`); // TODO: complete me! - const { poolAddress } = data; + const { steps } = data; // Encode here the payload for adapter const payload = ''; @@ -325,20 +323,32 @@ export class BalancerV3 extends SimpleExchange implements IDex { side: SwapSide, ): DexExchangeParam { if (side === SwapSide.SELL) { + return this.getExactInParam(srcToken, destToken, srcAmount, data); + } else { + return this.getExactOutParam(srcToken, destToken, destAmount, data); + } + } + + getExactInParam( + srcToken: Address, + destToken: Address, + srcAmount: NumberAsString, + data: BalancerV3Data, + ): DexExchangeParam { + if (data.steps.length === 1) { const exchangeData = this.balancerRouter.encodeFunctionData( 'swapSingleTokenExactIn', [ - data.poolAddress, + data.steps[0].pool, srcToken, destToken, srcAmount, '0', // This should be limit for min amount out. Assume this is set elsewhere via Paraswap contract. - MAX_UINT256, + MAX_UINT256, // Deadline this.needWrapNative, // TODO vault can handle native assets '0x', ], ); - return { needWrapNative: this.needWrapNative, dexFuncHasRecipient: false, @@ -352,15 +362,61 @@ export class BalancerV3 extends SimpleExchange implements IDex { ), }; } else { + // for each step: + // if tokenIn == pool router uses removeLiquidity SINGLE_TOKEN_EXACT_IN + // if tokenOut == pool router uses addLiquidity UNBALANCED + const exchangeData = this.balancerBatchRouter.encodeFunctionResult( + 'swapExactIn', + [ + [ + { + tokenIn: srcToken, + steps: data.steps.map(step => ({ + pool: step.pool, + tokenOut: step.tokenOut, + isBuffer: step.isBuffer, + })), + exactAmountIn: srcAmount, + minAmountOut: '0', // This should be limit for min amount out. Assume this is set elsewhere via Paraswap contract. + }, + ], + MAX_UINT256, // Deadline + this.needWrapNative, // TODO vault can handle native assets + '0x', + ], + ); + + return { + needWrapNative: this.needWrapNative, + dexFuncHasRecipient: false, + exchangeData, + // This router handles single swaps + targetExchange: + BalancerV3Config.BalancerV3[this.network].balancerBatchRouterAddress, + returnAmountPos: extractReturnAmountPosition( + this.balancerBatchRouter, + 'swapExactIn', + ), + }; + } + } + + getExactOutParam( + srcToken: Address, + destToken: Address, + destAmount: NumberAsString, + data: BalancerV3Data, + ): DexExchangeParam { + if (data.steps.length === 1) { const exchangeData = this.balancerRouter.encodeFunctionData( 'swapSingleTokenExactOut', [ - data.poolAddress, + data.steps[0].pool, srcToken, destToken, - srcAmount, + destAmount, MAX_UINT256, // This should be limit for max amount in. Assume this is set elsewhere via Paraswap contract. - MAX_UINT256, + MAX_UINT256, // Deadline this.needWrapNative, // TODO vault can handle native assets '0x', ], @@ -378,6 +434,43 @@ export class BalancerV3 extends SimpleExchange implements IDex { 'swapSingleTokenExactOut', ), }; + } else { + // for each step: + // if tokenIn == pool use removeLiquidity SINGLE_TOKEN_EXACT_OUT + // if tokenOut == pool use addLiquidity SINGLE_TOKEN_EXACT_OUT + const exchangeData = this.balancerBatchRouter.encodeFunctionResult( + 'swapExactOut', + [ + [ + { + tokenIn: srcToken, + steps: data.steps.map(step => ({ + pool: step.pool, + tokenOut: step.tokenOut, + isBuffer: step.isBuffer, + })), + exactAmountOut: destAmount, + maxAmountIn: MAX_UINT256, // This should be limit for min amount out. Assume this is set elsewhere via Paraswap contract. + }, + ], + MAX_UINT256, // Deadline + this.needWrapNative, // TODO vault can handle native assets + '0x', + ], + ); + + return { + needWrapNative: this.needWrapNative, + dexFuncHasRecipient: false, + exchangeData, + // This router handles single swaps + targetExchange: + BalancerV3Config.BalancerV3[this.network].balancerBatchRouterAddress, + returnAmountPos: extractReturnAmountPosition( + this.balancerBatchRouter, + 'swapExactIn', + ), + }; } } @@ -405,7 +498,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ): Promise { const poolsWithToken = Object.entries(this.eventPools.getStaleState() || {}) .filter(([, poolState]) => { - return poolState.tokens.includes(tokenAddress); + return this.hasTokens(poolState, [tokenAddress]); }) .map(([address]) => address); diff --git a/src/dex/balancer-v3/config.ts b/src/dex/balancer-v3/config.ts index 1654100c3..27359f21b 100644 --- a/src/dex/balancer-v3/config.ts +++ b/src/dex/balancer-v3/config.ts @@ -18,6 +18,7 @@ export const BalancerV3Config: DexConfigMap = { vaultAddress: '0x30AF3689547354f82C70256894B07C9D0f067BB6', apiNetworkName: 'SEPOLIA', balancerRouterAddress: '0x77eDc69766409C599F06Ef0B551a0990CBfe13A7', + balancerBatchRouterAddress: '0x16Cf31c5c4f92ad6185D583080C84FEeb6074c78', }, }, }; diff --git a/src/dex/balancer-v3/getPoolsApi.ts b/src/dex/balancer-v3/getPoolsApi.ts index 83af683be..14f537dee 100644 --- a/src/dex/balancer-v3/getPoolsApi.ts +++ b/src/dex/balancer-v3/getPoolsApi.ts @@ -7,13 +7,16 @@ import { parseUnits } from 'ethers/lib/utils'; interface PoolToken { address: string; weight: string | null; + isErc4626: boolean; + underlyingToken: { + address: string; + } | null; } interface Pool { id: string; type: string; poolTokens: PoolToken[]; - factory: string; } interface QueryResponse { @@ -52,8 +55,11 @@ function createQuery( poolTokens { address weight + isErc4626 + underlyingToken { + address + } } - factory } } `; @@ -64,6 +70,9 @@ function toImmutablePoolStateMap(pools: Pool[]): ImmutablePoolStateMap { const immutablePoolState: CommonImmutablePoolState = { address: pool.id, tokens: pool.poolTokens.map(t => t.address), + tokensUnderlying: pool.poolTokens.map(t => + t.underlyingToken ? t.underlyingToken.address : null, + ), weights: pool.poolTokens.map(t => t.weight ? parseUnits(t.weight, 18).toBigInt() : 0n, ), diff --git a/src/dex/balancer-v3/types.ts b/src/dex/balancer-v3/types.ts index a032a35b6..53cc73686 100644 --- a/src/dex/balancer-v3/types.ts +++ b/src/dex/balancer-v3/types.ts @@ -1,10 +1,14 @@ +import { BufferState } from '@balancer-labs/balancer-maths'; import { Address } from '../../types'; // Immutable data types available on all pools (Available from API) export type CommonImmutablePoolState = { address: string; poolType: string; + // For boosted pools tokens is the actual pool token wrapped, e.g. aUSDC/aDAI tokens: string[]; + // For boosted pools underlying is the unwrapped token, e.g. USDC/DAI + tokensUnderlying: (string | null)[]; weights: bigint[]; // TODO re-introduce this once added to API // scalingFactors: bigint[]; @@ -49,8 +53,19 @@ export type ImmutablePoolStateMap = { [address: string]: CommonImmutablePoolState; }; +export type Step = { + pool: Address; + tokenOut: Address; + isBuffer: boolean; + swapInput: { + tokenIn: Address; + tokenOut: Address; + }; + poolState: PoolState | BufferState; +}; + export type BalancerV3Data = { - poolAddress: string; + steps: Step[]; }; export type DexParams = { @@ -60,4 +75,13 @@ export type DexParams = { // This router handles single swaps // https://github.com/balancer/balancer-v3-monorepo/blob/main/pkg/interfaces/contracts/vault/IRouter.sol balancerRouterAddress: string; + balancerBatchRouterAddress: string; +}; + +export type TokenInfo = { + isBoosted: boolean; + underlyingToken: string | null; + mainToken: string; + index: number; + rate: bigint; }; diff --git a/tests/constants-e2e.ts b/tests/constants-e2e.ts index 1ef7d2229..5778a4bb9 100644 --- a/tests/constants-e2e.ts +++ b/tests/constants-e2e.ts @@ -1496,6 +1496,18 @@ export const Tokens: { address: `0xff34b3d4aee8ddcd6f9afffb6fe49bd371b8a357`, decimals: 18, }, + usdcAave: { + address: `0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8`, + decimals: 6, + }, + aDaiAave: { + address: `0xde46e43f46ff74a23a65ebb0580cbe3dfe684a17`, + decimals: 18, + }, + aUsdcAave: { + address: `0x8a88124522dbbf1e56352ba3de1d9f78c143751e`, + decimals: 6, + }, }, }; diff --git a/yarn.lock b/yarn.lock index 617be3909..8d5675a9e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -341,10 +341,10 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@balancer-labs/balancer-maths@^0.0.12": - version "0.0.12" - resolved "https://registry.yarnpkg.com/@balancer-labs/balancer-maths/-/balancer-maths-0.0.12.tgz#2a02a5768c1e81cdce4049dea86c990e83bb9396" - integrity sha512-IjjXyTAhVn/rtfMn9kEvv8gsOLAGg1yXh04zZb3GyYgbV89x08dsCivoLTvqj71cSlsnpbmYvpM9N3DEhVaczQ== +"@balancer-labs/balancer-maths@^0.0.13": + version "0.0.13" + resolved "https://registry.yarnpkg.com/@balancer-labs/balancer-maths/-/balancer-maths-0.0.13.tgz#86a20c20b09ce4dcde762ca373560bfac41d9097" + integrity sha512-/E6QdZ5u0XM0diZ8Cpk11vHIAqYgZXZ6WTQtaJTqzWC0K2HzBgZNjxVzP/UXyK8PZQx8ARd3vcJAY47Vohf0gQ== "@balancer-labs/sor@4.1.1-beta.4": version "4.1.1-beta.4" From 1f09ab38f19734bf7edf4079c9f815ae8bb5570c Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 18 Oct 2024 07:52:55 +0100 Subject: [PATCH 16/66] test: Add integration tests (including boosted). Currently fail because of maths mis-match. --- .../balancer-v3-integration.test.ts | 384 ++++++++++++++---- 1 file changed, 312 insertions(+), 72 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-integration.test.ts b/src/dex/balancer-v3/balancer-v3-integration.test.ts index b025b2de8..9ecdf9c98 100644 --- a/src/dex/balancer-v3/balancer-v3-integration.test.ts +++ b/src/dex/balancer-v3/balancer-v3-integration.test.ts @@ -9,85 +9,193 @@ import { BI_POWS } from '../../bigint-constants'; import { BalancerV3 } from './balancer-v3'; import { checkPoolPrices, - checkPoolsLiquidity, checkConstantPoolPrices, + checkPoolsLiquidity, } from '../../../tests/utils'; import { Tokens } from '../../../tests/constants-e2e'; +import { BalancerV3Config } from './config'; +import { balancerRouterAbi } from './abi/balancerRouter'; +import { BalancerV3Data, Step } from './types'; +import { Address, ExchangePrices, PoolPrices } from '../../types'; +import { balancerBatchRouterAbi } from './abi/balancerBatchRouter'; -/* - README - ====== - - This test script adds tests for BalancerV3 general integration - with the DEX interface. The test cases below are example tests. - It is recommended to add tests which cover BalancerV3 specific - logic. - - You can run this individual test script by running: - `npx jest src/dex//-integration.test.ts` - - (This comment should be removed from the final implementation) -*/ +function getQuerySwapSingleTokenCalldata( + routerAddress: Address, + routerInterface: Interface, + amounts: bigint[], + step: Step, + side: SwapSide, +) { + return amounts + .filter(amount => amount !== 0n) + .map(amount => { + return { + target: routerAddress, + callData: routerInterface.encodeFunctionData( + side === SwapSide.SELL + ? `querySwapSingleTokenExactIn` + : `querySwapSingleTokenExactOut`, + [ + step.pool, + step.swapInput.tokenIn, + step.swapInput.tokenOut, + amount, + '0x', + ], + ), + }; + }); +} -function getReaderCalldata( - exchangeAddress: string, - readerIface: Interface, +function getQuerySwapMultiTokenCalldata( + routerAddress: Address, + routerInterface: Interface, amounts: bigint[], - funcName: string, - // TODO: Put here additional arguments you need + steps: Step[], + side: SwapSide, ) { - return amounts.map(amount => ({ - target: exchangeAddress, - callData: readerIface.encodeFunctionData(funcName, [ - // TODO: Put here additional arguments to encode them - amount, - ]), + const tokenIn = steps[0].swapInput.tokenIn; + const stepsNew = steps.map(s => ({ + pool: s.pool, + tokenOut: s.tokenOut, + isBuffer: s.isBuffer, })); + return amounts + .filter(amount => amount !== 0n) + .map(amount => { + let args: any[] = []; + if (side === SwapSide.SELL) + args = [ + { + tokenIn, + steps: stepsNew, + exactAmountIn: amount, + minAmountOut: 0n, + }, + ]; + else + args = [ + { + tokenIn, + steps: stepsNew, + exactAmountOut: amount, + maxAmountIn: 0n, + }, + ]; + return { + target: routerAddress, + callData: routerInterface.encodeFunctionData( + side === SwapSide.SELL ? `querySwapExactIn` : `querySwapExactOut`, + [args, '0x'], + ), + }; + }); } -function decodeReaderResult( - results: Result, - readerIface: Interface, - funcName: string, +async function querySinglePathPrices( + network: number, + side: SwapSide, + balancerV3: BalancerV3, + blockNumber: number, + price: PoolPrices, + amounts: bigint[], ) { - // TODO: Adapt this function for your needs - return results.map(result => { - const parsed = readerIface.decodeFunctionResult(funcName, result); - return BigInt(parsed[0]._hex); - }); + const balancerRouter = new Interface(balancerRouterAbi); + const readerCallData = getQuerySwapSingleTokenCalldata( + BalancerV3Config.BalancerV3[network].balancerRouterAddress, + balancerRouter, + amounts, + price.data.steps[0], + side, + ); + + const expectedPrices = [0n]; + for (const call of readerCallData) { + const result = await balancerV3.dexHelper.provider.call( + { + to: call.target, + data: call.callData, + }, + blockNumber, + ); + const parsed = balancerRouter.decodeFunctionResult( + side === SwapSide.SELL + ? `querySwapSingleTokenExactIn` + : `querySwapSingleTokenExactOut`, + result, + ); + expectedPrices.push(BigInt(parsed[0]._hex)); + } + return expectedPrices; } -async function checkOnChainPricing( +async function queryMultiPathPrices( + network: number, + side: SwapSide, balancerV3: BalancerV3, - funcName: string, blockNumber: number, - prices: bigint[], + price: PoolPrices, amounts: bigint[], ) { - const exchangeAddress = ''; // TODO: Put here the real exchange address - - // TODO: Replace dummy interface with the real one - // Normally you can get it from balancerV3.Iface or from eventPool. - // It depends on your implementation - const readerIface = new Interface(''); - - const readerCallData = getReaderCalldata( - exchangeAddress, - readerIface, - amounts.slice(1), - funcName, - ); - const readerResult = ( - await balancerV3.dexHelper.multiContract.methods - .aggregate(readerCallData) - .call({}, blockNumber) - ).returnData; - - const expectedPrices = [0n].concat( - decodeReaderResult(readerResult, readerIface, funcName), + const balancerBatchRouter = new Interface(balancerBatchRouterAbi); + const readerCallData = getQuerySwapMultiTokenCalldata( + BalancerV3Config.BalancerV3[network].balancerBatchRouterAddress, + balancerBatchRouter, + amounts, + price.data.steps, + side, ); - expect(prices).toEqual(expectedPrices); + const expectedPrices = [0n]; + for (const call of readerCallData) { + const result = await balancerV3.dexHelper.provider.call( + { + to: call.target, + data: call.callData, + }, + blockNumber, + ); + const parsed = balancerBatchRouter.decodeFunctionResult( + side === SwapSide.SELL ? `querySwapExactIn` : `querySwapExactOut`, + result, + ); + expectedPrices.push(BigInt(parsed[2][0]._hex)); + } + return expectedPrices; +} + +// Note - this is currently needed because queries won't work with multicall but should be updated in future +async function checkOnChainPricingNonMulti( + network: number, + side: SwapSide, + balancerV3: BalancerV3, + blockNumber: number, + prices: ExchangePrices, + amounts: bigint[], +) { + // test match for each returned price + for (const price of prices) { + let expectedPrices: bigint[] = []; + if (price.data.steps.length === 1) + expectedPrices = await querySinglePathPrices( + network, + side, + balancerV3, + blockNumber, + price, + amounts, + ); + else + expectedPrices = await queryMultiPathPrices( + network, + side, + balancerV3, + blockNumber, + price, + amounts, + ); + expect(price.prices).toEqual(expectedPrices); + } } async function testPricingOnNetwork( @@ -99,7 +207,6 @@ async function testPricingOnNetwork( destTokenSymbol: string, side: SwapSide, amounts: bigint[], - funcNameToCheck: string, ) { const networkTokens = Tokens[network]; @@ -137,11 +244,12 @@ async function testPricingOnNetwork( } // Check if onchain pricing equals to calculated ones - await checkOnChainPricing( + await checkOnChainPricingNonMulti( + network, + side, balancerV3, - funcNameToCheck, blockNumber, - poolPrices![0].prices, + poolPrices!, amounts, ); } @@ -151,16 +259,106 @@ describe('BalancerV3', function () { let blockNumber: number; let balancerV3: BalancerV3; - describe('Mainnet', () => { - const network = Network.MAINNET; + describe('Weighted Pool', () => { + const network = Network.SEPOLIA; const dexHelper = new DummyDexHelper(network); const tokens = Tokens[network]; + const srcTokenSymbol = 'bal'; + const destTokenSymbol = 'daiAave'; + + const amountsForSell = [ + 0n, + 1n * BI_POWS[tokens[srcTokenSymbol].decimals], + 2n * BI_POWS[tokens[srcTokenSymbol].decimals], + 3n * BI_POWS[tokens[srcTokenSymbol].decimals], + 4n * BI_POWS[tokens[srcTokenSymbol].decimals], + 5n * BI_POWS[tokens[srcTokenSymbol].decimals], + 6n * BI_POWS[tokens[srcTokenSymbol].decimals], + 7n * BI_POWS[tokens[srcTokenSymbol].decimals], + 8n * BI_POWS[tokens[srcTokenSymbol].decimals], + 9n * BI_POWS[tokens[srcTokenSymbol].decimals], + 10n * BI_POWS[tokens[srcTokenSymbol].decimals], + ]; - // TODO: Put here token Symbol to check against - // Don't forget to update relevant tokens in constant-e2e.ts - const srcTokenSymbol = 'srcTokenSymbol'; - const destTokenSymbol = 'destTokenSymbol'; + const amountsForBuy = [ + 0n, + 1n * BI_POWS[tokens[destTokenSymbol].decimals], + 2n * BI_POWS[tokens[destTokenSymbol].decimals], + 3n * BI_POWS[tokens[destTokenSymbol].decimals], + 4n * BI_POWS[tokens[destTokenSymbol].decimals], + 5n * BI_POWS[tokens[destTokenSymbol].decimals], + 6n * BI_POWS[tokens[destTokenSymbol].decimals], + 7n * BI_POWS[tokens[destTokenSymbol].decimals], + 8n * BI_POWS[tokens[destTokenSymbol].decimals], + 9n * BI_POWS[tokens[destTokenSymbol].decimals], + 10n * BI_POWS[tokens[destTokenSymbol].decimals], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + balancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (balancerV3.initializePricing) { + await balancerV3.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.SELL, + amountsForSell, + ); + }); + + it('getPoolIdentifiers and getPricesVolume BUY', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.BUY, + amountsForBuy, + ); + }); + + it('getTopPoolsForToken', async function () { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (newBalancerV3.updatePoolState) { + await newBalancerV3.updatePoolState(); + } + const poolLiquidity = await newBalancerV3.getTopPoolsForToken( + tokens[srcTokenSymbol].address, + 10, + ); + console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); + + if (!newBalancerV3.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity( + poolLiquidity, + Tokens[network][srcTokenSymbol].address, + dexKey, + ); + } + }); + }); + + describe('Boosted Pool', () => { + const network = Network.SEPOLIA; + const dexHelper = new DummyDexHelper(network); + + const tokens = Tokens[network]; + const srcTokenSymbol = 'usdcAave'; + const destTokenSymbol = 'daiAave'; const amountsForSell = [ 0n, @@ -208,7 +406,6 @@ describe('BalancerV3', function () { destTokenSymbol, SwapSide.SELL, amountsForSell, - '', // TODO: Put here proper function name to check pricing ); }); @@ -222,7 +419,6 @@ describe('BalancerV3', function () { destTokenSymbol, SwapSide.BUY, amountsForBuy, - '', // TODO: Put here proper function name to check pricing ); }); @@ -249,3 +445,47 @@ describe('BalancerV3', function () { }); }); }); + +// Add back once multicall queries are working +/* +function decodeQuerySwapSingleTokenResult(results: Result, side: SwapSide) { + const balancerRouter = new Interface(balancerRouterAbi); + return results.map(result => { + const parsed = balancerRouter.decodeFunctionResult( + side === SwapSide.SELL + ? `querySwapSingleTokenExactIn` + : `querySwapSingleTokenExactOut`, + result, + ); + return BigInt(parsed[0]._hex); + }); +} + +async function checkOnChainPricing( + network: number, + side: SwapSide, + balancerV3: BalancerV3, + blockNumber: number, + prices: ExchangePrices, + amounts: bigint[], +) { + // test match for each returned price + for (const price of prices) { + const readerCallData = getQuerySwapSingleTokenCalldata( + network, + amounts, + price.data.steps[0], + side, + ); + const readerResult = ( + await balancerV3.dexHelper.multiContract.methods + .aggregate(readerCallData) + .call({}, blockNumber) + ).returnData; + const expectedPrices = [0n].concat( + decodeQuerySwapSingleTokenResult(readerResult, side), + ); + expect(price.prices).toEqual(expectedPrices); + } +} + */ From 43f12d71336e8b6f244f1e2eba3d57e7b1c3746d Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 6 Nov 2024 15:42:03 +0200 Subject: [PATCH 17/66] chore: remove redundant params on Sepolia config --- src/config.ts | 71 +++------------------------------------------------ 1 file changed, 3 insertions(+), 68 deletions(-) diff --git a/src/config.ts b/src/config.ts index f15bbb8a3..a8be00c2c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -431,84 +431,19 @@ const baseConfigs: { [network: number]: BaseConfig } = { multicallV2Address: '0xcA11bde05977b3631167028862bE2a173976CA11', privateHttpProvider: process.env.HTTP_PROVIDER_11155111, augustusV6Address: '0x6a000f20005980200259b80c5102003040001068', + adapterAddresses: {}, + rfqConfigs: {}, + hashFlowDisabledMMs: [], executorsAddresses: { Executor01: '0xa600910B670804230E00A100000D28000AE005C0', Executor02: '0x3800091020a00290f20606b000000000E38c33Ef', Executor03: '0x20004f017a0bC0050bc004d9C500a7A089800000', }, - adapterAddresses: { - Adapter01: '0x9bE264469eF954c139Da4A45Cf76CbCC5e3A6A73', - Adapter02: '0xFC2Ba6E830a04C25e207B8214b26d8C713F6881F', - Adapter03: '0xBAEeb4540f59d30E567a5B563CC0c4587eDd9366', - Adapter04: '0x369A2FDb910d432f0a07381a5E3d27572c876713', - Adapter05: '0x3329dfa55A40B450952FBE0203167Ae6908E656d', - Adapter06: '0xAeb7B3688a658C3f3B1AEd94d69b7b8045D64B57', - BuyAdapter: '0x84bEF12C9931cE12662cc9F2366b6a5029E4BD29', - BuyAdapter02: '0x2299568c3299e7420033deA9009233FF89F5C485', - }, uniswapV2ExchangeRouterAddress: '0xF9234CB08edb93c0d4a4d4c70cC3FfD070e78e07', rpcPollingMaxAllowedStateDelayInBlocks: 0, rpcPollingBlocksBackToTriggerUpdate: 0, - swaapV2AuthToken: process.env.API_KEY_SWAAP_V2_AUTH_TOKEN || '', - hashFlowAuthToken: process.env.API_KEY_HASHFLOW_AUTH_TOKEN || '', - idleDaoAuthToken: process.env.API_KEY_IDLEDAO_AUTH_TOKEN || '', - hashFlowDisabledMMs: - process.env[`HASHFLOW_DISABLED_MMS_1`]?.split(',') || [], uniswapV3EventLoggingSampleRate: 0, - rfqConfigs: { - DummyParaSwapPool: { - maker: process.env.TEST_ADDRESS!, - tokensConfig: { - reqParams: { - url: `http://localhost:${PORT_TEST_SERVER}/tokens`, - method: 'GET', - }, - secret: { - domain: 'paraswap-test', - accessKey: 'access', - secretKey: 'secret', - }, - intervalMs: 1000 * 60 * 60 * 10, // every 10 minutes - dataTTLS: 1000 * 60 * 60 * 11, // ttl 11 minutes - }, - pairsConfig: { - reqParams: { - url: `http://localhost:${PORT_TEST_SERVER}/pairs`, - method: 'GET', - }, - secret: { - domain: 'paraswap-test', - accessKey: 'access', - secretKey: 'secret', - }, - intervalMs: 1000 * 60 * 60 * 10, // every 10 minutes - dataTTLS: 1000 * 60 * 60 * 11, // ttl 11 minutes - }, - rateConfig: { - reqParams: { - url: `http://localhost:${PORT_TEST_SERVER}/prices`, - method: 'GET', - }, - secret: { - domain: 'paraswap-test', - accessKey: 'access', - secretKey: 'secret', - }, - intervalMs: 1000 * 60 * 60 * 1, // every 1 minute - dataTTLS: 1000 * 60 * 60 * 1, // ttl 1 minute - }, - firmRateConfig: { - url: `http://localhost:${PORT_TEST_SERVER}/firm`, - method: 'POST', - secret: { - domain: 'paraswap-test', - accessKey: 'access', - secretKey: 'secret', - }, - }, - }, - }, forceRpcFallbackDexs: [], }, }; From 820b7ecab63d5423671d14ef9eecb1811459efe3 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 6 Nov 2024 15:43:12 +0200 Subject: [PATCH 18/66] fix: remove adapters support --- src/dex/balancer-v3/balancer-v3.ts | 35 ++++++------------------------ src/dex/balancer-v3/config.ts | 6 ----- 2 files changed, 7 insertions(+), 34 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 0f0142401..5d002ee44 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -16,7 +16,7 @@ import { IDex } from '../../dex/idex'; import { IDexHelper } from '../../dex-helper/idex-helper'; import { BalancerV3Data, PoolState, PoolStateMap } from './types'; import { SimpleExchange } from '../simple-exchange'; -import { BalancerV3Config, Adapters } from './config'; +import { BalancerV3Config } from './config'; import { BalancerV3EventPool } from './balancer-v3-pool'; import { NumberAsString } from '@paraswap/core'; import { SwapKind } from '@balancer-labs/balancer-maths'; @@ -57,7 +57,6 @@ export class BalancerV3 extends SimpleExchange implements IDex { readonly network: Network, readonly dexKey: string, readonly dexHelper: IDexHelper, - protected adapters = Adapters[network] || {}, ) { super(dexHelper, dexKey); this.logger = dexHelper.getLogger(dexKey); @@ -101,10 +100,8 @@ export class BalancerV3 extends SimpleExchange implements IDex { } } - // Returns the list of contract adapters (name and index) - // for a buy/sell. Return null if there are no adapters. - getAdapters(side: SwapSide): { name: string; index: number }[] | null { - return this.adapters[side] ? this.adapters[side] : null; + getAdapters(side: SwapSide): null { + return null; } // Returns list of pool identifiers that can be used @@ -286,29 +283,11 @@ export class BalancerV3 extends SimpleExchange implements IDex { return CALLDATA_GAS_COST.DEX_NO_PAYLOAD; } - // Encode params required by the exchange adapter - // V5: Used for multiSwap, buy & megaSwap - // V6: Not used, can be left blank - // Hint: abiCoder.encodeParameter() could be useful - getAdapterParam( - srcToken: string, - destToken: string, - srcAmount: string, - destAmount: string, - data: BalancerV3Data, - side: SwapSide, - ): AdapterExchangeParam { - console.log(`!!!!!!!!!!!! getAdapterParam is being hit !!!!!!`); - // TODO: complete me! - const { steps } = data; - - // Encode here the payload for adapter - const payload = ''; - + // Not used for V6 + getAdapterParam(): AdapterExchangeParam { return { - targetExchange: - BalancerV3Config.BalancerV3[this.network].balancerRouterAddress, - payload, + targetExchange: '0x', + payload: '0x', networkFee: '0', }; } diff --git a/src/dex/balancer-v3/config.ts b/src/dex/balancer-v3/config.ts index 27359f21b..44ee33f5f 100644 --- a/src/dex/balancer-v3/config.ts +++ b/src/dex/balancer-v3/config.ts @@ -22,9 +22,3 @@ export const BalancerV3Config: DexConfigMap = { }, }, }; - -export const Adapters: Record = { - // TODO: add adapters for each chain - // This is an example to copy - [Network.MAINNET]: { [SwapSide.SELL]: [{ name: '', index: 0 }] }, -}; From 9622808f46dbcf396b83c3a3d791af83e833feb9 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 28 Nov 2024 09:58:13 +0000 Subject: [PATCH 19/66] chore: Bump maths package to latest. --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 53165156e..6251834a0 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ }, "dependencies": { "@0x/utils": "^4.5.2", - "@balancer-labs/balancer-maths": "^0.0.13", + "@balancer-labs/balancer-maths": "^0.0.18", "@balancer-labs/sor": "4.1.1-beta.4", "@bgd-labs/aave-address-book": "2.21.1", "@ethersproject/abi": "^5.7.0", diff --git a/yarn.lock b/yarn.lock index 8d5675a9e..98b9966fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -341,10 +341,10 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@balancer-labs/balancer-maths@^0.0.13": - version "0.0.13" - resolved "https://registry.yarnpkg.com/@balancer-labs/balancer-maths/-/balancer-maths-0.0.13.tgz#86a20c20b09ce4dcde762ca373560bfac41d9097" - integrity sha512-/E6QdZ5u0XM0diZ8Cpk11vHIAqYgZXZ6WTQtaJTqzWC0K2HzBgZNjxVzP/UXyK8PZQx8ARd3vcJAY47Vohf0gQ== +"@balancer-labs/balancer-maths@^0.0.18": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@balancer-labs/balancer-maths/-/balancer-maths-0.0.18.tgz#152c88a553fd1222d20e1e600f3c8c183e603e39" + integrity sha512-IVbaNQpcLaesjzZaMx6Hr2XJqgh+3lW3v8FthWpjavLJ6R8R2oBGi2IbrV7tER9rnTSv4IxKueCKMy6AialXlg== "@balancer-labs/sor@4.1.1-beta.4": version "4.1.1-beta.4" From 308a1a48fcc34f77d7d52e8130939a1e0bf4dea7 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 28 Nov 2024 10:04:12 +0000 Subject: [PATCH 20/66] chore: Update to deploy11, config, abis, etc. --- scripts/run-dex-integration-v3.ts | 2 +- .../balancer-v3/abi/balancerBatchRouter.ts | 365 +++- src/dex/balancer-v3/abi/balancerRouter.ts | 1113 ++++++++--- src/dex/balancer-v3/abi/vaultExtension.V3.ts | 1665 +++++++++++++---- src/dex/balancer-v3/balancer-v3-e2e.test.ts | 2 +- .../balancer-v3-integration.test.ts | 13 +- src/dex/balancer-v3/balancer-v3.ts | 8 +- src/dex/balancer-v3/config.ts | 6 +- src/dex/balancer-v3/getPoolsApi.ts | 2 +- src/dex/balancer-v3/types.ts | 2 +- tests/constants-e2e.ts | 6 +- 11 files changed, 2530 insertions(+), 654 deletions(-) diff --git a/scripts/run-dex-integration-v3.ts b/scripts/run-dex-integration-v3.ts index 17aefb8e9..e0c5b59a5 100644 --- a/scripts/run-dex-integration-v3.ts +++ b/scripts/run-dex-integration-v3.ts @@ -33,7 +33,7 @@ const usdcAave = { decimals: 6, }; -const amounts = [0n, BI_POWS[19], 20000000000000000000n]; +const amounts = [0n, BI_POWS[18], BI_POWS[19], 20000000000000000000n]; async function main() { const dexHelper = new DummyDexHelper(Network.SEPOLIA); diff --git a/src/dex/balancer-v3/abi/balancerBatchRouter.ts b/src/dex/balancer-v3/abi/balancerBatchRouter.ts index e15c2bc1d..8a3cd4d96 100644 --- a/src/dex/balancer-v3/abi/balancerBatchRouter.ts +++ b/src/dex/balancer-v3/abi/balancerBatchRouter.ts @@ -1,62 +1,159 @@ export const balancerBatchRouterAbi = [ { inputs: [ - { internalType: 'contract IVault', name: 'vault', type: 'address' }, - { internalType: 'contract IWETH', name: 'weth', type: 'address' }, + { + internalType: 'contract IVault', + name: 'vault', + type: 'address', + }, + { + internalType: 'contract IWETH', + name: 'weth', + type: 'address', + }, { internalType: 'contract IPermit2', name: 'permit2', type: 'address', }, + { + internalType: 'string', + name: 'version', + type: 'string', + }, ], stateMutability: 'nonpayable', type: 'constructor', }, { - inputs: [{ internalType: 'address', name: 'target', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + ], name: 'AddressEmptyCode', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'account', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + ], name: 'AddressInsufficientBalance', type: 'error', }, - { inputs: [], name: 'EthTransfer', type: 'error' }, - { inputs: [], name: 'FailedInnerCall', type: 'error' }, - { inputs: [], name: 'InsufficientEth', type: 'error' }, - { inputs: [], name: 'ReentrancyGuardReentrantCall', type: 'error' }, + { + inputs: [], + name: 'ErrorSelectorNotFound', + type: 'error', + }, + { + inputs: [], + name: 'EthTransfer', + type: 'error', + }, + { + inputs: [], + name: 'FailedInnerCall', + type: 'error', + }, + { + inputs: [], + name: 'InputLengthMismatch', + type: 'error', + }, + { + inputs: [], + name: 'InsufficientEth', + type: 'error', + }, + { + inputs: [], + name: 'ReentrancyGuardReentrantCall', + type: 'error', + }, { inputs: [ - { internalType: 'uint8', name: 'bits', type: 'uint8' }, - { internalType: 'uint256', name: 'value', type: 'uint256' }, + { + internalType: 'uint8', + name: 'bits', + type: 'uint8', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, ], name: 'SafeCastOverflowedUintDowncast', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'token', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'token', + type: 'address', + }, + ], name: 'SafeERC20FailedOperation', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + ], name: 'SenderIsNotVault', type: 'error', }, - { inputs: [], name: 'SwapDeadline', type: 'error' }, - { inputs: [], name: 'TransientIndexOutOfBounds', type: 'error' }, + { + inputs: [], + name: 'SwapDeadline', + type: 'error', + }, + { + inputs: [], + name: 'TransientIndexOutOfBounds', + type: 'error', + }, { inputs: [], name: 'getSender', - outputs: [{ internalType: 'address', name: '', type: 'address' }], + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], stateMutability: 'view', type: 'function', }, { - inputs: [{ internalType: 'bytes[]', name: 'data', type: 'bytes[]' }], + inputs: [ + { + internalType: 'bytes[]', + name: 'data', + type: 'bytes[]', + }, + ], name: 'multicall', - outputs: [{ internalType: 'bytes[]', name: 'results', type: 'bytes[]' }], + outputs: [ + { + internalType: 'bytes[]', + name: 'results', + type: 'bytes[]', + }, + ], stateMutability: 'payable', type: 'function', }, @@ -64,8 +161,16 @@ export const balancerBatchRouterAbi = [ inputs: [ { components: [ - { internalType: 'address', name: 'token', type: 'address' }, - { internalType: 'address', name: 'owner', type: 'address' }, + { + internalType: 'address', + name: 'token', + type: 'address', + }, + { + internalType: 'address', + name: 'owner', + type: 'address', + }, { internalType: 'address', name: 'spender', @@ -76,7 +181,11 @@ export const balancerBatchRouterAbi = [ name: 'amount', type: 'uint256', }, - { internalType: 'uint256', name: 'nonce', type: 'uint256' }, + { + internalType: 'uint256', + name: 'nonce', + type: 'uint256', + }, { internalType: 'uint256', name: 'deadline', @@ -136,11 +245,25 @@ export const balancerBatchRouterAbi = [ name: 'permit2Batch', type: 'tuple', }, - { internalType: 'bytes', name: 'permit2Signature', type: 'bytes' }, - { internalType: 'bytes[]', name: 'multicallData', type: 'bytes[]' }, + { + internalType: 'bytes', + name: 'permit2Signature', + type: 'bytes', + }, + { + internalType: 'bytes[]', + name: 'multicallData', + type: 'bytes[]', + }, ], name: 'permitBatchAndCall', - outputs: [{ internalType: 'bytes[]', name: 'results', type: 'bytes[]' }], + outputs: [ + { + internalType: 'bytes[]', + name: 'results', + type: 'bytes[]', + }, + ], stateMutability: 'payable', type: 'function', }, @@ -190,7 +313,16 @@ export const balancerBatchRouterAbi = [ name: 'paths', type: 'tuple[]', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'querySwapExactIn', outputs: [ @@ -199,7 +331,11 @@ export const balancerBatchRouterAbi = [ name: 'pathAmountsOut', type: 'uint256[]', }, - { internalType: 'address[]', name: 'tokensOut', type: 'address[]' }, + { + internalType: 'address[]', + name: 'tokensOut', + type: 'address[]', + }, { internalType: 'uint256[]', name: 'amountsOut', @@ -267,8 +403,16 @@ export const balancerBatchRouterAbi = [ name: 'deadline', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct IBatchRouter.SwapExactInHookParams', name: 'params', @@ -282,7 +426,11 @@ export const balancerBatchRouterAbi = [ name: 'pathAmountsOut', type: 'uint256[]', }, - { internalType: 'address[]', name: 'tokensOut', type: 'address[]' }, + { + internalType: 'address[]', + name: 'tokensOut', + type: 'address[]', + }, { internalType: 'uint256[]', name: 'amountsOut', @@ -338,7 +486,16 @@ export const balancerBatchRouterAbi = [ name: 'paths', type: 'tuple[]', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'querySwapExactOut', outputs: [ @@ -347,8 +504,16 @@ export const balancerBatchRouterAbi = [ name: 'pathAmountsIn', type: 'uint256[]', }, - { internalType: 'address[]', name: 'tokensIn', type: 'address[]' }, - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { + internalType: 'address[]', + name: 'tokensIn', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'amountsIn', + type: 'uint256[]', + }, ], stateMutability: 'nonpayable', type: 'function', @@ -411,8 +576,16 @@ export const balancerBatchRouterAbi = [ name: 'deadline', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct IBatchRouter.SwapExactOutHookParams', name: 'params', @@ -426,8 +599,16 @@ export const balancerBatchRouterAbi = [ name: 'pathAmountsIn', type: 'uint256[]', }, - { internalType: 'address[]', name: 'tokensIn', type: 'address[]' }, - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { + internalType: 'address[]', + name: 'tokensIn', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'amountsIn', + type: 'uint256[]', + }, ], stateMutability: 'nonpayable', type: 'function', @@ -478,9 +659,21 @@ export const balancerBatchRouterAbi = [ name: 'paths', type: 'tuple[]', }, - { internalType: 'uint256', name: 'deadline', type: 'uint256' }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'swapExactIn', outputs: [ @@ -489,7 +682,11 @@ export const balancerBatchRouterAbi = [ name: 'pathAmountsOut', type: 'uint256[]', }, - { internalType: 'address[]', name: 'tokensOut', type: 'address[]' }, + { + internalType: 'address[]', + name: 'tokensOut', + type: 'address[]', + }, { internalType: 'uint256[]', name: 'amountsOut', @@ -557,8 +754,16 @@ export const balancerBatchRouterAbi = [ name: 'deadline', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct IBatchRouter.SwapExactInHookParams', name: 'params', @@ -572,7 +777,11 @@ export const balancerBatchRouterAbi = [ name: 'pathAmountsOut', type: 'uint256[]', }, - { internalType: 'address[]', name: 'tokensOut', type: 'address[]' }, + { + internalType: 'address[]', + name: 'tokensOut', + type: 'address[]', + }, { internalType: 'uint256[]', name: 'amountsOut', @@ -628,9 +837,21 @@ export const balancerBatchRouterAbi = [ name: 'paths', type: 'tuple[]', }, - { internalType: 'uint256', name: 'deadline', type: 'uint256' }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'swapExactOut', outputs: [ @@ -639,8 +860,16 @@ export const balancerBatchRouterAbi = [ name: 'pathAmountsIn', type: 'uint256[]', }, - { internalType: 'address[]', name: 'tokensIn', type: 'address[]' }, - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { + internalType: 'address[]', + name: 'tokensIn', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'amountsIn', + type: 'uint256[]', + }, ], stateMutability: 'payable', type: 'function', @@ -703,8 +932,16 @@ export const balancerBatchRouterAbi = [ name: 'deadline', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct IBatchRouter.SwapExactOutHookParams', name: 'params', @@ -718,11 +955,35 @@ export const balancerBatchRouterAbi = [ name: 'pathAmountsIn', type: 'uint256[]', }, - { internalType: 'address[]', name: 'tokensIn', type: 'address[]' }, - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { + internalType: 'address[]', + name: 'tokensIn', + type: 'address[]', + }, + { + internalType: 'uint256[]', + name: 'amountsIn', + type: 'uint256[]', + }, ], stateMutability: 'nonpayable', type: 'function', }, - { stateMutability: 'payable', type: 'receive' }, + { + inputs: [], + name: 'version', + outputs: [ + { + internalType: 'string', + name: '', + type: 'string', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + stateMutability: 'payable', + type: 'receive', + }, ] as const; diff --git a/src/dex/balancer-v3/abi/balancerRouter.ts b/src/dex/balancer-v3/abi/balancerRouter.ts index c2431342e..41d85188b 100644 --- a/src/dex/balancer-v3/abi/balancerRouter.ts +++ b/src/dex/balancer-v3/abi/balancerRouter.ts @@ -1,53 +1,132 @@ export const balancerRouterAbi = [ { inputs: [ - { internalType: 'contract IVault', name: 'vault', type: 'address' }, - { internalType: 'contract IWETH', name: 'weth', type: 'address' }, + { + internalType: 'contract IVault', + name: 'vault', + type: 'address', + }, + { + internalType: 'contract IWETH', + name: 'weth', + type: 'address', + }, { internalType: 'contract IPermit2', name: 'permit2', type: 'address', }, + { + internalType: 'string', + name: 'version', + type: 'string', + }, ], stateMutability: 'nonpayable', type: 'constructor', }, { - inputs: [{ internalType: 'address', name: 'target', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + ], name: 'AddressEmptyCode', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'account', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + ], name: 'AddressInsufficientBalance', type: 'error', }, - { inputs: [], name: 'EthTransfer', type: 'error' }, - { inputs: [], name: 'FailedInnerCall', type: 'error' }, - { inputs: [], name: 'InsufficientEth', type: 'error' }, - { inputs: [], name: 'ReentrancyGuardReentrantCall', type: 'error' }, + { + inputs: [], + name: 'ErrorSelectorNotFound', + type: 'error', + }, + { + inputs: [], + name: 'EthTransfer', + type: 'error', + }, + { + inputs: [], + name: 'FailedInnerCall', + type: 'error', + }, + { + inputs: [], + name: 'InputLengthMismatch', + type: 'error', + }, + { + inputs: [], + name: 'InsufficientEth', + type: 'error', + }, + { + inputs: [], + name: 'ReentrancyGuardReentrantCall', + type: 'error', + }, { inputs: [ - { internalType: 'uint8', name: 'bits', type: 'uint8' }, - { internalType: 'uint256', name: 'value', type: 'uint256' }, + { + internalType: 'uint8', + name: 'bits', + type: 'uint8', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, ], name: 'SafeCastOverflowedUintDowncast', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'token', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'token', + type: 'address', + }, + ], name: 'SafeERC20FailedOperation', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + ], name: 'SenderIsNotVault', type: 'error', }, - { inputs: [], name: 'SwapDeadline', type: 'error' }, + { + inputs: [], + name: 'SwapDeadline', + type: 'error', + }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256[]', name: 'maxAmountsIn', @@ -58,14 +137,34 @@ export const balancerRouterAbi = [ name: 'minBptAmountOut', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'addLiquidityCustom', outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + { + internalType: 'uint256[]', + name: 'amountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'bptAmountOut', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, ], stateMutability: 'payable', type: 'function', @@ -79,7 +178,11 @@ export const balancerRouterAbi = [ name: 'sender', type: 'address', }, - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256[]', name: 'maxAmountsIn', @@ -95,8 +198,16 @@ export const balancerRouterAbi = [ name: 'kind', type: 'uint8', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct IRouterCommon.AddLiquidityHookParams', name: 'params', @@ -105,120 +216,115 @@ export const balancerRouterAbi = [ ], name: 'addLiquidityHook', outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, { internalType: 'uint256[]', - name: 'maxAmountsIn', + name: 'amountsIn', type: 'uint256[]', }, { internalType: 'uint256', - name: 'exactBptAmountOut', + name: 'bptAmountOut', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'addLiquidityProportional', - outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, ], - stateMutability: 'payable', + stateMutability: 'nonpayable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, { - internalType: 'contract IERC20', - name: 'tokenIn', + internalType: 'address', + name: 'pool', type: 'address', }, - { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + { + internalType: 'uint256[]', + name: 'maxAmountsIn', + type: 'uint256[]', + }, { internalType: 'uint256', name: 'exactBptAmountOut', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, + ], + name: 'addLiquidityProportional', + outputs: [ + { + internalType: 'uint256[]', + name: 'amountsIn', + type: 'uint256[]', + }, ], - name: 'addLiquiditySingleTokenExactOut', - outputs: [{ internalType: 'uint256', name: 'amountIn', type: 'uint256' }], stateMutability: 'payable', type: 'function', }, { inputs: [ { - internalType: 'contract IERC4626', - name: 'wrappedToken', + internalType: 'address', + name: 'pool', type: 'address', }, { - internalType: 'uint256', - name: 'exactSharesToIssue', - type: 'uint256', + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', }, - ], - name: 'addLiquidityToBuffer', - outputs: [ { internalType: 'uint256', - name: 'amountUnderlyingRaw', + name: 'maxAmountIn', type: 'uint256', }, { internalType: 'uint256', - name: 'amountWrappedRaw', + name: 'exactBptAmountOut', type: 'uint256', }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', }, { - internalType: 'uint256', - name: 'exactSharesToIssue', - type: 'uint256', + internalType: 'bytes', + name: 'userData', + type: 'bytes', }, - { internalType: 'address', name: 'sharesOwner', type: 'address' }, ], - name: 'addLiquidityToBufferHook', + name: 'addLiquiditySingleTokenExactOut', outputs: [ { internalType: 'uint256', - name: 'amountUnderlyingRaw', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'amountWrappedRaw', + name: 'amountIn', type: 'uint256', }, ], - stateMutability: 'nonpayable', + stateMutability: 'payable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256[]', name: 'exactAmountsIn', @@ -229,22 +335,50 @@ export const balancerRouterAbi = [ name: 'minBptAmountOut', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'addLiquidityUnbalanced', outputs: [ - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { + internalType: 'uint256', + name: 'bptAmountOut', + type: 'uint256', + }, ], stateMutability: 'payable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'uint256[]', + name: 'amountsIn', + type: 'uint256[]', + }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'donate', outputs: [], @@ -254,13 +388,23 @@ export const balancerRouterAbi = [ { inputs: [], name: 'getSender', - outputs: [{ internalType: 'address', name: '', type: 'address' }], + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], stateMutability: 'view', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'contract IERC20[]', name: 'tokens', @@ -276,65 +420,26 @@ export const balancerRouterAbi = [ name: 'minBptAmountOut', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, - ], - name: 'initialize', - outputs: [ - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, { - internalType: 'uint256', - name: 'amountUnderlyingRaw', - type: 'uint256', + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', }, { - internalType: 'uint256', - name: 'amountWrappedRaw', - type: 'uint256', + internalType: 'bytes', + name: 'userData', + type: 'bytes', }, ], - name: 'initializeBuffer', + name: 'initialize', outputs: [ - { internalType: 'uint256', name: 'issuedShares', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, { internalType: 'uint256', - name: 'amountUnderlyingRaw', + name: 'bptAmountOut', type: 'uint256', }, - { - internalType: 'uint256', - name: 'amountWrappedRaw', - type: 'uint256', - }, - { internalType: 'address', name: 'sharesOwner', type: 'address' }, ], - name: 'initializeBufferHook', - outputs: [ - { internalType: 'uint256', name: 'issuedShares', type: 'uint256' }, - ], - stateMutability: 'nonpayable', + stateMutability: 'payable', type: 'function', }, { @@ -346,7 +451,11 @@ export const balancerRouterAbi = [ name: 'sender', type: 'address', }, - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'contract IERC20[]', name: 'tokens', @@ -362,8 +471,16 @@ export const balancerRouterAbi = [ name: 'minBptAmountOut', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct IRouter.InitializeHookParams', name: 'params', @@ -372,15 +489,31 @@ export const balancerRouterAbi = [ ], name: 'initializeHook', outputs: [ - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { + internalType: 'uint256', + name: 'bptAmountOut', + type: 'uint256', + }, ], stateMutability: 'nonpayable', type: 'function', }, { - inputs: [{ internalType: 'bytes[]', name: 'data', type: 'bytes[]' }], + inputs: [ + { + internalType: 'bytes[]', + name: 'data', + type: 'bytes[]', + }, + ], name: 'multicall', - outputs: [{ internalType: 'bytes[]', name: 'results', type: 'bytes[]' }], + outputs: [ + { + internalType: 'bytes[]', + name: 'results', + type: 'bytes[]', + }, + ], stateMutability: 'payable', type: 'function', }, @@ -388,8 +521,16 @@ export const balancerRouterAbi = [ inputs: [ { components: [ - { internalType: 'address', name: 'token', type: 'address' }, - { internalType: 'address', name: 'owner', type: 'address' }, + { + internalType: 'address', + name: 'token', + type: 'address', + }, + { + internalType: 'address', + name: 'owner', + type: 'address', + }, { internalType: 'address', name: 'spender', @@ -400,7 +541,11 @@ export const balancerRouterAbi = [ name: 'amount', type: 'uint256', }, - { internalType: 'uint256', name: 'nonce', type: 'uint256' }, + { + internalType: 'uint256', + name: 'nonce', + type: 'uint256', + }, { internalType: 'uint256', name: 'deadline', @@ -460,17 +605,35 @@ export const balancerRouterAbi = [ name: 'permit2Batch', type: 'tuple', }, - { internalType: 'bytes', name: 'permit2Signature', type: 'bytes' }, - { internalType: 'bytes[]', name: 'multicallData', type: 'bytes[]' }, + { + internalType: 'bytes', + name: 'permit2Signature', + type: 'bytes', + }, + { + internalType: 'bytes[]', + name: 'multicallData', + type: 'bytes[]', + }, ], name: 'permitBatchAndCall', - outputs: [{ internalType: 'bytes[]', name: 'results', type: 'bytes[]' }], + outputs: [ + { + internalType: 'bytes[]', + name: 'results', + type: 'bytes[]', + }, + ], stateMutability: 'payable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256[]', name: 'maxAmountsIn', @@ -481,13 +644,34 @@ export const balancerRouterAbi = [ name: 'minBptAmountOut', type: 'uint256', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'queryAddLiquidityCustom', outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + { + internalType: 'uint256[]', + name: 'amountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'bptAmountOut', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, ], stateMutability: 'nonpayable', type: 'function', @@ -501,7 +685,11 @@ export const balancerRouterAbi = [ name: 'sender', type: 'address', }, - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256[]', name: 'maxAmountsIn', @@ -517,8 +705,16 @@ export const balancerRouterAbi = [ name: 'kind', type: 'uint8', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct IRouterCommon.AddLiquidityHookParams', name: 'params', @@ -527,33 +723,66 @@ export const balancerRouterAbi = [ ], name: 'queryAddLiquidityHook', outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + { + internalType: 'uint256[]', + name: 'amountsIn', + type: 'uint256[]', + }, + { + internalType: 'uint256', + name: 'bptAmountOut', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256', name: 'exactBptAmountOut', type: 'uint256', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'queryAddLiquidityProportional', outputs: [ - { internalType: 'uint256[]', name: 'amountsIn', type: 'uint256[]' }, + { + internalType: 'uint256[]', + name: 'amountsIn', + type: 'uint256[]', + }, ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'contract IERC20', name: 'tokenIn', @@ -564,33 +793,69 @@ export const balancerRouterAbi = [ name: 'exactBptAmountOut', type: 'uint256', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'queryAddLiquiditySingleTokenExactOut', - outputs: [{ internalType: 'uint256', name: 'amountIn', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: 'amountIn', + type: 'uint256', + }, + ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256[]', name: 'exactAmountsIn', type: 'uint256[]', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'queryAddLiquidityUnbalanced', outputs: [ - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { + internalType: 'uint256', + name: 'bptAmountOut', + type: 'uint256', + }, ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256', name: 'maxBptAmountIn', @@ -601,17 +866,34 @@ export const balancerRouterAbi = [ name: 'minAmountsOut', type: 'uint256[]', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'queryRemoveLiquidityCustom', outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256', + name: 'bptAmountIn', + type: 'uint256', + }, { internalType: 'uint256[]', name: 'amountsOut', type: 'uint256[]', }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, ], stateMutability: 'nonpayable', type: 'function', @@ -625,7 +907,11 @@ export const balancerRouterAbi = [ name: 'sender', type: 'address', }, - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256[]', name: 'minAmountsOut', @@ -641,8 +927,16 @@ export const balancerRouterAbi = [ name: 'kind', type: 'uint8', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct IRouterCommon.RemoveLiquidityHookParams', name: 'params', @@ -651,26 +945,47 @@ export const balancerRouterAbi = [ ], name: 'queryRemoveLiquidityHook', outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256', + name: 'bptAmountIn', + type: 'uint256', + }, { internalType: 'uint256[]', name: 'amountsOut', type: 'uint256[]', }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256', name: 'exactBptAmountIn', type: 'uint256', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'queryRemoveLiquidityProportional', outputs: [ @@ -685,7 +1000,11 @@ export const balancerRouterAbi = [ }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256', name: 'exactBptAmountIn', @@ -705,8 +1024,16 @@ export const balancerRouterAbi = [ }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'sender', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, { internalType: 'uint256', name: 'exactBptAmountIn', @@ -726,7 +1053,11 @@ export const balancerRouterAbi = [ }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256', name: 'exactBptAmountIn', @@ -737,16 +1068,35 @@ export const balancerRouterAbi = [ name: 'tokenOut', type: 'address', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'queryRemoveLiquiditySingleTokenExactIn', - outputs: [{ internalType: 'uint256', name: 'amountOut', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: 'amountOut', + type: 'uint256', + }, + ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'contract IERC20', name: 'tokenOut', @@ -757,11 +1107,24 @@ export const balancerRouterAbi = [ name: 'exactAmountOut', type: 'uint256', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'queryRemoveLiquiditySingleTokenExactOut', outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256', + name: 'bptAmountIn', + type: 'uint256', + }, ], stateMutability: 'nonpayable', type: 'function', @@ -780,7 +1143,11 @@ export const balancerRouterAbi = [ name: 'kind', type: 'uint8', }, - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'contract IERC20', name: 'tokenIn', @@ -796,14 +1163,26 @@ export const balancerRouterAbi = [ name: 'amountGiven', type: 'uint256', }, - { internalType: 'uint256', name: 'limit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'limit', + type: 'uint256', + }, { internalType: 'uint256', name: 'deadline', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct IRouter.SwapSingleTokenHookParams', name: 'params', @@ -811,13 +1190,23 @@ export const balancerRouterAbi = [ }, ], name: 'querySwapHook', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'contract IERC20', name: 'tokenIn', @@ -828,8 +1217,21 @@ export const balancerRouterAbi = [ name: 'tokenOut', type: 'address', }, - { internalType: 'uint256', name: 'exactAmountIn', type: 'uint256' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'uint256', + name: 'exactAmountIn', + type: 'uint256', + }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'querySwapSingleTokenExactIn', outputs: [ @@ -844,7 +1246,11 @@ export const balancerRouterAbi = [ }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'contract IERC20', name: 'tokenIn', @@ -860,7 +1266,16 @@ export const balancerRouterAbi = [ name: 'exactAmountOut', type: 'uint256', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'querySwapSingleTokenExactOut', outputs: [ @@ -875,7 +1290,11 @@ export const balancerRouterAbi = [ }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256', name: 'maxBptAmountIn', @@ -886,20 +1305,36 @@ export const balancerRouterAbi = [ name: 'minAmountsOut', type: 'uint256[]', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'removeLiquidityCustom', outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256', + name: 'bptAmountIn', + type: 'uint256', + }, { internalType: 'uint256[]', name: 'amountsOut', type: 'uint256[]', }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, ], - stateMutability: 'nonpayable', + stateMutability: 'payable', type: 'function', }, { @@ -911,7 +1346,11 @@ export const balancerRouterAbi = [ name: 'sender', type: 'address', }, - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256[]', name: 'minAmountsOut', @@ -927,8 +1366,16 @@ export const balancerRouterAbi = [ name: 'kind', type: 'uint8', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct IRouterCommon.RemoveLiquidityHookParams', name: 'params', @@ -937,20 +1384,32 @@ export const balancerRouterAbi = [ ], name: 'removeLiquidityHook', outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256', + name: 'bptAmountIn', + type: 'uint256', + }, { internalType: 'uint256[]', name: 'amountsOut', type: 'uint256[]', }, - { internalType: 'bytes', name: 'returnData', type: 'bytes' }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256', name: 'exactBptAmountIn', @@ -961,8 +1420,16 @@ export const balancerRouterAbi = [ name: 'minAmountsOut', type: 'uint256[]', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'removeLiquidityProportional', outputs: [ @@ -977,12 +1444,21 @@ export const balancerRouterAbi = [ }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256', name: 'exactBptAmountIn', type: 'uint256', }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, ], name: 'removeLiquidityRecovery', outputs: [ @@ -992,18 +1468,31 @@ export const balancerRouterAbi = [ type: 'uint256[]', }, ], - stateMutability: 'nonpayable', + stateMutability: 'payable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'sender', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'address', + name: 'sender', + type: 'address', + }, { internalType: 'uint256', name: 'exactBptAmountIn', type: 'uint256', }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, ], name: 'removeLiquidityRecoveryHook', outputs: [ @@ -1018,7 +1507,11 @@ export const balancerRouterAbi = [ }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256', name: 'exactBptAmountIn', @@ -1029,18 +1522,40 @@ export const balancerRouterAbi = [ name: 'tokenOut', type: 'address', }, - { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'uint256', + name: 'minAmountOut', + type: 'uint256', + }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'removeLiquiditySingleTokenExactIn', - outputs: [{ internalType: 'uint256', name: 'amountOut', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: 'amountOut', + type: 'uint256', + }, + ], stateMutability: 'payable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'uint256', name: 'maxBptAmountIn', @@ -1056,19 +1571,35 @@ export const balancerRouterAbi = [ name: 'exactAmountOut', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'removeLiquiditySingleTokenExactOut', outputs: [ - { internalType: 'uint256', name: 'bptAmountIn', type: 'uint256' }, + { + internalType: 'uint256', + name: 'bptAmountIn', + type: 'uint256', + }, ], stateMutability: 'payable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'contract IERC20', name: 'tokenIn', @@ -1079,20 +1610,50 @@ export const balancerRouterAbi = [ name: 'tokenOut', type: 'address', }, - { internalType: 'uint256', name: 'exactAmountIn', type: 'uint256' }, - { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, - { internalType: 'uint256', name: 'deadline', type: 'uint256' }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'uint256', + name: 'exactAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minAmountOut', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'swapSingleTokenExactIn', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], stateMutability: 'payable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'contract IERC20', name: 'tokenIn', @@ -1108,13 +1669,35 @@ export const balancerRouterAbi = [ name: 'exactAmountOut', type: 'uint256', }, - { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, - { internalType: 'uint256', name: 'deadline', type: 'uint256' }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'uint256', + name: 'maxAmountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'deadline', + type: 'uint256', + }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'swapSingleTokenExactOut', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], stateMutability: 'payable', type: 'function', }, @@ -1132,7 +1715,11 @@ export const balancerRouterAbi = [ name: 'kind', type: 'uint8', }, - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { internalType: 'contract IERC20', name: 'tokenIn', @@ -1148,14 +1735,26 @@ export const balancerRouterAbi = [ name: 'amountGiven', type: 'uint256', }, - { internalType: 'uint256', name: 'limit', type: 'uint256' }, + { + internalType: 'uint256', + name: 'limit', + type: 'uint256', + }, { internalType: 'uint256', name: 'deadline', type: 'uint256', }, - { internalType: 'bool', name: 'wethIsEth', type: 'bool' }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bool', + name: 'wethIsEth', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct IRouter.SwapSingleTokenHookParams', name: 'params', @@ -1163,9 +1762,31 @@ export const balancerRouterAbi = [ }, ], name: 'swapSingleTokenHook', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], stateMutability: 'nonpayable', type: 'function', }, - { stateMutability: 'payable', type: 'receive' }, + { + inputs: [], + name: 'version', + outputs: [ + { + internalType: 'string', + name: '', + type: 'string', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + stateMutability: 'payable', + type: 'receive', + }, ] as const; diff --git a/src/dex/balancer-v3/abi/vaultExtension.V3.ts b/src/dex/balancer-v3/abi/vaultExtension.V3.ts index d89a1f347..66a847d48 100644 --- a/src/dex/balancer-v3/abi/vaultExtension.V3.ts +++ b/src/dex/balancer-v3/abi/vaultExtension.V3.ts @@ -16,20 +16,52 @@ export const vaultExtensionAbi_V3 = [ type: 'constructor', }, { - inputs: [{ internalType: 'address', name: 'target', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + ], name: 'AddressEmptyCode', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'account', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'account', + type: 'address', + }, + ], name: 'AddressInsufficientBalance', type: 'error', }, - { inputs: [], name: 'AfterAddLiquidityHookFailed', type: 'error' }, - { inputs: [], name: 'AfterInitializeHookFailed', type: 'error' }, - { inputs: [], name: 'AfterRemoveLiquidityHookFailed', type: 'error' }, - { inputs: [], name: 'AfterSwapHookFailed', type: 'error' }, - { inputs: [], name: 'AmountGivenZero', type: 'error' }, + { + inputs: [], + name: 'AfterAddLiquidityHookFailed', + type: 'error', + }, + { + inputs: [], + name: 'AfterInitializeHookFailed', + type: 'error', + }, + { + inputs: [], + name: 'AfterRemoveLiquidityHookFailed', + type: 'error', + }, + { + inputs: [], + name: 'AfterSwapHookFailed', + type: 'error', + }, + { + inputs: [], + name: 'AmountGivenZero', + type: 'error', + }, { inputs: [ { @@ -37,8 +69,16 @@ export const vaultExtensionAbi_V3 = [ name: 'tokenIn', type: 'address', }, - { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, - { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + { + internalType: 'uint256', + name: 'amountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'maxAmountIn', + type: 'uint256', + }, ], name: 'AmountInAboveMax', type: 'error', @@ -50,30 +90,78 @@ export const vaultExtensionAbi_V3 = [ name: 'tokenOut', type: 'address', }, - { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, - { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + { + internalType: 'uint256', + name: 'amountOut', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minAmountOut', + type: 'uint256', + }, ], name: 'AmountOutBelowMin', type: 'error', }, - { inputs: [], name: 'BalanceNotSettled', type: 'error' }, - { inputs: [], name: 'BalanceOverflow', type: 'error' }, - { inputs: [], name: 'BeforeAddLiquidityHookFailed', type: 'error' }, - { inputs: [], name: 'BeforeInitializeHookFailed', type: 'error' }, - { inputs: [], name: 'BeforeRemoveLiquidityHookFailed', type: 'error' }, - { inputs: [], name: 'BeforeSwapHookFailed', type: 'error' }, + { + inputs: [], + name: 'BalanceNotSettled', + type: 'error', + }, + { + inputs: [], + name: 'BalanceOverflow', + type: 'error', + }, + { + inputs: [], + name: 'BeforeAddLiquidityHookFailed', + type: 'error', + }, + { + inputs: [], + name: 'BeforeInitializeHookFailed', + type: 'error', + }, + { + inputs: [], + name: 'BeforeRemoveLiquidityHookFailed', + type: 'error', + }, + { + inputs: [], + name: 'BeforeSwapHookFailed', + type: 'error', + }, { inputs: [ - { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, - { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, + { + internalType: 'uint256', + name: 'amountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'maxAmountIn', + type: 'uint256', + }, ], name: 'BptAmountInAboveMax', type: 'error', }, { inputs: [ - { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, - { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, + { + internalType: 'uint256', + name: 'amountOut', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minAmountOut', + type: 'uint256', + }, ], name: 'BptAmountOutBelowMin', type: 'error', @@ -86,301 +174,687 @@ export const vaultExtensionAbi_V3 = [ type: 'address', }, ], - name: 'BufferAlreadyInitialized', + name: 'BufferAlreadyInitialized', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'BufferNotInitialized', + type: 'error', + }, + { + inputs: [], + name: 'BufferSharesInvalidOwner', + type: 'error', + }, + { + inputs: [], + name: 'BufferSharesInvalidReceiver', + type: 'error', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'totalSupply', + type: 'uint256', + }, + ], + name: 'BufferTotalSupplyTooLow', + type: 'error', + }, + { + inputs: [], + name: 'CannotReceiveEth', + type: 'error', + }, + { + inputs: [], + name: 'CannotSwapSameToken', + type: 'error', + }, + { + inputs: [], + name: 'CodecOverflow', + type: 'error', + }, + { + inputs: [], + name: 'DoesNotSupportAddLiquidityCustom', + type: 'error', + }, + { + inputs: [], + name: 'DoesNotSupportDonation', + type: 'error', + }, + { + inputs: [], + name: 'DoesNotSupportRemoveLiquidityCustom', + type: 'error', + }, + { + inputs: [], + name: 'DoesNotSupportUnbalancedLiquidity', + type: 'error', + }, + { + inputs: [], + name: 'DynamicSwapFeeHookFailed', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'allowance', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'needed', + type: 'uint256', + }, + ], + name: 'ERC20InsufficientAllowance', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'balance', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'needed', + type: 'uint256', + }, + ], + name: 'ERC20InsufficientBalance', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'approver', + type: 'address', + }, + ], + name: 'ERC20InvalidApprover', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'receiver', + type: 'address', + }, + ], + name: 'ERC20InvalidReceiver', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'sender', + type: 'address', + }, + ], + name: 'ERC20InvalidSender', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + ], + name: 'ERC20InvalidSpender', + type: 'error', + }, + { + inputs: [], + name: 'ErrorSelectorNotFound', + type: 'error', + }, + { + inputs: [], + name: 'FailedInnerCall', + type: 'error', + }, + { + inputs: [], + name: 'FeePrecisionTooHigh', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC20', + name: 'tokenIn', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amountIn', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'maxAmountIn', + type: 'uint256', + }, + ], + name: 'HookAdjustedAmountInAboveMax', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC20', + name: 'tokenOut', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amountOut', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minAmountOut', + type: 'uint256', + }, + ], + name: 'HookAdjustedAmountOutBelowMin', + type: 'error', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'limit', + type: 'uint256', + }, + ], + name: 'HookAdjustedSwapLimit', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'poolHooksContract', + type: 'address', + }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'address', + name: 'poolFactory', + type: 'address', + }, + ], + name: 'HookRegistrationFailed', + type: 'error', + }, + { + inputs: [], + name: 'InputLengthMismatch', + type: 'error', + }, + { + inputs: [], + name: 'InvalidAddLiquidityKind', + type: 'error', + }, + { + inputs: [], + name: 'InvalidRemoveLiquidityKind', + type: 'error', + }, + { + inputs: [], + name: 'InvalidToken', + type: 'error', + }, + { + inputs: [], + name: 'InvalidTokenConfiguration', + type: 'error', + }, + { + inputs: [], + name: 'InvalidTokenDecimals', + type: 'error', + }, + { + inputs: [], + name: 'InvalidTokenType', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'InvalidUnderlyingToken', + type: 'error', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'issuedShares', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'minIssuedShares', + type: 'uint256', + }, + ], + name: 'IssuedSharesBelowMin', + type: 'error', + }, + { + inputs: [], + name: 'MaxTokens', + type: 'error', + }, + { + inputs: [], + name: 'MinTokens', + type: 'error', + }, + { + inputs: [], + name: 'NotEnoughBufferShares', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'expectedUnderlyingAmount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'actualUnderlyingAmount', + type: 'uint256', + }, + ], + name: 'NotEnoughUnderlying', + type: 'error', + }, + { + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + internalType: 'uint256', + name: 'expectedWrappedAmount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'actualWrappedAmount', + type: 'uint256', + }, + ], + name: 'NotEnoughWrapped', + type: 'error', + }, + { + inputs: [], + name: 'NotStaticCall', + type: 'error', + }, + { + inputs: [], + name: 'NotVaultDelegateCall', + type: 'error', + }, + { + inputs: [], + name: 'OutOfBounds', + type: 'error', + }, + { + inputs: [], + name: 'PauseBufferPeriodDurationTooLarge', + type: 'error', + }, + { + inputs: [], + name: 'PercentageAboveMax', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolAlreadyInitialized', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolAlreadyRegistered', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolInRecoveryMode', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolNotInRecoveryMode', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolNotInitialized', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolNotPaused', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolNotRegistered', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolPauseWindowExpired', + type: 'error', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolPaused', type: 'error', }, { inputs: [ { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', + internalType: 'uint256', + name: 'totalSupply', + type: 'uint256', }, ], - name: 'BufferNotInitialized', + name: 'PoolTotalSupplyTooLow', type: 'error', }, - { inputs: [], name: 'BufferSharesInvalidOwner', type: 'error' }, - { inputs: [], name: 'BufferSharesInvalidReceiver', type: 'error' }, { - inputs: [{ internalType: 'uint256', name: 'totalSupply', type: 'uint256' }], - name: 'BufferTotalSupplyTooLow', + inputs: [], + name: 'ProtocolFeesExceedTotalCollected', type: 'error', }, - { inputs: [], name: 'CannotReceiveEth', type: 'error' }, - { inputs: [], name: 'CannotSwapSameToken', type: 'error' }, - { inputs: [], name: 'CodecOverflow', type: 'error' }, - { inputs: [], name: 'DoesNotSupportAddLiquidityCustom', type: 'error' }, - { inputs: [], name: 'DoesNotSupportDonation', type: 'error' }, - { inputs: [], name: 'DoesNotSupportRemoveLiquidityCustom', type: 'error' }, - { inputs: [], name: 'DoesNotSupportUnbalancedLiquidity', type: 'error' }, - { inputs: [], name: 'DynamicSwapFeeHookFailed', type: 'error' }, { - inputs: [ - { internalType: 'address', name: 'spender', type: 'address' }, - { internalType: 'uint256', name: 'allowance', type: 'uint256' }, - { internalType: 'uint256', name: 'needed', type: 'uint256' }, - ], - name: 'ERC20InsufficientAllowance', + inputs: [], + name: 'QueriesDisabled', type: 'error', }, { - inputs: [ - { internalType: 'address', name: 'sender', type: 'address' }, - { internalType: 'uint256', name: 'balance', type: 'uint256' }, - { internalType: 'uint256', name: 'needed', type: 'uint256' }, - ], - name: 'ERC20InsufficientBalance', + inputs: [], + name: 'QueriesDisabledPermanently', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'approver', type: 'address' }], - name: 'ERC20InvalidApprover', + inputs: [], + name: 'QuoteResultSpoofed', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'receiver', type: 'address' }], - name: 'ERC20InvalidReceiver', + inputs: [], + name: 'ReentrancyGuardReentrantCall', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], - name: 'ERC20InvalidSender', + inputs: [ + { + internalType: 'bytes', + name: 'result', + type: 'bytes', + }, + ], + name: 'Result', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'spender', type: 'address' }], - name: 'ERC20InvalidSpender', + inputs: [], + name: 'RouterNotTrusted', type: 'error', }, - { inputs: [], name: 'ErrorSelectorNotFound', type: 'error' }, - { inputs: [], name: 'FailedInnerCall', type: 'error' }, - { inputs: [], name: 'FeePrecisionTooHigh', type: 'error' }, { inputs: [ { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', + internalType: 'uint256', + name: 'value', + type: 'uint256', }, - { internalType: 'uint256', name: 'amountIn', type: 'uint256' }, - { internalType: 'uint256', name: 'maxAmountIn', type: 'uint256' }, ], - name: 'HookAdjustedAmountInAboveMax', + name: 'SafeCastOverflowedUintToInt', type: 'error', }, { inputs: [ { - internalType: 'contract IERC20', - name: 'tokenOut', + internalType: 'address', + name: 'sender', type: 'address', }, - { internalType: 'uint256', name: 'amountOut', type: 'uint256' }, - { internalType: 'uint256', name: 'minAmountOut', type: 'uint256' }, ], - name: 'HookAdjustedAmountOutBelowMin', + name: 'SenderIsNotVault', type: 'error', }, { - inputs: [ - { internalType: 'uint256', name: 'amount', type: 'uint256' }, - { internalType: 'uint256', name: 'limit', type: 'uint256' }, - ], - name: 'HookAdjustedSwapLimit', + inputs: [], + name: 'SwapFeePercentageTooHigh', + type: 'error', + }, + { + inputs: [], + name: 'SwapFeePercentageTooLow', type: 'error', }, { inputs: [ { - internalType: 'address', - name: 'poolHooksContract', - type: 'address', + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'limit', + type: 'uint256', }, - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'poolFactory', type: 'address' }, ], - name: 'HookRegistrationFailed', + name: 'SwapLimit', type: 'error', }, - { inputs: [], name: 'InputLengthMismatch', type: 'error' }, - { inputs: [], name: 'InvalidAddLiquidityKind', type: 'error' }, - { inputs: [], name: 'InvalidRemoveLiquidityKind', type: 'error' }, - { inputs: [], name: 'InvalidToken', type: 'error' }, - { inputs: [], name: 'InvalidTokenConfiguration', type: 'error' }, - { inputs: [], name: 'InvalidTokenType', type: 'error' }, { inputs: [ { - internalType: 'contract IERC4626', - name: 'wrappedToken', + internalType: 'contract IERC20', + name: 'token', type: 'address', }, ], - name: 'InvalidUnderlyingToken', + name: 'TokenAlreadyRegistered', type: 'error', }, - { inputs: [], name: 'MaxTokens', type: 'error' }, - { inputs: [], name: 'MinTokens', type: 'error' }, - { inputs: [], name: 'NotEnoughBufferShares', type: 'error' }, { inputs: [ { - internalType: 'contract IERC4626', - name: 'wrappedToken', + internalType: 'contract IERC20', + name: 'token', type: 'address', }, - { - internalType: 'uint256', - name: 'expectedUnderlyingAmount', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'actualUnderlyingAmount', - type: 'uint256', - }, ], - name: 'NotEnoughUnderlying', + name: 'TokenNotRegistered', type: 'error', }, { inputs: [ { - internalType: 'contract IERC4626', - name: 'wrappedToken', + internalType: 'address', + name: 'pool', type: 'address', }, { - internalType: 'uint256', - name: 'expectedWrappedAmount', - type: 'uint256', + internalType: 'address', + name: 'expectedToken', + type: 'address', }, { - internalType: 'uint256', - name: 'actualWrappedAmount', - type: 'uint256', + internalType: 'address', + name: 'actualToken', + type: 'address', }, ], - name: 'NotEnoughWrapped', - type: 'error', - }, - { inputs: [], name: 'NotStaticCall', type: 'error' }, - { inputs: [], name: 'NotVaultDelegateCall', type: 'error' }, - { inputs: [], name: 'OutOfBounds', type: 'error' }, - { inputs: [], name: 'PauseBufferPeriodDurationTooLarge', type: 'error' }, - { inputs: [], name: 'PercentageAboveMax', type: 'error' }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolAlreadyInitialized', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolAlreadyRegistered', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolInRecoveryMode', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolNotInRecoveryMode', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolNotInitialized', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolNotPaused', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolNotRegistered', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolPauseWindowExpired', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'PoolPaused', + name: 'TokensMismatch', type: 'error', }, { - inputs: [{ internalType: 'uint256', name: 'totalSupply', type: 'uint256' }], - name: 'PoolTotalSupplyTooLow', + inputs: [], + name: 'TokensNotSorted', type: 'error', }, - { inputs: [], name: 'ProtocolFeesExceedTotalCollected', type: 'error' }, - { inputs: [], name: 'QueriesDisabled', type: 'error' }, - { inputs: [], name: 'QuoteResultSpoofed', type: 'error' }, - { inputs: [], name: 'ReentrancyGuardReentrantCall', type: 'error' }, { - inputs: [{ internalType: 'bytes', name: 'result', type: 'bytes' }], - name: 'Result', + inputs: [], + name: 'TradeAmountTooSmall', type: 'error', }, - { inputs: [], name: 'RouterNotTrusted', type: 'error' }, { - inputs: [{ internalType: 'uint256', name: 'value', type: 'uint256' }], - name: 'SafeCastOverflowedUintToInt', + inputs: [], + name: 'VaultBuffersArePaused', type: 'error', }, { - inputs: [{ internalType: 'address', name: 'sender', type: 'address' }], - name: 'SenderIsNotVault', + inputs: [], + name: 'VaultIsNotUnlocked', type: 'error', }, - { inputs: [], name: 'SwapFeePercentageTooHigh', type: 'error' }, - { inputs: [], name: 'SwapFeePercentageTooLow', type: 'error' }, { - inputs: [ - { internalType: 'uint256', name: 'amount', type: 'uint256' }, - { internalType: 'uint256', name: 'limit', type: 'uint256' }, - ], - name: 'SwapLimit', + inputs: [], + name: 'VaultNotPaused', type: 'error', }, { - inputs: [ - { internalType: 'contract IERC20', name: 'token', type: 'address' }, - ], - name: 'TokenAlreadyRegistered', + inputs: [], + name: 'VaultPauseWindowDurationTooLarge', type: 'error', }, { - inputs: [ - { internalType: 'contract IERC20', name: 'token', type: 'address' }, - ], - name: 'TokenNotRegistered', + inputs: [], + name: 'VaultPauseWindowExpired', type: 'error', }, { - inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'expectedToken', type: 'address' }, - { internalType: 'address', name: 'actualToken', type: 'address' }, - ], - name: 'TokensMismatch', + inputs: [], + name: 'VaultPaused', type: 'error', }, - { inputs: [], name: 'TokensNotSorted', type: 'error' }, - { inputs: [], name: 'TradeAmountTooSmall', type: 'error' }, - { inputs: [], name: 'VaultBuffersArePaused', type: 'error' }, - { inputs: [], name: 'VaultIsNotUnlocked', type: 'error' }, - { inputs: [], name: 'VaultNotPaused', type: 'error' }, - { inputs: [], name: 'VaultPauseWindowDurationTooLarge', type: 'error' }, - { inputs: [], name: 'VaultPauseWindowExpired', type: 'error' }, - { inputs: [], name: 'VaultPaused', type: 'error' }, { inputs: [ { @@ -392,7 +866,11 @@ export const vaultExtensionAbi_V3 = [ name: 'WrapAmountTooSmall', type: 'error', }, - { inputs: [], name: 'WrongProtocolFeeControllerDeployment', type: 'error' }, + { + inputs: [], + name: 'WrongProtocolFeeControllerDeployment', + type: 'error', + }, { inputs: [ { @@ -409,8 +887,16 @@ export const vaultExtensionAbi_V3 = [ name: 'WrongUnderlyingToken', type: 'error', }, - { inputs: [], name: 'WrongVaultAdminDeployment', type: 'error' }, - { inputs: [], name: 'WrongVaultExtensionDeployment', type: 'error' }, + { + inputs: [], + name: 'WrongVaultAdminDeployment', + type: 'error', + }, + { + inputs: [], + name: 'WrongVaultExtensionDeployment', + type: 'error', + }, { anonymous: false, inputs: [ @@ -548,24 +1034,42 @@ export const vaultExtensionAbi_V3 = [ inputs: [ { indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'liquidityProvider', type: 'address', }, + { + indexed: true, + internalType: 'enum AddLiquidityKind', + name: 'kind', + type: 'uint8', + }, { indexed: false, internalType: 'uint256', - name: 'amountUnderlying', + name: 'totalSupply', type: 'uint256', }, { indexed: false, - internalType: 'uint256', - name: 'amountWrapped', - type: 'uint256', + internalType: 'uint256[]', + name: 'amountsAddedRaw', + type: 'uint256[]', + }, + { + indexed: false, + internalType: 'uint256[]', + name: 'swapFeeAmountsRaw', + type: 'uint256[]', }, ], - name: 'LiquidityAddedToBuffer', + name: 'LiquidityAdded', type: 'event', }, { @@ -589,8 +1093,14 @@ export const vaultExtensionAbi_V3 = [ name: 'amountWrapped', type: 'uint256', }, + { + indexed: false, + internalType: 'bytes32', + name: 'bufferBalances', + type: 'bytes32', + }, ], - name: 'LiquidityRemovedFromBuffer', + name: 'LiquidityAddedToBuffer', type: 'event', }, { @@ -608,6 +1118,12 @@ export const vaultExtensionAbi_V3 = [ name: 'liquidityProvider', type: 'address', }, + { + indexed: true, + internalType: 'enum RemoveLiquidityKind', + name: 'kind', + type: 'uint8', + }, { indexed: false, internalType: 'uint256', @@ -616,9 +1132,9 @@ export const vaultExtensionAbi_V3 = [ }, { indexed: false, - internalType: 'int256[]', - name: 'deltas', - type: 'int256[]', + internalType: 'uint256[]', + name: 'amountsRemovedRaw', + type: 'uint256[]', }, { indexed: false, @@ -627,7 +1143,38 @@ export const vaultExtensionAbi_V3 = [ type: 'uint256[]', }, ], - name: 'PoolBalanceChanged', + name: 'LiquidityRemoved', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountUnderlying', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amountWrapped', + type: 'uint256', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'bufferBalances', + type: 'bytes32', + }, + ], + name: 'LiquidityRemovedFromBuffer', type: 'event', }, { @@ -976,25 +1523,50 @@ export const vaultExtensionAbi_V3 = [ type: 'address', }, { - indexed: true, - internalType: 'contract IERC20', - name: 'underlyingToken', + indexed: false, + internalType: 'uint256', + name: 'burnedShares', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'withdrawnUnderlying', + type: 'uint256', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'bufferBalances', + type: 'bytes32', + }, + ], + name: 'Unwrap', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'pool', type: 'address', }, { indexed: false, - internalType: 'uint256', - name: 'burnedShares', - type: 'uint256', + internalType: 'string', + name: 'eventKey', + type: 'string', }, { indexed: false, - internalType: 'uint256', - name: 'withdrawnUnderlying', - type: 'uint256', + internalType: 'bytes', + name: 'eventData', + type: 'bytes', }, ], - name: 'Unwrap', + name: 'VaultAuxiliary', type: 'event', }, { @@ -1029,15 +1601,15 @@ export const vaultExtensionAbi_V3 = [ name: 'VaultQueriesDisabled', type: 'event', }, + { + anonymous: false, + inputs: [], + name: 'VaultQueriesEnabled', + type: 'event', + }, { anonymous: false, inputs: [ - { - indexed: true, - internalType: 'contract IERC20', - name: 'underlyingToken', - type: 'address', - }, { indexed: true, internalType: 'contract IERC4626', @@ -1056,46 +1628,109 @@ export const vaultExtensionAbi_V3 = [ name: 'mintedShares', type: 'uint256', }, + { + indexed: false, + internalType: 'bytes32', + name: 'bufferBalances', + type: 'bytes32', + }, ], name: 'Wrap', type: 'event', }, - { stateMutability: 'payable', type: 'fallback' }, + { + stateMutability: 'payable', + type: 'fallback', + }, { inputs: [ - { internalType: 'address', name: 'token', type: 'address' }, - { internalType: 'address', name: 'owner', type: 'address' }, - { internalType: 'address', name: 'spender', type: 'address' }, + { + internalType: 'address', + name: 'token', + type: 'address', + }, + { + internalType: 'address', + name: 'owner', + type: 'address', + }, + { + internalType: 'address', + name: 'spender', + type: 'address', + }, ], name: 'allowance', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], stateMutability: 'view', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'owner', type: 'address' }, - { internalType: 'address', name: 'spender', type: 'address' }, - { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { + internalType: 'address', + name: 'owner', + type: 'address', + }, + { + internalType: 'address', + name: 'spender', + type: 'address', + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, ], name: 'approve', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'token', type: 'address' }, - { internalType: 'address', name: 'account', type: 'address' }, + { + internalType: 'address', + name: 'token', + type: 'address', + }, + { + internalType: 'address', + name: 'account', + type: 'address', + }, ], name: 'balanceOf', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], stateMutability: 'view', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { components: [ { @@ -1128,7 +1763,11 @@ export const vaultExtensionAbi_V3 = [ name: 'router', type: 'address', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], internalType: 'struct PoolSwapParams', name: 'swapParams', @@ -1148,33 +1787,116 @@ export const vaultExtensionAbi_V3 = [ }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'contract IERC20', name: 'token', type: 'address' }, + { + internalType: 'string', + name: 'eventKey', + type: 'string', + }, + { + internalType: 'bytes', + name: 'eventData', + type: 'bytes', + }, + ], + name: 'emitAuxiliaryEvent', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'getAddLiquidityCalledFlag', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, ], name: 'getAggregateSwapFeeAmount', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], stateMutability: 'view', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'contract IERC20', name: 'token', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, ], name: 'getAggregateYieldFeeAmount', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], stateMutability: 'view', type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'getBptRate', - outputs: [{ internalType: 'uint256', name: 'rate', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: 'rate', + type: 'uint256', + }, + ], stateMutability: 'view', type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'getCurrentLiveBalances', outputs: [ { @@ -1187,7 +1909,32 @@ export const vaultExtensionAbi_V3 = [ type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'contract IERC4626', + name: 'wrappedToken', + type: 'address', + }, + ], + name: 'getERC4626BufferAsset', + outputs: [ + { + internalType: 'address', + name: 'asset', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'getHooksConfig', outputs: [ { @@ -1259,12 +2006,24 @@ export const vaultExtensionAbi_V3 = [ { inputs: [], name: 'getNonzeroDeltaCount', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], stateMutability: 'view', type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'getPoolConfig', outputs: [ { @@ -1351,7 +2110,13 @@ export const vaultExtensionAbi_V3 = [ type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'getPoolData', outputs: [ { @@ -1411,26 +2176,54 @@ export const vaultExtensionAbi_V3 = [ ], internalType: 'struct PoolData', name: '', - type: 'tuple', + type: 'tuple', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'getPoolPausedState', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + { + internalType: 'uint32', + name: '', + type: 'uint32', + }, + { + internalType: 'uint32', + name: '', + type: 'uint32', + }, + { + internalType: 'address', + name: '', + type: 'address', }, ], stateMutability: 'view', type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], - name: 'getPoolPausedState', - outputs: [ - { internalType: 'bool', name: '', type: 'bool' }, - { internalType: 'uint32', name: '', type: 'uint32' }, - { internalType: 'uint32', name: '', type: 'uint32' }, - { internalType: 'address', name: '', type: 'address' }, + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], name: 'getPoolRoleAccounts', outputs: [ { @@ -1460,7 +2253,13 @@ export const vaultExtensionAbi_V3 = [ type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'getPoolTokenInfo', outputs: [ { @@ -1505,7 +2304,13 @@ export const vaultExtensionAbi_V3 = [ type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'getPoolTokenRates', outputs: [ { @@ -1523,7 +2328,13 @@ export const vaultExtensionAbi_V3 = [ type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'getPoolTokens', outputs: [ { @@ -1550,40 +2361,86 @@ export const vaultExtensionAbi_V3 = [ }, { inputs: [ - { internalType: 'contract IERC20', name: 'token', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, ], name: 'getReservesOf', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], stateMutability: 'view', type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'getStaticSwapFeePercentage', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], stateMutability: 'view', type: 'function', }, { inputs: [ - { internalType: 'contract IERC20', name: 'token', type: 'address' }, + { + internalType: 'contract IERC20', + name: 'token', + type: 'address', + }, ], name: 'getTokenDelta', - outputs: [{ internalType: 'int256', name: '', type: 'int256' }], + outputs: [ + { + internalType: 'int256', + name: '', + type: 'int256', + }, + ], stateMutability: 'view', type: 'function', }, { inputs: [], name: 'getVaultAdmin', - outputs: [{ internalType: 'address', name: '', type: 'address' }], + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], stateMutability: 'view', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'to', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'address', + name: 'to', + type: 'address', + }, { internalType: 'contract IERC20[]', name: 'tokens', @@ -1599,11 +2456,19 @@ export const vaultExtensionAbi_V3 = [ name: 'minBptAmountOut', type: 'uint256', }, - { internalType: 'bytes', name: 'userData', type: 'bytes' }, + { + internalType: 'bytes', + name: 'userData', + type: 'bytes', + }, ], name: 'initialize', outputs: [ - { internalType: 'uint256', name: 'bptAmountOut', type: 'uint256' }, + { + internalType: 'uint256', + name: 'bptAmountOut', + type: 'uint256', + }, ], stateMutability: 'nonpayable', type: 'function', @@ -1617,61 +2482,158 @@ export const vaultExtensionAbi_V3 = [ }, ], name: 'isERC4626BufferInitialized', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], stateMutability: 'view', type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'isPoolInRecoveryMode', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], stateMutability: 'view', type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'isPoolInitialized', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], stateMutability: 'view', type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'isPoolPaused', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], stateMutability: 'view', type: 'function', }, { - inputs: [{ internalType: 'address', name: 'pool', type: 'address' }], + inputs: [ + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], name: 'isPoolRegistered', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], stateMutability: 'view', type: 'function', }, { inputs: [], name: 'isQueryDisabled', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'isQueryDisabledPermanently', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], stateMutability: 'view', type: 'function', }, { inputs: [], name: 'isUnlocked', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], stateMutability: 'view', type: 'function', }, { - inputs: [{ internalType: 'bytes', name: 'data', type: 'bytes' }], + inputs: [ + { + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + ], name: 'quote', - outputs: [{ internalType: 'bytes', name: 'result', type: 'bytes' }], + outputs: [ + { + internalType: 'bytes', + name: 'result', + type: 'bytes', + }, + ], stateMutability: 'nonpayable', type: 'function', }, { - inputs: [{ internalType: 'bytes', name: 'data', type: 'bytes' }], + inputs: [ + { + internalType: 'bytes', + name: 'data', + type: 'bytes', + }, + ], name: 'quoteAndRevert', outputs: [], stateMutability: 'nonpayable', @@ -1680,13 +2642,23 @@ export const vaultExtensionAbi_V3 = [ { inputs: [], name: 'reentrancyGuardEntered', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], stateMutability: 'view', type: 'function', }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, { components: [ { @@ -1724,7 +2696,11 @@ export const vaultExtensionAbi_V3 = [ name: 'pauseWindowEndTime', type: 'uint32', }, - { internalType: 'bool', name: 'protocolFeeExempt', type: 'bool' }, + { + internalType: 'bool', + name: 'protocolFeeExempt', + type: 'bool', + }, { components: [ { @@ -1787,13 +2763,26 @@ export const vaultExtensionAbi_V3 = [ }, { inputs: [ - { internalType: 'address', name: 'pool', type: 'address' }, - { internalType: 'address', name: 'from', type: 'address' }, + { + internalType: 'address', + name: 'pool', + type: 'address', + }, + { + internalType: 'address', + name: 'from', + type: 'address', + }, { internalType: 'uint256', name: 'exactBptAmountIn', type: 'uint256', }, + { + internalType: 'uint256[]', + name: 'minAmountsOut', + type: 'uint256[]', + }, ], name: 'removeLiquidityRecovery', outputs: [ @@ -1806,42 +2795,40 @@ export const vaultExtensionAbi_V3 = [ stateMutability: 'nonpayable', type: 'function', }, - { - inputs: [{ internalType: 'address', name: 'token', type: 'address' }], - name: 'totalSupply', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, { inputs: [ - { internalType: 'address', name: 'owner', type: 'address' }, - { internalType: 'address', name: 'to', type: 'address' }, - { internalType: 'uint256', name: 'amount', type: 'uint256' }, + { + internalType: 'address', + name: 'token', + type: 'address', + }, ], - name: 'transfer', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: 'spender', type: 'address' }, - { internalType: 'address', name: 'from', type: 'address' }, - { internalType: 'address', name: 'to', type: 'address' }, - { internalType: 'uint256', name: 'amount', type: 'uint256' }, + name: 'totalSupply', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, ], - name: 'transferFrom', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'nonpayable', + stateMutability: 'view', type: 'function', }, { inputs: [], name: 'vault', - outputs: [{ internalType: 'contract IVault', name: '', type: 'address' }], + outputs: [ + { + internalType: 'contract IVault', + name: '', + type: 'address', + }, + ], stateMutability: 'view', type: 'function', }, - { stateMutability: 'payable', type: 'receive' }, + { + stateMutability: 'payable', + type: 'receive', + }, ] as const; diff --git a/src/dex/balancer-v3/balancer-v3-e2e.test.ts b/src/dex/balancer-v3/balancer-v3-e2e.test.ts index 250ddf333..ac260a4b6 100644 --- a/src/dex/balancer-v3/balancer-v3-e2e.test.ts +++ b/src/dex/balancer-v3/balancer-v3-e2e.test.ts @@ -157,7 +157,7 @@ describe('BalancerV3 E2E', () => { describe('Mainnet, Stable Path', () => { const network = Network.SEPOLIA; - const tokenASymbol: string = 'aUsdcAave'; + const tokenASymbol: string = 'stataUsdc'; const tokenBSymbol: string = 'aDaiAave'; const tokenAAmount: string = '10000000'; diff --git a/src/dex/balancer-v3/balancer-v3-integration.test.ts b/src/dex/balancer-v3/balancer-v3-integration.test.ts index 9ecdf9c98..49da8097b 100644 --- a/src/dex/balancer-v3/balancer-v3-integration.test.ts +++ b/src/dex/balancer-v3/balancer-v3-integration.test.ts @@ -4,7 +4,7 @@ dotenv.config(); import { Interface, Result } from '@ethersproject/abi'; import { DummyDexHelper } from '../../dex-helper/index'; -import { Network, SwapSide } from '../../constants'; +import { Network, NULL_ADDRESS, SwapSide } from '../../constants'; import { BI_POWS } from '../../bigint-constants'; import { BalancerV3 } from './balancer-v3'; import { @@ -40,6 +40,7 @@ function getQuerySwapSingleTokenCalldata( step.swapInput.tokenIn, step.swapInput.tokenOut, amount, + NULL_ADDRESS, '0x', ], ), @@ -86,7 +87,7 @@ function getQuerySwapMultiTokenCalldata( target: routerAddress, callData: routerInterface.encodeFunctionData( side === SwapSide.SELL ? `querySwapExactIn` : `querySwapExactOut`, - [args, '0x'], + [args, NULL_ADDRESS, '0x'], ), }; }); @@ -240,7 +241,7 @@ async function testPricingOnNetwork( if (balancerV3.hasConstantPriceLargeAmounts) { checkConstantPoolPrices(poolPrices!, amounts, dexKey); } else { - checkPoolPrices(poolPrices!, amounts, side, dexKey); + checkPoolPrices(poolPrices!, amounts, side, dexKey, false); } // Check if onchain pricing equals to calculated ones @@ -352,13 +353,13 @@ describe('BalancerV3', function () { }); }); - describe('Boosted Pool', () => { + describe('Stable/Boosted Pool', () => { const network = Network.SEPOLIA; const dexHelper = new DummyDexHelper(network); const tokens = Tokens[network]; - const srcTokenSymbol = 'usdcAave'; - const destTokenSymbol = 'daiAave'; + const srcTokenSymbol = 'stataUsdc'; + const destTokenSymbol = 'stataUsdt'; const amountsForSell = [ 0n, diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 5d002ee44..a6c49af40 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -249,8 +249,8 @@ export class BalancerV3 extends SimpleExchange implements IDex { }, exchange: this.dexKey, gasCost: 1, // TODO - this will be updated once final profiles done - poolAddresses: [pool.address], - poolIdentifier: `${this.dexKey}_${pool.address}`, + poolAddresses: [pool.poolAddress], + poolIdentifier: `${this.dexKey}_${pool.poolAddress}`, }; for (let j = 0; j < amounts.length; j++) { @@ -265,7 +265,9 @@ export class BalancerV3 extends SimpleExchange implements IDex { } poolPrices.push(poolExchangePrice); } catch (err) { - this.logger.error(`error fetching prices for pool`); + this.logger.error( + `error fetching prices for pool: ${pool.poolAddress}`, + ); this.logger.error(err); } } diff --git a/src/dex/balancer-v3/config.ts b/src/dex/balancer-v3/config.ts index 44ee33f5f..1032ed30b 100644 --- a/src/dex/balancer-v3/config.ts +++ b/src/dex/balancer-v3/config.ts @@ -15,10 +15,10 @@ export const apiUrl = 'https://test-api-v3.balancer.fi/'; export const BalancerV3Config: DexConfigMap = { BalancerV3: { [Network.SEPOLIA]: { - vaultAddress: '0x30AF3689547354f82C70256894B07C9D0f067BB6', + vaultAddress: '0xBC582d2628FcD404254a1e12CB714967Ce428915', apiNetworkName: 'SEPOLIA', - balancerRouterAddress: '0x77eDc69766409C599F06Ef0B551a0990CBfe13A7', - balancerBatchRouterAddress: '0x16Cf31c5c4f92ad6185D583080C84FEeb6074c78', + balancerRouterAddress: '0x4D2aA7a3CD7F8dA6feF37578A1881cD63Fd3715E', + balancerBatchRouterAddress: '0x4232e5EEaA16Bcf483d93BEA469296B4EeF22503', }, }, }; diff --git a/src/dex/balancer-v3/getPoolsApi.ts b/src/dex/balancer-v3/getPoolsApi.ts index 14f537dee..11c4a555a 100644 --- a/src/dex/balancer-v3/getPoolsApi.ts +++ b/src/dex/balancer-v3/getPoolsApi.ts @@ -68,7 +68,7 @@ function createQuery( function toImmutablePoolStateMap(pools: Pool[]): ImmutablePoolStateMap { return pools.reduce((map, pool) => { const immutablePoolState: CommonImmutablePoolState = { - address: pool.id, + poolAddress: pool.id, tokens: pool.poolTokens.map(t => t.address), tokensUnderlying: pool.poolTokens.map(t => t.underlyingToken ? t.underlyingToken.address : null, diff --git a/src/dex/balancer-v3/types.ts b/src/dex/balancer-v3/types.ts index 53cc73686..fc360d1a9 100644 --- a/src/dex/balancer-v3/types.ts +++ b/src/dex/balancer-v3/types.ts @@ -3,7 +3,7 @@ import { Address } from '../../types'; // Immutable data types available on all pools (Available from API) export type CommonImmutablePoolState = { - address: string; + poolAddress: string; poolType: string; // For boosted pools tokens is the actual pool token wrapped, e.g. aUSDC/aDAI tokens: string[]; diff --git a/tests/constants-e2e.ts b/tests/constants-e2e.ts index 5778a4bb9..dae0c8092 100644 --- a/tests/constants-e2e.ts +++ b/tests/constants-e2e.ts @@ -1504,10 +1504,14 @@ export const Tokens: { address: `0xde46e43f46ff74a23a65ebb0580cbe3dfe684a17`, decimals: 18, }, - aUsdcAave: { + stataUsdc: { address: `0x8a88124522dbbf1e56352ba3de1d9f78c143751e`, decimals: 6, }, + stataUsdt: { + address: `0x978206fae13faf5a8d293fb614326b237684b750`, + decimals: 6, + }, }, }; From f00c5cdfe3ea159f79a18abf0d1243d1cae428cb Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 28 Nov 2024 11:37:47 +0000 Subject: [PATCH 21/66] feat: Correctly handle amp onchain state and update. --- scripts/run-dex-integration-v3.ts | 15 ++++++--- src/dex/balancer-v3/balancer-v3-pool.ts | 26 +++++++++++++-- src/dex/balancer-v3/balancer-v3.ts | 11 ++++++- src/dex/balancer-v3/getOnChainState.ts | 28 ++++++++++++---- src/dex/balancer-v3/stablePool.ts | 43 +++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 14 deletions(-) create mode 100644 src/dex/balancer-v3/stablePool.ts diff --git a/scripts/run-dex-integration-v3.ts b/scripts/run-dex-integration-v3.ts index e0c5b59a5..cba5dd68d 100644 --- a/scripts/run-dex-integration-v3.ts +++ b/scripts/run-dex-integration-v3.ts @@ -18,6 +18,11 @@ const stataDAI = { decimals: 18, }; +const stataUSDT = { + address: '0x978206fae13faf5a8d293fb614326b237684b750'.toLowerCase(), + decimals: 6, +}; + const bal = { address: '0xb19382073c7a0addbb56ac6af1808fa49e377b75'.toLowerCase(), decimals: 18, @@ -33,7 +38,7 @@ const usdcAave = { decimals: 6, }; -const amounts = [0n, BI_POWS[18], BI_POWS[19], 20000000000000000000n]; +const amounts = [0n, BI_POWS[6], BI_POWS[7], BI_POWS[8]]; async function main() { const dexHelper = new DummyDexHelper(Network.SEPOLIA); @@ -43,10 +48,10 @@ async function main() { await balancerV3.initializePricing(blocknumber); - // const from = stataDAI; - // const to = stataUSDC; - const from = daiAave; - const to = usdcAave; + const from = stataUSDC; + const to = stataUSDT; + // const from = daiAave; + // const to = usdcAave; const pools = await balancerV3.getPoolIdentifiers( from, diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 38775d812..84cf14666 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -11,6 +11,7 @@ import { vaultExtensionAbi_V3 } from './abi/vaultExtension.V3'; import { decodeThrowError, getOnChainState } from './getOnChainState'; import { BalancerV3Config } from './config'; import { SwapKind, Vault } from '@balancer-labs/balancer-maths'; +import { getAmplificationParameter, isStableMutableState } from './stablePool'; export class BalancerV3EventPool extends StatefulEventSubscriber { handlers: { @@ -48,6 +49,7 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { ['VAULT']: new Interface(vaultExtensionAbi_V3), ['STABLE']: new Interface([ 'function getAmplificationParameter() external view returns (uint256 value, bool isUpdating, uint256 precision)', + 'function getAmplificationState() external view returns (tuple(uint64 startValue, uint64 endValue, uint32 startTime, uint32 endTime) amplificationState, uint256 precision)', ]), }; @@ -271,13 +273,33 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { return maxSwapAmount; } - getSwapResult(steps: Step[], amountRaw: bigint, swapKind: SwapKind): bigint { + getSwapResult( + steps: Step[], + amountRaw: bigint, + swapKind: SwapKind, + timestamp: number, + ): bigint { if (amountRaw === 0n) return 0n; let amount = amountRaw; let outputAmountRaw = 0n; // Simulates the result of a multi-step swap path for (let i = 0; i < steps.length; i++) { const step = steps[i]; + // If its a Stable Pool with an updating Amp factor calculate current Amp value + if ( + step.poolState.poolType === 'STABLE' && + isStableMutableState(step.poolState) + ) { + if (step.poolState.ampIsUpdating) { + step.poolState.amp = getAmplificationParameter( + step.poolState.ampStartValue, + step.poolState.ampEndValue, + step.poolState.ampStartTime, + step.poolState.ampStopTime, + BigInt(timestamp), + ); + } + } outputAmountRaw = this.vault.swap( { ...step.swapInput, @@ -493,7 +515,7 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { getSwapStep(pool: PoolState, tokenIn: TokenInfo, tokenOut: TokenInfo): Step { // A normal swap between two tokens in a pool return { - pool: pool.address, + pool: pool.poolAddress, tokenOut: tokenOut.mainToken, isBuffer: false, swapInput: { diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index a6c49af40..b87d73ea8 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -186,6 +186,9 @@ export class BalancerV3 extends SimpleExchange implements IDex { return null; } + // This is used to get block timestamp which is needed to calculate Amp if it is updating + const block = await this.dexHelper.provider.getBlock(blockNumber); + // get up to date pools and state const allPoolState = this.eventPools.getState(blockNumber); if (allPoolState === null) { @@ -239,7 +242,12 @@ export class BalancerV3 extends SimpleExchange implements IDex { let unit = 0n; if (unitAmount < maxSwapAmount) - unit = this.eventPools.getSwapResult(steps, unitAmount, swapKind); + unit = this.eventPools.getSwapResult( + steps, + unitAmount, + swapKind, + block.timestamp, + ); const poolExchangePrice: PoolPrices = { prices: new Array(amounts.length).fill(0n), @@ -260,6 +268,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { steps, amounts[j], swapKind, + block.timestamp, ); } } diff --git a/src/dex/balancer-v3/getOnChainState.ts b/src/dex/balancer-v3/getOnChainState.ts index 96edcaa6c..582e798f2 100644 --- a/src/dex/balancer-v3/getOnChainState.ts +++ b/src/dex/balancer-v3/getOnChainState.ts @@ -185,7 +185,7 @@ const poolOnChain: Record< }, }, ['STABLE']: { - count: 1, + count: 2, ['encode']: ( network: number, contractInterface: Interface, @@ -198,6 +198,12 @@ const poolOnChain: Record< 'getAmplificationParameter', ), }, + { + target: address, + callData: contractInterface.encodeFunctionData( + 'getAmplificationState', + ), + }, ]; }, ['decode']: ( @@ -216,14 +222,24 @@ const poolOnChain: Record< throw new Error( `Failed to get result for getAmplificationParameter for ${poolAddress}`, ); - // TODO requested SC to add view to stable pool to get amp update state if it is currently updating + const resultAmpState = decodeThrowError( + contractInterface, + 'getAmplificationState', + data[startIndex++], + poolAddress, + ); + if (!resultAmpState) + throw new Error( + `Failed to get result for getAmplificationState for ${poolAddress}`, + ); + return { amp: resultAmp[0].toBigInt(), ampIsUpdating: !!resultAmp[1], - ampStartTime: 0n, - ampStopTime: 0n, - ampStartValue: 0n, - ampEndValue: 0n, + ampStartValue: resultAmpState[0][0].toBigInt(), + ampEndValue: resultAmpState[0][1].toBigInt(), + ampStartTime: BigInt(resultAmpState[0][2]), + ampStopTime: BigInt(resultAmpState[0][3]), }; }, }, diff --git a/src/dex/balancer-v3/stablePool.ts b/src/dex/balancer-v3/stablePool.ts new file mode 100644 index 000000000..e8cd66f36 --- /dev/null +++ b/src/dex/balancer-v3/stablePool.ts @@ -0,0 +1,43 @@ +import { StableMutableState } from './types'; + +export function isStableMutableState( + poolState: any, +): poolState is StableMutableState { + return ( + poolState && + typeof poolState === 'object' && + 'amp' in poolState && + 'ampIsUpdating' in poolState && + 'ampStartValue' in poolState && + 'ampEndValue' in poolState && + 'ampStartTime' in poolState && + 'ampStopTime' in poolState + ); +} + +// https://github.com/balancer/balancer-v3-monorepo/blob/009f2793abda248b150ccd15c1db25930c96ca82/pkg/pool-stable/contracts/StablePool.sol#L274 +export function getAmplificationParameter( + startValue: bigint, + endValue: bigint, + startTime: bigint, + endTime: bigint, + timestamp: bigint, +): bigint { + let value: bigint; + if (timestamp < endTime) { + if (endValue > startValue) { + value = + startValue + + ((endValue - startValue) * (timestamp - startTime)) / + (endTime - startTime); + } else { + value = + startValue - + ((startValue - endValue) * (timestamp - startTime)) / + (endTime - startTime); + } + } else { + value = endValue; + } + return value; +} From 6f99f3675f10f4728ba0f16ea4bff2f710a3f30d Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 29 Nov 2024 14:50:37 +0000 Subject: [PATCH 22/66] feat: Update to use final events. Add tests. Add ampStart/Stop handling for Stable pool. --- .../balancer-v3/balancer-v3-events.test.ts | 92 +++++++++++- src/dex/balancer-v3/balancer-v3-pool.ts | 133 ++++++++++++++++-- src/dex/balancer-v3/stablePool.ts | 32 +++++ 3 files changed, 241 insertions(+), 16 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-events.test.ts b/src/dex/balancer-v3/balancer-v3-events.test.ts index 68fc95733..8c291c309 100644 --- a/src/dex/balancer-v3/balancer-v3-events.test.ts +++ b/src/dex/balancer-v3/balancer-v3-events.test.ts @@ -7,7 +7,7 @@ import { Network } from '../../constants'; import { Address } from '../../types'; import { DummyDexHelper } from '../../dex-helper/index'; import { testEventSubscriber } from '../../../tests/utils-events'; -import { PoolStateMap } from './types'; +import { PoolStateMap, StableMutableState } from './types'; import { BalancerV3Config } from './config'; import _ from 'lodash'; @@ -55,7 +55,7 @@ async function fetchPoolState( // Filter to pool of interest return Object.entries(_.cloneDeep(pools) as PoolStateMap) .filter(([address]) => { - return address === poolAddress; + return address.toLowerCase() === poolAddress.toLowerCase(); }) .reduce((acc, [address, pool]) => { acc[address] = pool; @@ -63,6 +63,66 @@ async function fetchPoolState( }, {} as PoolStateMap); } +function stateCompare(state: PoolStateMap, expectedState: PoolStateMap) { + if (state['0xd63db0b88dca565633fb8d70a70b9b8093d34a7e']) { + if ( + ( + expectedState[ + '0xd63db0b88dca565633fb8d70a70b9b8093d34a7e' + ] as StableMutableState + ).ampIsUpdating + ) { + compareAmpUpdating(state, expectedState); + } else compareAmpStopped(state, expectedState); + } else expect(state).toEqual(expectedState); +} + +function compareAmpUpdating(state: PoolStateMap, expectedState: PoolStateMap) { + // tokenRates and balancesLiveScaled18 are gradually increasing between blocks due to tokenRate (and can't be tracked via event) so will be ignored + const compare = { + ...state, + ['0xd63db0b88dca565633fb8d70a70b9b8093d34a7e']: _.omit( + state['0xd63db0b88dca565633fb8d70a70b9b8093d34a7e'], + ['balancesLiveScaled18', 'tokenRates'], + ), + }; + const expectedCompare = { + ...expectedState, + ['0xd63db0b88dca565633fb8d70a70b9b8093d34a7e']: _.omit( + expectedState['0xd63db0b88dca565633fb8d70a70b9b8093d34a7e'], + ['balancesLiveScaled18', 'tokenRates'], + ), + }; + expect(compare).toEqual(expectedCompare); +} + +function compareAmpStopped(state: PoolStateMap, expectedState: PoolStateMap) { + if (state['0xd63db0b88dca565633fb8d70a70b9b8093d34a7e']) { + // tokenRates and balancesLiveScaled18 are gradually increasing between blocks due to tokenRate (and can't be tracked via event) so will be ignored + // In Contract ampStartTime & ampStopTime are updated to timestamp event is called. + // There doesn't appear to be a way to easily get timestamp non-async so we default to 0n which should have no effect. + const compare = { + ...state, + ['0xd63db0b88dca565633fb8d70a70b9b8093d34a7e']: _.omit( + state['0xd63db0b88dca565633fb8d70a70b9b8093d34a7e'], + ['balancesLiveScaled18', 'tokenRates'], + ), + }; + const expectedCompare = { + ...expectedState, + ['0xd63db0b88dca565633fb8d70a70b9b8093d34a7e']: { + ..._.omit(expectedState['0xd63db0b88dca565633fb8d70a70b9b8093d34a7e'], [ + 'balancesLiveScaled18', + 'tokenRates', + ]), + ampStartTime: 0n, + ampStopTime: 0n, + }, + }; + expect(compare).toEqual(expectedCompare); + } else expect(state).toEqual(expectedState); +} + // eventName -> blockNumbers type EventMappings = Record; type EventData = { blockNumbers: number[]; poolAddress: string[] }; @@ -78,10 +138,29 @@ describe('BalancerV3 EventPool', function () { // TODO once we have a new test deployment add tests for: AggregateSwapFeePercentageChanged, SwapFeePercentageChanged, PoolPausedStateChanged const eventsToTest: Record = { [BalancerV3Config.BalancerV3[network].vaultAddress]: { - // - https://eth-sepolia.blockscout.com/tx/0x6c2a7a38fd469779269f11ff8366ef01de0977219972cbe2eaa3c9a0a9a91d1e - PoolBalanceChanged: { - blockNumbers: [6839703], - poolAddress: ['0xd71958aed5e2e835a648ff832a181f7bdabbaf13'], + // https://eth-sepolia.blockscout.com/tx/0xc417d38ad6e21250c9ddded37680b40f0991cfd3f8ae2d8b5800507a58d48c44 + LiquidityAdded: { + blockNumbers: [7170937], + poolAddress: ['0x2ff3b96e0057a1f25f1d62ab800554ccdb268ab8'], + }, + // https://sepolia.etherscan.io/tx/0xc1596e26d51104b9236a0debc3e1946b30b82f92b8331639ad6f6aea2ff2decc + LiquidityRemoved: { + blockNumbers: [7170957], + poolAddress: ['0x2ff3b96e0057a1f25f1d62ab800554ccdb268ab8'], + }, + // https://sepolia.etherscan.io/tx/0x78d18503c2dd4458c94ec916b10c088bb4e8b90059676d00dbcec83f763d8c0e + Swap: { + blockNumbers: [7175721], + poolAddress: ['0x2ff3b96e0057a1f25f1d62ab800554ccdb268ab8'], + }, + // 7170034, AmpUpdateStarted, https://eth-sepolia.blockscout.com/tx/0xfbe2e53d9cede1dc900100a1d6e809a89d909746ac7b8cc011e93227af8dda8b?tab=logs + // 7170069, AmpUpdateStopped, https://eth-sepolia.blockscout.com/tx/0x2ee2e1d5980013fdf1cf9c3789e0321fb598c2412db8ee8057fcfaffd1c792ab?tab=logs + VaultAuxiliary: { + blockNumbers: [7170034, 7170069], + poolAddress: [ + '0xD63dB0B88dca565633fB8d70a70b9b8093d34A7E', + '0xD63dB0B88dca565633fB8d70a70b9b8093d34A7E', + ], }, }, }; @@ -115,6 +194,7 @@ describe('BalancerV3 EventPool', function () { blockNumber, `${dexKey}_${vaultAddress}`, dexHelper.provider, + stateCompare, ); }); }); diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 84cf14666..54c3fe5c1 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -1,17 +1,31 @@ import _ from 'lodash'; -import { Interface } from '@ethersproject/abi'; +import { Interface, defaultAbiCoder } from '@ethersproject/abi'; import { DeepReadonly } from 'ts-essentials'; import { Log, Logger } from '../../types'; import { catchParseLogError } from '../../utils'; import { StatefulEventSubscriber } from '../../stateful-event-subscriber'; import { IDexHelper } from '../../dex-helper/idex-helper'; -import { PoolState, PoolStateMap, Step, TokenInfo } from './types'; +import { + PoolState, + PoolStateMap, + StableMutableState, + Step, + TokenInfo, +} from './types'; import { getPoolsApi } from './getPoolsApi'; import { vaultExtensionAbi_V3 } from './abi/vaultExtension.V3'; import { decodeThrowError, getOnChainState } from './getOnChainState'; import { BalancerV3Config } from './config'; import { SwapKind, Vault } from '@balancer-labs/balancer-maths'; -import { getAmplificationParameter, isStableMutableState } from './stablePool'; +import { + ampUpdateStartedEvent, + ampUpdateStoppedEvent, + getAmplificationParameter, + isStableMutableState, +} from './stablePool'; +import { BI_POWS } from '../../bigint-constants'; + +const WAD = BI_POWS[18]; export class BalancerV3EventPool extends StatefulEventSubscriber { handlers: { @@ -59,8 +73,10 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { ]; // Add handlers - this.handlers['PoolBalanceChanged'] = - this.poolBalanceChangedEvent.bind(this); + this.handlers['LiquidityAdded'] = this.liquidityAddedEvent.bind(this); + this.handlers['LiquidityRemoved'] = this.liquidityRemovedEvent.bind(this); + this.handlers['Swap'] = this.swapEvent.bind(this); + this.handlers['VaultAuxiliary'] = this.vaultAuxiliaryEvent.bind(this); this.handlers['AggregateSwapFeePercentageChanged'] = this.poolAggregateSwapFeePercentageEvent.bind(this); this.handlers['SwapFeePercentageChanged'] = @@ -178,7 +194,7 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { }; } - poolBalanceChangedEvent( + liquidityAddedEvent( event: any, state: DeepReadonly, log: Readonly, @@ -194,14 +210,103 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { i < newState[poolAddress].balancesLiveScaled18.length; i++ ) { - newState[poolAddress].balancesLiveScaled18[i] += BigInt( - event.args.deltas[i], + newState[poolAddress].balancesLiveScaled18[i] += this.toScaled18( + BigInt(event.args.amountsAddedRaw[i]), + newState[poolAddress].scalingFactors[i], ); } newState[poolAddress].totalSupply = BigInt(event.args.totalSupply); + + return newState; + } + + liquidityRemovedEvent( + event: any, + state: DeepReadonly, + log: Readonly, + ): DeepReadonly | null { + const poolAddress = event.args.pool.toLowerCase(); + // Vault will send events from all pools, some of which are not officially supported by Balancer + if (!state[poolAddress]) { + return null; + } + const newState = _.cloneDeep(state) as PoolStateMap; + for ( + let i = 0; + i < newState[poolAddress].balancesLiveScaled18.length; + i++ + ) { + newState[poolAddress].balancesLiveScaled18[i] -= this.toScaled18( + BigInt(event.args.amountsRemovedRaw[i]), + newState[poolAddress].scalingFactors[i], + ); + } + newState[poolAddress].totalSupply = BigInt(event.args.totalSupply); + + return newState; + } + + swapEvent( + event: any, + state: DeepReadonly, + log: Readonly, + ): DeepReadonly | null { + const poolAddress = event.args.pool.toLowerCase(); + // Vault will send events from all pools, some of which are not officially supported by Balancer + if (!state[poolAddress]) { + return null; + } + const newState = _.cloneDeep(state) as PoolStateMap; + const tokenInIndex = newState[poolAddress].tokens.findIndex( + address => address.toLowerCase() === event.args.tokenIn.toLowerCase(), + ); + const tokenOutIndex = newState[poolAddress].tokens.findIndex( + address => address.toLowerCase() === event.args.tokenOut.toLowerCase(), + ); + if (tokenInIndex === -1 || tokenOutIndex === -1) { + this.logger.error(`swapEvent - token index not found in pool state`); + return null; + } + newState[poolAddress].balancesLiveScaled18[tokenInIndex] += this.toScaled18( + BigInt(event.args.amountIn), + newState[poolAddress].scalingFactors[tokenInIndex], + ); + newState[poolAddress].balancesLiveScaled18[tokenOutIndex] -= + this.toScaled18( + BigInt(event.args.amountOut), + newState[poolAddress].scalingFactors[tokenOutIndex], + ); + return newState; } + vaultAuxiliaryEvent( + event: any, + state: DeepReadonly, + log: Readonly, + ): DeepReadonly | null { + // In SC Pools can use this event to emit event data from the Vault. + // Allows us to track pool specific events using only the Vault subscription. + // https://github.com/balancer/balancer-v3-monorepo/blob/main/pkg/interfaces/contracts/vault/IVaultExtension.sol + const poolAddress = event.args.pool.toLowerCase(); + // Vault will send events from all pools, some of which are not officially supported by Balancer + if (!state[poolAddress]) { + return null; + } + + const newState = _.cloneDeep(state) as PoolStateMap; + switch (event.args.eventKey) { + case 'AmpUpdateStarted': + ampUpdateStartedEvent(newState[poolAddress], event.args.eventData); + return newState; + case 'AmpUpdateStopped': + ampUpdateStoppedEvent(newState[poolAddress], event.args.eventData); + return newState; + default: + return null; + } + } + poolAggregateSwapFeePercentageEvent( event: any, state: DeepReadonly, @@ -391,7 +496,9 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { // need rate info to calculate wrap/unwrap getTokenInfo(poolState: PoolState, tokenAddress: string): TokenInfo | null { // Check in main tokens - let tokenIndex = poolState.tokens.indexOf(tokenAddress); + let tokenIndex = poolState.tokens.findIndex( + address => address.toLowerCase() === tokenAddress.toLowerCase(), + ); if (tokenIndex !== -1) { return { isBoosted: false, @@ -404,7 +511,9 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { // Check in underlying tokens if available if (poolState.tokensUnderlying) { - tokenIndex = poolState.tokensUnderlying.indexOf(tokenAddress); + tokenIndex = poolState.tokensUnderlying.findIndex( + address => address!.toLowerCase() === tokenAddress.toLowerCase(), + ); if (tokenIndex !== -1) { return { isBoosted: true, @@ -525,4 +634,8 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { poolState: pool, }; } + + toScaled18(amount: bigint, scalingFactor: bigint): bigint { + return (amount * scalingFactor * WAD) / WAD; + } } diff --git a/src/dex/balancer-v3/stablePool.ts b/src/dex/balancer-v3/stablePool.ts index e8cd66f36..b605e3382 100644 --- a/src/dex/balancer-v3/stablePool.ts +++ b/src/dex/balancer-v3/stablePool.ts @@ -1,3 +1,5 @@ +import { defaultAbiCoder } from '@ethersproject/abi'; +import { PoolState } from '@balancer-labs/balancer-maths'; import { StableMutableState } from './types'; export function isStableMutableState( @@ -41,3 +43,33 @@ export function getAmplificationParameter( } return value; } + +export function ampUpdateStartedEvent(poolState: PoolState, eventData: any) { + // abi.encode(currentValueUint64, endValueUint64, startTimeUint32, endTimeUint32) + const decodedParams = defaultAbiCoder.decode( + ['uint64', 'uint64', 'uint32', 'uint32'], + eventData, + ); + if (isStableMutableState(poolState)) { + if (decodedParams[3] > decodedParams[2]) poolState.ampIsUpdating = true; + poolState.ampStartValue = decodedParams[0].toBigInt(); + poolState.ampEndValue = decodedParams[1].toBigInt(); + poolState.ampStartTime = BigInt(decodedParams[2]); + poolState.ampStopTime = BigInt(decodedParams[3]); + } else throw new Error("Can't update amp on non-stable pool"); +} + +export function ampUpdateStoppedEvent(poolState: PoolState, eventData: any) { + // abi.encode(currentValue) + const decodedParams = defaultAbiCoder.decode(['uint256'], eventData); + if (isStableMutableState(poolState)) { + poolState.ampIsUpdating = false; + poolState.amp = decodedParams[0].toBigInt(); + poolState.ampStartValue = decodedParams[0].toBigInt(); + poolState.ampEndValue = decodedParams[0].toBigInt(); + // In Contract these are update to timestamp event is called. + // There doesn't appear to be a way to easily get timestamp non-async so default to 0n which should have no effect + poolState.ampStartTime = BigInt(0n); + poolState.ampStopTime = BigInt(0n); + } else throw new Error("Can't update amp on non-stable pool"); +} From 8b6bbb87858977eb10400f4fbe0ccaf50daf59ec Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 29 Nov 2024 15:51:12 +0000 Subject: [PATCH 23/66] test: Add boosted integration test. --- .../balancer-v3-integration.test.ts | 96 ++++++++++++++++++- tests/constants-e2e.ts | 4 + 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/dex/balancer-v3/balancer-v3-integration.test.ts b/src/dex/balancer-v3/balancer-v3-integration.test.ts index 49da8097b..797719686 100644 --- a/src/dex/balancer-v3/balancer-v3-integration.test.ts +++ b/src/dex/balancer-v3/balancer-v3-integration.test.ts @@ -353,7 +353,7 @@ describe('BalancerV3', function () { }); }); - describe('Stable/Boosted Pool', () => { + describe('Stable Pool', () => { const network = Network.SEPOLIA; const dexHelper = new DummyDexHelper(network); @@ -445,6 +445,100 @@ describe('BalancerV3', function () { } }); }); + + describe('Boosted Path', () => { + const network = Network.SEPOLIA; + const dexHelper = new DummyDexHelper(network); + + const tokens = Tokens[network]; + const srcTokenSymbol = 'usdcAave'; + const destTokenSymbol = 'usdtAave'; + + const amountsForSell = [ + 0n, + 1n * BI_POWS[tokens[srcTokenSymbol].decimals], + 2n * BI_POWS[tokens[srcTokenSymbol].decimals], + 3n * BI_POWS[tokens[srcTokenSymbol].decimals], + 4n * BI_POWS[tokens[srcTokenSymbol].decimals], + 5n * BI_POWS[tokens[srcTokenSymbol].decimals], + 6n * BI_POWS[tokens[srcTokenSymbol].decimals], + 7n * BI_POWS[tokens[srcTokenSymbol].decimals], + 8n * BI_POWS[tokens[srcTokenSymbol].decimals], + 9n * BI_POWS[tokens[srcTokenSymbol].decimals], + 10n * BI_POWS[tokens[srcTokenSymbol].decimals], + ]; + + const amountsForBuy = [ + 0n, + 1n * BI_POWS[tokens[destTokenSymbol].decimals], + 2n * BI_POWS[tokens[destTokenSymbol].decimals], + 3n * BI_POWS[tokens[destTokenSymbol].decimals], + 4n * BI_POWS[tokens[destTokenSymbol].decimals], + 5n * BI_POWS[tokens[destTokenSymbol].decimals], + 6n * BI_POWS[tokens[destTokenSymbol].decimals], + 7n * BI_POWS[tokens[destTokenSymbol].decimals], + 8n * BI_POWS[tokens[destTokenSymbol].decimals], + 9n * BI_POWS[tokens[destTokenSymbol].decimals], + 10n * BI_POWS[tokens[destTokenSymbol].decimals], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + balancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (balancerV3.initializePricing) { + await balancerV3.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.SELL, + amountsForSell, + ); + }); + + // TODO 1 WEI rounding issue in maths - investigating + it.skip('getPoolIdentifiers and getPricesVolume BUY', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.BUY, + amountsForBuy, + ); + }); + + it('getTopPoolsForToken', async function () { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (newBalancerV3.updatePoolState) { + await newBalancerV3.updatePoolState(); + } + const poolLiquidity = await newBalancerV3.getTopPoolsForToken( + tokens[srcTokenSymbol].address, + 10, + ); + console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); + + if (!newBalancerV3.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity( + poolLiquidity, + Tokens[network][srcTokenSymbol].address, + dexKey, + ); + } + }); + }); }); // Add back once multicall queries are working diff --git a/tests/constants-e2e.ts b/tests/constants-e2e.ts index dae0c8092..4ef679869 100644 --- a/tests/constants-e2e.ts +++ b/tests/constants-e2e.ts @@ -1500,6 +1500,10 @@ export const Tokens: { address: `0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8`, decimals: 6, }, + usdtAave: { + address: `0xaa8e23fb1079ea71e0a56f48a2aa51851d8433d0`, + decimals: 6, + }, aDaiAave: { address: `0xde46e43f46ff74a23a65ebb0580cbe3dfe684a17`, decimals: 18, From 81120b1334a77a9f7285170e11a8e8c41307b149 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 29 Nov 2024 15:59:18 +0000 Subject: [PATCH 24/66] feat: Gas costs - WIP but basics covered. --- src/dex/balancer-v3/balancer-v3.ts | 3 ++- src/dex/balancer-v3/getGasCost.ts | 21 +++++++++++++++++++++ src/dex/balancer-v3/stablePool.ts | 3 +++ src/dex/balancer-v3/weightedPool.ts | 2 ++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/dex/balancer-v3/getGasCost.ts create mode 100644 src/dex/balancer-v3/weightedPool.ts diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index b87d73ea8..735f53f97 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -25,6 +25,7 @@ import { balancerRouterAbi } from './abi/balancerRouter'; import { extractReturnAmountPosition } from '../../executor/utils'; import { getTopPoolsApi } from './getTopPoolsApi'; import { balancerBatchRouterAbi } from './abi/balancerBatchRouter'; +import { getGasCost } from './getGasCost'; const MAX_UINT256 = '115792089237316195423570985008687907853269984665640564039457584007913129639935'; @@ -256,7 +257,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { steps: steps, }, exchange: this.dexKey, - gasCost: 1, // TODO - this will be updated once final profiles done + gasCost: getGasCost(steps), poolAddresses: [pool.poolAddress], poolIdentifier: `${this.dexKey}_${pool.poolAddress}`, }; diff --git a/src/dex/balancer-v3/getGasCost.ts b/src/dex/balancer-v3/getGasCost.ts new file mode 100644 index 000000000..865be8272 --- /dev/null +++ b/src/dex/balancer-v3/getGasCost.ts @@ -0,0 +1,21 @@ +import { STABLE_GAS_COST } from './stablePool'; +import { Step } from './types'; +import { WEIGHTED_GAS_COST } from './weightedPool'; + +// This is a worst case gas cost for full buffer>swap>buffer steps +// https://sepolia.etherscan.io/tx/0x8c2c5ec7fc2855ed2ffab3467ee434f4e374e0ecf791e8d2b93c8d74e3f5b1fe +const BOOSTED_GAS_COST = 283058; + +export function getGasCost(steps: Step[]): number { + if (steps.length > 1) { + // TODO - Improve accuracy for different steps/length, need to setup profiling + // steps.forEach(s => console.log(s.isBuffer, s.poolState.poolType)); + return BOOSTED_GAS_COST; + } else { + // TODO Add cost for buffer pool type although this is a very unlikely single step + if (steps[0].poolState.poolType === 'STABLE') return STABLE_GAS_COST; + + return WEIGHTED_GAS_COST; + } + return 1; +} diff --git a/src/dex/balancer-v3/stablePool.ts b/src/dex/balancer-v3/stablePool.ts index b605e3382..1800d38b2 100644 --- a/src/dex/balancer-v3/stablePool.ts +++ b/src/dex/balancer-v3/stablePool.ts @@ -2,6 +2,9 @@ import { defaultAbiCoder } from '@ethersproject/abi'; import { PoolState } from '@balancer-labs/balancer-maths'; import { StableMutableState } from './types'; +// TODO - Update with more accurate +export const STABLE_GAS_COST = 155000; + export function isStableMutableState( poolState: any, ): poolState is StableMutableState { diff --git a/src/dex/balancer-v3/weightedPool.ts b/src/dex/balancer-v3/weightedPool.ts new file mode 100644 index 000000000..bbb30c753 --- /dev/null +++ b/src/dex/balancer-v3/weightedPool.ts @@ -0,0 +1,2 @@ +// https://sepolia.etherscan.io/tx/0xe07958ff341aab57ab96a10347b65979b5b041f6408336d7e160e59bd02f9a40 +export const WEIGHTED_GAS_COST = 154000; From d6458e1fd33e5a47e46722b1404572a883d55c87 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Mon, 2 Dec 2024 14:18:46 +0200 Subject: [PATCH 25/66] chore: move balancer-v3 abis to `src/abi/balancer-v3` folder --- src/abi/balancer-v3/batch-router.json | 989 ++++++ src/abi/balancer-v3/router.json | 1792 +++++++++++ src/abi/balancer-v3/vault-extension.json | 2834 +++++++++++++++++ .../balancer-v3/abi/balancerBatchRouter.ts | 989 ------ src/dex/balancer-v3/abi/balancerRouter.ts | 1792 ----------- src/dex/balancer-v3/abi/vaultExtension.V3.ts | 2834 ----------------- .../balancer-v3-integration.test.ts | 4 +- src/dex/balancer-v3/balancer-v3-pool.ts | 2 +- src/dex/balancer-v3/balancer-v3.ts | 4 +- 9 files changed, 5620 insertions(+), 5620 deletions(-) create mode 100644 src/abi/balancer-v3/batch-router.json create mode 100644 src/abi/balancer-v3/router.json create mode 100644 src/abi/balancer-v3/vault-extension.json delete mode 100644 src/dex/balancer-v3/abi/balancerBatchRouter.ts delete mode 100644 src/dex/balancer-v3/abi/balancerRouter.ts delete mode 100644 src/dex/balancer-v3/abi/vaultExtension.V3.ts diff --git a/src/abi/balancer-v3/batch-router.json b/src/abi/balancer-v3/batch-router.json new file mode 100644 index 000000000..878e3173a --- /dev/null +++ b/src/abi/balancer-v3/batch-router.json @@ -0,0 +1,989 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IWETH", + "name": "weth", + "type": "address" + }, + { + "internalType": "contract IPermit2", + "name": "permit2", + "type": "address" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorSelectorNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "EthTransfer", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [], + "name": "InputLengthMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientEth", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuardReentrantCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "bits", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintDowncast", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "SenderIsNotVault", + "type": "error" + }, + { + "inputs": [], + "name": "SwapDeadline", + "type": "error" + }, + { + "inputs": [], + "name": "TransientIndexOutOfBounds", + "type": "error" + }, + { + "inputs": [], + "name": "getSender", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct IRouterCommon.PermitApproval[]", + "name": "permitBatch", + "type": "tuple[]" + }, + { + "internalType": "bytes[]", + "name": "permitSignatures", + "type": "bytes[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "internalType": "struct IAllowanceTransfer.PermitDetails[]", + "name": "details", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sigDeadline", + "type": "uint256" + } + ], + "internalType": "struct IAllowanceTransfer.PermitBatch", + "name": "permit2Batch", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "permit2Signature", + "type": "bytes" + }, + { + "internalType": "bytes[]", + "name": "multicallData", + "type": "bytes[]" + } + ], + "name": "permitBatchAndCall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "bool", + "name": "isBuffer", + "type": "bool" + } + ], + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "exactAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minAmountOut", + "type": "uint256" + } + ], + "internalType": "struct IBatchRouter.SwapPathExactAmountIn[]", + "name": "paths", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "querySwapExactIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "pathAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "tokensOut", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "bool", + "name": "isBuffer", + "type": "bool" + } + ], + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "exactAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minAmountOut", + "type": "uint256" + } + ], + "internalType": "struct IBatchRouter.SwapPathExactAmountIn[]", + "name": "paths", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IBatchRouter.SwapExactInHookParams", + "name": "params", + "type": "tuple" + } + ], + "name": "querySwapExactInHook", + "outputs": [ + { + "internalType": "uint256[]", + "name": "pathAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "tokensOut", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "bool", + "name": "isBuffer", + "type": "bool" + } + ], + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exactAmountOut", + "type": "uint256" + } + ], + "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", + "name": "paths", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "querySwapExactOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "pathAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "tokensIn", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "bool", + "name": "isBuffer", + "type": "bool" + } + ], + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exactAmountOut", + "type": "uint256" + } + ], + "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", + "name": "paths", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IBatchRouter.SwapExactOutHookParams", + "name": "params", + "type": "tuple" + } + ], + "name": "querySwapExactOutHook", + "outputs": [ + { + "internalType": "uint256[]", + "name": "pathAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "tokensIn", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "bool", + "name": "isBuffer", + "type": "bool" + } + ], + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "exactAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minAmountOut", + "type": "uint256" + } + ], + "internalType": "struct IBatchRouter.SwapPathExactAmountIn[]", + "name": "paths", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "swapExactIn", + "outputs": [ + { + "internalType": "uint256[]", + "name": "pathAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "tokensOut", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "bool", + "name": "isBuffer", + "type": "bool" + } + ], + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "exactAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minAmountOut", + "type": "uint256" + } + ], + "internalType": "struct IBatchRouter.SwapPathExactAmountIn[]", + "name": "paths", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IBatchRouter.SwapExactInHookParams", + "name": "params", + "type": "tuple" + } + ], + "name": "swapExactInHook", + "outputs": [ + { + "internalType": "uint256[]", + "name": "pathAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "tokensOut", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "bool", + "name": "isBuffer", + "type": "bool" + } + ], + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exactAmountOut", + "type": "uint256" + } + ], + "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", + "name": "paths", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "swapExactOut", + "outputs": [ + { + "internalType": "uint256[]", + "name": "pathAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "tokensIn", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "bool", + "name": "isBuffer", + "type": "bool" + } + ], + "internalType": "struct IBatchRouter.SwapPathStep[]", + "name": "steps", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exactAmountOut", + "type": "uint256" + } + ], + "internalType": "struct IBatchRouter.SwapPathExactAmountOut[]", + "name": "paths", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IBatchRouter.SwapExactOutHookParams", + "name": "params", + "type": "tuple" + } + ], + "name": "swapExactOutHook", + "outputs": [ + { + "internalType": "uint256[]", + "name": "pathAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "tokensIn", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/src/abi/balancer-v3/router.json b/src/abi/balancer-v3/router.json new file mode 100644 index 000000000..e28912159 --- /dev/null +++ b/src/abi/balancer-v3/router.json @@ -0,0 +1,1792 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IWETH", + "name": "weth", + "type": "address" + }, + { + "internalType": "contract IPermit2", + "name": "permit2", + "type": "address" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorSelectorNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "EthTransfer", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [], + "name": "InputLengthMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientEth", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuardReentrantCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "bits", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintDowncast", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "SenderIsNotVault", + "type": "error" + }, + { + "inputs": [], + "name": "SwapDeadline", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "maxAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minBptAmountOut", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "addLiquidityCustom", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "bptAmountOut", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "maxAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minBptAmountOut", + "type": "uint256" + }, + { + "internalType": "enum AddLiquidityKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IRouterCommon.AddLiquidityHookParams", + "name": "params", + "type": "tuple" + } + ], + "name": "addLiquidityHook", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "bptAmountOut", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "maxAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "exactBptAmountOut", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "addLiquidityProportional", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "exactBptAmountOut", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "addLiquiditySingleTokenExactOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "exactAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minBptAmountOut", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "addLiquidityUnbalanced", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountOut", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "donate", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "getSender", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "exactAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minBptAmountOut", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "initialize", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountOut", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "exactAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minBptAmountOut", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IRouter.InitializeHookParams", + "name": "params", + "type": "tuple" + } + ], + "name": "initializeHook", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct IRouterCommon.PermitApproval[]", + "name": "permitBatch", + "type": "tuple[]" + }, + { + "internalType": "bytes[]", + "name": "permitSignatures", + "type": "bytes[]" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "internalType": "struct IAllowanceTransfer.PermitDetails[]", + "name": "details", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sigDeadline", + "type": "uint256" + } + ], + "internalType": "struct IAllowanceTransfer.PermitBatch", + "name": "permit2Batch", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "permit2Signature", + "type": "bytes" + }, + { + "internalType": "bytes[]", + "name": "multicallData", + "type": "bytes[]" + } + ], + "name": "permitBatchAndCall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "maxAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minBptAmountOut", + "type": "uint256" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "queryAddLiquidityCustom", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "bptAmountOut", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "maxAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minBptAmountOut", + "type": "uint256" + }, + { + "internalType": "enum AddLiquidityKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IRouterCommon.AddLiquidityHookParams", + "name": "params", + "type": "tuple" + } + ], + "name": "queryAddLiquidityHook", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "bptAmountOut", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountOut", + "type": "uint256" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "queryAddLiquidityProportional", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountOut", + "type": "uint256" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "queryAddLiquiditySingleTokenExactOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "exactAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "queryAddLiquidityUnbalanced", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxBptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "queryRemoveLiquidityCustom", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "maxBptAmountIn", + "type": "uint256" + }, + { + "internalType": "enum RemoveLiquidityKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IRouterCommon.RemoveLiquidityHookParams", + "name": "params", + "type": "tuple" + } + ], + "name": "queryRemoveLiquidityHook", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountIn", + "type": "uint256" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "queryRemoveLiquidityProportional", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountIn", + "type": "uint256" + } + ], + "name": "queryRemoveLiquidityRecovery", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountIn", + "type": "uint256" + } + ], + "name": "queryRemoveLiquidityRecoveryHook", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountIn", + "type": "uint256" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "queryRemoveLiquiditySingleTokenExactIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactAmountOut", + "type": "uint256" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "queryRemoveLiquiditySingleTokenExactOut", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountIn", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "enum SwapKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountGiven", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IRouter.SwapSingleTokenHookParams", + "name": "params", + "type": "tuple" + } + ], + "name": "querySwapHook", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactAmountIn", + "type": "uint256" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "querySwapSingleTokenExactIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountCalculated", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactAmountOut", + "type": "uint256" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "querySwapSingleTokenExactOut", + "outputs": [ + { + "internalType": "uint256", + "name": "amountCalculated", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxBptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "removeLiquidityCustom", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "maxBptAmountIn", + "type": "uint256" + }, + { + "internalType": "enum RemoveLiquidityKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IRouterCommon.RemoveLiquidityHookParams", + "name": "params", + "type": "tuple" + } + ], + "name": "removeLiquidityHook", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "removeLiquidityProportional", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + } + ], + "name": "removeLiquidityRecovery", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + } + ], + "name": "removeLiquidityRecoveryHook", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountIn", + "type": "uint256" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "minAmountOut", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "removeLiquiditySingleTokenExactIn", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "uint256", + "name": "maxBptAmountIn", + "type": "uint256" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactAmountOut", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "removeLiquiditySingleTokenExactOut", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountIn", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "swapSingleTokenExactIn", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactAmountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "swapSingleTokenExactOut", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "enum SwapKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountGiven", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "wethIsEth", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IRouter.SwapSingleTokenHookParams", + "name": "params", + "type": "tuple" + } + ], + "name": "swapSingleTokenHook", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/src/abi/balancer-v3/vault-extension.json b/src/abi/balancer-v3/vault-extension.json new file mode 100644 index 000000000..c4f0f76c0 --- /dev/null +++ b/src/abi/balancer-v3/vault-extension.json @@ -0,0 +1,2834 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "mainVault", + "type": "address" + }, + { + "internalType": "contract IVaultAdmin", + "name": "vaultAdmin", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, + { + "inputs": [], + "name": "AfterAddLiquidityHookFailed", + "type": "error" + }, + { + "inputs": [], + "name": "AfterInitializeHookFailed", + "type": "error" + }, + { + "inputs": [], + "name": "AfterRemoveLiquidityHookFailed", + "type": "error" + }, + { + "inputs": [], + "name": "AfterSwapHookFailed", + "type": "error" + }, + { + "inputs": [], + "name": "AmountGivenZero", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + } + ], + "name": "AmountInAboveMax", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minAmountOut", + "type": "uint256" + } + ], + "name": "AmountOutBelowMin", + "type": "error" + }, + { + "inputs": [], + "name": "BalanceNotSettled", + "type": "error" + }, + { + "inputs": [], + "name": "BalanceOverflow", + "type": "error" + }, + { + "inputs": [], + "name": "BeforeAddLiquidityHookFailed", + "type": "error" + }, + { + "inputs": [], + "name": "BeforeInitializeHookFailed", + "type": "error" + }, + { + "inputs": [], + "name": "BeforeRemoveLiquidityHookFailed", + "type": "error" + }, + { + "inputs": [], + "name": "BeforeSwapHookFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + } + ], + "name": "BptAmountInAboveMax", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minAmountOut", + "type": "uint256" + } + ], + "name": "BptAmountOutBelowMin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + } + ], + "name": "BufferAlreadyInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + } + ], + "name": "BufferNotInitialized", + "type": "error" + }, + { + "inputs": [], + "name": "BufferSharesInvalidOwner", + "type": "error" + }, + { + "inputs": [], + "name": "BufferSharesInvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "totalSupply", + "type": "uint256" + } + ], + "name": "BufferTotalSupplyTooLow", + "type": "error" + }, + { + "inputs": [], + "name": "CannotReceiveEth", + "type": "error" + }, + { + "inputs": [], + "name": "CannotSwapSameToken", + "type": "error" + }, + { + "inputs": [], + "name": "CodecOverflow", + "type": "error" + }, + { + "inputs": [], + "name": "DoesNotSupportAddLiquidityCustom", + "type": "error" + }, + { + "inputs": [], + "name": "DoesNotSupportDonation", + "type": "error" + }, + { + "inputs": [], + "name": "DoesNotSupportRemoveLiquidityCustom", + "type": "error" + }, + { + "inputs": [], + "name": "DoesNotSupportUnbalancedLiquidity", + "type": "error" + }, + { + "inputs": [], + "name": "DynamicSwapFeeHookFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "allowance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC20InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC20InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC20InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "ERC20InvalidSpender", + "type": "error" + }, + { + "inputs": [], + "name": "ErrorSelectorNotFound", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [], + "name": "FeePrecisionTooHigh", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxAmountIn", + "type": "uint256" + } + ], + "name": "HookAdjustedAmountInAboveMax", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minAmountOut", + "type": "uint256" + } + ], + "name": "HookAdjustedAmountOutBelowMin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "HookAdjustedSwapLimit", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "poolHooksContract", + "type": "address" + }, + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "poolFactory", + "type": "address" + } + ], + "name": "HookRegistrationFailed", + "type": "error" + }, + { + "inputs": [], + "name": "InputLengthMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidAddLiquidityKind", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidRemoveLiquidityKind", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidToken", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTokenConfiguration", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTokenDecimals", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidTokenType", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + } + ], + "name": "InvalidUnderlyingToken", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "issuedShares", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minIssuedShares", + "type": "uint256" + } + ], + "name": "IssuedSharesBelowMin", + "type": "error" + }, + { + "inputs": [], + "name": "MaxTokens", + "type": "error" + }, + { + "inputs": [], + "name": "MinTokens", + "type": "error" + }, + { + "inputs": [], + "name": "NotEnoughBufferShares", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expectedUnderlyingAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actualUnderlyingAmount", + "type": "uint256" + } + ], + "name": "NotEnoughUnderlying", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "expectedWrappedAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "actualWrappedAmount", + "type": "uint256" + } + ], + "name": "NotEnoughWrapped", + "type": "error" + }, + { + "inputs": [], + "name": "NotStaticCall", + "type": "error" + }, + { + "inputs": [], + "name": "NotVaultDelegateCall", + "type": "error" + }, + { + "inputs": [], + "name": "OutOfBounds", + "type": "error" + }, + { + "inputs": [], + "name": "PauseBufferPeriodDurationTooLarge", + "type": "error" + }, + { + "inputs": [], + "name": "PercentageAboveMax", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolAlreadyInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolAlreadyRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolInRecoveryMode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotInRecoveryMode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolNotRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolPauseWindowExpired", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "totalSupply", + "type": "uint256" + } + ], + "name": "PoolTotalSupplyTooLow", + "type": "error" + }, + { + "inputs": [], + "name": "ProtocolFeesExceedTotalCollected", + "type": "error" + }, + { + "inputs": [], + "name": "QueriesDisabled", + "type": "error" + }, + { + "inputs": [], + "name": "QueriesDisabledPermanently", + "type": "error" + }, + { + "inputs": [], + "name": "QuoteResultSpoofed", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuardReentrantCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "result", + "type": "bytes" + } + ], + "name": "Result", + "type": "error" + }, + { + "inputs": [], + "name": "RouterNotTrusted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintToInt", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "SenderIsNotVault", + "type": "error" + }, + { + "inputs": [], + "name": "SwapFeePercentageTooHigh", + "type": "error" + }, + { + "inputs": [], + "name": "SwapFeePercentageTooLow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + } + ], + "name": "SwapLimit", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "TokenAlreadyRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "TokenNotRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "expectedToken", + "type": "address" + }, + { + "internalType": "address", + "name": "actualToken", + "type": "address" + } + ], + "name": "TokensMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "TokensNotSorted", + "type": "error" + }, + { + "inputs": [], + "name": "TradeAmountTooSmall", + "type": "error" + }, + { + "inputs": [], + "name": "VaultBuffersArePaused", + "type": "error" + }, + { + "inputs": [], + "name": "VaultIsNotUnlocked", + "type": "error" + }, + { + "inputs": [], + "name": "VaultNotPaused", + "type": "error" + }, + { + "inputs": [], + "name": "VaultPauseWindowDurationTooLarge", + "type": "error" + }, + { + "inputs": [], + "name": "VaultPauseWindowExpired", + "type": "error" + }, + { + "inputs": [], + "name": "VaultPaused", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + } + ], + "name": "WrapAmountTooSmall", + "type": "error" + }, + { + "inputs": [], + "name": "WrongProtocolFeeControllerDeployment", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + }, + { + "internalType": "address", + "name": "underlyingToken", + "type": "address" + } + ], + "name": "WrongUnderlyingToken", + "type": "error" + }, + { + "inputs": [], + "name": "WrongVaultAdminDeployment", + "type": "error" + }, + { + "inputs": [], + "name": "WrongVaultExtensionDeployment", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "aggregateSwapFeePercentage", + "type": "uint256" + } + ], + "name": "AggregateSwapFeePercentageChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "aggregateYieldFeePercentage", + "type": "uint256" + } + ], + "name": "AggregateYieldFeePercentageChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IAuthorizer", + "name": "newAuthorizer", + "type": "address" + } + ], + "name": "AuthorizerChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "burnedShares", + "type": "uint256" + } + ], + "name": "BufferSharesBurned", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "issuedShares", + "type": "uint256" + } + ], + "name": "BufferSharesMinted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "liquidityProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "enum AddLiquidityKind", + "name": "kind", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalSupply", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "amountsAddedRaw", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "swapFeeAmountsRaw", + "type": "uint256[]" + } + ], + "name": "LiquidityAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountUnderlying", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountWrapped", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "bufferBalances", + "type": "bytes32" + } + ], + "name": "LiquidityAddedToBuffer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "liquidityProvider", + "type": "address" + }, + { + "indexed": true, + "internalType": "enum RemoveLiquidityKind", + "name": "kind", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "totalSupply", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "amountsRemovedRaw", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "swapFeeAmountsRaw", + "type": "uint256[]" + } + ], + "name": "LiquidityRemoved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountUnderlying", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountWrapped", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "bufferBalances", + "type": "bytes32" + } + ], + "name": "LiquidityRemovedFromBuffer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolInitialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "name": "PoolPausedStateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "recoveryMode", + "type": "bool" + } + ], + "name": "PoolRecoveryModeStateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "factory", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "enum TokenType", + "name": "tokenType", + "type": "uint8" + }, + { + "internalType": "contract IRateProvider", + "name": "rateProvider", + "type": "address" + }, + { + "internalType": "bool", + "name": "paysYieldFees", + "type": "bool" + } + ], + "indexed": false, + "internalType": "struct TokenConfig[]", + "name": "tokenConfig", + "type": "tuple[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "pauseWindowEndTime", + "type": "uint32" + }, + { + "components": [ + { + "internalType": "address", + "name": "pauseManager", + "type": "address" + }, + { + "internalType": "address", + "name": "swapFeeManager", + "type": "address" + }, + { + "internalType": "address", + "name": "poolCreator", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct PoolRoleAccounts", + "name": "roleAccounts", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "enableHookAdjustedAmounts", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallComputeDynamicSwapFee", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeRemoveLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterRemoveLiquidity", + "type": "bool" + }, + { + "internalType": "address", + "name": "hooksContract", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct HooksConfig", + "name": "hooksConfig", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "bool", + "name": "disableUnbalancedLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "enableAddLiquidityCustom", + "type": "bool" + }, + { + "internalType": "bool", + "name": "enableRemoveLiquidityCustom", + "type": "bool" + }, + { + "internalType": "bool", + "name": "enableDonation", + "type": "bool" + } + ], + "indexed": false, + "internalType": "struct LiquidityManagement", + "name": "liquidityManagement", + "type": "tuple" + } + ], + "name": "PoolRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IProtocolFeeController", + "name": "newProtocolFeeController", + "type": "address" + } + ], + "name": "ProtocolFeeControllerChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "swapFeeAmount", + "type": "uint256" + } + ], + "name": "Swap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + } + ], + "name": "SwapFeePercentageChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "burnedShares", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "withdrawnUnderlying", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "bufferBalances", + "type": "bytes32" + } + ], + "name": "Unwrap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "eventKey", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "eventData", + "type": "bytes" + } + ], + "name": "VaultAuxiliary", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "name": "VaultBuffersPausedStateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "name": "VaultPausedStateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "VaultQueriesDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "VaultQueriesEnabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "depositedUnderlying", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "mintedShares", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "bufferBalances", + "type": "bytes32" + } + ], + "name": "Wrap", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "components": [ + { + "internalType": "enum SwapKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "amountGivenScaled18", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "balancesScaled18", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "indexIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "indexOut", + "type": "uint256" + }, + { + "internalType": "address", + "name": "router", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct PoolSwapParams", + "name": "swapParams", + "type": "tuple" + } + ], + "name": "computeDynamicSwapFeePercentage", + "outputs": [ + { + "internalType": "uint256", + "name": "dynamicSwapFeePercentage", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "eventKey", + "type": "string" + }, + { + "internalType": "bytes", + "name": "eventData", + "type": "bytes" + } + ], + "name": "emitAuxiliaryEvent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getAddLiquidityCalledFlag", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "getAggregateSwapFeeAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "getAggregateYieldFeeAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getBptRate", + "outputs": [ + { + "internalType": "uint256", + "name": "rate", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getCurrentLiveBalances", + "outputs": [ + { + "internalType": "uint256[]", + "name": "balancesLiveScaled18", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + } + ], + "name": "getERC4626BufferAsset", + "outputs": [ + { + "internalType": "address", + "name": "asset", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getHooksConfig", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "enableHookAdjustedAmounts", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterInitialize", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallComputeDynamicSwapFee", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterSwap", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterAddLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallBeforeRemoveLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "shouldCallAfterRemoveLiquidity", + "type": "bool" + }, + { + "internalType": "address", + "name": "hooksContract", + "type": "address" + } + ], + "internalType": "struct HooksConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getNonzeroDeltaCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolConfig", + "outputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "bool", + "name": "disableUnbalancedLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "enableAddLiquidityCustom", + "type": "bool" + }, + { + "internalType": "bool", + "name": "enableRemoveLiquidityCustom", + "type": "bool" + }, + { + "internalType": "bool", + "name": "enableDonation", + "type": "bool" + } + ], + "internalType": "struct LiquidityManagement", + "name": "liquidityManagement", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "staticSwapFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "aggregateSwapFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "aggregateYieldFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint40", + "name": "tokenDecimalDiffs", + "type": "uint40" + }, + { + "internalType": "uint32", + "name": "pauseWindowEndTime", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "isPoolRegistered", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isPoolInitialized", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isPoolPaused", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isPoolInRecoveryMode", + "type": "bool" + } + ], + "internalType": "struct PoolConfig", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolData", + "outputs": [ + { + "components": [ + { + "internalType": "PoolConfigBits", + "name": "poolConfigBits", + "type": "bytes32" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "enum TokenType", + "name": "tokenType", + "type": "uint8" + }, + { + "internalType": "contract IRateProvider", + "name": "rateProvider", + "type": "address" + }, + { + "internalType": "bool", + "name": "paysYieldFees", + "type": "bool" + } + ], + "internalType": "struct TokenInfo[]", + "name": "tokenInfo", + "type": "tuple[]" + }, + { + "internalType": "uint256[]", + "name": "balancesRaw", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "balancesLiveScaled18", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "tokenRates", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "decimalScalingFactors", + "type": "uint256[]" + } + ], + "internalType": "struct PoolData", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolPausedState", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + }, + { + "internalType": "uint32", + "name": "", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "", + "type": "uint32" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolRoleAccounts", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "pauseManager", + "type": "address" + }, + { + "internalType": "address", + "name": "swapFeeManager", + "type": "address" + }, + { + "internalType": "address", + "name": "poolCreator", + "type": "address" + } + ], + "internalType": "struct PoolRoleAccounts", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolTokenInfo", + "outputs": [ + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "enum TokenType", + "name": "tokenType", + "type": "uint8" + }, + { + "internalType": "contract IRateProvider", + "name": "rateProvider", + "type": "address" + }, + { + "internalType": "bool", + "name": "paysYieldFees", + "type": "bool" + } + ], + "internalType": "struct TokenInfo[]", + "name": "tokenInfo", + "type": "tuple[]" + }, + { + "internalType": "uint256[]", + "name": "balancesRaw", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "lastBalancesLiveScaled18", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolTokenRates", + "outputs": [ + { + "internalType": "uint256[]", + "name": "decimalScalingFactors", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "tokenRates", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getPoolTokens", + "outputs": [ + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeeController", + "outputs": [ + { + "internalType": "contract IProtocolFeeController", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "getReservesOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "getStaticSwapFeePercentage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "getTokenDelta", + "outputs": [ + { + "internalType": "int256", + "name": "", + "type": "int256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVaultAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "exactAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "minBptAmountOut", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "initialize", + "outputs": [ + { + "internalType": "uint256", + "name": "bptAmountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + } + ], + "name": "isERC4626BufferInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolInRecoveryMode", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolInitialized", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolPaused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolRegistered", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isQueryDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isQueryDisabledPermanently", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isUnlocked", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "quote", + "outputs": [ + { + "internalType": "bytes", + "name": "result", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "quoteAndRevert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "reentrancyGuardEntered", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "enum TokenType", + "name": "tokenType", + "type": "uint8" + }, + { + "internalType": "contract IRateProvider", + "name": "rateProvider", + "type": "address" + }, + { + "internalType": "bool", + "name": "paysYieldFees", + "type": "bool" + } + ], + "internalType": "struct TokenConfig[]", + "name": "tokenConfig", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "pauseWindowEndTime", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "protocolFeeExempt", + "type": "bool" + }, + { + "components": [ + { + "internalType": "address", + "name": "pauseManager", + "type": "address" + }, + { + "internalType": "address", + "name": "swapFeeManager", + "type": "address" + }, + { + "internalType": "address", + "name": "poolCreator", + "type": "address" + } + ], + "internalType": "struct PoolRoleAccounts", + "name": "roleAccounts", + "type": "tuple" + }, + { + "internalType": "address", + "name": "poolHooksContract", + "type": "address" + }, + { + "components": [ + { + "internalType": "bool", + "name": "disableUnbalancedLiquidity", + "type": "bool" + }, + { + "internalType": "bool", + "name": "enableAddLiquidityCustom", + "type": "bool" + }, + { + "internalType": "bool", + "name": "enableRemoveLiquidityCustom", + "type": "bool" + }, + { + "internalType": "bool", + "name": "enableDonation", + "type": "bool" + } + ], + "internalType": "struct LiquidityManagement", + "name": "liquidityManagement", + "type": "tuple" + } + ], + "name": "registerPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "exactBptAmountIn", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + } + ], + "name": "removeLiquidityRecovery", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsOutRaw", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "vault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/src/dex/balancer-v3/abi/balancerBatchRouter.ts b/src/dex/balancer-v3/abi/balancerBatchRouter.ts deleted file mode 100644 index 8a3cd4d96..000000000 --- a/src/dex/balancer-v3/abi/balancerBatchRouter.ts +++ /dev/null @@ -1,989 +0,0 @@ -export const balancerBatchRouterAbi = [ - { - inputs: [ - { - internalType: 'contract IVault', - name: 'vault', - type: 'address', - }, - { - internalType: 'contract IWETH', - name: 'weth', - type: 'address', - }, - { - internalType: 'contract IPermit2', - name: 'permit2', - type: 'address', - }, - { - internalType: 'string', - name: 'version', - type: 'string', - }, - ], - stateMutability: 'nonpayable', - type: 'constructor', - }, - { - inputs: [ - { - internalType: 'address', - name: 'target', - type: 'address', - }, - ], - name: 'AddressEmptyCode', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'account', - type: 'address', - }, - ], - name: 'AddressInsufficientBalance', - type: 'error', - }, - { - inputs: [], - name: 'ErrorSelectorNotFound', - type: 'error', - }, - { - inputs: [], - name: 'EthTransfer', - type: 'error', - }, - { - inputs: [], - name: 'FailedInnerCall', - type: 'error', - }, - { - inputs: [], - name: 'InputLengthMismatch', - type: 'error', - }, - { - inputs: [], - name: 'InsufficientEth', - type: 'error', - }, - { - inputs: [], - name: 'ReentrancyGuardReentrantCall', - type: 'error', - }, - { - inputs: [ - { - internalType: 'uint8', - name: 'bits', - type: 'uint8', - }, - { - internalType: 'uint256', - name: 'value', - type: 'uint256', - }, - ], - name: 'SafeCastOverflowedUintDowncast', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'token', - type: 'address', - }, - ], - name: 'SafeERC20FailedOperation', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - ], - name: 'SenderIsNotVault', - type: 'error', - }, - { - inputs: [], - name: 'SwapDeadline', - type: 'error', - }, - { - inputs: [], - name: 'TransientIndexOutOfBounds', - type: 'error', - }, - { - inputs: [], - name: 'getSender', - outputs: [ - { - internalType: 'address', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes[]', - name: 'data', - type: 'bytes[]', - }, - ], - name: 'multicall', - outputs: [ - { - internalType: 'bytes[]', - name: 'results', - type: 'bytes[]', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'token', - type: 'address', - }, - { - internalType: 'address', - name: 'owner', - type: 'address', - }, - { - internalType: 'address', - name: 'spender', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amount', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'nonce', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - ], - internalType: 'struct IRouterCommon.PermitApproval[]', - name: 'permitBatch', - type: 'tuple[]', - }, - { - internalType: 'bytes[]', - name: 'permitSignatures', - type: 'bytes[]', - }, - { - components: [ - { - components: [ - { - internalType: 'address', - name: 'token', - type: 'address', - }, - { - internalType: 'uint160', - name: 'amount', - type: 'uint160', - }, - { - internalType: 'uint48', - name: 'expiration', - type: 'uint48', - }, - { - internalType: 'uint48', - name: 'nonce', - type: 'uint48', - }, - ], - internalType: 'struct IAllowanceTransfer.PermitDetails[]', - name: 'details', - type: 'tuple[]', - }, - { - internalType: 'address', - name: 'spender', - type: 'address', - }, - { - internalType: 'uint256', - name: 'sigDeadline', - type: 'uint256', - }, - ], - internalType: 'struct IAllowanceTransfer.PermitBatch', - name: 'permit2Batch', - type: 'tuple', - }, - { - internalType: 'bytes', - name: 'permit2Signature', - type: 'bytes', - }, - { - internalType: 'bytes[]', - name: 'multicallData', - type: 'bytes[]', - }, - ], - name: 'permitBatchAndCall', - outputs: [ - { - internalType: 'bytes[]', - name: 'results', - type: 'bytes[]', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - components: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'bool', - name: 'isBuffer', - type: 'bool', - }, - ], - internalType: 'struct IBatchRouter.SwapPathStep[]', - name: 'steps', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'exactAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'minAmountOut', - type: 'uint256', - }, - ], - internalType: 'struct IBatchRouter.SwapPathExactAmountIn[]', - name: 'paths', - type: 'tuple[]', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'querySwapExactIn', - outputs: [ - { - internalType: 'uint256[]', - name: 'pathAmountsOut', - type: 'uint256[]', - }, - { - internalType: 'address[]', - name: 'tokensOut', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - components: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - components: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'bool', - name: 'isBuffer', - type: 'bool', - }, - ], - internalType: 'struct IBatchRouter.SwapPathStep[]', - name: 'steps', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'exactAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'minAmountOut', - type: 'uint256', - }, - ], - internalType: 'struct IBatchRouter.SwapPathExactAmountIn[]', - name: 'paths', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct IBatchRouter.SwapExactInHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'querySwapExactInHook', - outputs: [ - { - internalType: 'uint256[]', - name: 'pathAmountsOut', - type: 'uint256[]', - }, - { - internalType: 'address[]', - name: 'tokensOut', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - components: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'bool', - name: 'isBuffer', - type: 'bool', - }, - ], - internalType: 'struct IBatchRouter.SwapPathStep[]', - name: 'steps', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'maxAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - ], - internalType: 'struct IBatchRouter.SwapPathExactAmountOut[]', - name: 'paths', - type: 'tuple[]', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'querySwapExactOut', - outputs: [ - { - internalType: 'uint256[]', - name: 'pathAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'address[]', - name: 'tokensIn', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'amountsIn', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - components: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - components: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'bool', - name: 'isBuffer', - type: 'bool', - }, - ], - internalType: 'struct IBatchRouter.SwapPathStep[]', - name: 'steps', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'maxAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - ], - internalType: 'struct IBatchRouter.SwapPathExactAmountOut[]', - name: 'paths', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct IBatchRouter.SwapExactOutHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'querySwapExactOutHook', - outputs: [ - { - internalType: 'uint256[]', - name: 'pathAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'address[]', - name: 'tokensIn', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'amountsIn', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - components: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'bool', - name: 'isBuffer', - type: 'bool', - }, - ], - internalType: 'struct IBatchRouter.SwapPathStep[]', - name: 'steps', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'exactAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'minAmountOut', - type: 'uint256', - }, - ], - internalType: 'struct IBatchRouter.SwapPathExactAmountIn[]', - name: 'paths', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'swapExactIn', - outputs: [ - { - internalType: 'uint256[]', - name: 'pathAmountsOut', - type: 'uint256[]', - }, - { - internalType: 'address[]', - name: 'tokensOut', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - components: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - components: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'bool', - name: 'isBuffer', - type: 'bool', - }, - ], - internalType: 'struct IBatchRouter.SwapPathStep[]', - name: 'steps', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'exactAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'minAmountOut', - type: 'uint256', - }, - ], - internalType: 'struct IBatchRouter.SwapPathExactAmountIn[]', - name: 'paths', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct IBatchRouter.SwapExactInHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'swapExactInHook', - outputs: [ - { - internalType: 'uint256[]', - name: 'pathAmountsOut', - type: 'uint256[]', - }, - { - internalType: 'address[]', - name: 'tokensOut', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - components: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'bool', - name: 'isBuffer', - type: 'bool', - }, - ], - internalType: 'struct IBatchRouter.SwapPathStep[]', - name: 'steps', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'maxAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - ], - internalType: 'struct IBatchRouter.SwapPathExactAmountOut[]', - name: 'paths', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'swapExactOut', - outputs: [ - { - internalType: 'uint256[]', - name: 'pathAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'address[]', - name: 'tokensIn', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'amountsIn', - type: 'uint256[]', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - components: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - components: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'bool', - name: 'isBuffer', - type: 'bool', - }, - ], - internalType: 'struct IBatchRouter.SwapPathStep[]', - name: 'steps', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'maxAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - ], - internalType: 'struct IBatchRouter.SwapPathExactAmountOut[]', - name: 'paths', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct IBatchRouter.SwapExactOutHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'swapExactOutHook', - outputs: [ - { - internalType: 'uint256[]', - name: 'pathAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'address[]', - name: 'tokensIn', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'amountsIn', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [], - name: 'version', - outputs: [ - { - internalType: 'string', - name: '', - type: 'string', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - stateMutability: 'payable', - type: 'receive', - }, -] as const; diff --git a/src/dex/balancer-v3/abi/balancerRouter.ts b/src/dex/balancer-v3/abi/balancerRouter.ts deleted file mode 100644 index 41d85188b..000000000 --- a/src/dex/balancer-v3/abi/balancerRouter.ts +++ /dev/null @@ -1,1792 +0,0 @@ -export const balancerRouterAbi = [ - { - inputs: [ - { - internalType: 'contract IVault', - name: 'vault', - type: 'address', - }, - { - internalType: 'contract IWETH', - name: 'weth', - type: 'address', - }, - { - internalType: 'contract IPermit2', - name: 'permit2', - type: 'address', - }, - { - internalType: 'string', - name: 'version', - type: 'string', - }, - ], - stateMutability: 'nonpayable', - type: 'constructor', - }, - { - inputs: [ - { - internalType: 'address', - name: 'target', - type: 'address', - }, - ], - name: 'AddressEmptyCode', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'account', - type: 'address', - }, - ], - name: 'AddressInsufficientBalance', - type: 'error', - }, - { - inputs: [], - name: 'ErrorSelectorNotFound', - type: 'error', - }, - { - inputs: [], - name: 'EthTransfer', - type: 'error', - }, - { - inputs: [], - name: 'FailedInnerCall', - type: 'error', - }, - { - inputs: [], - name: 'InputLengthMismatch', - type: 'error', - }, - { - inputs: [], - name: 'InsufficientEth', - type: 'error', - }, - { - inputs: [], - name: 'ReentrancyGuardReentrantCall', - type: 'error', - }, - { - inputs: [ - { - internalType: 'uint8', - name: 'bits', - type: 'uint8', - }, - { - internalType: 'uint256', - name: 'value', - type: 'uint256', - }, - ], - name: 'SafeCastOverflowedUintDowncast', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'token', - type: 'address', - }, - ], - name: 'SafeERC20FailedOperation', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - ], - name: 'SenderIsNotVault', - type: 'error', - }, - { - inputs: [], - name: 'SwapDeadline', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256[]', - name: 'maxAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'addLiquidityCustom', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'bptAmountOut', - type: 'uint256', - }, - { - internalType: 'bytes', - name: 'returnData', - type: 'bytes', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256[]', - name: 'maxAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { - internalType: 'enum AddLiquidityKind', - name: 'kind', - type: 'uint8', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct IRouterCommon.AddLiquidityHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'addLiquidityHook', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'bptAmountOut', - type: 'uint256', - }, - { - internalType: 'bytes', - name: 'returnData', - type: 'bytes', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256[]', - name: 'maxAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'exactBptAmountOut', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'addLiquidityProportional', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsIn', - type: 'uint256[]', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'uint256', - name: 'maxAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'exactBptAmountOut', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'addLiquiditySingleTokenExactOut', - outputs: [ - { - internalType: 'uint256', - name: 'amountIn', - type: 'uint256', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256[]', - name: 'exactAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'addLiquidityUnbalanced', - outputs: [ - { - internalType: 'uint256', - name: 'bptAmountOut', - type: 'uint256', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256[]', - name: 'amountsIn', - type: 'uint256[]', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'donate', - outputs: [], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [], - name: 'getSender', - outputs: [ - { - internalType: 'address', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'exactAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'initialize', - outputs: [ - { - internalType: 'uint256', - name: 'bptAmountOut', - type: 'uint256', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'exactAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct IRouter.InitializeHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'initializeHook', - outputs: [ - { - internalType: 'uint256', - name: 'bptAmountOut', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes[]', - name: 'data', - type: 'bytes[]', - }, - ], - name: 'multicall', - outputs: [ - { - internalType: 'bytes[]', - name: 'results', - type: 'bytes[]', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'token', - type: 'address', - }, - { - internalType: 'address', - name: 'owner', - type: 'address', - }, - { - internalType: 'address', - name: 'spender', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amount', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'nonce', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - ], - internalType: 'struct IRouterCommon.PermitApproval[]', - name: 'permitBatch', - type: 'tuple[]', - }, - { - internalType: 'bytes[]', - name: 'permitSignatures', - type: 'bytes[]', - }, - { - components: [ - { - components: [ - { - internalType: 'address', - name: 'token', - type: 'address', - }, - { - internalType: 'uint160', - name: 'amount', - type: 'uint160', - }, - { - internalType: 'uint48', - name: 'expiration', - type: 'uint48', - }, - { - internalType: 'uint48', - name: 'nonce', - type: 'uint48', - }, - ], - internalType: 'struct IAllowanceTransfer.PermitDetails[]', - name: 'details', - type: 'tuple[]', - }, - { - internalType: 'address', - name: 'spender', - type: 'address', - }, - { - internalType: 'uint256', - name: 'sigDeadline', - type: 'uint256', - }, - ], - internalType: 'struct IAllowanceTransfer.PermitBatch', - name: 'permit2Batch', - type: 'tuple', - }, - { - internalType: 'bytes', - name: 'permit2Signature', - type: 'bytes', - }, - { - internalType: 'bytes[]', - name: 'multicallData', - type: 'bytes[]', - }, - ], - name: 'permitBatchAndCall', - outputs: [ - { - internalType: 'bytes[]', - name: 'results', - type: 'bytes[]', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256[]', - name: 'maxAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'queryAddLiquidityCustom', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'bptAmountOut', - type: 'uint256', - }, - { - internalType: 'bytes', - name: 'returnData', - type: 'bytes', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256[]', - name: 'maxAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { - internalType: 'enum AddLiquidityKind', - name: 'kind', - type: 'uint8', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct IRouterCommon.AddLiquidityHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'queryAddLiquidityHook', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'bptAmountOut', - type: 'uint256', - }, - { - internalType: 'bytes', - name: 'returnData', - type: 'bytes', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountOut', - type: 'uint256', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'queryAddLiquidityProportional', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsIn', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountOut', - type: 'uint256', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'queryAddLiquiditySingleTokenExactOut', - outputs: [ - { - internalType: 'uint256', - name: 'amountIn', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256[]', - name: 'exactAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'queryAddLiquidityUnbalanced', - outputs: [ - { - internalType: 'uint256', - name: 'bptAmountOut', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256', - name: 'maxBptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'queryRemoveLiquidityCustom', - outputs: [ - { - internalType: 'uint256', - name: 'bptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - { - internalType: 'bytes', - name: 'returnData', - type: 'bytes', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'maxBptAmountIn', - type: 'uint256', - }, - { - internalType: 'enum RemoveLiquidityKind', - name: 'kind', - type: 'uint8', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct IRouterCommon.RemoveLiquidityHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'queryRemoveLiquidityHook', - outputs: [ - { - internalType: 'uint256', - name: 'bptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - { - internalType: 'bytes', - name: 'returnData', - type: 'bytes', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'queryRemoveLiquidityProportional', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - ], - name: 'queryRemoveLiquidityRecovery', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - ], - name: 'queryRemoveLiquidityRecoveryHook', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'queryRemoveLiquiditySingleTokenExactIn', - outputs: [ - { - internalType: 'uint256', - name: 'amountOut', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'queryRemoveLiquiditySingleTokenExactOut', - outputs: [ - { - internalType: 'uint256', - name: 'bptAmountIn', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'enum SwapKind', - name: 'kind', - type: 'uint8', - }, - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amountGiven', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'limit', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct IRouter.SwapSingleTokenHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'querySwapHook', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactAmountIn', - type: 'uint256', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'querySwapSingleTokenExactIn', - outputs: [ - { - internalType: 'uint256', - name: 'amountCalculated', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'querySwapSingleTokenExactOut', - outputs: [ - { - internalType: 'uint256', - name: 'amountCalculated', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256', - name: 'maxBptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'removeLiquidityCustom', - outputs: [ - { - internalType: 'uint256', - name: 'bptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - { - internalType: 'bytes', - name: 'returnData', - type: 'bytes', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'maxBptAmountIn', - type: 'uint256', - }, - { - internalType: 'enum RemoveLiquidityKind', - name: 'kind', - type: 'uint8', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct IRouterCommon.RemoveLiquidityHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'removeLiquidityHook', - outputs: [ - { - internalType: 'uint256', - name: 'bptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - { - internalType: 'bytes', - name: 'returnData', - type: 'bytes', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'removeLiquidityProportional', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - ], - name: 'removeLiquidityRecovery', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - ], - name: 'removeLiquidityRecoveryHook', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOut', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'minAmountOut', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'removeLiquiditySingleTokenExactIn', - outputs: [ - { - internalType: 'uint256', - name: 'amountOut', - type: 'uint256', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'uint256', - name: 'maxBptAmountIn', - type: 'uint256', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'removeLiquiditySingleTokenExactOut', - outputs: [ - { - internalType: 'uint256', - name: 'bptAmountIn', - type: 'uint256', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'minAmountOut', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'swapSingleTokenExactIn', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactAmountOut', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'maxAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'swapSingleTokenExactOut', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'payable', - type: 'function', - }, - { - inputs: [ - { - components: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'enum SwapKind', - name: 'kind', - type: 'uint8', - }, - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amountGiven', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'limit', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'deadline', - type: 'uint256', - }, - { - internalType: 'bool', - name: 'wethIsEth', - type: 'bool', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct IRouter.SwapSingleTokenHookParams', - name: 'params', - type: 'tuple', - }, - ], - name: 'swapSingleTokenHook', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [], - name: 'version', - outputs: [ - { - internalType: 'string', - name: '', - type: 'string', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - stateMutability: 'payable', - type: 'receive', - }, -] as const; diff --git a/src/dex/balancer-v3/abi/vaultExtension.V3.ts b/src/dex/balancer-v3/abi/vaultExtension.V3.ts deleted file mode 100644 index 66a847d48..000000000 --- a/src/dex/balancer-v3/abi/vaultExtension.V3.ts +++ /dev/null @@ -1,2834 +0,0 @@ -export const vaultExtensionAbi_V3 = [ - { - inputs: [ - { - internalType: 'contract IVault', - name: 'mainVault', - type: 'address', - }, - { - internalType: 'contract IVaultAdmin', - name: 'vaultAdmin', - type: 'address', - }, - ], - stateMutability: 'nonpayable', - type: 'constructor', - }, - { - inputs: [ - { - internalType: 'address', - name: 'target', - type: 'address', - }, - ], - name: 'AddressEmptyCode', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'account', - type: 'address', - }, - ], - name: 'AddressInsufficientBalance', - type: 'error', - }, - { - inputs: [], - name: 'AfterAddLiquidityHookFailed', - type: 'error', - }, - { - inputs: [], - name: 'AfterInitializeHookFailed', - type: 'error', - }, - { - inputs: [], - name: 'AfterRemoveLiquidityHookFailed', - type: 'error', - }, - { - inputs: [], - name: 'AfterSwapHookFailed', - type: 'error', - }, - { - inputs: [], - name: 'AmountGivenZero', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'maxAmountIn', - type: 'uint256', - }, - ], - name: 'AmountInAboveMax', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amountOut', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'minAmountOut', - type: 'uint256', - }, - ], - name: 'AmountOutBelowMin', - type: 'error', - }, - { - inputs: [], - name: 'BalanceNotSettled', - type: 'error', - }, - { - inputs: [], - name: 'BalanceOverflow', - type: 'error', - }, - { - inputs: [], - name: 'BeforeAddLiquidityHookFailed', - type: 'error', - }, - { - inputs: [], - name: 'BeforeInitializeHookFailed', - type: 'error', - }, - { - inputs: [], - name: 'BeforeRemoveLiquidityHookFailed', - type: 'error', - }, - { - inputs: [], - name: 'BeforeSwapHookFailed', - type: 'error', - }, - { - inputs: [ - { - internalType: 'uint256', - name: 'amountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'maxAmountIn', - type: 'uint256', - }, - ], - name: 'BptAmountInAboveMax', - type: 'error', - }, - { - inputs: [ - { - internalType: 'uint256', - name: 'amountOut', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'minAmountOut', - type: 'uint256', - }, - ], - name: 'BptAmountOutBelowMin', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - ], - name: 'BufferAlreadyInitialized', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - ], - name: 'BufferNotInitialized', - type: 'error', - }, - { - inputs: [], - name: 'BufferSharesInvalidOwner', - type: 'error', - }, - { - inputs: [], - name: 'BufferSharesInvalidReceiver', - type: 'error', - }, - { - inputs: [ - { - internalType: 'uint256', - name: 'totalSupply', - type: 'uint256', - }, - ], - name: 'BufferTotalSupplyTooLow', - type: 'error', - }, - { - inputs: [], - name: 'CannotReceiveEth', - type: 'error', - }, - { - inputs: [], - name: 'CannotSwapSameToken', - type: 'error', - }, - { - inputs: [], - name: 'CodecOverflow', - type: 'error', - }, - { - inputs: [], - name: 'DoesNotSupportAddLiquidityCustom', - type: 'error', - }, - { - inputs: [], - name: 'DoesNotSupportDonation', - type: 'error', - }, - { - inputs: [], - name: 'DoesNotSupportRemoveLiquidityCustom', - type: 'error', - }, - { - inputs: [], - name: 'DoesNotSupportUnbalancedLiquidity', - type: 'error', - }, - { - inputs: [], - name: 'DynamicSwapFeeHookFailed', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'spender', - type: 'address', - }, - { - internalType: 'uint256', - name: 'allowance', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'needed', - type: 'uint256', - }, - ], - name: 'ERC20InsufficientAllowance', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - { - internalType: 'uint256', - name: 'balance', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'needed', - type: 'uint256', - }, - ], - name: 'ERC20InsufficientBalance', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'approver', - type: 'address', - }, - ], - name: 'ERC20InvalidApprover', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'receiver', - type: 'address', - }, - ], - name: 'ERC20InvalidReceiver', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - ], - name: 'ERC20InvalidSender', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'spender', - type: 'address', - }, - ], - name: 'ERC20InvalidSpender', - type: 'error', - }, - { - inputs: [], - name: 'ErrorSelectorNotFound', - type: 'error', - }, - { - inputs: [], - name: 'FailedInnerCall', - type: 'error', - }, - { - inputs: [], - name: 'FeePrecisionTooHigh', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amountIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'maxAmountIn', - type: 'uint256', - }, - ], - name: 'HookAdjustedAmountInAboveMax', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amountOut', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'minAmountOut', - type: 'uint256', - }, - ], - name: 'HookAdjustedAmountOutBelowMin', - type: 'error', - }, - { - inputs: [ - { - internalType: 'uint256', - name: 'amount', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'limit', - type: 'uint256', - }, - ], - name: 'HookAdjustedSwapLimit', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'poolHooksContract', - type: 'address', - }, - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'address', - name: 'poolFactory', - type: 'address', - }, - ], - name: 'HookRegistrationFailed', - type: 'error', - }, - { - inputs: [], - name: 'InputLengthMismatch', - type: 'error', - }, - { - inputs: [], - name: 'InvalidAddLiquidityKind', - type: 'error', - }, - { - inputs: [], - name: 'InvalidRemoveLiquidityKind', - type: 'error', - }, - { - inputs: [], - name: 'InvalidToken', - type: 'error', - }, - { - inputs: [], - name: 'InvalidTokenConfiguration', - type: 'error', - }, - { - inputs: [], - name: 'InvalidTokenDecimals', - type: 'error', - }, - { - inputs: [], - name: 'InvalidTokenType', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - ], - name: 'InvalidUnderlyingToken', - type: 'error', - }, - { - inputs: [ - { - internalType: 'uint256', - name: 'issuedShares', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'minIssuedShares', - type: 'uint256', - }, - ], - name: 'IssuedSharesBelowMin', - type: 'error', - }, - { - inputs: [], - name: 'MaxTokens', - type: 'error', - }, - { - inputs: [], - name: 'MinTokens', - type: 'error', - }, - { - inputs: [], - name: 'NotEnoughBufferShares', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - internalType: 'uint256', - name: 'expectedUnderlyingAmount', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'actualUnderlyingAmount', - type: 'uint256', - }, - ], - name: 'NotEnoughUnderlying', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - internalType: 'uint256', - name: 'expectedWrappedAmount', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'actualWrappedAmount', - type: 'uint256', - }, - ], - name: 'NotEnoughWrapped', - type: 'error', - }, - { - inputs: [], - name: 'NotStaticCall', - type: 'error', - }, - { - inputs: [], - name: 'NotVaultDelegateCall', - type: 'error', - }, - { - inputs: [], - name: 'OutOfBounds', - type: 'error', - }, - { - inputs: [], - name: 'PauseBufferPeriodDurationTooLarge', - type: 'error', - }, - { - inputs: [], - name: 'PercentageAboveMax', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'PoolAlreadyInitialized', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'PoolAlreadyRegistered', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'PoolInRecoveryMode', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'PoolNotInRecoveryMode', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'PoolNotInitialized', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'PoolNotPaused', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'PoolNotRegistered', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'PoolPauseWindowExpired', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'PoolPaused', - type: 'error', - }, - { - inputs: [ - { - internalType: 'uint256', - name: 'totalSupply', - type: 'uint256', - }, - ], - name: 'PoolTotalSupplyTooLow', - type: 'error', - }, - { - inputs: [], - name: 'ProtocolFeesExceedTotalCollected', - type: 'error', - }, - { - inputs: [], - name: 'QueriesDisabled', - type: 'error', - }, - { - inputs: [], - name: 'QueriesDisabledPermanently', - type: 'error', - }, - { - inputs: [], - name: 'QuoteResultSpoofed', - type: 'error', - }, - { - inputs: [], - name: 'ReentrancyGuardReentrantCall', - type: 'error', - }, - { - inputs: [ - { - internalType: 'bytes', - name: 'result', - type: 'bytes', - }, - ], - name: 'Result', - type: 'error', - }, - { - inputs: [], - name: 'RouterNotTrusted', - type: 'error', - }, - { - inputs: [ - { - internalType: 'uint256', - name: 'value', - type: 'uint256', - }, - ], - name: 'SafeCastOverflowedUintToInt', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'sender', - type: 'address', - }, - ], - name: 'SenderIsNotVault', - type: 'error', - }, - { - inputs: [], - name: 'SwapFeePercentageTooHigh', - type: 'error', - }, - { - inputs: [], - name: 'SwapFeePercentageTooLow', - type: 'error', - }, - { - inputs: [ - { - internalType: 'uint256', - name: 'amount', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'limit', - type: 'uint256', - }, - ], - name: 'SwapLimit', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'token', - type: 'address', - }, - ], - name: 'TokenAlreadyRegistered', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'token', - type: 'address', - }, - ], - name: 'TokenNotRegistered', - type: 'error', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'address', - name: 'expectedToken', - type: 'address', - }, - { - internalType: 'address', - name: 'actualToken', - type: 'address', - }, - ], - name: 'TokensMismatch', - type: 'error', - }, - { - inputs: [], - name: 'TokensNotSorted', - type: 'error', - }, - { - inputs: [], - name: 'TradeAmountTooSmall', - type: 'error', - }, - { - inputs: [], - name: 'VaultBuffersArePaused', - type: 'error', - }, - { - inputs: [], - name: 'VaultIsNotUnlocked', - type: 'error', - }, - { - inputs: [], - name: 'VaultNotPaused', - type: 'error', - }, - { - inputs: [], - name: 'VaultPauseWindowDurationTooLarge', - type: 'error', - }, - { - inputs: [], - name: 'VaultPauseWindowExpired', - type: 'error', - }, - { - inputs: [], - name: 'VaultPaused', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - ], - name: 'WrapAmountTooSmall', - type: 'error', - }, - { - inputs: [], - name: 'WrongProtocolFeeControllerDeployment', - type: 'error', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - internalType: 'address', - name: 'underlyingToken', - type: 'address', - }, - ], - name: 'WrongUnderlyingToken', - type: 'error', - }, - { - inputs: [], - name: 'WrongVaultAdminDeployment', - type: 'error', - }, - { - inputs: [], - name: 'WrongVaultExtensionDeployment', - type: 'error', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'aggregateSwapFeePercentage', - type: 'uint256', - }, - ], - name: 'AggregateSwapFeePercentageChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'aggregateYieldFeePercentage', - type: 'uint256', - }, - ], - name: 'AggregateYieldFeePercentageChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'owner', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'spender', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'value', - type: 'uint256', - }, - ], - name: 'Approval', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IAuthorizer', - name: 'newAuthorizer', - type: 'address', - }, - ], - name: 'AuthorizerChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'from', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'burnedShares', - type: 'uint256', - }, - ], - name: 'BufferSharesBurned', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'to', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'issuedShares', - type: 'uint256', - }, - ], - name: 'BufferSharesMinted', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'liquidityProvider', - type: 'address', - }, - { - indexed: true, - internalType: 'enum AddLiquidityKind', - name: 'kind', - type: 'uint8', - }, - { - indexed: false, - internalType: 'uint256', - name: 'totalSupply', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256[]', - name: 'amountsAddedRaw', - type: 'uint256[]', - }, - { - indexed: false, - internalType: 'uint256[]', - name: 'swapFeeAmountsRaw', - type: 'uint256[]', - }, - ], - name: 'LiquidityAdded', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountUnderlying', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountWrapped', - type: 'uint256', - }, - { - indexed: false, - internalType: 'bytes32', - name: 'bufferBalances', - type: 'bytes32', - }, - ], - name: 'LiquidityAddedToBuffer', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'liquidityProvider', - type: 'address', - }, - { - indexed: true, - internalType: 'enum RemoveLiquidityKind', - name: 'kind', - type: 'uint8', - }, - { - indexed: false, - internalType: 'uint256', - name: 'totalSupply', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256[]', - name: 'amountsRemovedRaw', - type: 'uint256[]', - }, - { - indexed: false, - internalType: 'uint256[]', - name: 'swapFeeAmountsRaw', - type: 'uint256[]', - }, - ], - name: 'LiquidityRemoved', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountUnderlying', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountWrapped', - type: 'uint256', - }, - { - indexed: false, - internalType: 'bytes32', - name: 'bufferBalances', - type: 'bytes32', - }, - ], - name: 'LiquidityRemovedFromBuffer', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'PoolInitialized', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: false, - internalType: 'bool', - name: 'paused', - type: 'bool', - }, - ], - name: 'PoolPausedStateChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: false, - internalType: 'bool', - name: 'recoveryMode', - type: 'bool', - }, - ], - name: 'PoolRecoveryModeStateChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'factory', - type: 'address', - }, - { - components: [ - { - internalType: 'contract IERC20', - name: 'token', - type: 'address', - }, - { - internalType: 'enum TokenType', - name: 'tokenType', - type: 'uint8', - }, - { - internalType: 'contract IRateProvider', - name: 'rateProvider', - type: 'address', - }, - { - internalType: 'bool', - name: 'paysYieldFees', - type: 'bool', - }, - ], - indexed: false, - internalType: 'struct TokenConfig[]', - name: 'tokenConfig', - type: 'tuple[]', - }, - { - indexed: false, - internalType: 'uint256', - name: 'swapFeePercentage', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint32', - name: 'pauseWindowEndTime', - type: 'uint32', - }, - { - components: [ - { - internalType: 'address', - name: 'pauseManager', - type: 'address', - }, - { - internalType: 'address', - name: 'swapFeeManager', - type: 'address', - }, - { - internalType: 'address', - name: 'poolCreator', - type: 'address', - }, - ], - indexed: false, - internalType: 'struct PoolRoleAccounts', - name: 'roleAccounts', - type: 'tuple', - }, - { - components: [ - { - internalType: 'bool', - name: 'enableHookAdjustedAmounts', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeInitialize', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterInitialize', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallComputeDynamicSwapFee', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeSwap', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterSwap', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeAddLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterAddLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeRemoveLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterRemoveLiquidity', - type: 'bool', - }, - { - internalType: 'address', - name: 'hooksContract', - type: 'address', - }, - ], - indexed: false, - internalType: 'struct HooksConfig', - name: 'hooksConfig', - type: 'tuple', - }, - { - components: [ - { - internalType: 'bool', - name: 'disableUnbalancedLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableAddLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableRemoveLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableDonation', - type: 'bool', - }, - ], - indexed: false, - internalType: 'struct LiquidityManagement', - name: 'liquidityManagement', - type: 'tuple', - }, - ], - name: 'PoolRegistered', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IProtocolFeeController', - name: 'newProtocolFeeController', - type: 'address', - }, - ], - name: 'ProtocolFeeControllerChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: true, - internalType: 'contract IERC20', - name: 'tokenIn', - type: 'address', - }, - { - indexed: true, - internalType: 'contract IERC20', - name: 'tokenOut', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountIn', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amountOut', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'swapFeePercentage', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'swapFeeAmount', - type: 'uint256', - }, - ], - name: 'Swap', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'swapFeePercentage', - type: 'uint256', - }, - ], - name: 'SwapFeePercentageChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'from', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'to', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'value', - type: 'uint256', - }, - ], - name: 'Transfer', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'burnedShares', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'withdrawnUnderlying', - type: 'uint256', - }, - { - indexed: false, - internalType: 'bytes32', - name: 'bufferBalances', - type: 'bytes32', - }, - ], - name: 'Unwrap', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - indexed: false, - internalType: 'string', - name: 'eventKey', - type: 'string', - }, - { - indexed: false, - internalType: 'bytes', - name: 'eventData', - type: 'bytes', - }, - ], - name: 'VaultAuxiliary', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'bool', - name: 'paused', - type: 'bool', - }, - ], - name: 'VaultBuffersPausedStateChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'bool', - name: 'paused', - type: 'bool', - }, - ], - name: 'VaultPausedStateChanged', - type: 'event', - }, - { - anonymous: false, - inputs: [], - name: 'VaultQueriesDisabled', - type: 'event', - }, - { - anonymous: false, - inputs: [], - name: 'VaultQueriesEnabled', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'depositedUnderlying', - type: 'uint256', - }, - { - indexed: false, - internalType: 'uint256', - name: 'mintedShares', - type: 'uint256', - }, - { - indexed: false, - internalType: 'bytes32', - name: 'bufferBalances', - type: 'bytes32', - }, - ], - name: 'Wrap', - type: 'event', - }, - { - stateMutability: 'payable', - type: 'fallback', - }, - { - inputs: [ - { - internalType: 'address', - name: 'token', - type: 'address', - }, - { - internalType: 'address', - name: 'owner', - type: 'address', - }, - { - internalType: 'address', - name: 'spender', - type: 'address', - }, - ], - name: 'allowance', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'owner', - type: 'address', - }, - { - internalType: 'address', - name: 'spender', - type: 'address', - }, - { - internalType: 'uint256', - name: 'amount', - type: 'uint256', - }, - ], - name: 'approve', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'token', - type: 'address', - }, - { - internalType: 'address', - name: 'account', - type: 'address', - }, - ], - name: 'balanceOf', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - components: [ - { - internalType: 'enum SwapKind', - name: 'kind', - type: 'uint8', - }, - { - internalType: 'uint256', - name: 'amountGivenScaled18', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'balancesScaled18', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'indexIn', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'indexOut', - type: 'uint256', - }, - { - internalType: 'address', - name: 'router', - type: 'address', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - internalType: 'struct PoolSwapParams', - name: 'swapParams', - type: 'tuple', - }, - ], - name: 'computeDynamicSwapFeePercentage', - outputs: [ - { - internalType: 'uint256', - name: 'dynamicSwapFeePercentage', - type: 'uint256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'string', - name: 'eventKey', - type: 'string', - }, - { - internalType: 'bytes', - name: 'eventData', - type: 'bytes', - }, - ], - name: 'emitAuxiliaryEvent', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getAddLiquidityCalledFlag', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'token', - type: 'address', - }, - ], - name: 'getAggregateSwapFeeAmount', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'contract IERC20', - name: 'token', - type: 'address', - }, - ], - name: 'getAggregateYieldFeeAmount', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getBptRate', - outputs: [ - { - internalType: 'uint256', - name: 'rate', - type: 'uint256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getCurrentLiveBalances', - outputs: [ - { - internalType: 'uint256[]', - name: 'balancesLiveScaled18', - type: 'uint256[]', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - ], - name: 'getERC4626BufferAsset', - outputs: [ - { - internalType: 'address', - name: 'asset', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getHooksConfig', - outputs: [ - { - components: [ - { - internalType: 'bool', - name: 'enableHookAdjustedAmounts', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeInitialize', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterInitialize', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallComputeDynamicSwapFee', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeSwap', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterSwap', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeAddLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterAddLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallBeforeRemoveLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'shouldCallAfterRemoveLiquidity', - type: 'bool', - }, - { - internalType: 'address', - name: 'hooksContract', - type: 'address', - }, - ], - internalType: 'struct HooksConfig', - name: '', - type: 'tuple', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'getNonzeroDeltaCount', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getPoolConfig', - outputs: [ - { - components: [ - { - components: [ - { - internalType: 'bool', - name: 'disableUnbalancedLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableAddLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableRemoveLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableDonation', - type: 'bool', - }, - ], - internalType: 'struct LiquidityManagement', - name: 'liquidityManagement', - type: 'tuple', - }, - { - internalType: 'uint256', - name: 'staticSwapFeePercentage', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'aggregateSwapFeePercentage', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'aggregateYieldFeePercentage', - type: 'uint256', - }, - { - internalType: 'uint40', - name: 'tokenDecimalDiffs', - type: 'uint40', - }, - { - internalType: 'uint32', - name: 'pauseWindowEndTime', - type: 'uint32', - }, - { - internalType: 'bool', - name: 'isPoolRegistered', - type: 'bool', - }, - { - internalType: 'bool', - name: 'isPoolInitialized', - type: 'bool', - }, - { - internalType: 'bool', - name: 'isPoolPaused', - type: 'bool', - }, - { - internalType: 'bool', - name: 'isPoolInRecoveryMode', - type: 'bool', - }, - ], - internalType: 'struct PoolConfig', - name: '', - type: 'tuple', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getPoolData', - outputs: [ - { - components: [ - { - internalType: 'PoolConfigBits', - name: 'poolConfigBits', - type: 'bytes32', - }, - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - { - components: [ - { - internalType: 'enum TokenType', - name: 'tokenType', - type: 'uint8', - }, - { - internalType: 'contract IRateProvider', - name: 'rateProvider', - type: 'address', - }, - { - internalType: 'bool', - name: 'paysYieldFees', - type: 'bool', - }, - ], - internalType: 'struct TokenInfo[]', - name: 'tokenInfo', - type: 'tuple[]', - }, - { - internalType: 'uint256[]', - name: 'balancesRaw', - type: 'uint256[]', - }, - { - internalType: 'uint256[]', - name: 'balancesLiveScaled18', - type: 'uint256[]', - }, - { - internalType: 'uint256[]', - name: 'tokenRates', - type: 'uint256[]', - }, - { - internalType: 'uint256[]', - name: 'decimalScalingFactors', - type: 'uint256[]', - }, - ], - internalType: 'struct PoolData', - name: '', - type: 'tuple', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getPoolPausedState', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - { - internalType: 'uint32', - name: '', - type: 'uint32', - }, - { - internalType: 'uint32', - name: '', - type: 'uint32', - }, - { - internalType: 'address', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getPoolRoleAccounts', - outputs: [ - { - components: [ - { - internalType: 'address', - name: 'pauseManager', - type: 'address', - }, - { - internalType: 'address', - name: 'swapFeeManager', - type: 'address', - }, - { - internalType: 'address', - name: 'poolCreator', - type: 'address', - }, - ], - internalType: 'struct PoolRoleAccounts', - name: '', - type: 'tuple', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getPoolTokenInfo', - outputs: [ - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - { - components: [ - { - internalType: 'enum TokenType', - name: 'tokenType', - type: 'uint8', - }, - { - internalType: 'contract IRateProvider', - name: 'rateProvider', - type: 'address', - }, - { - internalType: 'bool', - name: 'paysYieldFees', - type: 'bool', - }, - ], - internalType: 'struct TokenInfo[]', - name: 'tokenInfo', - type: 'tuple[]', - }, - { - internalType: 'uint256[]', - name: 'balancesRaw', - type: 'uint256[]', - }, - { - internalType: 'uint256[]', - name: 'lastBalancesLiveScaled18', - type: 'uint256[]', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getPoolTokenRates', - outputs: [ - { - internalType: 'uint256[]', - name: 'decimalScalingFactors', - type: 'uint256[]', - }, - { - internalType: 'uint256[]', - name: 'tokenRates', - type: 'uint256[]', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getPoolTokens', - outputs: [ - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'getProtocolFeeController', - outputs: [ - { - internalType: 'contract IProtocolFeeController', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'token', - type: 'address', - }, - ], - name: 'getReservesOf', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'getStaticSwapFeePercentage', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'contract IERC20', - name: 'token', - type: 'address', - }, - ], - name: 'getTokenDelta', - outputs: [ - { - internalType: 'int256', - name: '', - type: 'int256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'getVaultAdmin', - outputs: [ - { - internalType: 'address', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'address', - name: 'to', - type: 'address', - }, - { - internalType: 'contract IERC20[]', - name: 'tokens', - type: 'address[]', - }, - { - internalType: 'uint256[]', - name: 'exactAmountsIn', - type: 'uint256[]', - }, - { - internalType: 'uint256', - name: 'minBptAmountOut', - type: 'uint256', - }, - { - internalType: 'bytes', - name: 'userData', - type: 'bytes', - }, - ], - name: 'initialize', - outputs: [ - { - internalType: 'uint256', - name: 'bptAmountOut', - type: 'uint256', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'contract IERC4626', - name: 'wrappedToken', - type: 'address', - }, - ], - name: 'isERC4626BufferInitialized', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'isPoolInRecoveryMode', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'isPoolInitialized', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'isPoolPaused', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - ], - name: 'isPoolRegistered', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'isQueryDisabled', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'isQueryDisabledPermanently', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'isUnlocked', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes', - name: 'data', - type: 'bytes', - }, - ], - name: 'quote', - outputs: [ - { - internalType: 'bytes', - name: 'result', - type: 'bytes', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes', - name: 'data', - type: 'bytes', - }, - ], - name: 'quoteAndRevert', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [], - name: 'reentrancyGuardEntered', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - components: [ - { - internalType: 'contract IERC20', - name: 'token', - type: 'address', - }, - { - internalType: 'enum TokenType', - name: 'tokenType', - type: 'uint8', - }, - { - internalType: 'contract IRateProvider', - name: 'rateProvider', - type: 'address', - }, - { - internalType: 'bool', - name: 'paysYieldFees', - type: 'bool', - }, - ], - internalType: 'struct TokenConfig[]', - name: 'tokenConfig', - type: 'tuple[]', - }, - { - internalType: 'uint256', - name: 'swapFeePercentage', - type: 'uint256', - }, - { - internalType: 'uint32', - name: 'pauseWindowEndTime', - type: 'uint32', - }, - { - internalType: 'bool', - name: 'protocolFeeExempt', - type: 'bool', - }, - { - components: [ - { - internalType: 'address', - name: 'pauseManager', - type: 'address', - }, - { - internalType: 'address', - name: 'swapFeeManager', - type: 'address', - }, - { - internalType: 'address', - name: 'poolCreator', - type: 'address', - }, - ], - internalType: 'struct PoolRoleAccounts', - name: 'roleAccounts', - type: 'tuple', - }, - { - internalType: 'address', - name: 'poolHooksContract', - type: 'address', - }, - { - components: [ - { - internalType: 'bool', - name: 'disableUnbalancedLiquidity', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableAddLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableRemoveLiquidityCustom', - type: 'bool', - }, - { - internalType: 'bool', - name: 'enableDonation', - type: 'bool', - }, - ], - internalType: 'struct LiquidityManagement', - name: 'liquidityManagement', - type: 'tuple', - }, - ], - name: 'registerPool', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'pool', - type: 'address', - }, - { - internalType: 'address', - name: 'from', - type: 'address', - }, - { - internalType: 'uint256', - name: 'exactBptAmountIn', - type: 'uint256', - }, - { - internalType: 'uint256[]', - name: 'minAmountsOut', - type: 'uint256[]', - }, - ], - name: 'removeLiquidityRecovery', - outputs: [ - { - internalType: 'uint256[]', - name: 'amountsOutRaw', - type: 'uint256[]', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'token', - type: 'address', - }, - ], - name: 'totalSupply', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'vault', - outputs: [ - { - internalType: 'contract IVault', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - stateMutability: 'payable', - type: 'receive', - }, -] as const; diff --git a/src/dex/balancer-v3/balancer-v3-integration.test.ts b/src/dex/balancer-v3/balancer-v3-integration.test.ts index 797719686..3e0b4b390 100644 --- a/src/dex/balancer-v3/balancer-v3-integration.test.ts +++ b/src/dex/balancer-v3/balancer-v3-integration.test.ts @@ -14,10 +14,10 @@ import { } from '../../../tests/utils'; import { Tokens } from '../../../tests/constants-e2e'; import { BalancerV3Config } from './config'; -import { balancerRouterAbi } from './abi/balancerRouter'; import { BalancerV3Data, Step } from './types'; import { Address, ExchangePrices, PoolPrices } from '../../types'; -import { balancerBatchRouterAbi } from './abi/balancerBatchRouter'; +import balancerBatchRouterAbi from '../../abi/balancer-v3/batch-router.json'; +import balancerRouterAbi from '../../abi/balancer-v3/router.json'; function getQuerySwapSingleTokenCalldata( routerAddress: Address, diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 54c3fe5c1..e44f390f8 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -13,7 +13,7 @@ import { TokenInfo, } from './types'; import { getPoolsApi } from './getPoolsApi'; -import { vaultExtensionAbi_V3 } from './abi/vaultExtension.V3'; +import vaultExtensionAbi_V3 from '../../abi/balancer-v3/vault-extension.json'; import { decodeThrowError, getOnChainState } from './getOnChainState'; import { BalancerV3Config } from './config'; import { SwapKind, Vault } from '@balancer-labs/balancer-maths'; diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 735f53f97..f70af2cb6 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -21,10 +21,10 @@ import { BalancerV3EventPool } from './balancer-v3-pool'; import { NumberAsString } from '@paraswap/core'; import { SwapKind } from '@balancer-labs/balancer-maths'; import { Interface } from '@ethersproject/abi'; -import { balancerRouterAbi } from './abi/balancerRouter'; import { extractReturnAmountPosition } from '../../executor/utils'; import { getTopPoolsApi } from './getTopPoolsApi'; -import { balancerBatchRouterAbi } from './abi/balancerBatchRouter'; +import balancerRouterAbi from '../../abi/balancer-v3/router.json'; +import balancerBatchRouterAbi from '../../abi/balancer-v3/batch-router.json'; import { getGasCost } from './getGasCost'; const MAX_UINT256 = From 8dfe4263d7c3c63913a0d9652a4e61ea2f0e40dc Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Mon, 2 Dec 2024 15:59:42 +0200 Subject: [PATCH 26/66] fix: set correct Augustus addresses on Sepolia --- src/config.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/config.ts b/src/config.ts index a8be00c2c..a7a4620d9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -425,9 +425,9 @@ const baseConfigs: { [network: number]: BaseConfig } = { nativeTokenSymbol: 'ETH', wrappedNativeTokenAddress: '0x7b79995e5f793a07bc00c21412e50ecae098e7f9', hasEIP1559: true, - augustusAddress: '0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57', - augustusRFQAddress: '0xe92b586627ccA7a83dC919cc7127196d70f55a06', - tokenTransferProxyAddress: '0x216b4b4ba9f3e719726886d34a177484278bfcae', + augustusAddress: '0x0000000000000000000000000000000000000000', + augustusRFQAddress: '0xF6322953d6bFcEACf77D90BC9a01B055249D44fE', + tokenTransferProxyAddress: '0x0000000000000000000000000000000000000000', multicallV2Address: '0xcA11bde05977b3631167028862bE2a173976CA11', privateHttpProvider: process.env.HTTP_PROVIDER_11155111, augustusV6Address: '0x6a000f20005980200259b80c5102003040001068', @@ -435,12 +435,12 @@ const baseConfigs: { [network: number]: BaseConfig } = { rfqConfigs: {}, hashFlowDisabledMMs: [], executorsAddresses: { - Executor01: '0xa600910B670804230E00A100000D28000AE005C0', - Executor02: '0x3800091020a00290f20606b000000000E38c33Ef', - Executor03: '0x20004f017a0bC0050bc004d9C500a7A089800000', + Executor01: '0x000010036c0190e009a000d0fc3541100a07380a', + Executor02: '0x00c600b30fb0400701010f4b080409018b9006e0', + Executor03: '0xe009f00e200a090090fc70e02d70b232000c0802', }, uniswapV2ExchangeRouterAddress: - '0xF9234CB08edb93c0d4a4d4c70cC3FfD070e78e07', + '0x0000000000000000000000000000000000000000', rpcPollingMaxAllowedStateDelayInBlocks: 0, rpcPollingBlocksBackToTriggerUpdate: 0, uniswapV3EventLoggingSampleRate: 0, From 32b3b6d723083ce82116a2572153bcc027a716ea Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Tue, 3 Dec 2024 15:05:03 +0000 Subject: [PATCH 27/66] feat: Updated gasCosts with more accurate results. --- src/dex/balancer-v3/getGasCost.ts | 38 ++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/dex/balancer-v3/getGasCost.ts b/src/dex/balancer-v3/getGasCost.ts index 865be8272..1dc97b786 100644 --- a/src/dex/balancer-v3/getGasCost.ts +++ b/src/dex/balancer-v3/getGasCost.ts @@ -2,20 +2,36 @@ import { STABLE_GAS_COST } from './stablePool'; import { Step } from './types'; import { WEIGHTED_GAS_COST } from './weightedPool'; -// This is a worst case gas cost for full buffer>swap>buffer steps // https://sepolia.etherscan.io/tx/0x8c2c5ec7fc2855ed2ffab3467ee434f4e374e0ecf791e8d2b93c8d74e3f5b1fe -const BOOSTED_GAS_COST = 283058; +// 0x7ec61d6dcf0ea412327c30f013e60578c0ff4d83c334a95fb3a68739860e6f59 +// 0xb45331fe60091bdf4ba4c201b7fdfefc1ca8087fa1b6bc28877ef84d167809f4 +const FULL_BOOSTED_SWAP_GAS_COST = 283070; +// 0xb47bcae19ba4693d18f2148073d0d469ff59223e90d6f75eb25e06b0063f1556 +// 0x4730b0c1dce820f14747698446865364b98d96d3ed926e8e74bbead6482b8f8b +const PARTIAL_BOOSTED_SWAP_GAS_COST = 259815; +// 0xef9037f992645a9ecf26ddbdf65690a71acbffce2cc68445c869bb9707cb706a +// 0x77aa06350df079a077147f1051b10e0612542eb3aff3ae1b3d4004341cb64690 +const BUFFER_WRAP_UNWRAP_GAS_COST = 155921; export function getGasCost(steps: Step[]): number { - if (steps.length > 1) { - // TODO - Improve accuracy for different steps/length, need to setup profiling - // steps.forEach(s => console.log(s.isBuffer, s.poolState.poolType)); - return BOOSTED_GAS_COST; + if (steps.length === 2) { + // Partial boosted/buffer swap: + // token[wrap]wrappedToken[swap]wrappedToken or + // wrappedToken[swap]wrappedToken[unwrap]token + return PARTIAL_BOOSTED_SWAP_GAS_COST; + } else if (steps.length === 3) { + // Full boosted/buffer swap: token[wrap]wrappedToken[swap]wrappedToken[unwrap]token + return FULL_BOOSTED_SWAP_GAS_COST; } else { - // TODO Add cost for buffer pool type although this is a very unlikely single step - if (steps[0].poolState.poolType === 'STABLE') return STABLE_GAS_COST; - - return WEIGHTED_GAS_COST; + switch (steps[0].poolState.poolType) { + case 'WEIGHTED': + return WEIGHTED_GAS_COST; + case 'STABLE': + return STABLE_GAS_COST; + case 'BUFFER': + return BUFFER_WRAP_UNWRAP_GAS_COST; + default: + return WEIGHTED_GAS_COST; + } } - return 1; } From b8ffe041396d0ed0975114cbb5077790054c1800 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Tue, 3 Dec 2024 15:28:04 +0000 Subject: [PATCH 28/66] fix: Handle partially boosted pool tokenInfo. --- src/dex/balancer-v3/balancer-v3-pool.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index e44f390f8..45ce7603c 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -512,7 +512,8 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { // Check in underlying tokens if available if (poolState.tokensUnderlying) { tokenIndex = poolState.tokensUnderlying.findIndex( - address => address!.toLowerCase() === tokenAddress.toLowerCase(), + address => + address && address.toLowerCase() === tokenAddress.toLowerCase(), ); if (tokenIndex !== -1) { return { From 2ec2b72126cad9108e95e7913b8ada693c96444a Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Tue, 3 Dec 2024 15:50:50 +0000 Subject: [PATCH 29/66] feat: Support direct buffer wrap/unwrap path. --- src/dex/balancer-v3/balancer-v3-pool.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 45ce7603c..762a225de 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -555,6 +555,11 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { this.getUnwrapStep(tokenOut), ]; } else if (tokenIn.isBoosted) { + if (tokenIn.mainToken === tokenOut.mainToken) { + // wrap, token > erc4626 + // tokenIn is boosted, e.g. isn't pool token and must be wrapped + return [this.getWrapStep(tokenIn)]; + } return [ // Wrap tokenIn underlying to main token this.getWrapStep(tokenIn), @@ -562,6 +567,11 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { this.getSwapStep(pool, tokenIn, tokenOut), ]; } else if (tokenOut.isBoosted) { + if (tokenIn.mainToken === tokenOut.mainToken) { + // unwrap, stata > token + // token out is boosted, e.g. isn't pool token + return [this.getUnwrapStep(tokenOut)]; + } return [ // Swap main > main this.getSwapStep(pool, tokenIn, tokenOut), From 932cc1a3576ec620f44773f37fe0ca7f6bc6a390 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Wed, 4 Dec 2024 10:26:12 +0000 Subject: [PATCH 30/66] test: Add missing event tests. --- src/dex/balancer-v3/balancer-v3-events.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/dex/balancer-v3/balancer-v3-events.test.ts b/src/dex/balancer-v3/balancer-v3-events.test.ts index 8c291c309..f6ccdbab5 100644 --- a/src/dex/balancer-v3/balancer-v3-events.test.ts +++ b/src/dex/balancer-v3/balancer-v3-events.test.ts @@ -162,6 +162,22 @@ describe('BalancerV3 EventPool', function () { '0xD63dB0B88dca565633fB8d70a70b9b8093d34A7E', ], }, + // https://sepolia.etherscan.io/tx/0x71f9879485f4e4cf97aa42381988ffe277f05a872d6b507cfa007cec1239a3f8#eventlog + SwapFeePercentageChanged: { + blockNumbers: [7206571], + poolAddress: ['0xe69b70a86A4e1fD33dA95693A1aE12Be1c26C8ea'], + }, + // https://sepolia.etherscan.io/tx/0xaf232ca2df59ba5fad38d74e9b54ec2ae1ad2e6abca8348f107cf3fd94c787c7#eventlog + // Should remove pool from state as its paused and no longer supports swaps + PoolPausedStateChanged: { + blockNumbers: [7206586], + poolAddress: ['0xe69b70a86A4e1fD33dA95693A1aE12Be1c26C8ea'], + }, + // https://sepolia.etherscan.io/tx/0xa23dc10bd0fbed7ffffe867766d9b0d7670ca4a0bc352669f547bc7775644349#eventlog + AggregateSwapFeePercentageChanged: { + blockNumbers: [7206701], + poolAddress: ['0xe69b70a86A4e1fD33dA95693A1aE12Be1c26C8ea'], + }, }, }; From 0da3f84f424f6d271a7b7cf551a345130cad6f01 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Wed, 4 Dec 2024 12:12:59 +0000 Subject: [PATCH 31/66] fix: Use correct step order for ExactOut/Buy. Re-enable BUY integration test. --- src/dex/balancer-v3/balancer-v3-integration.test.ts | 2 +- src/dex/balancer-v3/balancer-v3-pool.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-integration.test.ts b/src/dex/balancer-v3/balancer-v3-integration.test.ts index 3e0b4b390..1abf52c24 100644 --- a/src/dex/balancer-v3/balancer-v3-integration.test.ts +++ b/src/dex/balancer-v3/balancer-v3-integration.test.ts @@ -504,7 +504,7 @@ describe('BalancerV3', function () { }); // TODO 1 WEI rounding issue in maths - investigating - it.skip('getPoolIdentifiers and getPricesVolume BUY', async function () { + it('getPoolIdentifiers and getPricesVolume BUY', async function () { await testPricingOnNetwork( balancerV3, network, diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 762a225de..8bc3dff5b 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -385,10 +385,16 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { timestamp: number, ): bigint { if (amountRaw === 0n) return 0n; + + // A GivenOut needs to use steps in reverse during calculation + const indices = + swapKind === SwapKind.GivenIn + ? steps.keys() + : Array.from(steps.keys()).reverse(); + let amount = amountRaw; let outputAmountRaw = 0n; - // Simulates the result of a multi-step swap path - for (let i = 0; i < steps.length; i++) { + for (const i of indices) { const step = steps[i]; // If its a Stable Pool with an updating Amp factor calculate current Amp value if ( From d7520657199476f2db3ab9b46c0aebbaab65f21f Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 4 Dec 2024 14:47:31 +0200 Subject: [PATCH 32/66] feat: add permit2 approval for generic-swap encoding --- src/abi/permit2.json | 581 ++++++++++++++++++++++ src/bigint-constants.ts | 1 + src/constants.ts | 3 + src/dex/augustus-approvals.ts | 71 ++- src/executor/Executor01BytecodeBuilder.ts | 2 + src/executor/Executor02BytecodeBuilder.ts | 2 + src/executor/Executor03BytecodeBuilder.ts | 2 + src/executor/ExecutorBytecodeBuilder.ts | 65 ++- src/generic-swap-transaction-builder.ts | 8 +- src/types.ts | 1 + 10 files changed, 713 insertions(+), 23 deletions(-) create mode 100644 src/abi/permit2.json diff --git a/src/abi/permit2.json b/src/abi/permit2.json new file mode 100644 index 000000000..22201c714 --- /dev/null +++ b/src/abi/permit2.json @@ -0,0 +1,581 @@ +[ + { + "inputs": [ + { "internalType": "uint256", "name": "deadline", "type": "uint256" } + ], + "name": "AllowanceExpired", + "type": "error" + }, + { "inputs": [], "name": "ExcessiveInvalidation", "type": "error" }, + { + "inputs": [ + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "maxAmount", "type": "uint256" } + ], + "name": "InvalidAmount", + "type": "error" + }, + { "inputs": [], "name": "InvalidContractSignature", "type": "error" }, + { "inputs": [], "name": "InvalidNonce", "type": "error" }, + { "inputs": [], "name": "InvalidSignature", "type": "error" }, + { "inputs": [], "name": "InvalidSignatureLength", "type": "error" }, + { "inputs": [], "name": "InvalidSigner", "type": "error" }, + { "inputs": [], "name": "LengthMismatch", "type": "error" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "signatureDeadline", + "type": "uint256" + } + ], + "name": "SignatureExpired", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "Lockdown", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "newNonce", + "type": "uint48" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "oldNonce", + "type": "uint48" + } + ], + "name": "NonceInvalidation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "name": "Permit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "word", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "mask", + "type": "uint256" + } + ], + "name": "UnorderedNonceInvalidation", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "allowance", + "outputs": [ + { "internalType": "uint160", "name": "amount", "type": "uint160" }, + { "internalType": "uint48", "name": "expiration", "type": "uint48" }, + { "internalType": "uint48", "name": "nonce", "type": "uint48" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "token", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint160", "name": "amount", "type": "uint160" }, + { "internalType": "uint48", "name": "expiration", "type": "uint48" } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "token", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint48", "name": "newNonce", "type": "uint48" } + ], + "name": "invalidateNonces", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "wordPos", "type": "uint256" }, + { "internalType": "uint256", "name": "mask", "type": "uint256" } + ], + "name": "invalidateUnorderedNonces", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "token", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" } + ], + "internalType": "struct IAllowanceTransfer.TokenSpenderPair[]", + "name": "approvals", + "type": "tuple[]" + } + ], + "name": "lockdown", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "name": "nonceBitmap", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { + "components": [ + { + "components": [ + { "internalType": "address", "name": "token", "type": "address" }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { "internalType": "uint48", "name": "nonce", "type": "uint48" } + ], + "internalType": "struct IAllowanceTransfer.PermitDetails[]", + "name": "details", + "type": "tuple[]" + }, + { "internalType": "address", "name": "spender", "type": "address" }, + { + "internalType": "uint256", + "name": "sigDeadline", + "type": "uint256" + } + ], + "internalType": "struct IAllowanceTransfer.PermitBatch", + "name": "permitBatch", + "type": "tuple" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { + "components": [ + { + "components": [ + { "internalType": "address", "name": "token", "type": "address" }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { "internalType": "uint48", "name": "nonce", "type": "uint48" } + ], + "internalType": "struct IAllowanceTransfer.PermitDetails", + "name": "details", + "type": "tuple" + }, + { "internalType": "address", "name": "spender", "type": "address" }, + { + "internalType": "uint256", + "name": "sigDeadline", + "type": "uint256" + } + ], + "internalType": "struct IAllowanceTransfer.PermitSingle", + "name": "permitSingle", + "type": "tuple" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { "internalType": "address", "name": "token", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { "internalType": "uint256", "name": "deadline", "type": "uint256" } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { "internalType": "address", "name": "to", "type": "address" }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails", + "name": "transferDetails", + "type": "tuple" + }, + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "name": "permitTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { "internalType": "address", "name": "token", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions[]", + "name": "permitted", + "type": "tuple[]" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { "internalType": "uint256", "name": "deadline", "type": "uint256" } + ], + "internalType": "struct ISignatureTransfer.PermitBatchTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { "internalType": "address", "name": "to", "type": "address" }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails[]", + "name": "transferDetails", + "type": "tuple[]" + }, + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "name": "permitTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { "internalType": "address", "name": "token", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { "internalType": "uint256", "name": "deadline", "type": "uint256" } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { "internalType": "address", "name": "to", "type": "address" }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails", + "name": "transferDetails", + "type": "tuple" + }, + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "bytes32", "name": "witness", "type": "bytes32" }, + { + "internalType": "string", + "name": "witnessTypeString", + "type": "string" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "name": "permitWitnessTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { "internalType": "address", "name": "token", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions[]", + "name": "permitted", + "type": "tuple[]" + }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { "internalType": "uint256", "name": "deadline", "type": "uint256" } + ], + "internalType": "struct ISignatureTransfer.PermitBatchTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { "internalType": "address", "name": "to", "type": "address" }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails[]", + "name": "transferDetails", + "type": "tuple[]" + }, + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "bytes32", "name": "witness", "type": "bytes32" }, + { + "internalType": "string", + "name": "witnessTypeString", + "type": "string" + }, + { "internalType": "bytes", "name": "signature", "type": "bytes" } + ], + "name": "permitWitnessTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint160", "name": "amount", "type": "uint160" }, + { "internalType": "address", "name": "token", "type": "address" } + ], + "internalType": "struct IAllowanceTransfer.AllowanceTransferDetails[]", + "name": "transferDetails", + "type": "tuple[]" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint160", "name": "amount", "type": "uint160" }, + { "internalType": "address", "name": "token", "type": "address" } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/bigint-constants.ts b/src/bigint-constants.ts index 08e714a74..33754b387 100644 --- a/src/bigint-constants.ts +++ b/src/bigint-constants.ts @@ -11,6 +11,7 @@ export const BI_MAX_INT = BigInt(MAX_INT); export const BI_MAX_UINT8 = 2n ** 8n - 1n; export const BI_MAX_UINT16 = 2n ** 16n - 1n; export const BI_MAX_UINT32 = 2n ** 32n - 1n; +export const BI_MAX_UINT48 = 2n ** 48n - 1n; export const BI_MAX_UINT64 = 2n ** 64n - 1n; export const BI_MAX_UINT96 = 2n ** 96n - 1n; export const BI_MAX_UINT128 = 2n ** 128n - 1n; diff --git a/src/constants.ts b/src/constants.ts index bc3ee69f1..236dd69f2 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -7,6 +7,9 @@ export const PORT_TEST_SERVER = process.env.TEST_PORT; export const ETHER_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'.toLowerCase(); +// address is the same on all chains +export const PERMIT2_ADDRESS = '0x000000000022d473030f116ddee9f6b43ac78ba3'; + export const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'; export const CACHE_PREFIX = 'dl'; diff --git a/src/dex/augustus-approvals.ts b/src/dex/augustus-approvals.ts index 81a6ea3db..fe47d1e01 100644 --- a/src/dex/augustus-approvals.ts +++ b/src/dex/augustus-approvals.ts @@ -1,11 +1,13 @@ -import { Address, ParaSwapVersion } from '@paraswap/core'; -import { CACHE_PREFIX, ETHER_ADDRESS } from '../constants'; -import { ICache, IDexHelper } from '../dex-helper'; +import { Address } from '@paraswap/core'; +import { CACHE_PREFIX, ETHER_ADDRESS, PERMIT2_ADDRESS } from '../constants'; +import { ICache } from '../dex-helper'; import { Interface } from '@ethersproject/abi'; import ERC20ABI from '../abi/erc20.json'; +import Permit2Abi from '../abi/permit2.json'; import { uint256ToBigInt } from '../lib/decoders'; import { MultiCallParams, MultiWrapper } from '../lib/multi-wrapper'; import { ConfigHelper } from '../config'; +import { BigNumber } from 'ethers'; const DEFAULT_APPROVE_CACHE_KEY_VALUE = 'true'; @@ -14,6 +16,7 @@ type ApprovalsMapping = Record; export class AugustusApprovals { erc20Interface: Interface; + permit2Interface: Interface; private cache: ICache; @@ -32,6 +35,7 @@ export class AugustusApprovals { this.augustusAddress = config.data.augustusAddress; this.augustusV6Address = config.data.augustusV6Address; this.erc20Interface = new Interface(ERC20ABI); + this.permit2Interface = new Interface(Permit2Abi); this.cache = cache; this.cacheApprovesKey = `${CACHE_PREFIX}_${this.network}_generic_approves`; @@ -41,19 +45,22 @@ export class AugustusApprovals { spender: Address, token: Address, target: Address, + permit2 = false, ): Promise { - const approvals = await this.hasApprovals(spender, [[token, target]]); + const approvals = await this.hasApprovals(spender, [ + [token, target, permit2], + ]); return approvals[0]; } async hasApprovals( spender: Address, - tokenTargetMapping: [token: Address, target: Address][], + tokenTargetMapping: [token: Address, target: Address, permit2: boolean][], ): Promise { let approvalsMapping: Record = {}; - tokenTargetMapping.forEach(([token, target]) => { - const key = this.createCacheKey(spender, token, target); + tokenTargetMapping.forEach(([token, target, permit2]) => { + const key = this.createCacheKey(spender, token, target, permit2); // set approved 'true' for ETH approvalsMapping[key] = token.toLowerCase() === ETHER_ADDRESS; }); @@ -68,7 +75,9 @@ export class AugustusApprovals { // to keep same order and length as input return tokenTargetMapping - .map(([token, target]) => this.createCacheKey(spender, token, target)) + .map(([token, target, permit2]) => + this.createCacheKey(spender, token, target, permit2), + ) .map(key => approvalsMapping[key]); } @@ -107,17 +116,37 @@ export class AugustusApprovals { spender: Address, token: Address, target: Address, + permit2: boolean, ][], ): Promise { const allowanceCalldata: MultiCallParams[] = - spenderTokenTargetMapping.map(([spender, token, target]) => ({ - target: token, - callData: this.erc20Interface.encodeFunctionData('allowance', [ - spender, - target, - ]), - decodeFunction: uint256ToBigInt, - })); + spenderTokenTargetMapping.map(([spender, token, target, permit2]) => + permit2 + ? { + target: PERMIT2_ADDRESS, + callData: this.permit2Interface.encodeFunctionData('allowance', [ + spender, + token, + target, + ]), + decodeFunction: value => { + const [amount, expiration, nonce] = + this.permit2Interface.decodeFunctionResult( + 'allowance', + value.toString(), + ) as [BigNumber, BigNumber, BigNumber]; + return amount.toBigInt(); + }, + } + : { + target: token, + callData: this.erc20Interface.encodeFunctionData('allowance', [ + spender, + target, + ]), + decodeFunction: uint256ToBigInt, + }, + ); const allowances = await this.multiWrapper.tryAggregate( false, @@ -157,14 +186,18 @@ export class AugustusApprovals { spender: Address, token: Address, target: Address, + permit2 = false, ): string { - return `${spender}_${token}_${target}`; + return `${spender}_${token}_${target}${ + permit2 ? '_permit2' : '' + }`.toLowerCase(); } private splitCacheKey( key: string, - ): [spender: Address, token: Address, target: Address] { - return key.split('_') as [Address, Address, Address]; + ): [spender: Address, token: Address, target: Address, permit2: boolean] { + const [spender, token, target, permit2] = key.split('_'); + return [spender, token, target, permit2 === 'permit2']; } private filterKeys(tokenTargetMapping: ApprovalsMapping, approved = false) { diff --git a/src/executor/Executor01BytecodeBuilder.ts b/src/executor/Executor01BytecodeBuilder.ts index 71cff4d90..9509e768f 100644 --- a/src/executor/Executor01BytecodeBuilder.ts +++ b/src/executor/Executor01BytecodeBuilder.ts @@ -274,6 +274,7 @@ export class Executor01BytecodeBuilder extends ExecutorBytecodeBuilder< curExchangeParam.approveData.target, curExchangeParam.approveData.token, flags.approves[index], + curExchangeParam.permit2Approval, ); swapCallData = hexConcat([approveCallData, swapCallData]); @@ -297,6 +298,7 @@ export class Executor01BytecodeBuilder extends ExecutorBytecodeBuilder< curExchangeParam.approveData.target, curExchangeParam.approveData.token, flags.approves[index], + curExchangeParam.permit2Approval, ); } diff --git a/src/executor/Executor02BytecodeBuilder.ts b/src/executor/Executor02BytecodeBuilder.ts index 6876609f0..9baaf3987 100644 --- a/src/executor/Executor02BytecodeBuilder.ts +++ b/src/executor/Executor02BytecodeBuilder.ts @@ -608,6 +608,7 @@ export class Executor02BytecodeBuilder extends ExecutorBytecodeBuilder< curExchangeParam.approveData.target, curExchangeParam.approveData.token, flags.approves[exchangeParamIndex], + curExchangeParam.permit2Approval, ); swapExchangeCallData = hexConcat([approveCallData, swapExchangeCallData]); @@ -625,6 +626,7 @@ export class Executor02BytecodeBuilder extends ExecutorBytecodeBuilder< curExchangeParam.approveData.target, curExchangeParam.approveData.token, flags.approves[exchangeParamIndex], + curExchangeParam.permit2Approval, ); } diff --git a/src/executor/Executor03BytecodeBuilder.ts b/src/executor/Executor03BytecodeBuilder.ts index 146dc82d0..0b4a534fe 100644 --- a/src/executor/Executor03BytecodeBuilder.ts +++ b/src/executor/Executor03BytecodeBuilder.ts @@ -177,6 +177,7 @@ export class Executor03BytecodeBuilder extends ExecutorBytecodeBuilder< curExchangeParam.approveData.target, curExchangeParam.approveData.token, flags.approves[index], + curExchangeParam.permit2Approval, ); swapCallData = hexConcat([approveCallData, swapCallData]); @@ -196,6 +197,7 @@ export class Executor03BytecodeBuilder extends ExecutorBytecodeBuilder< curExchangeParam.approveData.target, curExchangeParam.approveData.token, flags.approves[index], + curExchangeParam.permit2Approval, ); } diff --git a/src/executor/ExecutorBytecodeBuilder.ts b/src/executor/ExecutorBytecodeBuilder.ts index ce333eabe..e81fc5be1 100644 --- a/src/executor/ExecutorBytecodeBuilder.ts +++ b/src/executor/ExecutorBytecodeBuilder.ts @@ -1,6 +1,7 @@ import { Interface } from '@ethersproject/abi'; import { IDexHelper } from '../dex-helper'; import ERC20ABI from '../abi/erc20.json'; +import Permit2Abi from '../abi/permit2.json'; import { ethers } from 'ethers'; import { Address, @@ -23,14 +24,17 @@ import { DISABLED_MAX_UNIT_APPROVAL_TOKENS, } from './constants'; import { Executors, Flag, SpecialDex } from './types'; -import { MAX_UINT, Network } from '../constants'; +import { MAX_UINT, Network, PERMIT2_ADDRESS } from '../constants'; import { DexExchangeBuildParam, DexExchangeParam } from '../types'; -import { ExecutorDetector } from './ExecutorDetector'; +import { BI_MAX_UINT160, BI_MAX_UINT48 } from '../bigint-constants'; const { utils: { hexlify, hexDataLength, hexConcat, hexZeroPad, solidityPack }, } = ethers; +const MAX_UINT48 = BI_MAX_UINT48.toString(); +const MAX_UINT160 = BI_MAX_UINT160.toString(); + export type SingleSwapCallDataParams = { priceRoute: OptimalRate; exchangeParams: DexExchangeBuildParam[]; @@ -54,9 +58,11 @@ export type DexCallDataParams = { export abstract class ExecutorBytecodeBuilder { type!: Executors; erc20Interface: Interface; + permit2Interface: Interface; constructor(protected dexHelper: IDexHelper) { this.erc20Interface = new Interface(ERC20ABI); + this.permit2Interface = new Interface(Permit2Abi); } protected buildSimpleSwapFlags( @@ -120,8 +126,13 @@ export abstract class ExecutorBytecodeBuilder { spender: string, tokenAddr: Address, flag: Flag, + permit2 = false, amount = MAX_UINT, ): string { + if (permit2) { + return this.buildPermit2CallData(spender, tokenAddr, flag); + } + let approveCalldata = this.erc20Interface.encodeFunctionData('approve', [ spender, amount, @@ -155,6 +166,7 @@ export abstract class ExecutorBytecodeBuilder { spender, tokenAddr, Flag.DONT_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP, + false, '0', ), approvalCalldata, @@ -164,6 +176,55 @@ export abstract class ExecutorBytecodeBuilder { return approvalCalldata; } + protected buildPermit2CallData( + spender: string, + tokenAddr: Address, + flag: Flag, + ): string { + // first, give approval for Permit2 on the token contract + // (with this approval, Permit2 contract can invoke safeTransferFrom on the token) + let approveData = this.erc20Interface.encodeFunctionData('approve', [ + PERMIT2_ADDRESS, + MAX_UINT, + ]); + + let approvalCalldata = this.buildCallData( + tokenAddr, + approveData, + 0, + APPROVE_CALLDATA_DEST_TOKEN_POS, + SpecialDex.DEFAULT, + Flag.DONT_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP, + ); + + // second, give approval for spender on Permit2 contract + // (with this approval, spender can interact with Permit2 on behalf of the executor) + let permit2Data = this.permit2Interface.encodeFunctionData('approve', [ + tokenAddr, + spender, + MAX_UINT160, + MAX_UINT48, + ]); + + let permit2Calldata = this.buildCallData( + PERMIT2_ADDRESS, + permit2Data, + 0, + APPROVE_CALLDATA_DEST_TOKEN_POS, + SpecialDex.DEFAULT, + flag, + ); + + // as approval given only for MAX_UNIT or 0, no need to use insertFromAmount flag + const checkSrcTokenBalance = flag % 3 === 2; + + if (checkSrcTokenBalance) { + permit2Calldata = hexConcat([permit2Calldata, ZEROS_12_BYTES, tokenAddr]); + } + + return hexConcat([approvalCalldata, permit2Calldata]); + } + protected buildWrapEthCallData( wethAddress: string, depositCallData: string, diff --git a/src/generic-swap-transaction-builder.ts b/src/generic-swap-transaction-builder.ts index 4e862934e..951c49bdb 100644 --- a/src/generic-swap-transaction-builder.ts +++ b/src/generic-swap-transaction-builder.ts @@ -673,7 +673,7 @@ export class GenericSwapTransactionBuilder { ): Promise { const spender = bytecodeBuilder.getAddress(); const tokenTargetMapping: { - params: [token: Address, target: Address]; + params: [token: Address, target: Address, permit2: boolean]; exchangeParamIndex: number; }[] = []; @@ -690,7 +690,11 @@ export class GenericSwapTransactionBuilder { if (approveParams) { tokenTargetMapping.push({ - params: [approveParams.token, approveParams?.target], + params: [ + approveParams.token, + approveParams.target, + !!curExchangeParam.permit2Approval, + ], exchangeParamIndex: currentExchangeParamIndex, }); } diff --git a/src/types.ts b/src/types.ts index ac3ffb0ea..8e7bf35ac 100644 --- a/src/types.ts +++ b/src/types.ts @@ -172,6 +172,7 @@ export type DexExchangeParam = { swappedAmountNotPresentInExchangeData?: boolean; preSwapUnwrapCalldata?: string; returnAmountPos: number | undefined; + permit2Approval?: boolean; }; export type DexExchangeBuildParam = DexExchangeParam & { From 446028fb1852d15b47b401c052f41f03c45f0b5d Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 4 Dec 2024 15:09:38 +0200 Subject: [PATCH 33/66] fix: use permit2Approval for balancer-v3 --- src/dex/balancer-v3/balancer-v3.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index f70af2cb6..a3730d06b 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -341,6 +341,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ], ); return { + permit2Approval: true, needWrapNative: this.needWrapNative, dexFuncHasRecipient: false, exchangeData, @@ -378,6 +379,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ); return { + permit2Approval: true, needWrapNative: this.needWrapNative, dexFuncHasRecipient: false, exchangeData, From b3ae600a800435d9da575eac90e6f94f998c8757 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 4 Dec 2024 20:17:35 +0200 Subject: [PATCH 34/66] feat: add balancer-v3 optimizer --- src/dex/balancer-v3/optimizer.ts | 66 ++++++++++++++++++++++++++++++++ src/dex/index.ts | 2 + 2 files changed, 68 insertions(+) create mode 100644 src/dex/balancer-v3/optimizer.ts diff --git a/src/dex/balancer-v3/optimizer.ts b/src/dex/balancer-v3/optimizer.ts new file mode 100644 index 000000000..3925a25a6 --- /dev/null +++ b/src/dex/balancer-v3/optimizer.ts @@ -0,0 +1,66 @@ +import { UnoptimizedRate, OptimalSwap } from '../../types'; +import _ from 'lodash'; + +export function balancerV3Merge(or: UnoptimizedRate): UnoptimizedRate { + const fixRoute = (rawRate: OptimalSwap[]): OptimalSwap[] => { + let lastExchange: false | OptimalSwap = false; + + let optimizedRate = new Array(); + + rawRate.forEach((s: OptimalSwap) => { + if ( + s.swapExchanges.length !== 1 || + s.swapExchanges[0].exchange.toLowerCase() !== 'balancerv3' + ) { + lastExchange = false; + optimizedRate.push(s); + return; + } + + if ( + lastExchange && + lastExchange.swapExchanges[0].exchange.toLowerCase() === + s.swapExchanges[0].exchange.toLowerCase() && + _.last( + lastExchange.swapExchanges[0].data.steps, + )!.swapInput.tokenOut.toLowerCase() === + s.swapExchanges[0].data.steps[0].swapInput.tokenIn.toLowerCase() + ) { + lastExchange.swapExchanges[0].data.steps = + lastExchange.swapExchanges[0].data.steps.concat( + s.swapExchanges[0].data.steps, + ); + + lastExchange.swapExchanges[0].poolAddresses = + lastExchange.swapExchanges[0].poolAddresses!.concat( + s.swapExchanges[0].poolAddresses!, + ); + + lastExchange.swapExchanges[0].data.gasUSD = ( + parseFloat(lastExchange.swapExchanges[0].data.gasUSD) + + parseFloat(s.swapExchanges[0].data.gasUSD) + ).toFixed(6); + + lastExchange.destToken = s.destToken; + lastExchange.destDecimals = s.destDecimals; + + lastExchange.swapExchanges[0].destAmount = + s.swapExchanges[0].destAmount; + + return; + } + + lastExchange = _.cloneDeep(s); + optimizedRate.push(lastExchange); + }); + + return optimizedRate; + }; + + or.bestRoute = or.bestRoute.map(r => ({ + ...r, + swaps: fixRoute(r.swaps), + })); + + return or; +} diff --git a/src/dex/index.ts b/src/dex/index.ts index 011a1928f..24d2f2ae7 100644 --- a/src/dex/index.ts +++ b/src/dex/index.ts @@ -90,6 +90,7 @@ import { AaveGsm } from './aave-gsm/aave-gsm'; import { LitePsm } from './lite-psm/lite-psm'; import { StkGHO } from './stkgho/stkgho'; import { BalancerV3 } from './balancer-v3/balancer-v3'; +import { balancerV3Merge } from './balancer-v3/optimizer'; const LegacyDexes = [ CurveV2, @@ -205,6 +206,7 @@ export class DexAdapterService { public routeOptimizers: IRouteOptimizer[] = [ balancerV1Merge, balancerV2Merge, + balancerV3Merge, uniswapMerge, curveV1Merge, ]; From 4c28b650323f68e1de7330a4e4ba1add48a89a4f Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 4 Dec 2024 20:18:55 +0200 Subject: [PATCH 35/66] chore: remove duplicated `tokenOut` field in balancer-v3 step --- src/dex/balancer-v3/balancer-v3-pool.ts | 3 --- src/dex/balancer-v3/balancer-v3.ts | 4 ++-- src/dex/balancer-v3/types.ts | 1 - 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 8bc3dff5b..8d7daccf4 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -600,7 +600,6 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { // Vault expects pool to be the ERC4626 wrapped token, e.g. aUSDC return { pool: token.mainToken, - tokenOut: token.mainToken, isBuffer: true, swapInput: { tokenIn: token.underlyingToken, @@ -623,7 +622,6 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { // Vault expects pool to be the ERC4626 wrapped token, e.g. aUSDC return { pool: token.mainToken, - tokenOut: token.underlyingToken, isBuffer: true, swapInput: { tokenIn: token.mainToken, @@ -642,7 +640,6 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { // A normal swap between two tokens in a pool return { pool: pool.poolAddress, - tokenOut: tokenOut.mainToken, isBuffer: false, swapInput: { tokenIn: tokenIn.mainToken, diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index a3730d06b..84573d13f 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -365,7 +365,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { tokenIn: srcToken, steps: data.steps.map(step => ({ pool: step.pool, - tokenOut: step.tokenOut, + tokenOut: step.swapInput.tokenOut, isBuffer: step.isBuffer, })), exactAmountIn: srcAmount, @@ -439,7 +439,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { tokenIn: srcToken, steps: data.steps.map(step => ({ pool: step.pool, - tokenOut: step.tokenOut, + tokenOut: step.swapInput.tokenOut, isBuffer: step.isBuffer, })), exactAmountOut: destAmount, diff --git a/src/dex/balancer-v3/types.ts b/src/dex/balancer-v3/types.ts index fc360d1a9..dc803977e 100644 --- a/src/dex/balancer-v3/types.ts +++ b/src/dex/balancer-v3/types.ts @@ -55,7 +55,6 @@ export type ImmutablePoolStateMap = { export type Step = { pool: Address; - tokenOut: Address; isBuffer: boolean; swapInput: { tokenIn: Address; From 20bbaa2b3c29e44c565a233698eab1637be7de53 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 4 Dec 2024 20:29:47 +0200 Subject: [PATCH 36/66] fix: use permit2 approval on BUY for balancer-v3 --- src/dex/balancer-v3/balancer-v3.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 84573d13f..02b72b802 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -416,6 +416,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ); return { + permit2Approval: true, needWrapNative: this.needWrapNative, dexFuncHasRecipient: false, exchangeData, @@ -453,6 +454,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ); return { + permit2Approval: true, needWrapNative: this.needWrapNative, dexFuncHasRecipient: false, exchangeData, From 7269f9f9eae6b3d02734548a582b853daf3180e6 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 4 Dec 2024 20:31:25 +0200 Subject: [PATCH 37/66] chore: use lowered token addresses on balancer-v3 --- src/dex/balancer-v3/balancer-v3.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 02b72b802..98def7027 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -121,8 +121,8 @@ export class BalancerV3 extends SimpleExchange implements IDex { if (poolState === null) return []; return this.findPoolAddressesWithTokens( poolState, - _from.address, - _to.address, + _from.address.toLowerCase(), + _to.address.toLowerCase(), ); } @@ -200,8 +200,8 @@ export class BalancerV3 extends SimpleExchange implements IDex { // filter for pools with tokens and to only use limit pools const allowedPools = this.filterPools( allPoolState, - _from.address, - _to.address, + _from.address.toLowerCase(), + _to.address.toLowerCase(), limitPools, ); From b31b5ca5aaa5186ea15d713d46b6d3fc88d64366 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 4 Dec 2024 20:32:21 +0200 Subject: [PATCH 38/66] fix: batch swap encoding on balancer-v3 --- src/dex/balancer-v3/balancer-v3.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 98def7027..b37e965b9 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -357,7 +357,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { // for each step: // if tokenIn == pool router uses removeLiquidity SINGLE_TOKEN_EXACT_IN // if tokenOut == pool router uses addLiquidity UNBALANCED - const exchangeData = this.balancerBatchRouter.encodeFunctionResult( + const exchangeData = this.balancerBatchRouter.encodeFunctionData( 'swapExactIn', [ [ @@ -432,7 +432,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { // for each step: // if tokenIn == pool use removeLiquidity SINGLE_TOKEN_EXACT_OUT // if tokenOut == pool use addLiquidity SINGLE_TOKEN_EXACT_OUT - const exchangeData = this.balancerBatchRouter.encodeFunctionResult( + const exchangeData = this.balancerBatchRouter.encodeFunctionData( 'swapExactOut', [ [ From fb01192760b2d5d6e13cf201ba77c5368595722f Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 4 Dec 2024 20:33:24 +0200 Subject: [PATCH 39/66] fix: wrap/unwrap on balancer-v3 --- src/dex/balancer-v3/balancer-v3.ts | 41 ++++++++++++------------------ 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index b37e965b9..9f6fd85b6 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -11,7 +11,7 @@ import { } from '../../types'; import { SwapSide, Network } from '../../constants'; import * as CALLDATA_GAS_COST from '../../calldata-gas-cost'; -import { getBigIntPow, getDexKeysWithNetwork } from '../../utils'; +import { getBigIntPow, getDexKeysWithNetwork, isETHAddress } from '../../utils'; import { IDex } from '../../dex/idex'; import { IDexHelper } from '../../dex-helper/idex-helper'; import { BalancerV3Data, PoolState, PoolStateMap } from './types'; @@ -40,8 +40,8 @@ export class BalancerV3 extends SimpleExchange implements IDex { protected eventPools: BalancerV3EventPool; readonly hasConstantPriceLargeAmounts = false; - // TODO: vault can handle native - readonly needWrapNative = true; + // Vault can handle native + readonly needWrapNative = false; readonly isFeeOnTransferSupported = false; @@ -331,12 +331,12 @@ export class BalancerV3 extends SimpleExchange implements IDex { 'swapSingleTokenExactIn', [ data.steps[0].pool, - srcToken, - destToken, + this.dexHelper.config.wrapETH(srcToken), + this.dexHelper.config.wrapETH(destToken), srcAmount, '0', // This should be limit for min amount out. Assume this is set elsewhere via Paraswap contract. MAX_UINT256, // Deadline - this.needWrapNative, // TODO vault can handle native assets + isETHAddress(srcToken) || isETHAddress(destToken), '0x', ], ); @@ -373,7 +373,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { }, ], MAX_UINT256, // Deadline - this.needWrapNative, // TODO vault can handle native assets + isETHAddress(srcToken) || isETHAddress(destToken), '0x', ], ); @@ -383,13 +383,10 @@ export class BalancerV3 extends SimpleExchange implements IDex { needWrapNative: this.needWrapNative, dexFuncHasRecipient: false, exchangeData, - // This router handles single swaps + // This router handles batch swaps targetExchange: BalancerV3Config.BalancerV3[this.network].balancerBatchRouterAddress, - returnAmountPos: extractReturnAmountPosition( - this.balancerBatchRouter, - 'swapExactIn', - ), + returnAmountPos: undefined, }; } } @@ -405,12 +402,12 @@ export class BalancerV3 extends SimpleExchange implements IDex { 'swapSingleTokenExactOut', [ data.steps[0].pool, - srcToken, - destToken, + this.dexHelper.config.wrapETH(srcToken), + this.dexHelper.config.wrapETH(destToken), destAmount, MAX_UINT256, // This should be limit for max amount in. Assume this is set elsewhere via Paraswap contract. MAX_UINT256, // Deadline - this.needWrapNative, // TODO vault can handle native assets + isETHAddress(srcToken) || isETHAddress(destToken), '0x', ], ); @@ -423,10 +420,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { // Single swaps are submitted via Balancer Router targetExchange: BalancerV3Config.BalancerV3[this.network].balancerRouterAddress, - returnAmountPos: extractReturnAmountPosition( - this.balancerRouter, - 'swapSingleTokenExactOut', - ), + returnAmountPos: undefined, }; } else { // for each step: @@ -448,7 +442,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { }, ], MAX_UINT256, // Deadline - this.needWrapNative, // TODO vault can handle native assets + isETHAddress(srcToken) || isETHAddress(destToken), '0x', ], ); @@ -458,13 +452,10 @@ export class BalancerV3 extends SimpleExchange implements IDex { needWrapNative: this.needWrapNative, dexFuncHasRecipient: false, exchangeData, - // This router handles single swaps + // This router handles batch swaps targetExchange: BalancerV3Config.BalancerV3[this.network].balancerBatchRouterAddress, - returnAmountPos: extractReturnAmountPosition( - this.balancerBatchRouter, - 'swapExactIn', - ), + returnAmountPos: undefined, }; } } From 33063cb69d735845b5e05dee18bac8b97df521c1 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 4 Dec 2024 20:36:28 +0200 Subject: [PATCH 40/66] test: balancer-v3 tokens --- src/dex/balancer-v3/balancer-v3-e2e.test.ts | 6 +++--- tests/constants-e2e.ts | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-e2e.test.ts b/src/dex/balancer-v3/balancer-v3-e2e.test.ts index ac260a4b6..30564945b 100644 --- a/src/dex/balancer-v3/balancer-v3-e2e.test.ts +++ b/src/dex/balancer-v3/balancer-v3-e2e.test.ts @@ -157,11 +157,11 @@ describe('BalancerV3 E2E', () => { describe('Mainnet, Stable Path', () => { const network = Network.SEPOLIA; - const tokenASymbol: string = 'stataUsdc'; - const tokenBSymbol: string = 'aDaiAave'; + const tokenASymbol: string = 'stataUSDT'; + const tokenBSymbol: string = 'stataUSDC'; const tokenAAmount: string = '10000000'; - const tokenBAmount: string = '1000000000000000000'; + const tokenBAmount: string = '10000000'; const nativeTokenAmount = '0'; testForNetwork( diff --git a/tests/constants-e2e.ts b/tests/constants-e2e.ts index 4ef679869..ac417e2ee 100644 --- a/tests/constants-e2e.ts +++ b/tests/constants-e2e.ts @@ -1508,11 +1508,11 @@ export const Tokens: { address: `0xde46e43f46ff74a23a65ebb0580cbe3dfe684a17`, decimals: 18, }, - stataUsdc: { + stataUSDC: { address: `0x8a88124522dbbf1e56352ba3de1d9f78c143751e`, decimals: 6, }, - stataUsdt: { + stataUSDT: { address: `0x978206fae13faf5a8d293fb614326b237684b750`, decimals: 6, }, @@ -1870,6 +1870,10 @@ export const Holders: { bal: '0xDb4ff41B4C1222c2b1869A67Be115070688989a2', daiAave: '0xbB0bc84687fFb642fd90a3D12215e7eC16352A49', WETH: '0x546e37DAA15cdb82fd1a717E5dEEa4AF08D4349A', + ETH: '0x2CdA41645F2dBffB852a605E92B185501801FC28', + stataUSDC: '0x75D06bae37a9c349142fE7cee77804900b1C0EC3', + stataUSDT: '0x75D06bae37a9c349142fE7cee77804900b1C0EC3', + usdcAave: '0xdD5De55eA6804EFb283f43b0C091C25000a6486c', }, }; From 7e214113408d3053dd122abdada464bb9c0d4c1b Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Tue, 10 Dec 2024 16:26:25 +0200 Subject: [PATCH 41/66] @balancer-labs/balancer-maths: 0.0.19 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6251834a0..84a7b85c7 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ }, "dependencies": { "@0x/utils": "^4.5.2", - "@balancer-labs/balancer-maths": "^0.0.18", + "@balancer-labs/balancer-maths": "^0.0.19", "@balancer-labs/sor": "4.1.1-beta.4", "@bgd-labs/aave-address-book": "2.21.1", "@ethersproject/abi": "^5.7.0", diff --git a/yarn.lock b/yarn.lock index 98b9966fb..114de2724 100644 --- a/yarn.lock +++ b/yarn.lock @@ -341,10 +341,10 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@balancer-labs/balancer-maths@^0.0.18": - version "0.0.18" - resolved "https://registry.yarnpkg.com/@balancer-labs/balancer-maths/-/balancer-maths-0.0.18.tgz#152c88a553fd1222d20e1e600f3c8c183e603e39" - integrity sha512-IVbaNQpcLaesjzZaMx6Hr2XJqgh+3lW3v8FthWpjavLJ6R8R2oBGi2IbrV7tER9rnTSv4IxKueCKMy6AialXlg== +"@balancer-labs/balancer-maths@^0.0.19": + version "0.0.19" + resolved "https://registry.yarnpkg.com/@balancer-labs/balancer-maths/-/balancer-maths-0.0.19.tgz#d3b92c4b17caca67894806bd7768af1ea31cb956" + integrity sha512-x8t17q8fbXYZJSaidr4BWBg3O9jVnF6xoAsoMWWyUd6AnaxPyFnxAGs76+iQln4WEmC7S5G5uufWJ0OefvcqXQ== "@balancer-labs/sor@4.1.1-beta.4": version "4.1.1-beta.4" From c7ced48d652cf3165520d891d4ea0426d9935b95 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Tue, 10 Dec 2024 16:30:01 +0200 Subject: [PATCH 42/66] feat: introduced `disabledPoolIds` for balancer-v3 --- src/dex/balancer-v3/config.ts | 6 ++++++ src/dex/balancer-v3/getPoolsApi.ts | 13 +++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/dex/balancer-v3/config.ts b/src/dex/balancer-v3/config.ts index 1032ed30b..ea2469cfe 100644 --- a/src/dex/balancer-v3/config.ts +++ b/src/dex/balancer-v3/config.ts @@ -8,6 +8,12 @@ export enum SUPPORTED_POOLS { STABLE = 'STABLE', } +export const disabledPoolIds: Record> = { + BalancerV3: { + [Network.SEPOLIA]: ['0x0d7291d8bdc6b376aadacbf05b1ef8a8292ef58a'], // incorrect token rate config for 0x978206fae13faf5a8d293fb614326b237684b750 token + }, +}; + // Balancer API - aggregatorSpecific query serves all useful static pool data export const apiUrl = 'https://test-api-v3.balancer.fi/'; diff --git a/src/dex/balancer-v3/getPoolsApi.ts b/src/dex/balancer-v3/getPoolsApi.ts index 11c4a555a..ba3bce72f 100644 --- a/src/dex/balancer-v3/getPoolsApi.ts +++ b/src/dex/balancer-v3/getPoolsApi.ts @@ -1,6 +1,10 @@ import axios from 'axios'; -import { DeepReadonly } from 'ts-essentials'; -import { apiUrl, BalancerV3Config, SUPPORTED_POOLS } from './config'; +import { + apiUrl, + BalancerV3Config, + disabledPoolIds, + SUPPORTED_POOLS, +} from './config'; import { CommonImmutablePoolState, ImmutablePoolStateMap } from './types'; import { parseUnits } from 'ethers/lib/utils'; @@ -32,6 +36,10 @@ function createQuery( ): string { const poolTypesString = poolTypes.map(type => `${type}`).join(', '); const networkString = BalancerV3Config.BalancerV3[networkId].apiNetworkName; + const disabledPoolIdsString = disabledPoolIds.BalancerV3[networkId] + ?.map(p => `"${p}"`) + .join(', '); + // Build the where clause conditionally const whereClause = { chainIn: networkString, @@ -39,6 +47,7 @@ function createQuery( hasHook: false, poolTypeIn: `[${poolTypesString}]`, ...(timestamp && { createTime: `{lt: ${timestamp}}` }), + ...(disabledPoolIdsString && { idNotIn: `[${disabledPoolIdsString}]` }), }; // Convert where clause to string, filtering out undefined values From 4414991dda66cef0c8a5bffb736afe507253f92b Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Tue, 10 Dec 2024 16:30:52 +0200 Subject: [PATCH 43/66] feat: reduced `RATE_UPDATE_TTL` to 1min on balancer-v3 --- src/dex/balancer-v3/balancer-v3.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 9f6fd85b6..fa113ae6d 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -30,7 +30,7 @@ import { getGasCost } from './getGasCost'; const MAX_UINT256 = '115792089237316195423570985008687907853269984665640564039457584007913129639935'; const POOL_UPDATE_TTL = 5 * 60; // 5mins -const RATE_UPDATE_TTL = 30 * 60; // 30mins +const RATE_UPDATE_TTL = 1 * 60; // 1min type DeepMutable = { -readonly [P in keyof T]: T[P] extends object ? DeepMutable : T[P]; From fb51c26fae6c93b6390932a9ef776ea787286655 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Tue, 10 Dec 2024 16:33:33 +0200 Subject: [PATCH 44/66] feat: introduced release version for balancer-v3 config --- src/dex/balancer-v3/config.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dex/balancer-v3/config.ts b/src/dex/balancer-v3/config.ts index ea2469cfe..3a51112d6 100644 --- a/src/dex/balancer-v3/config.ts +++ b/src/dex/balancer-v3/config.ts @@ -21,10 +21,10 @@ export const apiUrl = 'https://test-api-v3.balancer.fi/'; export const BalancerV3Config: DexConfigMap = { BalancerV3: { [Network.SEPOLIA]: { - vaultAddress: '0xBC582d2628FcD404254a1e12CB714967Ce428915', + vaultAddress: '0xbA1333333333a1BA1108E8412f11850A5C319bA9', apiNetworkName: 'SEPOLIA', - balancerRouterAddress: '0x4D2aA7a3CD7F8dA6feF37578A1881cD63Fd3715E', - balancerBatchRouterAddress: '0x4232e5EEaA16Bcf483d93BEA469296B4EeF22503', + balancerRouterAddress: '0x0BF61f706105EA44694f2e92986bD01C39930280', + balancerBatchRouterAddress: '0xC85b652685567C1B074e8c0D4389f83a2E458b1C', }, }, }; From 7b23f90a35a64ebce4b586a36d1ce8deb99ea64a Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 12:44:04 +0200 Subject: [PATCH 45/66] fix: use srcAmount as maxAmountIn for batch swap on balancer-v3 --- src/dex/balancer-v3/balancer-v3.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index fa113ae6d..5ac0f6d68 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -316,7 +316,13 @@ export class BalancerV3 extends SimpleExchange implements IDex { if (side === SwapSide.SELL) { return this.getExactInParam(srcToken, destToken, srcAmount, data); } else { - return this.getExactOutParam(srcToken, destToken, destAmount, data); + return this.getExactOutParam( + srcToken, + destToken, + srcAmount, + destAmount, + data, + ); } } @@ -394,6 +400,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { getExactOutParam( srcToken: Address, destToken: Address, + srcAmount: NumberAsString, destAmount: NumberAsString, data: BalancerV3Data, ): DexExchangeParam { @@ -438,7 +445,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { isBuffer: step.isBuffer, })), exactAmountOut: destAmount, - maxAmountIn: MAX_UINT256, // This should be limit for min amount out. Assume this is set elsewhere via Paraswap contract. + maxAmountIn: srcAmount, }, ], MAX_UINT256, // Deadline From 2bc71f227bd49b30dfefc437acbf18f9201767f5 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 12:45:18 +0200 Subject: [PATCH 46/66] fix: add underlying tokens as connectors on balancer-v3 --- src/dex/balancer-v3/balancer-v3.ts | 18 ++++++++++++++---- src/dex/balancer-v3/getTopPoolsApi.ts | 10 +++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 5ac0f6d68..0bb27f3d5 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -491,20 +491,30 @@ export class BalancerV3 extends SimpleExchange implements IDex { ): Promise { const poolsWithToken = Object.entries(this.eventPools.getStaleState() || {}) .filter(([, poolState]) => { - return this.hasTokens(poolState, [tokenAddress]); + return this.hasTokens(poolState, [tokenAddress.toLowerCase()]); }) .map(([address]) => address); const topPools = await getTopPoolsApi(this.network, poolsWithToken, count); return topPools.map(pool => { + const tokens = pool.poolTokens + .filter(t => t.address !== tokenAddress) + .map(t => ({ + address: t.address, + decimals: t.decimals, + })); + + const underlyingTokens = pool.poolTokens + .map(t => t.underlyingToken) + .filter(t => !!t) + .filter(t => t?.address !== tokenAddress) as Token[]; + return { exchange: this.dexKey, address: pool.address, liquidityUSD: parseFloat(pool.dynamicData.totalLiquidity), - connectorTokens: pool.poolTokens.filter( - t => t.address !== tokenAddress, - ), + connectorTokens: tokens.concat(underlyingTokens), }; }); } diff --git a/src/dex/balancer-v3/getTopPoolsApi.ts b/src/dex/balancer-v3/getTopPoolsApi.ts index eb3b48aaa..a89d9a871 100644 --- a/src/dex/balancer-v3/getTopPoolsApi.ts +++ b/src/dex/balancer-v3/getTopPoolsApi.ts @@ -4,9 +4,13 @@ import { apiUrl, BalancerV3Config } from './config'; interface PoolToken { address: string; decimals: number; + underlyingToken?: { + address: string; + decimals: number; + }; } -interface Pool { +export interface Pool { address: string; poolTokens: PoolToken[]; dynamicData: { @@ -51,6 +55,10 @@ function createQuery( poolTokens { address decimals + underlyingToken { + address + decimals + } } dynamicData { totalLiquidity From 27bd01734f44a94976cc39befbcc36ad097799c6 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 12:48:41 +0200 Subject: [PATCH 47/66] test: adapt integration tests on balancer-v3 --- .../balancer-v3-integration.test.ts | 64 +++++++++++-------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-integration.test.ts b/src/dex/balancer-v3/balancer-v3-integration.test.ts index 1abf52c24..616d711be 100644 --- a/src/dex/balancer-v3/balancer-v3-integration.test.ts +++ b/src/dex/balancer-v3/balancer-v3-integration.test.ts @@ -58,7 +58,7 @@ function getQuerySwapMultiTokenCalldata( const tokenIn = steps[0].swapInput.tokenIn; const stepsNew = steps.map(s => ({ pool: s.pool, - tokenOut: s.tokenOut, + tokenOut: s.swapInput.tokenOut, isBuffer: s.isBuffer, })); return amounts @@ -112,20 +112,25 @@ async function querySinglePathPrices( const expectedPrices = [0n]; for (const call of readerCallData) { - const result = await balancerV3.dexHelper.provider.call( - { - to: call.target, - data: call.callData, - }, - blockNumber, - ); - const parsed = balancerRouter.decodeFunctionResult( - side === SwapSide.SELL - ? `querySwapSingleTokenExactIn` - : `querySwapSingleTokenExactOut`, - result, - ); - expectedPrices.push(BigInt(parsed[0]._hex)); + try { + const result = await balancerV3.dexHelper.provider.call( + { + to: call.target, + data: call.callData, + }, + blockNumber, + ); + const parsed = balancerRouter.decodeFunctionResult( + side === SwapSide.SELL + ? `querySwapSingleTokenExactIn` + : `querySwapSingleTokenExactOut`, + result, + ); + expectedPrices.push(BigInt(parsed[0]._hex)); + } catch (error) { + console.log('Error in querySinglePathPrices', error); + expectedPrices.push(0n); + } } return expectedPrices; } @@ -149,18 +154,23 @@ async function queryMultiPathPrices( const expectedPrices = [0n]; for (const call of readerCallData) { - const result = await balancerV3.dexHelper.provider.call( - { - to: call.target, - data: call.callData, - }, - blockNumber, - ); - const parsed = balancerBatchRouter.decodeFunctionResult( - side === SwapSide.SELL ? `querySwapExactIn` : `querySwapExactOut`, - result, - ); - expectedPrices.push(BigInt(parsed[2][0]._hex)); + try { + const result = await balancerV3.dexHelper.provider.call( + { + to: call.target, + data: call.callData, + }, + blockNumber, + ); + const parsed = balancerBatchRouter.decodeFunctionResult( + side === SwapSide.SELL ? `querySwapExactIn` : `querySwapExactOut`, + result, + ); + expectedPrices.push(BigInt(parsed[2][0]._hex)); + } catch (error) { + console.log('Error in queryMultiPathPrices', error); + expectedPrices.push(0n); + } } return expectedPrices; } From 8e46a8b4d842a360c7035e6c2f4ea26a7b3e63f6 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 12:50:12 +0200 Subject: [PATCH 48/66] feat: integrated Gnosis on balancer-v3 --- src/dex/balancer-v3/balancer-v3-e2e.test.ts | 189 +++-- .../balancer-v3-integration.test.ts | 789 ++++++++++++------ src/dex/balancer-v3/config.ts | 8 +- 3 files changed, 675 insertions(+), 311 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-e2e.test.ts b/src/dex/balancer-v3/balancer-v3-e2e.test.ts index 30564945b..8c612c876 100644 --- a/src/dex/balancer-v3/balancer-v3-e2e.test.ts +++ b/src/dex/balancer-v3/balancer-v3-e2e.test.ts @@ -121,6 +121,19 @@ function testForNetwork( provider, ); }); + it(`${tokenBSymbol} -> ${tokenASymbol}`, async () => { + await testE2E( + tokens[tokenBSymbol], + tokens[tokenASymbol], + holders[tokenBSymbol], + side === SwapSide.SELL ? tokenBAmount : tokenAAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); }); }); }), @@ -132,69 +145,131 @@ function testForNetwork( describe('BalancerV3 E2E', () => { const dexKey = 'BalancerV3'; - describe('Mainnet, Weighted Path', () => { + describe('Sepolia', () => { const network = Network.SEPOLIA; - const tokenASymbol: string = 'bal'; - const tokenBSymbol: string = 'daiAave'; - - const tokenAAmount: string = '1000000000000000000'; - const tokenBAmount: string = '1000000000000000000'; - const nativeTokenAmount = '100000000000000'; - - testForNetwork( - network, - dexKey, - tokenASymbol, - tokenBSymbol, - tokenAAmount, - tokenBAmount, - nativeTokenAmount, - true, - ); - }); + describe('Weighted Path', () => { + const tokenASymbol: string = 'bal'; + const tokenBSymbol: string = 'daiAave'; - describe('Mainnet, Stable Path', () => { - const network = Network.SEPOLIA; + const tokenAAmount: string = '1000000000000000000'; + const tokenBAmount: string = '1000000000000000000'; + const nativeTokenAmount = '100000000000000'; - const tokenASymbol: string = 'stataUSDT'; - const tokenBSymbol: string = 'stataUSDC'; - - const tokenAAmount: string = '10000000'; - const tokenBAmount: string = '10000000'; - const nativeTokenAmount = '0'; - - testForNetwork( - network, - dexKey, - tokenASymbol, - tokenBSymbol, - tokenAAmount, - tokenBAmount, - nativeTokenAmount, - false, - ); + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + nativeTokenAmount, + true, + ); + }); + + describe('Stable Path', () => { + const tokenASymbol: string = 'stataUSDT'; + const tokenBSymbol: string = 'stataUSDC'; + + const tokenAAmount: string = '10000000'; + const tokenBAmount: string = '10000000'; + const nativeTokenAmount = '0'; + + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + nativeTokenAmount, + false, + ); + }); + + describe('Boosted Path', () => { + const tokenASymbol: string = 'usdcAave'; + const tokenBSymbol: string = 'daiAave'; + + const tokenAAmount: string = '10000000'; + const tokenBAmount: string = '1000000000000000000'; + const nativeTokenAmount = '0'; + + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + nativeTokenAmount, + false, + ); + }); }); - describe('Mainnet, Boosted Path', () => { - const network = Network.SEPOLIA; + describe('Gnosis', () => { + const network = Network.GNOSIS; - const tokenASymbol: string = 'usdcAave'; - const tokenBSymbol: string = 'daiAave'; - - const tokenAAmount: string = '10000000'; - const tokenBAmount: string = '1000000000000000000'; - const nativeTokenAmount = '0'; - - testForNetwork( - network, - dexKey, - tokenASymbol, - tokenBSymbol, - tokenAAmount, - tokenBAmount, - nativeTokenAmount, - false, - ); + describe('Stable Path', () => { + const tokenASymbol: string = 'WXDAI'; + const tokenBSymbol: string = 'COW'; + + const tokenAAmount: string = '1000000000000000000'; + const tokenBAmount: string = '1000000000000000000'; + const nativeTokenAmount = '100000000000000'; + + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + nativeTokenAmount, + false, + ); + }); + + describe('Weighed Path', () => { + const tokenASymbol: string = 'USDCe'; + const tokenBSymbol: string = 'sDAI'; + + const tokenAAmount: string = '1000000'; + const tokenBAmount: string = '100000000000000000'; + const nativeTokenAmount = '0'; + + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + nativeTokenAmount, + false, + ); + }); + + describe('Boosted Path', () => { + const tokenASymbol: string = 'waGnoWETH'; + const tokenBSymbol: string = 'waGnowstETH'; + + const tokenAAmount: string = '1000000000000000'; + const tokenBAmount: string = '1000000000000000'; + const nativeTokenAmount = '0'; + + testForNetwork( + network, + dexKey, + tokenASymbol, + tokenBSymbol, + tokenAAmount, + tokenBAmount, + nativeTokenAmount, + false, + ); + }); }); }); diff --git a/src/dex/balancer-v3/balancer-v3-integration.test.ts b/src/dex/balancer-v3/balancer-v3-integration.test.ts index 616d711be..ae659cf7b 100644 --- a/src/dex/balancer-v3/balancer-v3-integration.test.ts +++ b/src/dex/balancer-v3/balancer-v3-integration.test.ts @@ -270,283 +270,566 @@ describe('BalancerV3', function () { let blockNumber: number; let balancerV3: BalancerV3; - describe('Weighted Pool', () => { + describe('Sepolia', () => { const network = Network.SEPOLIA; - const dexHelper = new DummyDexHelper(network); - - const tokens = Tokens[network]; - const srcTokenSymbol = 'bal'; - const destTokenSymbol = 'daiAave'; - - const amountsForSell = [ - 0n, - 1n * BI_POWS[tokens[srcTokenSymbol].decimals], - 2n * BI_POWS[tokens[srcTokenSymbol].decimals], - 3n * BI_POWS[tokens[srcTokenSymbol].decimals], - 4n * BI_POWS[tokens[srcTokenSymbol].decimals], - 5n * BI_POWS[tokens[srcTokenSymbol].decimals], - 6n * BI_POWS[tokens[srcTokenSymbol].decimals], - 7n * BI_POWS[tokens[srcTokenSymbol].decimals], - 8n * BI_POWS[tokens[srcTokenSymbol].decimals], - 9n * BI_POWS[tokens[srcTokenSymbol].decimals], - 10n * BI_POWS[tokens[srcTokenSymbol].decimals], - ]; - - const amountsForBuy = [ - 0n, - 1n * BI_POWS[tokens[destTokenSymbol].decimals], - 2n * BI_POWS[tokens[destTokenSymbol].decimals], - 3n * BI_POWS[tokens[destTokenSymbol].decimals], - 4n * BI_POWS[tokens[destTokenSymbol].decimals], - 5n * BI_POWS[tokens[destTokenSymbol].decimals], - 6n * BI_POWS[tokens[destTokenSymbol].decimals], - 7n * BI_POWS[tokens[destTokenSymbol].decimals], - 8n * BI_POWS[tokens[destTokenSymbol].decimals], - 9n * BI_POWS[tokens[destTokenSymbol].decimals], - 10n * BI_POWS[tokens[destTokenSymbol].decimals], - ]; - - beforeAll(async () => { - blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); - balancerV3 = new BalancerV3(network, dexKey, dexHelper); - if (balancerV3.initializePricing) { - await balancerV3.initializePricing(blockNumber); - } - }); - it('getPoolIdentifiers and getPricesVolume SELL', async function () { - await testPricingOnNetwork( - balancerV3, - network, - dexKey, - blockNumber, - srcTokenSymbol, - destTokenSymbol, - SwapSide.SELL, - amountsForSell, - ); - }); - - it('getPoolIdentifiers and getPricesVolume BUY', async function () { - await testPricingOnNetwork( - balancerV3, - network, - dexKey, - blockNumber, - srcTokenSymbol, - destTokenSymbol, - SwapSide.BUY, - amountsForBuy, - ); - }); - - it('getTopPoolsForToken', async function () { - // We have to check without calling initializePricing, because - // pool-tracker is not calling that function - const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); - if (newBalancerV3.updatePoolState) { - await newBalancerV3.updatePoolState(); - } - const poolLiquidity = await newBalancerV3.getTopPoolsForToken( - tokens[srcTokenSymbol].address, - 10, - ); - console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); - - if (!newBalancerV3.hasConstantPriceLargeAmounts) { - checkPoolsLiquidity( - poolLiquidity, - Tokens[network][srcTokenSymbol].address, + describe('Weighted Pool', () => { + const dexHelper = new DummyDexHelper(network); + + const tokens = Tokens[network]; + const srcTokenSymbol = 'bal'; + const destTokenSymbol = 'daiAave'; + + const amountsForSell = [ + 0n, + 1n * BI_POWS[tokens[srcTokenSymbol].decimals], + 2n * BI_POWS[tokens[srcTokenSymbol].decimals], + 3n * BI_POWS[tokens[srcTokenSymbol].decimals], + 4n * BI_POWS[tokens[srcTokenSymbol].decimals], + 5n * BI_POWS[tokens[srcTokenSymbol].decimals], + 6n * BI_POWS[tokens[srcTokenSymbol].decimals], + 7n * BI_POWS[tokens[srcTokenSymbol].decimals], + 8n * BI_POWS[tokens[srcTokenSymbol].decimals], + 9n * BI_POWS[tokens[srcTokenSymbol].decimals], + 10n * BI_POWS[tokens[srcTokenSymbol].decimals], + ]; + + const amountsForBuy = [ + 0n, + 1n * BI_POWS[tokens[destTokenSymbol].decimals], + 2n * BI_POWS[tokens[destTokenSymbol].decimals], + 3n * BI_POWS[tokens[destTokenSymbol].decimals], + 4n * BI_POWS[tokens[destTokenSymbol].decimals], + 5n * BI_POWS[tokens[destTokenSymbol].decimals], + 6n * BI_POWS[tokens[destTokenSymbol].decimals], + 7n * BI_POWS[tokens[destTokenSymbol].decimals], + 8n * BI_POWS[tokens[destTokenSymbol].decimals], + 9n * BI_POWS[tokens[destTokenSymbol].decimals], + 10n * BI_POWS[tokens[destTokenSymbol].decimals], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + balancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (balancerV3.initializePricing) { + await balancerV3.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + balancerV3, + network, dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.SELL, + amountsForSell, ); - } - }); - }); + }); - describe('Stable Pool', () => { - const network = Network.SEPOLIA; - const dexHelper = new DummyDexHelper(network); - - const tokens = Tokens[network]; - const srcTokenSymbol = 'stataUsdc'; - const destTokenSymbol = 'stataUsdt'; - - const amountsForSell = [ - 0n, - 1n * BI_POWS[tokens[srcTokenSymbol].decimals], - 2n * BI_POWS[tokens[srcTokenSymbol].decimals], - 3n * BI_POWS[tokens[srcTokenSymbol].decimals], - 4n * BI_POWS[tokens[srcTokenSymbol].decimals], - 5n * BI_POWS[tokens[srcTokenSymbol].decimals], - 6n * BI_POWS[tokens[srcTokenSymbol].decimals], - 7n * BI_POWS[tokens[srcTokenSymbol].decimals], - 8n * BI_POWS[tokens[srcTokenSymbol].decimals], - 9n * BI_POWS[tokens[srcTokenSymbol].decimals], - 10n * BI_POWS[tokens[srcTokenSymbol].decimals], - ]; - - const amountsForBuy = [ - 0n, - 1n * BI_POWS[tokens[destTokenSymbol].decimals], - 2n * BI_POWS[tokens[destTokenSymbol].decimals], - 3n * BI_POWS[tokens[destTokenSymbol].decimals], - 4n * BI_POWS[tokens[destTokenSymbol].decimals], - 5n * BI_POWS[tokens[destTokenSymbol].decimals], - 6n * BI_POWS[tokens[destTokenSymbol].decimals], - 7n * BI_POWS[tokens[destTokenSymbol].decimals], - 8n * BI_POWS[tokens[destTokenSymbol].decimals], - 9n * BI_POWS[tokens[destTokenSymbol].decimals], - 10n * BI_POWS[tokens[destTokenSymbol].decimals], - ]; - - beforeAll(async () => { - blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); - balancerV3 = new BalancerV3(network, dexKey, dexHelper); - if (balancerV3.initializePricing) { - await balancerV3.initializePricing(blockNumber); - } + it('getPoolIdentifiers and getPricesVolume BUY', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.BUY, + amountsForBuy, + ); + }); + + it('getTopPoolsForToken', async function () { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (newBalancerV3.updatePoolState) { + await newBalancerV3.updatePoolState(); + } + const poolLiquidity = await newBalancerV3.getTopPoolsForToken( + tokens[srcTokenSymbol].address, + 10, + ); + console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); + + if (!newBalancerV3.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity( + poolLiquidity, + Tokens[network][srcTokenSymbol].address, + dexKey, + ); + } + }); }); - it('getPoolIdentifiers and getPricesVolume SELL', async function () { - await testPricingOnNetwork( - balancerV3, - network, - dexKey, - blockNumber, - srcTokenSymbol, - destTokenSymbol, - SwapSide.SELL, - amountsForSell, - ); - }); + describe('Stable Pool', () => { + const dexHelper = new DummyDexHelper(network); + + const tokens = Tokens[network]; + const srcTokenSymbol = 'stataUSDC'; + const destTokenSymbol = 'stataUSDT'; + + const amountsForSell = [ + 0n, + 1n * BI_POWS[tokens[srcTokenSymbol].decimals], + 2n * BI_POWS[tokens[srcTokenSymbol].decimals], + 3n * BI_POWS[tokens[srcTokenSymbol].decimals], + 4n * BI_POWS[tokens[srcTokenSymbol].decimals], + 5n * BI_POWS[tokens[srcTokenSymbol].decimals], + 6n * BI_POWS[tokens[srcTokenSymbol].decimals], + 7n * BI_POWS[tokens[srcTokenSymbol].decimals], + 8n * BI_POWS[tokens[srcTokenSymbol].decimals], + 9n * BI_POWS[tokens[srcTokenSymbol].decimals], + 10n * BI_POWS[tokens[srcTokenSymbol].decimals], + ]; + + const amountsForBuy = [ + 0n, + 1n * BI_POWS[tokens[destTokenSymbol].decimals], + 2n * BI_POWS[tokens[destTokenSymbol].decimals], + 3n * BI_POWS[tokens[destTokenSymbol].decimals], + 4n * BI_POWS[tokens[destTokenSymbol].decimals], + 5n * BI_POWS[tokens[destTokenSymbol].decimals], + 6n * BI_POWS[tokens[destTokenSymbol].decimals], + 7n * BI_POWS[tokens[destTokenSymbol].decimals], + 8n * BI_POWS[tokens[destTokenSymbol].decimals], + 9n * BI_POWS[tokens[destTokenSymbol].decimals], + 10n * BI_POWS[tokens[destTokenSymbol].decimals], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + balancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (balancerV3.initializePricing) { + await balancerV3.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.SELL, + amountsForSell, + ); + }); - it('getPoolIdentifiers and getPricesVolume BUY', async function () { - await testPricingOnNetwork( - balancerV3, - network, - dexKey, - blockNumber, - srcTokenSymbol, - destTokenSymbol, - SwapSide.BUY, - amountsForBuy, - ); + it('getPoolIdentifiers and getPricesVolume BUY', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.BUY, + amountsForBuy, + ); + }); + + it('getTopPoolsForToken', async function () { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (newBalancerV3.updatePoolState) { + await newBalancerV3.updatePoolState(); + } + const poolLiquidity = await newBalancerV3.getTopPoolsForToken( + tokens[srcTokenSymbol].address, + 10, + ); + console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); + + if (!newBalancerV3.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity( + poolLiquidity, + Tokens[network][srcTokenSymbol].address, + dexKey, + ); + } + }); }); - it('getTopPoolsForToken', async function () { - // We have to check without calling initializePricing, because - // pool-tracker is not calling that function - const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); - if (newBalancerV3.updatePoolState) { - await newBalancerV3.updatePoolState(); - } - const poolLiquidity = await newBalancerV3.getTopPoolsForToken( - tokens[srcTokenSymbol].address, - 10, - ); - console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); + describe('Boosted Path', () => { + const dexHelper = new DummyDexHelper(network); + + const tokens = Tokens[network]; + const srcTokenSymbol = 'usdcAave'; + const destTokenSymbol = 'usdtAave'; + + const amountsForSell = [ + 0n, + 1n * BI_POWS[tokens[srcTokenSymbol].decimals], + 2n * BI_POWS[tokens[srcTokenSymbol].decimals], + 3n * BI_POWS[tokens[srcTokenSymbol].decimals], + 4n * BI_POWS[tokens[srcTokenSymbol].decimals], + 5n * BI_POWS[tokens[srcTokenSymbol].decimals], + 6n * BI_POWS[tokens[srcTokenSymbol].decimals], + 7n * BI_POWS[tokens[srcTokenSymbol].decimals], + 8n * BI_POWS[tokens[srcTokenSymbol].decimals], + 9n * BI_POWS[tokens[srcTokenSymbol].decimals], + 10n * BI_POWS[tokens[srcTokenSymbol].decimals], + ]; + + const amountsForBuy = [ + 0n, + 1n * BI_POWS[tokens[destTokenSymbol].decimals], + 2n * BI_POWS[tokens[destTokenSymbol].decimals], + 3n * BI_POWS[tokens[destTokenSymbol].decimals], + 4n * BI_POWS[tokens[destTokenSymbol].decimals], + 5n * BI_POWS[tokens[destTokenSymbol].decimals], + 6n * BI_POWS[tokens[destTokenSymbol].decimals], + 7n * BI_POWS[tokens[destTokenSymbol].decimals], + 8n * BI_POWS[tokens[destTokenSymbol].decimals], + 9n * BI_POWS[tokens[destTokenSymbol].decimals], + 10n * BI_POWS[tokens[destTokenSymbol].decimals], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + balancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (balancerV3.initializePricing) { + await balancerV3.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.SELL, + amountsForSell, + ); + }); - if (!newBalancerV3.hasConstantPriceLargeAmounts) { - checkPoolsLiquidity( - poolLiquidity, - Tokens[network][srcTokenSymbol].address, + // TODO 1 WEI rounding issue in maths - investigating + it('getPoolIdentifiers and getPricesVolume BUY', async function () { + await testPricingOnNetwork( + balancerV3, + network, dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.BUY, + amountsForBuy, ); - } + }); + + it('getTopPoolsForToken', async function () { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (newBalancerV3.updatePoolState) { + await newBalancerV3.updatePoolState(); + } + const poolLiquidity = await newBalancerV3.getTopPoolsForToken( + tokens[srcTokenSymbol].address, + 10, + ); + console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); + + if (!newBalancerV3.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity( + poolLiquidity, + Tokens[network][srcTokenSymbol].address, + dexKey, + ); + } + }); }); }); - describe('Boosted Path', () => { - const network = Network.SEPOLIA; - const dexHelper = new DummyDexHelper(network); - - const tokens = Tokens[network]; - const srcTokenSymbol = 'usdcAave'; - const destTokenSymbol = 'usdtAave'; - - const amountsForSell = [ - 0n, - 1n * BI_POWS[tokens[srcTokenSymbol].decimals], - 2n * BI_POWS[tokens[srcTokenSymbol].decimals], - 3n * BI_POWS[tokens[srcTokenSymbol].decimals], - 4n * BI_POWS[tokens[srcTokenSymbol].decimals], - 5n * BI_POWS[tokens[srcTokenSymbol].decimals], - 6n * BI_POWS[tokens[srcTokenSymbol].decimals], - 7n * BI_POWS[tokens[srcTokenSymbol].decimals], - 8n * BI_POWS[tokens[srcTokenSymbol].decimals], - 9n * BI_POWS[tokens[srcTokenSymbol].decimals], - 10n * BI_POWS[tokens[srcTokenSymbol].decimals], - ]; - - const amountsForBuy = [ - 0n, - 1n * BI_POWS[tokens[destTokenSymbol].decimals], - 2n * BI_POWS[tokens[destTokenSymbol].decimals], - 3n * BI_POWS[tokens[destTokenSymbol].decimals], - 4n * BI_POWS[tokens[destTokenSymbol].decimals], - 5n * BI_POWS[tokens[destTokenSymbol].decimals], - 6n * BI_POWS[tokens[destTokenSymbol].decimals], - 7n * BI_POWS[tokens[destTokenSymbol].decimals], - 8n * BI_POWS[tokens[destTokenSymbol].decimals], - 9n * BI_POWS[tokens[destTokenSymbol].decimals], - 10n * BI_POWS[tokens[destTokenSymbol].decimals], - ]; - - beforeAll(async () => { - blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); - balancerV3 = new BalancerV3(network, dexKey, dexHelper); - if (balancerV3.initializePricing) { - await balancerV3.initializePricing(blockNumber); - } - }); + describe('Gnosis', () => { + const network = Network.GNOSIS; + + describe('Weighted Pool', () => { + const dexHelper = new DummyDexHelper(network); + + const tokens = Tokens[network]; + const srcTokenSymbol = 'USDCe'; + const destTokenSymbol = 'sDAI'; + + const amountsForSell = [ + 0n, + 1n * BI_POWS[tokens[srcTokenSymbol].decimals], + 2n * BI_POWS[tokens[srcTokenSymbol].decimals], + 3n * BI_POWS[tokens[srcTokenSymbol].decimals], + 4n * BI_POWS[tokens[srcTokenSymbol].decimals], + 5n * BI_POWS[tokens[srcTokenSymbol].decimals], + 6n * BI_POWS[tokens[srcTokenSymbol].decimals], + 7n * BI_POWS[tokens[srcTokenSymbol].decimals], + 8n * BI_POWS[tokens[srcTokenSymbol].decimals], + 9n * BI_POWS[tokens[srcTokenSymbol].decimals], + 10n * BI_POWS[tokens[srcTokenSymbol].decimals], + ]; + + const amountsForBuy = [ + 0n, + 1n * BI_POWS[tokens[destTokenSymbol].decimals], + 2n * BI_POWS[tokens[destTokenSymbol].decimals], + 3n * BI_POWS[tokens[destTokenSymbol].decimals], + 4n * BI_POWS[tokens[destTokenSymbol].decimals], + 5n * BI_POWS[tokens[destTokenSymbol].decimals], + 6n * BI_POWS[tokens[destTokenSymbol].decimals], + 7n * BI_POWS[tokens[destTokenSymbol].decimals], + 8n * BI_POWS[tokens[destTokenSymbol].decimals], + 9n * BI_POWS[tokens[destTokenSymbol].decimals], + 10n * BI_POWS[tokens[destTokenSymbol].decimals], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + balancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (balancerV3.initializePricing) { + await balancerV3.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.SELL, + amountsForSell, + ); + }); - it('getPoolIdentifiers and getPricesVolume SELL', async function () { - await testPricingOnNetwork( - balancerV3, - network, - dexKey, - blockNumber, - srcTokenSymbol, - destTokenSymbol, - SwapSide.SELL, - amountsForSell, - ); + it('getPoolIdentifiers and getPricesVolume BUY', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.BUY, + amountsForBuy, + ); + }); + + it('getTopPoolsForToken', async function () { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (newBalancerV3.updatePoolState) { + await newBalancerV3.updatePoolState(); + } + const poolLiquidity = await newBalancerV3.getTopPoolsForToken( + tokens[srcTokenSymbol].address, + 10, + ); + console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); + + if (!newBalancerV3.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity( + poolLiquidity, + Tokens[network][srcTokenSymbol].address, + dexKey, + ); + } + }); }); - // TODO 1 WEI rounding issue in maths - investigating - it('getPoolIdentifiers and getPricesVolume BUY', async function () { - await testPricingOnNetwork( - balancerV3, - network, - dexKey, - blockNumber, - srcTokenSymbol, - destTokenSymbol, - SwapSide.BUY, - amountsForBuy, - ); + describe('Stable Pool', () => { + const dexHelper = new DummyDexHelper(network); + + const tokens = Tokens[network]; + const srcTokenSymbol = 'WXDAI'; + const destTokenSymbol = 'COW'; + + const amountsForSell = [ + 0n, + 1n * BI_POWS[tokens[srcTokenSymbol].decimals], + 2n * BI_POWS[tokens[srcTokenSymbol].decimals], + 3n * BI_POWS[tokens[srcTokenSymbol].decimals], + 4n * BI_POWS[tokens[srcTokenSymbol].decimals], + 5n * BI_POWS[tokens[srcTokenSymbol].decimals], + 6n * BI_POWS[tokens[srcTokenSymbol].decimals], + 7n * BI_POWS[tokens[srcTokenSymbol].decimals], + 8n * BI_POWS[tokens[srcTokenSymbol].decimals], + 9n * BI_POWS[tokens[srcTokenSymbol].decimals], + 10n * BI_POWS[tokens[srcTokenSymbol].decimals], + ]; + + const amountsForBuy = [ + 0n, + 1n * BI_POWS[tokens[destTokenSymbol].decimals], + 2n * BI_POWS[tokens[destTokenSymbol].decimals], + 3n * BI_POWS[tokens[destTokenSymbol].decimals], + 4n * BI_POWS[tokens[destTokenSymbol].decimals], + 5n * BI_POWS[tokens[destTokenSymbol].decimals], + 6n * BI_POWS[tokens[destTokenSymbol].decimals], + 7n * BI_POWS[tokens[destTokenSymbol].decimals], + 8n * BI_POWS[tokens[destTokenSymbol].decimals], + 9n * BI_POWS[tokens[destTokenSymbol].decimals], + 10n * BI_POWS[tokens[destTokenSymbol].decimals], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + balancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (balancerV3.initializePricing) { + await balancerV3.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.SELL, + amountsForSell, + ); + }); + + it('getPoolIdentifiers and getPricesVolume BUY', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.BUY, + amountsForBuy, + ); + }); + + it('getTopPoolsForToken', async function () { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (newBalancerV3.updatePoolState) { + await newBalancerV3.updatePoolState(); + } + const poolLiquidity = await newBalancerV3.getTopPoolsForToken( + tokens[srcTokenSymbol].address, + 10, + ); + console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); + + if (!newBalancerV3.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity( + poolLiquidity, + Tokens[network][srcTokenSymbol].address, + dexKey, + ); + } + }); }); - it('getTopPoolsForToken', async function () { - // We have to check without calling initializePricing, because - // pool-tracker is not calling that function - const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); - if (newBalancerV3.updatePoolState) { - await newBalancerV3.updatePoolState(); - } - const poolLiquidity = await newBalancerV3.getTopPoolsForToken( - tokens[srcTokenSymbol].address, - 10, - ); - console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); + describe('Boosted Path', () => { + const dexHelper = new DummyDexHelper(network); + + const tokens = Tokens[network]; + const srcTokenSymbol = 'waGnoWETH'; + const destTokenSymbol = 'waGnowstETH'; + + const amountsForSell = [ + 0n, + (1n * BI_POWS[tokens[srcTokenSymbol].decimals]) / 1000n, + (2n * BI_POWS[tokens[srcTokenSymbol].decimals]) / 1000n, + (3n * BI_POWS[tokens[srcTokenSymbol].decimals]) / 1000n, + (4n * BI_POWS[tokens[srcTokenSymbol].decimals]) / 1000n, + (5n * BI_POWS[tokens[srcTokenSymbol].decimals]) / 1000n, + (6n * BI_POWS[tokens[srcTokenSymbol].decimals]) / 1000n, + (7n * BI_POWS[tokens[srcTokenSymbol].decimals]) / 1000n, + (8n * BI_POWS[tokens[srcTokenSymbol].decimals]) / 1000n, + (9n * BI_POWS[tokens[srcTokenSymbol].decimals]) / 1000n, + (10n * BI_POWS[tokens[srcTokenSymbol].decimals]) / 1000n, + ]; + + const amountsForBuy = [ + 0n, + (1n * BI_POWS[tokens[destTokenSymbol].decimals]) / 1000n, + (2n * BI_POWS[tokens[destTokenSymbol].decimals]) / 1000n, + (3n * BI_POWS[tokens[destTokenSymbol].decimals]) / 1000n, + (4n * BI_POWS[tokens[destTokenSymbol].decimals]) / 1000n, + (5n * BI_POWS[tokens[destTokenSymbol].decimals]) / 1000n, + (6n * BI_POWS[tokens[destTokenSymbol].decimals]) / 1000n, + (7n * BI_POWS[tokens[destTokenSymbol].decimals]) / 1000n, + (8n * BI_POWS[tokens[destTokenSymbol].decimals]) / 1000n, + (9n * BI_POWS[tokens[destTokenSymbol].decimals]) / 1000n, + (10n * BI_POWS[tokens[destTokenSymbol].decimals]) / 1000n, + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + balancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (balancerV3.initializePricing) { + await balancerV3.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.SELL, + amountsForSell, + ); + }); - if (!newBalancerV3.hasConstantPriceLargeAmounts) { - checkPoolsLiquidity( - poolLiquidity, - Tokens[network][srcTokenSymbol].address, + // TODO 1 WEI rounding issue in maths - investigating + it('getPoolIdentifiers and getPricesVolume BUY', async function () { + await testPricingOnNetwork( + balancerV3, + network, dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.BUY, + amountsForBuy, + ); + }); + + it('getTopPoolsForToken', async function () { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newBalancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (newBalancerV3.updatePoolState) { + await newBalancerV3.updatePoolState(); + } + const poolLiquidity = await newBalancerV3.getTopPoolsForToken( + tokens[srcTokenSymbol].address, + 10, ); - } + + console.log(`${srcTokenSymbol} Top Pools:`, poolLiquidity); + + if (!newBalancerV3.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity( + poolLiquidity, + Tokens[network][srcTokenSymbol].address, + dexKey, + ); + } + }); }); }); }); diff --git a/src/dex/balancer-v3/config.ts b/src/dex/balancer-v3/config.ts index 3a51112d6..6829d440a 100644 --- a/src/dex/balancer-v3/config.ts +++ b/src/dex/balancer-v3/config.ts @@ -10,7 +10,7 @@ export enum SUPPORTED_POOLS { export const disabledPoolIds: Record> = { BalancerV3: { - [Network.SEPOLIA]: ['0x0d7291d8bdc6b376aadacbf05b1ef8a8292ef58a'], // incorrect token rate config for 0x978206fae13faf5a8d293fb614326b237684b750 token + [Network.SEPOLIA]: [], // incorrect token rate config for 0x978206fae13faf5a8d293fb614326b237684b750 token }, }; @@ -26,5 +26,11 @@ export const BalancerV3Config: DexConfigMap = { balancerRouterAddress: '0x0BF61f706105EA44694f2e92986bD01C39930280', balancerBatchRouterAddress: '0xC85b652685567C1B074e8c0D4389f83a2E458b1C', }, + [Network.GNOSIS]: { + vaultAddress: '0xbA1333333333a1BA1108E8412f11850A5C319bA9', + apiNetworkName: 'GNOSIS', + balancerRouterAddress: '0x84813aA3e079A665C0B80F944427eE83cBA63617', + balancerBatchRouterAddress: '0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b', + }, }, }; From 028decb1acb11fb7373da361202294c41fc49fd0 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 13:12:57 +0200 Subject: [PATCH 49/66] feat: integrated Mainnet on balancer-v3 --- src/dex/balancer-v3/config.ts | 6 ++++++ tests/constants-e2e.ts | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/dex/balancer-v3/config.ts b/src/dex/balancer-v3/config.ts index 6829d440a..1a9f65b56 100644 --- a/src/dex/balancer-v3/config.ts +++ b/src/dex/balancer-v3/config.ts @@ -32,5 +32,11 @@ export const BalancerV3Config: DexConfigMap = { balancerRouterAddress: '0x84813aA3e079A665C0B80F944427eE83cBA63617', balancerBatchRouterAddress: '0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b', }, + [Network.MAINNET]: { + vaultAddress: '0xbA1333333333a1BA1108E8412f11850A5C319bA9', + apiNetworkName: 'MAINNET', + balancerRouterAddress: '0x5C6fb490BDFD3246EB0bB062c168DeCAF4bD9FDd', + balancerBatchRouterAddress: '0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1', + }, }, }; diff --git a/tests/constants-e2e.ts b/tests/constants-e2e.ts index 90ff2d221..a924a7192 100644 --- a/tests/constants-e2e.ts +++ b/tests/constants-e2e.ts @@ -1480,10 +1480,18 @@ export const Tokens: { address: '0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83', decimals: 6, }, + USDCe: { + address: '0x2a22f9c3b484c3629090feed35f17ff8f88f76f0', + decimals: 6, + }, USDT: { address: '0x4ECaBa5870353805a9F068101A40E0f32ed605C6', decimals: 6, }, + COW: { + address: '0x177127622c4A00F3d409B75571e12cB3c8973d3c', + decimals: 18, + }, WXDAI: { address: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d', decimals: 18, @@ -1492,10 +1500,18 @@ export const Tokens: { address: '0xa818f1b57c201e092c4a2017a91815034326efd1', decimals: 18, }, + waGnoWETH: { + address: '0x57f664882F762FA37903FC864e2B633D384B411A', + decimals: 18, + }, aGnowstETH: { address: '0x23e4e76d01b2002be436ce8d6044b0aa2f68b68a', decimals: 18, }, + waGnowstETH: { + address: '0x773CDA0CADe2A3d86E6D4e30699d40bB95174ff2', + decimals: 18, + }, aGnoUSDC: { address: '0xc6b7aca6de8a6044e0e32d0c841a89244a10d284', decimals: 6, @@ -1995,6 +2011,7 @@ export const Holders: { USDC: '0x99b31498b0a1dae01fc3433e3cb60f095340935c', }, [Network.GNOSIS]: { + COW: '0x4fFAD6ac852c0Af0AA301376F4C5Dea3a928b120', XDAI: '0x9fc062032d4F2Fe7dAA601bd8B06C45F9c8f17Be', WXDAI: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', WETH: '0x800e12aF6c96790EDDdc5B3f3302899e27B2A918', @@ -2006,8 +2023,11 @@ export const Holders: { wstETH: '0x458cD345B4C05e8DF39d0A07220feb4Ec19F5e6f', aGnowstETH: '0x458cD345B4C05e8DF39d0A07220feb4Ec19F5e6f', sDAI: '0x79f08F2e75A8C99428DE4A2e6456c07C99E55da5', + USDCe: '0x555CE236C0220695b68341bc48C68d52210cC35b', crvUSD: '0xE4A982fa1f1E8AD1AF238A7b1226b13b56bf5CcD', SWPR: '0x9467dcFD4519287e3878C018c02f5670465a9003', + waGnoWETH: '0x854B004700885A61107B458f11eCC169A019b764', + waGnowstETH: '0x854B004700885A61107B458f11eCC169A019b764', }, [Network.BASE]: { WETH: '0x4bb6b2efe7036020ba6f02a05602546c9f25bf28', From 889bd80bd41a561259c3b61d8243d177638f7f6e Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 13:14:39 +0200 Subject: [PATCH 50/66] chore: comment console logs --- src/dex/balancer-v3/getPoolsApi.ts | 2 +- src/dex/balancer-v3/getTopPoolsApi.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dex/balancer-v3/getPoolsApi.ts b/src/dex/balancer-v3/getPoolsApi.ts index ba3bce72f..4056bf802 100644 --- a/src/dex/balancer-v3/getPoolsApi.ts +++ b/src/dex/balancer-v3/getPoolsApi.ts @@ -123,7 +123,7 @@ export async function getPoolsApi( const pools = response.data.data.poolGetAggregatorPools; return toImmutablePoolStateMap(pools); } catch (error) { - console.error('Error executing GraphQL query:', error); + // console.error('Error executing GraphQL query:', error); throw error; } } diff --git a/src/dex/balancer-v3/getTopPoolsApi.ts b/src/dex/balancer-v3/getTopPoolsApi.ts index a89d9a871..701b82f59 100644 --- a/src/dex/balancer-v3/getTopPoolsApi.ts +++ b/src/dex/balancer-v3/getTopPoolsApi.ts @@ -90,7 +90,7 @@ export async function getTopPoolsApi( const pools = response.data.data.poolGetAggregatorPools; return pools; } catch (error) { - console.error('Error executing GraphQL query:', error); + // console.error('Error executing GraphQL query:', error); throw error; } } From 268b19e657054a03bedfd6509bdf3b15d9f3dc59 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 14:03:09 +0200 Subject: [PATCH 51/66] fix: temporary replace @balancer-labs/balancer-maths with @paraswap/balancer-maths --- package.json | 2 +- src/dex/balancer-v3/balancer-v3-pool.ts | 2 +- src/dex/balancer-v3/balancer-v3.ts | 3 ++- src/dex/balancer-v3/stablePool.ts | 2 +- src/dex/balancer-v3/types.ts | 2 +- yarn.lock | 10 +++++----- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index c960fef77..84c30babf 100644 --- a/package.json +++ b/package.json @@ -52,12 +52,12 @@ }, "dependencies": { "@0x/utils": "^4.5.2", - "@balancer-labs/balancer-maths": "^0.0.19", "@balancer-labs/sor": "4.1.1-beta.4", "@bgd-labs/aave-address-book": "2.21.1", "@ethersproject/abi": "^5.7.0", "@hashflow/sdk": "^2.2.7", "@hashflow/taker-js": "^0.3.7", + "@paraswap/balancer-maths": "0.0.1", "@paraswap/core": "2.4.0", "@types/ws": "^8.5.12", "async": "^3.2.4", diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 8d7daccf4..9736f0497 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -16,7 +16,7 @@ import { getPoolsApi } from './getPoolsApi'; import vaultExtensionAbi_V3 from '../../abi/balancer-v3/vault-extension.json'; import { decodeThrowError, getOnChainState } from './getOnChainState'; import { BalancerV3Config } from './config'; -import { SwapKind, Vault } from '@balancer-labs/balancer-maths'; +import { SwapKind, Vault } from '@paraswap/balancer-maths'; import { ampUpdateStartedEvent, ampUpdateStoppedEvent, diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 0bb27f3d5..3730bf40b 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -19,7 +19,8 @@ import { SimpleExchange } from '../simple-exchange'; import { BalancerV3Config } from './config'; import { BalancerV3EventPool } from './balancer-v3-pool'; import { NumberAsString } from '@paraswap/core'; -import { SwapKind } from '@balancer-labs/balancer-maths'; +// TODO: replace @paraswap/balancer-maths to @balancer-labs/balancer-maths after node migration +import { SwapKind } from '@paraswap/balancer-maths'; import { Interface } from '@ethersproject/abi'; import { extractReturnAmountPosition } from '../../executor/utils'; import { getTopPoolsApi } from './getTopPoolsApi'; diff --git a/src/dex/balancer-v3/stablePool.ts b/src/dex/balancer-v3/stablePool.ts index 1800d38b2..81f532d8e 100644 --- a/src/dex/balancer-v3/stablePool.ts +++ b/src/dex/balancer-v3/stablePool.ts @@ -1,5 +1,5 @@ import { defaultAbiCoder } from '@ethersproject/abi'; -import { PoolState } from '@balancer-labs/balancer-maths'; +import { PoolState } from '@paraswap/balancer-maths'; import { StableMutableState } from './types'; // TODO - Update with more accurate diff --git a/src/dex/balancer-v3/types.ts b/src/dex/balancer-v3/types.ts index dc803977e..f31dec4ee 100644 --- a/src/dex/balancer-v3/types.ts +++ b/src/dex/balancer-v3/types.ts @@ -1,4 +1,4 @@ -import { BufferState } from '@balancer-labs/balancer-maths'; +import { BufferState } from '@paraswap/balancer-maths'; import { Address } from '../../types'; // Immutable data types available on all pools (Available from API) diff --git a/yarn.lock b/yarn.lock index cb6b0907f..13f24f7f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -348,11 +348,6 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@balancer-labs/balancer-maths@^0.0.19": - version "0.0.19" - resolved "https://registry.yarnpkg.com/@balancer-labs/balancer-maths/-/balancer-maths-0.0.19.tgz#d3b92c4b17caca67894806bd7768af1ea31cb956" - integrity sha512-x8t17q8fbXYZJSaidr4BWBg3O9jVnF6xoAsoMWWyUd6AnaxPyFnxAGs76+iQln4WEmC7S5G5uufWJ0OefvcqXQ== - "@balancer-labs/sor@4.1.1-beta.4": version "4.1.1-beta.4" resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.1.1-beta.4.tgz#9369435f8bbc781e9048f33aa496a484631b56e9" @@ -1219,6 +1214,11 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.5.tgz#1eed23d4844c861a1835b5d33507c1017fa98de8" integrity sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg== +"@paraswap/balancer-maths@0.0.1": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@paraswap/balancer-maths/-/balancer-maths-0.0.1.tgz#592c07db9c65f1b08fbd12461ed60395962c166e" + integrity sha512-cjflViyZTo2p0OnDqnBCKPTdTXP0Cah/6kORseNVNxOnkno8pcaCrcZC3yVTJ7ofe9lGDCAZV5/IvS+OSzDIHg== + "@paraswap/core@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@paraswap/core/-/core-2.2.0.tgz#848175c7729f1064e715019269b1c193a23a5be8" From e50cf882f38edf6d000bf6e6368c42e0c80e04c6 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 16:59:15 +0200 Subject: [PATCH 52/66] fix: temporary disable pools with nested rate on bal-v3 --- src/dex/balancer-v3/balancer-v3-pool.ts | 1 + src/dex/balancer-v3/config.ts | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 9736f0497..61094eb27 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -629,6 +629,7 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { }, poolState: { poolType: 'Buffer', + // TODO: for ERC4626 fetch the wrap/unwrap rate rate: token.rate, poolAddress: token.mainToken, tokens: [token.mainToken, token.underlyingToken], // staticToken & underlying diff --git a/src/dex/balancer-v3/config.ts b/src/dex/balancer-v3/config.ts index 1a9f65b56..d670beac1 100644 --- a/src/dex/balancer-v3/config.ts +++ b/src/dex/balancer-v3/config.ts @@ -10,7 +10,11 @@ export enum SUPPORTED_POOLS { export const disabledPoolIds: Record> = { BalancerV3: { - [Network.SEPOLIA]: [], // incorrect token rate config for 0x978206fae13faf5a8d293fb614326b237684b750 token + [Network.GNOSIS]: [ + // pools with rate provider that returns nested rate instead of wrap/unwrap rate + '0x6e6bb18449fcf15b79efa2cfa70acf7593088029', + '0x272d6be442e30d7c87390edeb9b96f1e84cecd8d', + ], }, }; From f51155dd6dcae654cb6d14e199f0ee21d736f71b Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 21:32:44 +0200 Subject: [PATCH 53/66] Revert "fix: temporary replace @balancer-labs/balancer-maths with @paraswap/balancer-maths" This reverts commit 268b19e657054a03bedfd6509bdf3b15d9f3dc59. --- package.json | 2 +- src/dex/balancer-v3/balancer-v3-pool.ts | 2 +- src/dex/balancer-v3/balancer-v3.ts | 3 +-- src/dex/balancer-v3/stablePool.ts | 2 +- src/dex/balancer-v3/types.ts | 2 +- yarn.lock | 10 +++++----- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 4e4eb7655..38b4127f3 100644 --- a/package.json +++ b/package.json @@ -52,12 +52,12 @@ }, "dependencies": { "@0x/utils": "^4.5.2", + "@balancer-labs/balancer-maths": "^0.0.19", "@balancer-labs/sor": "4.1.1-beta.4", "@bgd-labs/aave-address-book": "2.21.1", "@ethersproject/abi": "^5.7.0", "@hashflow/sdk": "^2.2.7", "@hashflow/taker-js": "^0.3.7", - "@paraswap/balancer-maths": "0.0.1", "@paraswap/core": "2.4.0", "@types/ws": "^8.5.12", "async": "^3.2.4", diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 61094eb27..28af50f21 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -16,7 +16,7 @@ import { getPoolsApi } from './getPoolsApi'; import vaultExtensionAbi_V3 from '../../abi/balancer-v3/vault-extension.json'; import { decodeThrowError, getOnChainState } from './getOnChainState'; import { BalancerV3Config } from './config'; -import { SwapKind, Vault } from '@paraswap/balancer-maths'; +import { SwapKind, Vault } from '@balancer-labs/balancer-maths'; import { ampUpdateStartedEvent, ampUpdateStoppedEvent, diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 3730bf40b..0bb27f3d5 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -19,8 +19,7 @@ import { SimpleExchange } from '../simple-exchange'; import { BalancerV3Config } from './config'; import { BalancerV3EventPool } from './balancer-v3-pool'; import { NumberAsString } from '@paraswap/core'; -// TODO: replace @paraswap/balancer-maths to @balancer-labs/balancer-maths after node migration -import { SwapKind } from '@paraswap/balancer-maths'; +import { SwapKind } from '@balancer-labs/balancer-maths'; import { Interface } from '@ethersproject/abi'; import { extractReturnAmountPosition } from '../../executor/utils'; import { getTopPoolsApi } from './getTopPoolsApi'; diff --git a/src/dex/balancer-v3/stablePool.ts b/src/dex/balancer-v3/stablePool.ts index 81f532d8e..1800d38b2 100644 --- a/src/dex/balancer-v3/stablePool.ts +++ b/src/dex/balancer-v3/stablePool.ts @@ -1,5 +1,5 @@ import { defaultAbiCoder } from '@ethersproject/abi'; -import { PoolState } from '@paraswap/balancer-maths'; +import { PoolState } from '@balancer-labs/balancer-maths'; import { StableMutableState } from './types'; // TODO - Update with more accurate diff --git a/src/dex/balancer-v3/types.ts b/src/dex/balancer-v3/types.ts index f31dec4ee..dc803977e 100644 --- a/src/dex/balancer-v3/types.ts +++ b/src/dex/balancer-v3/types.ts @@ -1,4 +1,4 @@ -import { BufferState } from '@paraswap/balancer-maths'; +import { BufferState } from '@balancer-labs/balancer-maths'; import { Address } from '../../types'; // Immutable data types available on all pools (Available from API) diff --git a/yarn.lock b/yarn.lock index 5f782bfaa..ba5b0cc5c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -348,6 +348,11 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@balancer-labs/balancer-maths@^0.0.19": + version "0.0.19" + resolved "https://registry.yarnpkg.com/@balancer-labs/balancer-maths/-/balancer-maths-0.0.19.tgz#d3b92c4b17caca67894806bd7768af1ea31cb956" + integrity sha512-x8t17q8fbXYZJSaidr4BWBg3O9jVnF6xoAsoMWWyUd6AnaxPyFnxAGs76+iQln4WEmC7S5G5uufWJ0OefvcqXQ== + "@balancer-labs/sor@4.1.1-beta.4": version "4.1.1-beta.4" resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.1.1-beta.4.tgz#9369435f8bbc781e9048f33aa496a484631b56e9" @@ -1226,11 +1231,6 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.5.tgz#1eed23d4844c861a1835b5d33507c1017fa98de8" integrity sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg== -"@paraswap/balancer-maths@0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@paraswap/balancer-maths/-/balancer-maths-0.0.1.tgz#592c07db9c65f1b08fbd12461ed60395962c166e" - integrity sha512-cjflViyZTo2p0OnDqnBCKPTdTXP0Cah/6kORseNVNxOnkno8pcaCrcZC3yVTJ7ofe9lGDCAZV5/IvS+OSzDIHg== - "@paraswap/core@2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@paraswap/core/-/core-2.2.0.tgz#848175c7729f1064e715019269b1c193a23a5be8" From 5d174ac18184e88d83da5fcf2adda23ce8061a53 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 21:38:17 +0200 Subject: [PATCH 54/66] fix: use nodejs timeout for balancer-v3 intervals --- src/dex/balancer-v3/balancer-v3.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 0bb27f3d5..c93ff1467 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -51,8 +51,8 @@ export class BalancerV3 extends SimpleExchange implements IDex { logger: Logger; balancerRouter: Interface; balancerBatchRouter: Interface; - updateNewPoolsTimer?: NodeJS.Timer; - updateRatesTimer?: NodeJS.Timer; + updateNewPoolsTimer?: NodeJS.Timeout; + updateRatesTimer?: NodeJS.Timeout; constructor( readonly network: Network, From d1d71630c2e5c275062805ca1f2b9a5583357682 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 21:45:31 +0200 Subject: [PATCH 55/66] 4.0.1-balancer-v3-cables.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 38b4127f3..ebe605dac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@paraswap/dex-lib", - "version": "4.0.0", + "version": "4.0.1-balancer-v3-cables.0", "main": "build/index.js", "types": "build/index.d.ts", "repository": "https://github.com/paraswap/paraswap-dex-lib", From dab1ca56f407472815d98726388f42b6385dd5c0 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 21:58:21 +0200 Subject: [PATCH 56/66] feat: ignore disabled pools in getTopPools on bal-v3 --- src/dex/balancer-v3/getTopPoolsApi.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dex/balancer-v3/getTopPoolsApi.ts b/src/dex/balancer-v3/getTopPoolsApi.ts index 701b82f59..26db2d0ba 100644 --- a/src/dex/balancer-v3/getTopPoolsApi.ts +++ b/src/dex/balancer-v3/getTopPoolsApi.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import { apiUrl, BalancerV3Config } from './config'; +import { apiUrl, BalancerV3Config, disabledPoolIds } from './config'; interface PoolToken { address: string; @@ -29,6 +29,10 @@ function createQuery( poolsFilter: string[], count: number, ): string { + const disabledPoolIdsString = disabledPoolIds.BalancerV3[networkId] + ?.map(p => `"${p}"`) + .join(', '); + const networkString = BalancerV3Config.BalancerV3[networkId].apiNetworkName; const poolIdString = poolsFilter.map(a => `"${a}"`).join(', '); // Build the where clause conditionally @@ -37,6 +41,7 @@ function createQuery( protocolVersionIn: 3, hasHook: false, idIn: `[${poolIdString}]`, + ...(disabledPoolIdsString && { idNotIn: `[${disabledPoolIdsString}]` }), }; // Convert where clause to string, filtering out undefined values From c57a724158a8a96c9867e0d6e650f5e209e9929e Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 22:16:08 +0200 Subject: [PATCH 57/66] fix: wrap ETH for batch swap on bal-v3 --- src/dex/balancer-v3/balancer-v3.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index c93ff1467..760999fc5 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -368,7 +368,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { [ [ { - tokenIn: srcToken, + tokenIn: this.dexHelper.config.wrapETH(srcToken), steps: data.steps.map(step => ({ pool: step.pool, tokenOut: step.swapInput.tokenOut, @@ -438,7 +438,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { [ [ { - tokenIn: srcToken, + tokenIn: this.dexHelper.config.wrapETH(srcToken), steps: data.steps.map(step => ({ pool: step.pool, tokenOut: step.swapInput.tokenOut, From b40c84a20a9fa56986ffb26eb189c09a6e740f73 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Wed, 11 Dec 2024 22:16:47 +0200 Subject: [PATCH 58/66] 4.0.1-balancer-v3-cables.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ebe605dac..97ddfcf97 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@paraswap/dex-lib", - "version": "4.0.1-balancer-v3-cables.0", + "version": "4.0.1-balancer-v3-cables.1", "main": "build/index.js", "types": "build/index.d.ts", "repository": "https://github.com/paraswap/paraswap-dex-lib", From 403012c1a357d89649dba81b49caad47d89c4d41 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Thu, 12 Dec 2024 11:17:12 +0200 Subject: [PATCH 59/66] feat: add getCalldataGasCost on bal-v3 --- src/dex/balancer-v3/balancer-v3.ts | 60 +++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 760999fc5..abe3910c0 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -291,8 +291,64 @@ export class BalancerV3 extends SimpleExchange implements IDex { getCalldataGasCost( poolPrices: PoolPrices, ): number | number[] { - // TODO: update if there is any payload in getAdapterParam - return CALLDATA_GAS_COST.DEX_NO_PAYLOAD; + if (poolPrices.data.steps.length === 1) { + return ( + CALLDATA_GAS_COST.DEX_OVERHEAD + + // pool + CALLDATA_GAS_COST.ADDRESS + + // tokenIn + CALLDATA_GAS_COST.ADDRESS + + // tokenOut + CALLDATA_GAS_COST.ADDRESS + + // exactAmountOut + CALLDATA_GAS_COST.AMOUNT + + // maxAmountIn + CALLDATA_GAS_COST.AMOUNT + + // deadline + CALLDATA_GAS_COST.TIMESTAMP + + // wethIsEth + CALLDATA_GAS_COST.BOOL + + // userData + CALLDATA_GAS_COST.FULL_WORD + ); + } + + return ( + CALLDATA_GAS_COST.DEX_OVERHEAD + + CALLDATA_GAS_COST.LENGTH_LARGE + + // ParentStruct header + CALLDATA_GAS_COST.OFFSET_SMALL + + // ParentStruct -> paths[] header + CALLDATA_GAS_COST.OFFSET_LARGE + + // ParentStruct -> paths[] + CALLDATA_GAS_COST.LENGTH_SMALL + + // ParentStruct -> paths header + CALLDATA_GAS_COST.OFFSET_SMALL + + // ParentStruct -> paths -> exactAmountIn + CALLDATA_GAS_COST.AMOUNT + + // ParentStruct -> paths -> minAmountOut + CALLDATA_GAS_COST.AMOUNT + + // ParentStruct -> paths -> tokenIn + CALLDATA_GAS_COST.ADDRESS + + poolPrices.data.steps.reduce(step => { + return ( + // ParentStruct -> paths -> step header + CALLDATA_GAS_COST.OFFSET_SMALL + + // ParentStruct -> paths -> step -> isBuffer + CALLDATA_GAS_COST.BOOL + + // ParentStruct -> paths -> step -> pool + CALLDATA_GAS_COST.ADDRESS + + // ParentStruct -> paths -> step -> tokenOut + CALLDATA_GAS_COST.ADDRESS + ); + }, 0) + + // deadline + CALLDATA_GAS_COST.TIMESTAMP + + // wethIsEth + CALLDATA_GAS_COST.BOOL + + // userData + CALLDATA_GAS_COST.FULL_WORD + ); } // Not used for V6 From f1e850fed26580eb3d1dd13817e73267df21b78a Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Thu, 12 Dec 2024 12:11:30 +0200 Subject: [PATCH 60/66] test: make approval for v5 only if v5 is supported --- tests/utils-e2e.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/utils-e2e.ts b/tests/utils-e2e.ts index 8c448bcae..a0343d057 100644 --- a/tests/utils-e2e.ts +++ b/tests/utils-e2e.ts @@ -397,15 +397,18 @@ export async function testE2E( await ts.setup(); if (srcToken.address.toLowerCase() !== ETHER_ADDRESS.toLowerCase()) { - const allowanceTx = await ts.simulate( - allowTokenTransferProxyParams(srcToken.address, senderAddress, network), - ); + // check if v5 is available in the config + if (generateConfig(network).tokenTransferProxyAddress !== NULL_ADDRESS) { + const allowanceTx = await ts.simulate( + allowTokenTransferProxyParams(srcToken.address, senderAddress, network), + ); + if (!allowanceTx.success) console.log(allowanceTx.url); + expect(allowanceTx!.success).toEqual(true); + } const augustusV6Allowance = await ts.simulate( allowAugustusV6(srcToken.address, senderAddress, network), ); - if (!allowanceTx.success) console.log(allowanceTx.url); if (!augustusV6Allowance.success) console.log(augustusV6Allowance.url); - expect(allowanceTx!.success).toEqual(true); expect(augustusV6Allowance!.success).toEqual(true); } From 1b4f611875e4573e0e547e1ef65f7bc4e6441785 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 12 Dec 2024 11:00:13 +0000 Subject: [PATCH 61/66] fix: Correctly handle single step buffer encoding. Use lowercase compare. --- src/dex/balancer-v3/balancer-v3-pool.ts | 8 ++++++-- src/dex/balancer-v3/balancer-v3.ts | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 28af50f21..6b6e97575 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -561,7 +561,9 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { this.getUnwrapStep(tokenOut), ]; } else if (tokenIn.isBoosted) { - if (tokenIn.mainToken === tokenOut.mainToken) { + if ( + tokenIn.mainToken.toLowerCase() === tokenOut.mainToken.toLowerCase() + ) { // wrap, token > erc4626 // tokenIn is boosted, e.g. isn't pool token and must be wrapped return [this.getWrapStep(tokenIn)]; @@ -573,7 +575,9 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { this.getSwapStep(pool, tokenIn, tokenOut), ]; } else if (tokenOut.isBoosted) { - if (tokenIn.mainToken === tokenOut.mainToken) { + if ( + tokenIn.mainToken.toLowerCase() === tokenOut.mainToken.toLowerCase() + ) { // unwrap, stata > token // token out is boosted, e.g. isn't pool token return [this.getUnwrapStep(tokenOut)]; diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index abe3910c0..2c1d4f1bb 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -388,7 +388,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { srcAmount: NumberAsString, data: BalancerV3Data, ): DexExchangeParam { - if (data.steps.length === 1) { + if (data.steps.length === 1 && !data.steps[0].isBuffer) { const exchangeData = this.balancerRouter.encodeFunctionData( 'swapSingleTokenExactIn', [ @@ -460,7 +460,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { destAmount: NumberAsString, data: BalancerV3Data, ): DexExchangeParam { - if (data.steps.length === 1) { + if (data.steps.length === 1 && !data.steps[0].isBuffer) { const exchangeData = this.balancerRouter.encodeFunctionData( 'swapSingleTokenExactOut', [ From c48fb5fb656e7291f036d69d55c96b197c37a156 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Thu, 12 Dec 2024 13:17:38 +0200 Subject: [PATCH 62/66] fix: consider first step isBuffer for calldataGasCost --- src/dex/balancer-v3/balancer-v3.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 2c1d4f1bb..97c50e97f 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -291,7 +291,10 @@ export class BalancerV3 extends SimpleExchange implements IDex { getCalldataGasCost( poolPrices: PoolPrices, ): number | number[] { - if (poolPrices.data.steps.length === 1) { + if ( + poolPrices.data.steps.length === 1 && + !poolPrices.data.steps[0].isBuffer + ) { return ( CALLDATA_GAS_COST.DEX_OVERHEAD + // pool From 9aaf07e3a74d2f8c3f3248bfd0d9269258b0affe Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Thu, 12 Dec 2024 13:18:17 +0200 Subject: [PATCH 63/66] fix: insert fromAmount for eth case --- src/dex/balancer-v3/balancer-v3.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 97c50e97f..1fd9d9e9b 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -406,6 +406,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ], ); return { + sendEthButSupportsInsertFromAmount: true, permit2Approval: true, needWrapNative: this.needWrapNative, dexFuncHasRecipient: false, @@ -444,6 +445,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ); return { + sendEthButSupportsInsertFromAmount: true, permit2Approval: true, needWrapNative: this.needWrapNative, dexFuncHasRecipient: false, @@ -479,6 +481,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ); return { + sendEthButSupportsInsertFromAmount: true, permit2Approval: true, needWrapNative: this.needWrapNative, dexFuncHasRecipient: false, @@ -514,6 +517,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { ); return { + sendEthButSupportsInsertFromAmount: true, permit2Approval: true, needWrapNative: this.needWrapNative, dexFuncHasRecipient: false, From 9a6d6a786cf56899292d32c949298e7e0cc9344c Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Thu, 12 Dec 2024 13:20:41 +0200 Subject: [PATCH 64/66] 4.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 97ddfcf97..ebd082810 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@paraswap/dex-lib", - "version": "4.0.1-balancer-v3-cables.1", + "version": "4.0.1", "main": "build/index.js", "types": "build/index.d.ts", "repository": "https://github.com/paraswap/paraswap-dex-lib", From 7cfdd5886f305b7e6a59f5c8e2cc1d5c88e517c4 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Thu, 12 Dec 2024 13:31:03 +0200 Subject: [PATCH 65/66] feat: add caching for get latest block --- src/dex/balancer-v3/balancer-v3.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index 1fd9d9e9b..fb1ecfbb3 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -26,6 +26,7 @@ import { getTopPoolsApi } from './getTopPoolsApi'; import balancerRouterAbi from '../../abi/balancer-v3/router.json'; import balancerBatchRouterAbi from '../../abi/balancer-v3/batch-router.json'; import { getGasCost } from './getGasCost'; +import { Block } from '@ethersproject/abstract-provider'; const MAX_UINT256 = '115792089237316195423570985008687907853269984665640564039457584007913129639935'; @@ -54,6 +55,8 @@ export class BalancerV3 extends SimpleExchange implements IDex { updateNewPoolsTimer?: NodeJS.Timeout; updateRatesTimer?: NodeJS.Timeout; + latestBlock?: Block; + constructor( readonly network: Network, readonly dexKey: string, @@ -126,6 +129,16 @@ export class BalancerV3 extends SimpleExchange implements IDex { ); } + async getBlock(blockNumber: number): Promise { + if (this.latestBlock && this.latestBlock.number === blockNumber) { + return this.latestBlock; + } + + const block = await this.dexHelper.provider.getBlock(blockNumber); + this.latestBlock = block; + return block; + } + findPoolAddressesWithTokens( pools: DeepReadonly, tokenA: string, @@ -188,7 +201,7 @@ export class BalancerV3 extends SimpleExchange implements IDex { } // This is used to get block timestamp which is needed to calculate Amp if it is updating - const block = await this.dexHelper.provider.getBlock(blockNumber); + const block = await this.getBlock(blockNumber); // get up to date pools and state const allPoolState = this.eventPools.getState(blockNumber); From a1d5190bdaf80da0ce2afabaaebcde3bdab24d56 Mon Sep 17 00:00:00 2001 From: Danylo Kanievskyi Date: Thu, 12 Dec 2024 13:31:56 +0200 Subject: [PATCH 66/66] 4.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ebd082810..cdb086212 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@paraswap/dex-lib", - "version": "4.0.1", + "version": "4.0.2", "main": "build/index.js", "types": "build/index.d.ts", "repository": "https://github.com/paraswap/paraswap-dex-lib",