diff --git a/balancer-js/examples/data/pool-subgraph.ts b/balancer-js/examples/data/pool-subgraph.ts index 1e11898ea..f5c0f22dd 100644 --- a/balancer-js/examples/data/pool-subgraph.ts +++ b/balancer-js/examples/data/pool-subgraph.ts @@ -9,6 +9,9 @@ const pools = new PoolsSubgraphRepository({ isInRecoveryMode: { eq: true, }, + isPaused: { + eq: true, + }, }, }, attrs: {}, diff --git a/balancer-js/examples/exitGeneralised.ts b/balancer-js/examples/exitGeneralised.ts index c8cf11e82..718a93c8c 100644 --- a/balancer-js/examples/exitGeneralised.ts +++ b/balancer-js/examples/exitGeneralised.ts @@ -146,7 +146,7 @@ const exit = async () => { provider ); const relayerAuth = await Relayer.signRelayerApproval( - contractAddresses.relayerV5 as string, + contractAddresses.relayer, signerAddress, signer, contracts.vault diff --git a/balancer-js/examples/joinGeneralised.ts b/balancer-js/examples/joinGeneralised.ts index 20ab30141..cf03229da 100644 --- a/balancer-js/examples/joinGeneralised.ts +++ b/balancer-js/examples/joinGeneralised.ts @@ -164,7 +164,7 @@ async function join() { provider ); const authorisation = await Relayer.signRelayerApproval( - contractAddresses.relayerV5 as string, + contractAddresses.relayer, signerAddress, signer, contracts.vault diff --git a/balancer-js/examples/joinGeneralisedComposableStable.ts b/balancer-js/examples/joinGeneralisedComposableStable.ts index 5c37cecc4..54898a1e2 100644 --- a/balancer-js/examples/joinGeneralisedComposableStable.ts +++ b/balancer-js/examples/joinGeneralisedComposableStable.ts @@ -56,7 +56,7 @@ const balancer = new BalancerSDK({ }, }); -const { provider, contracts, balancerContracts } = balancer; +const { provider, contracts } = balancer; const { ERC20 } = contracts; const signer = (provider as JsonRpcProvider).getSigner(); @@ -98,12 +98,12 @@ async function join() { const signerAddress = await signer.getAddress(); await getTokens(signerAddress); - const relayerAddress = balancerContracts.relayerV5?.address as string; + const relayerAddress = contracts.relayer.address as string; console.log('Relayer address:', relayerAddress); // Need to sign the approval only once per relayer const relayerAuth = await Relayer.signRelayerApproval( - relayerAddress, + contracts.relayer.address, signerAddress, signer, contracts.vault diff --git a/balancer-js/examples/pools/queries.ts b/balancer-js/examples/pools/queries.ts index 89e2728e4..c2f771b06 100644 --- a/balancer-js/examples/pools/queries.ts +++ b/balancer-js/examples/pools/queries.ts @@ -13,7 +13,10 @@ const sdk = new BalancerSDK({ rpcUrl: 'https://eth-rpc.gateway.pokt.network', }); -const { pools, balancerContracts: contracts } = sdk; +const { + pools, + balancerContracts: { contracts }, +} = sdk; // Joining with a single token const queryJoin = async (pool: PoolWithMethods) => { diff --git a/balancer-js/examples/swapQuery.ts b/balancer-js/examples/swapQuery.ts index ecee01472..7c5f9b912 100644 --- a/balancer-js/examples/swapQuery.ts +++ b/balancer-js/examples/swapQuery.ts @@ -9,13 +9,13 @@ import { ADDRESSES } from '../src/test/lib/constants'; dotenv.config(); -const network = Network.POLYGON; -// const rpcUrl = `https://mainnet.infura.io/v3/${process.env.INFURA}`; -const rpcUrl = `https://polygon-mainnet.infura.io/v3/${process.env.INFURA}`; +const network = Network.MAINNET; +const rpcUrl = `https://mainnet.infura.io/v3/${process.env.INFURA}`; +// const rpcUrl = `https://polygon-mainnet.infura.io/v3/${process.env.INFURA}`; const tokenIn = ADDRESSES[network].DAI.address; const tokenOut = ADDRESSES[network].USDC.address; const swapType = SwapTypes.SwapExactIn; -const amount = parseFixed('1', 18); +const amount = parseFixed('100', 18); async function swap() { const balancer = new BalancerSDK({ diff --git a/balancer-js/examples/swapSor.ts b/balancer-js/examples/swapSor.ts index 61c67ad91..64a96b49d 100644 --- a/balancer-js/examples/swapSor.ts +++ b/balancer-js/examples/swapSor.ts @@ -63,7 +63,7 @@ async function getAndProcessSwaps( swapInfo, pools, wallet.address, - balancer.contracts.relayerV3!.address, + balancer.contracts.relayer.address, balancer.networkConfig.addresses.tokens.wrappedNativeAsset, slippage, undefined @@ -73,7 +73,7 @@ async function getAndProcessSwaps( // console.log(wallet.address); // console.log(await balancer.sor.provider.getBlockNumber()); // console.log(relayerCallData.data); - const result = await balancer.contracts.relayerV3 + const result = await balancer.contracts.relayer ?.connect(wallet) .callStatic.multicall(relayerCallData.rawCalls); console.log(result); diff --git a/balancer-js/hardhat.config.arbitrum.ts b/balancer-js/hardhat.config.arbitrum.ts new file mode 100644 index 000000000..be128a2fe --- /dev/null +++ b/balancer-js/hardhat.config.arbitrum.ts @@ -0,0 +1,12 @@ +import '@nomiclabs/hardhat-ethers'; + +/** + * @type import('hardhat/config').HardhatUserConfig + */ +export default { + networks: { + hardhat: { + chainId: 42161, + }, + }, +}; diff --git a/balancer-js/package.json b/balancer-js/package.json index 6d1cbfc7f..64ba6e8d8 100644 --- a/balancer-js/package.json +++ b/balancer-js/package.json @@ -1,6 +1,6 @@ { "name": "@balancer-labs/sdk", - "version": "1.0.4", + "version": "1.0.5", "description": "JavaScript SDK for interacting with the Balancer Protocol V2", "license": "GPL-3.0-only", "homepage": "https://github.com/balancer-labs/balancer-sdk#readme", @@ -29,9 +29,10 @@ "subgraph:generate": "graphql-codegen --config src/modules/subgraph/codegen.yml -r dotenv/config", "examples:run": "npx ts-node -P tsconfig.testing.json -r tsconfig-paths/register", "node": "npx hardhat node --tsconfig tsconfig.testing.json --fork $(. ./.env && echo $ALCHEMY_URL)", - "node:goerli": "npx hardhat --tsconfig tsconfig.testing.json --config hardhat.config.goerli.ts node --fork $(grep ALCHEMY_URL_GOERLI .env | cut -d '=' -f2 | tail -1) --port 8000", - "node:polygon": "npx hardhat --tsconfig tsconfig.testing.json --config hardhat.config.polygon.ts node --fork $(grep ALCHEMY_URL_POLYGON .env | cut -d '=' -f2 | tail -1) --port 8137", - "typechain:generate": "npx typechain --target ethers-v5 --out-dir src/contracts './src/lib/abi/Vault.json' './src/lib/abi/WeightedPoolFactory.json' './src/lib/abi/ComposableStableFactory.json' './src/lib/abi/BalancerHelpers.json' './src/lib/abi/LidoRelayer.json' './src/lib/abi/WeightedPool.json' './src/lib/abi/ComposableStable.json' './src/lib/abi/ERC4626LinearPoolFactory.json' './src/lib/abi/ERC4626LinearPool.json' './src/lib/abi/AaveLinearPoolFactory.json' './src/lib/abi/AaveLinearPool.json' './src/lib/abi/EulerLinearPoolFactory.json' './src/lib/abi/EulerLinearPool.json' './src/lib/abi/GearboxLinearPoolFactory.json' './src/lib/abi/GearboxLinearPool.json' './src/lib/abi/YearnLinearPoolFactory.json' './src/lib/abi/YearnLinearPool.json' './src/lib/abi/RelayerV5.json'" + "node:goerli": "npx hardhat --tsconfig tsconfig.testing.json --config hardhat.config.goerli.ts node --fork $(. ./.env && echo $ALCHEMY_URL_GOERLI) --port 8000", + "node:polygon": "npx hardhat --tsconfig tsconfig.testing.json --config hardhat.config.polygon.ts node --fork $(. ./.env && echo $ALCHEMY_URL_POLYGON) --port 8137", + "node:arbitrum": "npx hardhat --tsconfig tsconfig.testing.json --config hardhat.config.arbitrum.ts node --fork $(. ./.env && echo $ALCHEMY_URL_ARBITRUM) --port 8161", + "typechain:generate": "npx typechain --target ethers-v5 --out-dir src/contracts './src/lib/abi/*.json'" }, "devDependencies": { "@ethersproject/solidity": "^5.6.1", @@ -83,7 +84,7 @@ "typescript": "^4.0.2" }, "dependencies": { - "@balancer-labs/sor": "^4.1.1-beta.7", + "@balancer-labs/sor": "^4.1.1-beta.8", "@ethersproject/abi": "^5.4.0", "@ethersproject/abstract-signer": "^5.4.0", "@ethersproject/address": "^5.4.0", diff --git a/balancer-js/src/balancerErrors.ts b/balancer-js/src/balancerErrors.ts index 8bc8b8288..0a2a899e5 100644 --- a/balancer-js/src/balancerErrors.ts +++ b/balancer-js/src/balancerErrors.ts @@ -12,7 +12,6 @@ export enum BalancerErrorCode { INPUT_LENGTH_MISMATCH = 'INPUT_LENGTH_MISMATCH', INPUT_OUT_OF_BOUNDS = 'INPUT_OUT_OF_BOUNDS', INPUT_TOKEN_INVALID = 'INPUT_TOKEN_INVALID', - INPUT_ZERO_NOT_ALLOWED = 'INPUT_ZERO_NOT_ALLOWED', INVALID_PROTOCOL_ID = 'INVALID_PROTOCOL_ID', INVALID_SWAP_FEE_PERCENTAGE = 'INVALID_SWAP_FEE_PERCENTAGE', INVALID_WEIGHTS = 'INVALID_WEIGHTS', @@ -65,8 +64,6 @@ export class BalancerError extends Error { return 'input out of bounds'; case BalancerErrorCode.INPUT_TOKEN_INVALID: return 'input token invalid'; - case BalancerErrorCode.INPUT_ZERO_NOT_ALLOWED: - return 'zero input not allowed'; case BalancerErrorCode.INVALID_PROTOCOL_ID: return 'The provided protocol id does not correspond to a protocol'; case BalancerErrorCode.INVALID_SWAP_FEE_PERCENTAGE: diff --git a/balancer-js/src/lib/abi/BalancerRelayer.json b/balancer-js/src/lib/abi/BalancerRelayer.json index d2f79fcf5..523cbbdea 100644 --- a/balancer-js/src/lib/abi/BalancerRelayer.json +++ b/balancer-js/src/lib/abi/BalancerRelayer.json @@ -64,4 +64,4 @@ "stateMutability": "payable", "type": "receive" } -] +] \ No newline at end of file diff --git a/balancer-js/src/lib/abi/ComposableStable.json b/balancer-js/src/lib/abi/ComposableStablePool.json similarity index 100% rename from balancer-js/src/lib/abi/ComposableStable.json rename to balancer-js/src/lib/abi/ComposableStablePool.json diff --git a/balancer-js/src/lib/abi/ComposableStableFactory.json b/balancer-js/src/lib/abi/ComposableStablePoolFactory.json similarity index 100% rename from balancer-js/src/lib/abi/ComposableStableFactory.json rename to balancer-js/src/lib/abi/ComposableStablePoolFactory.json diff --git a/balancer-js/src/lib/abi/FXPool.json b/balancer-js/src/lib/abi/FXPool.json new file mode 100644 index 000000000..3d20e4e10 --- /dev/null +++ b/balancer-js/src/lib/abi/FXPool.json @@ -0,0 +1,1346 @@ +[ + { + "inputs": [ + { + "internalType": "address[]", + "name": "_assetsToRegister", + "type": "address[]" + }, + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_protocolPercentFee", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "string", + "name": "_symbol", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "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": "address", + "name": "numeraire", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "reserve", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "weight", + "type": "uint256" + } + ], + "name": "AssetIncluded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "derivative", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "numeraire", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "reserve", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "assimilator", + "type": "address" + } + ], + "name": "AssimilatorIncluded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newCollector", + "type": "address" + } + ], + "name": "ChangeCollectorAddress", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "isEmergency", + "type": "bool" + } + ], + "name": "EmergencyAlarm", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "lptAmountBurned", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "amountsWithdrawn", + "type": "uint256[]" + } + ], + "name": "EmergencyWithdraw", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "feesCollected", + "type": "uint256" + } + ], + "name": "FeesAccrued", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feesCollected", + "type": "uint256" + } + ], + "name": "FeesCollected", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "lptAmountBurned", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "amountsWithdrawn", + "type": "uint256[]" + } + ], + "name": "OnExitPool", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "lptAmountMinted", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "amountsDeposited", + "type": "uint256[]" + } + ], + "name": "OnJoinPool", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "alpha", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "beta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delta", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "epsilon", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "lambda", + "type": "uint256" + } + ], + "name": "ParametersSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "updater", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newProtocolPercentage", + "type": "uint256" + } + ], + "name": "ProtocolFeeShareUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "trader", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "origin", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "originAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "targetAmount", + "type": "uint256" + } + ], + "name": "Trade", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "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": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "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": "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": "_derivative", + "type": "address" + } + ], + "name": "assimilator", + "outputs": [ + { + "internalType": "address", + "name": "assimilator_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectorAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "curve", + "outputs": [ + { + "internalType": "int128", + "name": "alpha", + "type": "int128" + }, + { + "internalType": "int128", + "name": "beta", + "type": "int128" + }, + { + "internalType": "int128", + "name": "delta", + "type": "int128" + }, + { + "internalType": "int128", + "name": "epsilon", + "type": "int128" + }, + { + "internalType": "int128", + "name": "lambda", + "type": "int128" + }, + { + "internalType": "uint256", + "name": "cap", + "type": "uint256" + }, + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "address", + "name": "fxPoolAddress", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "derivatives", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "emergency", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_assetWeights", + "type": "uint256[]" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "liquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "total_", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "individual_", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "numeraires", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "onExitPool", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsOut", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "dueProtocolFeeAmounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "onJoinPool", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "dueProtocolFeeAmounts", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum IVault.SwapKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "lastChangeBlock", + "type": "uint256" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IPoolSwapStructs.SwapRequest", + "name": "swapRequest", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "onSwap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "protocolPercentFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "reserves", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_cap", + "type": "uint256" + } + ], + "name": "setCap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_collectorAddress", + "type": "address" + } + ], + "name": "setCollectorAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_emergency", + "type": "bool" + } + ], + "name": "setEmergency", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_alpha", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_beta", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_feeAtHalt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_epsilon", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_lambda", + "type": "uint256" + } + ], + "name": "setParams", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "setPaused", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_protocolPercentFee", + "type": "uint256" + } + ], + "name": "setProtocolPercentFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalUnclaimedFeesInNumeraire", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "totalDepositNumeraire", + "type": "uint256" + } + ], + "name": "viewDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "viewParameters", + "outputs": [ + { + "internalType": "uint256", + "name": "alpha_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "beta_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "delta_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "epsilon_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lambda_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_curvesToBurn", + "type": "uint256" + } + ], + "name": "viewWithdraw", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/balancer-js/src/lib/abi/RelayerV4.json b/balancer-js/src/lib/abi/RelayerV4.json deleted file mode 100644 index 523cbbdea..000000000 --- a/balancer-js/src/lib/abi/RelayerV4.json +++ /dev/null @@ -1,67 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "contract IVault", - "name": "vault", - "type": "address" - }, - { - "internalType": "address", - "name": "libraryAddress", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "getLibrary", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getVault", - "outputs": [ - { - "internalType": "contract IVault", - "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" - }, - { - "stateMutability": "payable", - "type": "receive" - } -] \ No newline at end of file diff --git a/balancer-js/src/lib/abi/RelayerV5.json b/balancer-js/src/lib/abi/RelayerV5.json deleted file mode 100644 index f564802e9..000000000 --- a/balancer-js/src/lib/abi/RelayerV5.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "inputs": [ - { "internalType": "contract IVault", "name": "vault", "type": "address" }, - { "internalType": "address", "name": "libraryAddress", "type": "address" } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "getLibrary", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getVault", - "outputs": [ - { "internalType": "contract IVault", "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" - }, - { "stateMutability": "payable", "type": "receive" } -] diff --git a/balancer-js/src/lib/constants/config.ts b/balancer-js/src/lib/constants/config.ts index 8ce6f1f2e..d58189ac9 100644 --- a/balancer-js/src/lib/constants/config.ts +++ b/balancer-js/src/lib/constants/config.ts @@ -18,9 +18,7 @@ export const BALANCER_NETWORK_CONFIG: Record = { balancerHelpers: '0x5aDDCCa35b7A0D07C74063c48700C8590E87864E', balancerMinterAddress: '0x239e55F427D44C3cc793f49bFB507ebe76638a2b', lidoRelayer: '0xdcdbf71A870cc60C6F9B621E28a7D3Ffd6Dd4965', - relayerV3: '0x886A3Ec7bcC508B8795990B60Fa21f85F9dB7948', - relayerV4: '0x2536dfeeCB7A0397CF98eDaDA8486254533b1aFA', - relayerV5: '0xfeA793Aa415061C483D2390414275AD314B3F621', + relayer: '0xfeA793Aa415061C483D2390414275AD314B3F621', gaugeController: '0xc128468b7ce63ea702c1f104d55a2566b13d3abd', feeDistributor: '0xD3cf852898b21fc233251427c2DC93d3d604F3BB', protocolFeePercentagesProvider: @@ -96,9 +94,7 @@ export const BALANCER_NETWORK_CONFIG: Record = { vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', multicall: '0xa1B2b503959aedD81512C37e9dce48164ec6a94d', gaugeClaimHelper: '0xaeb406b0e430bf5ea2dc0b9fe62e4e53f74b3a33', - relayerV3: '0xcf6a66E32dCa0e26AcC3426b851FD8aCbF12Dac7', - relayerV4: '0x28A224d9d398a1eBB7BA69BCA515898966Bb1B6b', - relayerV5: '0xd18d5D377eb23362e54Fa496597d7E962d56C554', + relayer: '0xd18d5D377eb23362e54Fa496597d7E962d56C554', balancerHelpers: '0x239e55F427D44C3cc793f49bFB507ebe76638a2b', weightedPoolFactory: '0xfc8a407bba312ac761d8bfe04ce1201904842b76', composableStablePoolFactory: @@ -149,9 +145,7 @@ export const BALANCER_NETWORK_CONFIG: Record = { vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', multicall: '0x269ff446d9892c9e19082564df3f5e8741e190a1', gaugeClaimHelper: '0xa0dabebaad1b243bbb243f933013d560819eb66f', - relayerV3: '0x42E49B48573c725ee32d2579060Ed06894f97002', - relayerV4: '0x5bf3B7c14b10f16939d63Bd679264A1Aa951B4D5', - relayerV5: '0x598ce0f1ab64B27256759ef99d883EE51138b9bd', + relayer: '0x598ce0f1ab64B27256759ef99d883EE51138b9bd', balancerHelpers: '0x77d46184d22CA6a3726a2F500c776767b6A3d6Ab', weightedPoolFactory: '0xc7e5ed1054a24ef31d827e6f86caa58b3bc168d7', composableStablePoolFactory: @@ -196,6 +190,7 @@ export const BALANCER_NETWORK_CONFIG: Record = { veBalProxy: '0x98D0d0a65cBeCCaa647a5a95cf27Cf2f00E1231C', balancerHelpers: '0x94905e703fEAd7f0fD0eEe355D267eE909784e6d', weightedPoolFactory: '0x8df6EfEc5547e31B0eb7d1291B511FF8a2bf987c', + relayer: '', }, tokens: { wrappedNativeAsset: '0xdFCeA9088c8A88A76FF74892C1457C17dfeef9C1', @@ -216,6 +211,7 @@ export const BALANCER_NETWORK_CONFIG: Record = { vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', multicall: '0x53c43764255c17bd724f74c4ef150724ac50a3ed', balancerHelpers: '', + relayer: '', }, tokens: { wrappedNativeAsset: '0xdFCeA9088c8A88A76FF74892C1457C17dfeef9C1', @@ -236,6 +232,7 @@ export const BALANCER_NETWORK_CONFIG: Record = { multicall: '0x42ad527de7d4e9d9d011ac45b31d8551f8fe9821', balancerHelpers: '0x5aDDCCa35b7A0D07C74063c48700C8590E87864E', weightedPoolFactory: '0x8df6EfEc5547e31B0eb7d1291B511FF8a2bf987c', + relayer: '', }, tokens: { wrappedNativeAsset: '0xdFCeA9088c8A88A76FF74892C1457C17dfeef9C1', @@ -256,9 +253,7 @@ export const BALANCER_NETWORK_CONFIG: Record = { contracts: { vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', multicall: '0x77dCa2C955b15e9dE4dbBCf1246B4B85b651e50e', - relayerV3: '0x7b9B6f094DC2Bd1c12024b0D9CC63d6993Be1888', - relayerV4: '0x00e695aA8000df01B8DC8401B4C34Fba5D56BBb2', - relayerV5: '0x03F1ab8b19bcE21EB06C364aEc9e40322572a1e9', + relayer: '0x03F1ab8b19bcE21EB06C364aEc9e40322572a1e9', gaugeController: '0xBB1CE49b16d55A1f2c6e88102f32144C7334B116', veBal: '0x33A99Dcc4C85C014cf12626959111D5898bbCAbF', veBalProxy: '0xA1F107D1cD709514AE8A914eCB757E95f9cedB31', @@ -299,9 +294,7 @@ export const BALANCER_NETWORK_CONFIG: Record = { contracts: { vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', multicall: '0x2dc0e2aa608532da689e89e237df582b783e552c', - relayerV3: '0x195CcCBE464EF9073d1f7A1ba1C9Bf0f56dfFFff', - relayerV4: '0x1a58897Ab366082028ced3740900ecBD765Af738', - relayerV5: '0x03F1ab8b19bcE21EB06C364aEc9e40322572a1e9', + relayer: '0x03F1ab8b19bcE21EB06C364aEc9e40322572a1e9', balancerHelpers: '0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9', weightedPoolFactory: '0x230a59f4d9adc147480f03b0d3fffecd56c3289a', composableStablePoolFactory: @@ -339,8 +332,7 @@ export const BALANCER_NETWORK_CONFIG: Record = { contracts: { vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8', multicall: '0xbb6fab6b627947dae0a75808250d8b2652952cb5', - relayerV4: '0xeF606F58A4FD0fCcb066c6203d0994694d3eB2D3', - relayerV5: '0x3536fD480CA495Ac91E698A703248A8915c137a3', + relayer: '0x3536fD480CA495Ac91E698A703248A8915c137a3', balancerHelpers: '0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9', weightedPoolFactory: '0x6cad2ea22bfa7f4c14aae92e47f510cd5c509bc7', composableStablePoolFactory: @@ -373,8 +365,7 @@ export const BALANCER_NETWORK_CONFIG: Record = { vault: '0x20dd72Ed959b6147912C2e529F0a0C651c33c9ce', multicall: '0x66335d7ad8011f6aa3f48aadcb523b62b38ed961', gaugeClaimHelper: '0x0000000000000000000000000000000000000000', // no guages on fantom - relayerV3: '0xC852F984CA3310AFc596adeB17EfcB0542646920', - relayerV4: '0x419f7925b8c9e409b6ee8792242556fa210a7a09', + relayer: '0x419f7925b8c9e409b6ee8792242556fa210a7a09', balancerHelpers: '0xfE18C7C70b0a2c6541bEde0367124278BC345Dc8', weightedPoolFactory: '0x60467cb225092cE0c989361934311175f437Cf53', composableStablePoolFactory: diff --git a/balancer-js/src/lib/utils/aaveHelpers.ts b/balancer-js/src/lib/utils/aaveHelpers.ts index c1e04c11e..147e63f66 100644 --- a/balancer-js/src/lib/utils/aaveHelpers.ts +++ b/balancer-js/src/lib/utils/aaveHelpers.ts @@ -1,7 +1,6 @@ import { JsonRpcProvider } from '@ethersproject/providers'; import { Contract } from '@ethersproject/contracts'; - -import aTokenRateProviderAbi from '../abi/StaticATokenRateProvider.json'; +import { StaticATokenRateProvider__factory } from '@/contracts'; export class AaveHelpers { static async getRate( @@ -10,7 +9,7 @@ export class AaveHelpers { ): Promise { const rateProviderContract = new Contract( rateProviderAddress, - aTokenRateProviderAbi, + StaticATokenRateProvider__factory.createInterface(), provider ); diff --git a/balancer-js/src/modules/contracts/contracts.module.ts b/balancer-js/src/modules/contracts/contracts.module.ts index 2df504559..914a69c71 100644 --- a/balancer-js/src/modules/contracts/contracts.module.ts +++ b/balancer-js/src/modules/contracts/contracts.module.ts @@ -1,30 +1,43 @@ import { Contract } from '@ethersproject/contracts'; import { Provider } from '@ethersproject/providers'; import { Signer } from '@ethersproject/abstract-signer'; -import { ContractAddresses } from '@/types'; -import { Network } from '@/lib/constants/network'; -import { BALANCER_NETWORK_CONFIG } from '@/lib/constants/config'; -import { LidoRelayer__factory } from '@/contracts/factories/LidoRelayer__factory'; -import { LidoRelayer } from '@/contracts/LidoRelayer'; -import { BalancerHelpers } from '@/contracts/BalancerHelpers'; -import { BalancerHelpers__factory } from '@/contracts/factories/BalancerHelpers__factory'; -import { Vault__factory } from '@/contracts/factories/Vault__factory'; -import { Vault } from '@/contracts/Vault'; + import { Multicall } from './implementations/multicall'; -import { ERC20 } from './implementations/ERC20'; import { BasePool } from './implementations/base-pool'; import { VeBal } from './implementations/veBAL'; import { VeBalProxy } from './implementations/veBAL-proxy'; -import { Relayer } from './implementations/relayer'; -import { LiquidityGauge } from './implementations/liquidity-gauge'; -import { GaugeClaimHelper } from './implementations/GaugeClaimHelper'; -import { ComposableStablePoolFactory } from '@/modules/contracts/implementations/factories/composable-stable-pool-factory'; -import { WeightedPoolFactory } from '@/modules/contracts/implementations/factories/weighted-pool-factory'; -import { AaveLinearPoolFactory } from '@/modules/contracts/implementations/factories/aave-linear-pool-factory'; -import { Erc4626LinearPoolFactory } from '@/modules/contracts/implementations/factories/erc4626-linear-pool-factory'; -import { EulerLinearPoolFactory } from '@/modules/contracts/implementations/factories/euler-linear-pool-factory'; -import { YearnLinearPoolFactory } from '@/modules/contracts/implementations/factories/yearn-linear-pool-factory'; -import { GearboxLinearPoolFactory } from '@/modules/contracts/implementations/factories/gearbox-linear-pool-factory'; +import { + AaveLinearPoolFactory, + AaveLinearPoolFactory__factory, + BalancerHelpers, + BalancerHelpers__factory, + BalancerRelayer__factory, + ComposableStablePoolFactory, + ComposableStablePoolFactory__factory, + ERC20, + ERC20__factory, + ERC4626LinearPoolFactory, + ERC4626LinearPoolFactory__factory, + EulerLinearPoolFactory, + EulerLinearPoolFactory__factory, + GaugeClaimHelper, + GaugeClaimHelper__factory, + GearboxLinearPoolFactory, + GearboxLinearPoolFactory__factory, + LidoRelayer, + LidoRelayer__factory, + LiquidityGaugeV5, + LiquidityGaugeV5__factory, + Vault, + Vault__factory, + WeightedPoolFactory, + WeightedPoolFactory__factory, + YearnLinearPoolFactory, + YearnLinearPoolFactory__factory, +} from '@/contracts'; +import { Network } from '@/lib/constants/network'; +import { BALANCER_NETWORK_CONFIG } from '@/lib/constants/config'; +import { ContractAddresses } from '@/types'; type ContractFactory = ( address: string, @@ -32,47 +45,29 @@ type ContractFactory = ( ) => Contract; export interface ContractInstances { - aaveLinearPoolFactory?: Contract; + aaveLinearPoolFactory?: AaveLinearPoolFactory; balancerHelpers: BalancerHelpers; BasePool: ContractFactory; - composableStablePoolFactory?: Contract; + composableStablePoolFactory?: ComposableStablePoolFactory; ERC20: ContractFactory; - erc4626LinearPoolFactory?: Contract; - eulerLinearPoolFactory?: Contract; - gaugeClaimHelper?: Contract; - gearboxLinearPoolFactory?: Contract; + erc4626LinearPoolFactory?: ERC4626LinearPoolFactory; + eulerLinearPoolFactory?: EulerLinearPoolFactory; + gaugeClaimHelper?: GaugeClaimHelper; + gearboxLinearPoolFactory?: GearboxLinearPoolFactory; lidoRelayer?: LidoRelayer; liquidityGauge: ContractFactory; multicall: Contract; - relayerV3?: Contract; - relayerV4?: Contract; - relayerV5?: Contract; + relayer: Contract; vault: Vault; veBal?: VeBal; veBalProxy?: VeBalProxy; - weightedPoolFactory?: Contract; - yearnLinearPoolFactory?: Contract; + weightedPoolFactory?: WeightedPoolFactory; + yearnLinearPoolFactory?: YearnLinearPoolFactory; } export class Contracts { - aaveLinearPoolFactory?: Contract; - balancerHelpers: BalancerHelpers; - composableStablePoolFactory?: Contract; contractAddresses: ContractAddresses; - erc4626LinearPoolFactory?: Contract; - eulerLinearPoolFactory?: Contract; - gaugeClaimHelper?: Contract; - gearboxLinearPoolFactory?: Contract; - lidoRelayer?: LidoRelayer; - multicall: Contract; - relayerV3?: Contract; - relayerV4?: Contract; - relayerV5?: Contract; - vault: Vault; - veBal?: VeBal; - veBalProxy?: VeBalProxy; - weightedPoolFactory?: Contract; - yearnLinearPoolFactory?: Contract; + private instances: ContractInstances; /** * Create instances of Balancer contracts connected to passed provider. @@ -91,110 +86,122 @@ export class Contracts { this.contractAddresses = networkOrAddresses; } - this.vault = Vault__factory.connect(this.contractAddresses.vault, provider); - this.balancerHelpers = BalancerHelpers__factory.connect( + const vault: Vault = Vault__factory.connect( + this.contractAddresses.vault, + provider + ); + const balancerHelpers: BalancerHelpers = BalancerHelpers__factory.connect( this.contractAddresses.balancerHelpers, provider ); - + let lidoRelayer: undefined | LidoRelayer; if (this.contractAddresses.lidoRelayer) - this.lidoRelayer = LidoRelayer__factory.connect( + lidoRelayer = LidoRelayer__factory.connect( this.contractAddresses.lidoRelayer, provider ); // These contracts aren't included in Balancer Typechain but are still useful. // TO DO - Possibly create via Typechain but seems unnecessary? - this.multicall = Multicall(this.contractAddresses.multicall, provider); - if (this.contractAddresses.relayerV3) - this.relayerV3 = Relayer(this.contractAddresses.relayerV3, provider, 3); - if (this.contractAddresses.relayerV4) - this.relayerV4 = Relayer(this.contractAddresses.relayerV4, provider, 4); - if (this.contractAddresses.relayerV5) - this.relayerV5 = Relayer(this.contractAddresses.relayerV5, provider, 5); - + const multicall: Contract = Multicall( + this.contractAddresses.multicall, + provider + ); + const relayer = BalancerRelayer__factory.connect( + this.contractAddresses.relayer, + provider + ); + let veBal: undefined | VeBal; if (this.contractAddresses.veBal) { - this.veBal = new VeBal(this.contractAddresses, provider); + veBal = new VeBal(this.contractAddresses, provider); } - + let veBalProxy: undefined | VeBalProxy; if (this.contractAddresses.veBalProxy) { - this.veBalProxy = new VeBalProxy(this.contractAddresses, provider); + veBalProxy = new VeBalProxy(this.contractAddresses, provider); } - + let gaugeClaimHelper: undefined | GaugeClaimHelper; if (this.contractAddresses.gaugeClaimHelper) - this.gaugeClaimHelper = GaugeClaimHelper( + gaugeClaimHelper = GaugeClaimHelper__factory.connect( this.contractAddresses.gaugeClaimHelper, provider ); + let composableStablePoolFactory: undefined | ComposableStablePoolFactory; if (this.contractAddresses.composableStablePoolFactory) { - this.composableStablePoolFactory = ComposableStablePoolFactory( - this.contractAddresses.composableStablePoolFactory, - provider - ); + composableStablePoolFactory = + ComposableStablePoolFactory__factory.connect( + this.contractAddresses.composableStablePoolFactory, + provider + ); } + let weightedPoolFactory: undefined | WeightedPoolFactory; if (this.contractAddresses.weightedPoolFactory) { - this.weightedPoolFactory = WeightedPoolFactory( + weightedPoolFactory = WeightedPoolFactory__factory.connect( this.contractAddresses.weightedPoolFactory, provider ); } + let aaveLinearPoolFactory: undefined | AaveLinearPoolFactory; if (this.contractAddresses.aaveLinearPoolFactory) { - this.aaveLinearPoolFactory = AaveLinearPoolFactory( + aaveLinearPoolFactory = AaveLinearPoolFactory__factory.connect( this.contractAddresses.aaveLinearPoolFactory, provider ); } + let erc4626LinearPoolFactory: undefined | ERC4626LinearPoolFactory; if (this.contractAddresses.erc4626LinearPoolFactory) { - this.erc4626LinearPoolFactory = Erc4626LinearPoolFactory( + erc4626LinearPoolFactory = ERC4626LinearPoolFactory__factory.connect( this.contractAddresses.erc4626LinearPoolFactory, provider ); } + let eulerLinearPoolFactory: undefined | EulerLinearPoolFactory; if (this.contractAddresses.eulerLinearPoolFactory) { - this.eulerLinearPoolFactory = EulerLinearPoolFactory( + eulerLinearPoolFactory = EulerLinearPoolFactory__factory.connect( this.contractAddresses.eulerLinearPoolFactory, provider ); } + let gearboxLinearPoolFactory: undefined | GearboxLinearPoolFactory; if (this.contractAddresses.gearboxLinearPoolFactory) { - this.gearboxLinearPoolFactory = GearboxLinearPoolFactory( + gearboxLinearPoolFactory = GearboxLinearPoolFactory__factory.connect( this.contractAddresses.gearboxLinearPoolFactory, provider ); } + let yearnLinearPoolFactory: undefined | YearnLinearPoolFactory; if (this.contractAddresses.yearnLinearPoolFactory) { - this.yearnLinearPoolFactory = YearnLinearPoolFactory( + yearnLinearPoolFactory = YearnLinearPoolFactory__factory.connect( this.contractAddresses.yearnLinearPoolFactory, provider ); } + this.instances = { + aaveLinearPoolFactory, + balancerHelpers, + BasePool: this.getBasePool, + composableStablePoolFactory, + ERC20: this.getErc20, + erc4626LinearPoolFactory, + eulerLinearPoolFactory, + gaugeClaimHelper, + gearboxLinearPoolFactory, + liquidityGauge: this.getLiquidityGauge, + lidoRelayer, + multicall, + relayer, + veBal, + veBalProxy, + weightedPoolFactory, + yearnLinearPoolFactory, + vault, + }; } /** * Expose contract instances. */ get contracts(): ContractInstances { - return { - aaveLinearPoolFactory: this.aaveLinearPoolFactory, - balancerHelpers: this.balancerHelpers, - BasePool: this.getBasePool, - composableStablePoolFactory: this.composableStablePoolFactory, - ERC20: this.getErc20, - erc4626LinearPoolFactory: this.erc4626LinearPoolFactory, - eulerLinearPoolFactory: this.eulerLinearPoolFactory, - gaugeClaimHelper: this.gaugeClaimHelper, - gearboxLinearPoolFactory: this.gearboxLinearPoolFactory, - liquidityGauge: this.getLiquidityGauge, - lidoRelayer: this.lidoRelayer, - multicall: this.multicall, - relayerV3: this.relayerV3, - relayerV4: this.relayerV4, - vault: this.vault, - veBal: this.veBal, - veBalProxy: this.veBalProxy, - weightedPoolFactory: this.weightedPoolFactory, - yearnLinearPoolFactory: this.yearnLinearPoolFactory, - }; + return this.instances; } /** @@ -203,8 +210,8 @@ export class Contracts { * @param { Signer | Provider } signerOrProvider Signer or Provider. * @returns Contract. */ - getErc20(address: string, signerOrProvider: Signer | Provider): Contract { - return ERC20(address, signerOrProvider); + getErc20(address: string, signerOrProvider: Signer | Provider): ERC20 { + return ERC20__factory.connect(address, signerOrProvider); } /** @@ -226,7 +233,7 @@ export class Contracts { getLiquidityGauge( address: string, signerOrProvider: Signer | Provider - ): Contract { - return LiquidityGauge(address, signerOrProvider); + ): LiquidityGaugeV5 { + return LiquidityGaugeV5__factory.connect(address, signerOrProvider); } } diff --git a/balancer-js/src/modules/contracts/implementations/ERC20.ts b/balancer-js/src/modules/contracts/implementations/ERC20.ts deleted file mode 100644 index f6f1ceb98..000000000 --- a/balancer-js/src/modules/contracts/implementations/ERC20.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Contract } from '@ethersproject/contracts'; -import { Provider } from '@ethersproject/providers'; -import { Signer } from '@ethersproject/abstract-signer'; -import abi from '../../../lib/abi/ERC20.json'; - -export const ERC20 = ( - address: string, - signerOrProvider: Signer | Provider -): Contract => new Contract(address, abi, signerOrProvider); diff --git a/balancer-js/src/modules/contracts/implementations/GaugeClaimHelper.ts b/balancer-js/src/modules/contracts/implementations/GaugeClaimHelper.ts index f278ec30a..1490b854b 100644 --- a/balancer-js/src/modules/contracts/implementations/GaugeClaimHelper.ts +++ b/balancer-js/src/modules/contracts/implementations/GaugeClaimHelper.ts @@ -1,9 +1,14 @@ import { Provider } from '@ethersproject/providers'; import { Signer } from '@ethersproject/abstract-signer'; import { Contract } from '@ethersproject/contracts'; -import abi from '@/lib/abi/GaugeClaimHelper.json'; +import { GaugeClaimHelper__factory } from '@/contracts'; export const GaugeClaimHelper = ( address: string, signerOrProvider: Signer | Provider -): Contract => new Contract(address, abi, signerOrProvider); +): Contract => + new Contract( + address, + GaugeClaimHelper__factory.createInterface(), + signerOrProvider + ); diff --git a/balancer-js/src/modules/contracts/implementations/factories/aave-linear-pool-factory.ts b/balancer-js/src/modules/contracts/implementations/factories/aave-linear-pool-factory.ts deleted file mode 100644 index 913d6c383..000000000 --- a/balancer-js/src/modules/contracts/implementations/factories/aave-linear-pool-factory.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Provider } from '@ethersproject/providers'; -import { Signer } from '@ethersproject/abstract-signer'; -import { Contract } from '@ethersproject/contracts'; -import { AaveLinearPoolFactory__factory } from '@/contracts'; - -export const AaveLinearPoolFactory = ( - address: string, - signerOrProvider: Signer | Provider -): Contract => { - return new Contract( - address, - AaveLinearPoolFactory__factory.createInterface(), - signerOrProvider - ); -}; diff --git a/balancer-js/src/modules/contracts/implementations/factories/composable-stable-pool-factory.ts b/balancer-js/src/modules/contracts/implementations/factories/composable-stable-pool-factory.ts deleted file mode 100644 index 1339eae98..000000000 --- a/balancer-js/src/modules/contracts/implementations/factories/composable-stable-pool-factory.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Provider } from '@ethersproject/providers'; -import { Signer } from '@ethersproject/abstract-signer'; -import { Contract } from '@ethersproject/contracts'; -import { ComposableStableFactory__factory } from '@/contracts'; - -export const ComposableStablePoolFactory = ( - address: string, - signerOrProvider: Signer | Provider -): Contract => { - return new Contract( - address, - ComposableStableFactory__factory.createInterface(), - signerOrProvider - ); -}; diff --git a/balancer-js/src/modules/contracts/implementations/factories/erc4626-linear-pool-factory.ts b/balancer-js/src/modules/contracts/implementations/factories/erc4626-linear-pool-factory.ts deleted file mode 100644 index aa268b16d..000000000 --- a/balancer-js/src/modules/contracts/implementations/factories/erc4626-linear-pool-factory.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Provider } from '@ethersproject/providers'; -import { Signer } from '@ethersproject/abstract-signer'; -import { ERC4626LinearPoolFactory__factory } from '@/contracts'; -import { Contract } from '@ethersproject/contracts'; - -export const Erc4626LinearPoolFactory = ( - address: string, - signerOrProvider: Signer | Provider -): Contract => { - return new Contract( - address, - ERC4626LinearPoolFactory__factory.createInterface(), - signerOrProvider - ); -}; diff --git a/balancer-js/src/modules/contracts/implementations/factories/euler-linear-pool-factory.ts b/balancer-js/src/modules/contracts/implementations/factories/euler-linear-pool-factory.ts deleted file mode 100644 index 37818b234..000000000 --- a/balancer-js/src/modules/contracts/implementations/factories/euler-linear-pool-factory.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { EulerLinearPoolFactory__factory } from '@/contracts'; -import { Provider } from '@ethersproject/providers'; -import { Signer } from '@ethersproject/abstract-signer'; -import { Contract } from '@ethersproject/contracts'; - -export const EulerLinearPoolFactory = ( - address: string, - signerOrProvider: Signer | Provider -): Contract => { - return new Contract( - address, - EulerLinearPoolFactory__factory.createInterface(), - signerOrProvider - ); -}; diff --git a/balancer-js/src/modules/contracts/implementations/factories/gearbox-linear-pool-factory.ts b/balancer-js/src/modules/contracts/implementations/factories/gearbox-linear-pool-factory.ts deleted file mode 100644 index 0cff72334..000000000 --- a/balancer-js/src/modules/contracts/implementations/factories/gearbox-linear-pool-factory.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { GearboxLinearPoolFactory__factory } from '@/contracts'; -import { Contract } from '@ethersproject/contracts'; -import { Provider } from '@ethersproject/providers'; -import { Signer } from '@ethersproject/abstract-signer'; - -export const GearboxLinearPoolFactory = ( - address: string, - signerOrProvider: Signer | Provider -): Contract => { - return new Contract( - address, - GearboxLinearPoolFactory__factory.createInterface(), - signerOrProvider - ); -}; diff --git a/balancer-js/src/modules/contracts/implementations/factories/weighted-pool-factory.ts b/balancer-js/src/modules/contracts/implementations/factories/weighted-pool-factory.ts deleted file mode 100644 index cbd9630cf..000000000 --- a/balancer-js/src/modules/contracts/implementations/factories/weighted-pool-factory.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Provider } from '@ethersproject/providers'; -import { Signer } from '@ethersproject/abstract-signer'; -import { Contract } from '@ethersproject/contracts'; -import { WeightedPoolFactory__factory } from '@/contracts'; - -export const WeightedPoolFactory = ( - address: string, - signerOrProvider: Signer | Provider -): Contract => { - return new Contract( - address, - WeightedPoolFactory__factory.createInterface(), - signerOrProvider - ); -}; diff --git a/balancer-js/src/modules/contracts/implementations/factories/yearn-linear-pool-factory.ts b/balancer-js/src/modules/contracts/implementations/factories/yearn-linear-pool-factory.ts deleted file mode 100644 index 7954ecc24..000000000 --- a/balancer-js/src/modules/contracts/implementations/factories/yearn-linear-pool-factory.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { YearnLinearPoolFactory__factory } from '@/contracts'; -import { Contract } from '@ethersproject/contracts'; -import { Signer } from '@ethersproject/abstract-signer'; -import { Provider } from '@ethersproject/providers'; - -export const YearnLinearPoolFactory = ( - address: string, - signerOrProvider: Signer | Provider -): Contract => { - return new Contract( - address, - YearnLinearPoolFactory__factory.createInterface(), - signerOrProvider - ); -}; diff --git a/balancer-js/src/modules/contracts/implementations/liquidity-gauge.ts b/balancer-js/src/modules/contracts/implementations/liquidity-gauge.ts deleted file mode 100644 index b0faa9fce..000000000 --- a/balancer-js/src/modules/contracts/implementations/liquidity-gauge.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Provider } from '@ethersproject/providers'; -import { Signer } from '@ethersproject/abstract-signer'; -import { Contract } from '@ethersproject/contracts'; -import abi from '@/lib/abi/LiquidityGaugeV5.json'; - -export const LiquidityGauge = ( - address: string, - signerOrProvider: Signer | Provider -): Contract => new Contract(address, abi, signerOrProvider); diff --git a/balancer-js/src/modules/contracts/implementations/relayer.ts b/balancer-js/src/modules/contracts/implementations/relayer.ts deleted file mode 100644 index de373057f..000000000 --- a/balancer-js/src/modules/contracts/implementations/relayer.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Contract } from '@ethersproject/contracts'; -import { Provider } from '@ethersproject/providers'; -import RelayerV3ABI from '@/lib/abi/BalancerRelayer.json'; -import RelayerV4ABI from '@/lib/abi/RelayerV4.json'; -import RelayerV5ABI from '@/lib/abi/RelayerV5.json'; - -export const Relayer = ( - address: string, - provider: Provider, - version: number -): Contract => { - switch (version) { - case 3: - return new Contract(address, RelayerV3ABI, provider); - case 4: - return new Contract(address, RelayerV4ABI, provider); - case 5: - return new Contract(address, RelayerV5ABI, provider); - default: - throw new Error('relayer not supported'); - } -}; diff --git a/balancer-js/src/modules/contracts/implementations/veBAL-proxy.ts b/balancer-js/src/modules/contracts/implementations/veBAL-proxy.ts index fdcb1370a..8191217c8 100644 --- a/balancer-js/src/modules/contracts/implementations/veBAL-proxy.ts +++ b/balancer-js/src/modules/contracts/implementations/veBAL-proxy.ts @@ -1,8 +1,9 @@ -import { ContractAddresses } from '@/types'; import { Provider } from '@ethersproject/providers'; import { Contract } from '@ethersproject/contracts'; import { formatUnits } from '@ethersproject/units'; -import veBalProxyAbi from '@/lib/abi/veDelegationProxy.json'; + +import { VeDelegationProxy__factory } from '@/contracts'; +import { ContractAddresses } from '@/types'; export class VeBalProxy { instance: Contract; @@ -10,7 +11,10 @@ export class VeBalProxy { constructor(addresses: ContractAddresses, provider: Provider) { if (!addresses.veBalProxy) throw new Error('veBalProxy address must be defined'); - this.instance = new Contract(addresses.veBalProxy, veBalProxyAbi, provider); + this.instance = VeDelegationProxy__factory.connect( + addresses.veBalProxy, + provider + ); } async getAdjustedBalance(account: string): Promise { diff --git a/balancer-js/src/modules/contracts/implementations/veBAL.ts b/balancer-js/src/modules/contracts/implementations/veBAL.ts index 6aa669f03..476444648 100644 --- a/balancer-js/src/modules/contracts/implementations/veBAL.ts +++ b/balancer-js/src/modules/contracts/implementations/veBAL.ts @@ -1,10 +1,11 @@ -import { Provider } from '@ethersproject/providers'; +import { JsonFragment } from '@ethersproject/abi'; import { BigNumber } from '@ethersproject/bignumber'; +import { Provider } from '@ethersproject/providers'; import { formatUnits } from '@ethersproject/units'; +import { VeBal__factory } from '@/contracts'; import { Multicaller } from '@/lib/utils/multiCaller'; import { toJsTimestamp } from '@/lib/utils/time'; import { ContractAddresses } from '@/types'; -import veBalAbi from '@/lib/abi/veBal.json'; export type VeBalLockInfo = { lockedEndDate: number; @@ -38,7 +39,7 @@ export class VeBal { const multicaller = new Multicaller( this.addresses.multicall, this.provider, - veBalAbi + [...(VeBal__factory.abi as readonly JsonFragment[])] ); multicaller.call('locked', this.addresses.veBal, 'locked', [account]); diff --git a/balancer-js/src/modules/data/pool/subgraph-helpers.ts b/balancer-js/src/modules/data/pool/subgraph-helpers.ts index 7d48b3a77..099f6d77d 100644 --- a/balancer-js/src/modules/data/pool/subgraph-helpers.ts +++ b/balancer-js/src/modules/data/pool/subgraph-helpers.ts @@ -58,6 +58,7 @@ export const mapType = (subgraphPool: SubgraphPool, chainId: number): Pool => { lowerTarget: subgraphPool.lowerTarget ?? '0', upperTarget: subgraphPool.upperTarget ?? '0', isInRecoveryMode: subgraphPool.isInRecoveryMode ?? false, + isPaused: subgraphPool.isPaused ?? false, }; }; diff --git a/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts b/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts index f9536614e..fa6dfc9cb 100644 --- a/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts +++ b/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts @@ -86,7 +86,7 @@ const { contracts, contractAddresses } = new Contracts( network as number, provider ); -const relayer = contractAddresses.relayerV5 as string; +const relayer = contractAddresses.relayer; interface Test { signer: JsonRpcSigner; diff --git a/balancer-js/src/modules/exits/exits.module.integration.spec.ts b/balancer-js/src/modules/exits/exits.module.integration.spec.ts index 9d2f547cd..79b65a0eb 100644 --- a/balancer-js/src/modules/exits/exits.module.integration.spec.ts +++ b/balancer-js/src/modules/exits/exits.module.integration.spec.ts @@ -113,7 +113,7 @@ const { contracts, contractAddresses } = new Contracts( network as number, provider ); -const relayer = contractAddresses.relayerV5 as string; +const relayer = contractAddresses.relayer; const testFlow = async ( pool: { id: string; address: string; slot: number }, diff --git a/balancer-js/src/modules/exits/exits.module.ts b/balancer-js/src/modules/exits/exits.module.ts index 37d655393..6f94a24d3 100644 --- a/balancer-js/src/modules/exits/exits.module.ts +++ b/balancer-js/src/modules/exits/exits.module.ts @@ -1,33 +1,36 @@ import { cloneDeep } from 'lodash'; import { BigNumber } from '@ethersproject/bignumber'; import { WeiPerEther, Zero } from '@ethersproject/constants'; +import { JsonRpcSigner } from '@ethersproject/providers'; import { BalancerError, BalancerErrorCode } from '@/balancerErrors'; +import { BalancerRelayer__factory } from '@/contracts/factories/BalancerRelayer__factory'; +import { networkAddresses } from '@/lib/constants/config'; +import { AssetHelpers, subSlippage } from '@/lib/utils'; +import { PoolGraph, Node } from '@/modules/graph/graph'; +import { Join } from '@/modules/joins/joins.module'; +import { calcPriceImpact } from '@/modules/pricing/priceImpact'; import { Relayer } from '@/modules/relayer/relayer.module'; +import { + Simulation, + SimulationType, +} from '@/modules/simulation/simulation.module'; import { FundManagement, SingleSwap, Swap, SwapType, } from '@/modules/swaps/types'; -import { WeightedPoolEncoder } from '@/pool-weighted'; +import { ExitPoolRequest as ExitPoolModelRequest } from '@/modules/vaultModel/poolModel/exit'; +import { SwapRequest } from '@/modules/vaultModel/poolModel/swap'; +import { Requests, VaultModel } from '@/modules/vaultModel/vaultModel.module'; +import { ComposableStablePoolEncoder } from '@/pool-composable-stable'; import { StablePoolEncoder } from '@/pool-stable'; -import { BalancerNetworkConfig, ExitPoolRequest, PoolType } from '@/types'; -import { PoolGraph, Node } from '../graph/graph'; - -import { subSlippage } from '@/lib/utils/slippageHelper'; -import { networkAddresses } from '@/lib/constants/config'; -import { AssetHelpers } from '@/lib/utils'; import { getPoolAddress } from '@/pool-utils'; -import { Join } from '../joins/joins.module'; -import { calcPriceImpact } from '../pricing/priceImpact'; -import { Simulation, SimulationType } from '../simulation/simulation.module'; -import { Requests, VaultModel } from '../vaultModel/vaultModel.module'; -import { SwapRequest } from '../vaultModel/poolModel/swap'; -import { ExitPoolRequest as ExitPoolModelRequest } from '../vaultModel/poolModel/exit'; -import { JsonRpcSigner } from '@ethersproject/providers'; +import { WeightedPoolEncoder } from '@/pool-weighted'; +import { BalancerNetworkConfig, ExitPoolRequest, PoolType } from '@/types'; -import { RelayerV5__factory } from '@/contracts'; +const balancerRelayerInterface = BalancerRelayer__factory.createInterface(); export class Exit { private wrappedNativeAsset: string; @@ -40,7 +43,7 @@ export class Exit { ) { const { tokens, contracts } = networkAddresses(networkConfig.chainId); this.wrappedNativeAsset = tokens.wrappedNativeAsset; - this.relayer = contracts.relayerV5 as string; + this.relayer = contracts.relayer; } async exitPool( @@ -72,13 +75,30 @@ export class Exit { // Create nodes and order by breadth first const orderedNodes = await this.poolGraph.getGraphNodes(false, poolId); - // Create exit paths for each output node and splits amount in proportionally between them + const isProportional = PoolGraph.isProportionalPools(orderedNodes); + console.log(`isProportional`, isProportional); + + let exitPaths: Node[][] = []; + let tokensOutByExitPath: string[] = []; + let tokensOut: string[] = []; + const outputNodes = orderedNodes.filter((n) => n.exitAction === 'output'); + tokensOutByExitPath = outputNodes.map((n) => n.address.toLowerCase()); - const exitPaths = this.getExitPaths(outputNodes, amountBptIn); + tokensOut = [...new Set(tokensOutByExitPath)].sort(); - const tokensOutByExitPath = outputNodes.map((n) => n.address.toLowerCase()); - const tokensOut = [...new Set(tokensOutByExitPath)].sort(); + if (isProportional) { + // All proportional will have single path from root node, exiting proportionally by ref all the way to leafs + const path = orderedNodes.map((node, i) => { + // First node should exit with full BPT amount in + if (i === 0) node.index = amountBptIn; + return node; + }); + exitPaths[0] = path; + } else { + // Create exit paths for each output node and splits amount in proportionally between them + exitPaths = this.getExitPaths(outputNodes, amountBptIn); + } // Create calls with minimum expected amount out for each exit path const { @@ -88,6 +108,7 @@ export class Exit { } = await this.createCalls( exitPaths, userAddress, + isProportional, undefined, authorisation ); @@ -119,6 +140,7 @@ export class Exit { const { encodedCall, deltas } = await this.createCalls( exitPaths, userAddress, + isProportional, minAmountsOutByExitPath, authorisation ); @@ -337,6 +359,7 @@ export class Exit { private async createCalls( exitPaths: Node[][], userAddress: string, + isProportional: boolean, minAmountsOut?: string[], authorisation?: string ): Promise<{ @@ -346,7 +369,12 @@ export class Exit { deltas: Record; }> { const { multiRequests, calls, outputIndexes, deltas } = - this.createActionCalls(cloneDeep(exitPaths), userAddress, minAmountsOut); + this.createActionCalls( + cloneDeep(exitPaths), + userAddress, + isProportional, + minAmountsOut + ); if (authorisation) { calls.unshift( @@ -354,10 +382,10 @@ export class Exit { ); } - const relayerInterface = RelayerV5__factory.createInterface(); - const encodedCall = relayerInterface.encodeFunctionData('multicall', [ - calls, - ]); + const encodedCall = balancerRelayerInterface.encodeFunctionData( + 'multicall', + [calls] + ); return { multiRequests, @@ -385,6 +413,7 @@ export class Exit { private createActionCalls( exitPaths: Node[][], userAddress: string, + isProportional: boolean, minAmountsOut?: string[] ): { multiRequests: Requests[][]; @@ -398,23 +427,74 @@ export class Exit { const isPeek = !minAmountsOut; const deltas: Record = {}; + const getSenderAddress = (exitPath: Node[], node: Node) => { + // Calls from root node are sent by the user + if (!node.parent) return userAddress; + // Otherwise sent by the parent's recipient + return getRecipientAddress(exitPath, node.parent); + }; + + const getRecipientAddress = (exitPath: Node[], node: Node) => { + // Always send to user on calls that contain outputs, otherwise send to relayer + const exitChildren = node.children.filter((child) => + exitPath.map((n) => n.index).includes(child.index) + ); + const hasOutputChild = exitChildren.some( + (c) => c.exitAction === 'output' + ); + return hasOutputChild ? userAddress : this.relayer; + }; + // Create actions for each Node and return in multicall array exitPaths.forEach((exitPath, i) => { const modelRequests: Requests[] = []; + const outputNodes = exitPath.filter( + (node) => node.exitAction === 'output' + ); exitPath.forEach((node) => { - // Calls from root node are sent by the user. Otherwise sent by the relayer - const isRootNode = !node.parent; - const sender = isRootNode ? userAddress : this.relayer; - // Always send to user on output calls otherwise send to relayer + // Find the exit child node const exitChild = node.children.find((child) => exitPath.map((n) => n.index).includes(child.index) ); - const isLastActionFromExitPath = exitChild?.exitAction === 'output'; - const recipient = isLastActionFromExitPath ? userAddress : this.relayer; + + const sender = getSenderAddress(exitPath, node); + const recipient = getRecipientAddress(exitPath, node); + + const exitChildren = node.children.filter((child) => + exitPath.map((n) => n.index).includes(child.index) + ); + const hasOutputChild = exitChildren.some( + (c) => c.exitAction === 'output' + ); + // Last calls will use minAmountsOut to protect user. Middle calls can safely have 0 minimum as tx will revert if last fails. - const minAmountOut = - isLastActionFromExitPath && minAmountsOut ? minAmountsOut[i] : '0'; + let minAmountOut = '0'; + const minAmountsOutProportional = Array(node.children.length).fill('0'); + if (minAmountsOut && hasOutputChild) { + if (isProportional) { + /** + * minAmountsOut is related to the whole multicall transaction, while + * minAmountsOutProportional is related only to the current node/transaction + * This section is responsible for mapping each minAmountOut to their + * respective position on the minAmountsOutProportional array + * TODO: extract to a function so it's easier to understand + */ + node.children.forEach((child, i) => { + if (child.exitAction === 'output') { + minAmountsOutProportional[i] = + minAmountsOut[outputNodes.indexOf(child)]; + } + }); + + // Proportional exits have a minAmountOut for each output node within a single exit path + minAmountOut = + minAmountsOut[outputNodes.indexOf(exitChild as Node)]; + } else { + // Non-proportional exits have a minAmountOut for each exit path + minAmountOut = minAmountsOut[i]; + } + } switch (node.exitAction) { case 'batchSwap': { @@ -433,8 +513,16 @@ export class Exit { break; } case 'exitPool': { - const { modelRequest, encodedCall, bptIn, tokensOut, amountsOut } = - this.createExitPool( + let exit; + if (isProportional) { + exit = this.createExitPoolProportional( + node, + minAmountsOutProportional, + sender, + recipient + ); + } else { + exit = this.createExitPool( node, exitChild as Node, i, @@ -442,6 +530,9 @@ export class Exit { sender, recipient ); + } + const { modelRequest, encodedCall, bptIn, tokensOut, amountsOut } = + exit; modelRequests.push(modelRequest); calls.push(encodedCall); this.updateDeltas( @@ -699,6 +790,131 @@ export class Exit { }; } + private createExitPoolProportional( + node: Node, + minAmountsOut: string[], + sender: string, + recipient: string + ): { + modelRequest: ExitPoolModelRequest; + encodedCall: string; + bptIn: string; + tokensOut: string[]; + amountsOut: string[]; + } { + const isRootNode = !node.parent; + const amountIn = isRootNode + ? node.index + : Relayer.toChainedReference(this.getOutputRef(0, node.index)).toString(); + + const tokensOut = node.children.map((child) => child.address); + const amountsOut = [...minAmountsOut]; + + if (node.type === PoolType.ComposableStable) { + // assets need to include the phantomPoolToken + tokensOut.push(node.address); + // need to add a placeholder so sorting works + amountsOut.push('0'); + } + + // TODO: we shoule consider let the graph handle sorting instead of manipulating + // token order within actions - specially now that we have different sorting + // cases and that the subgraph is already handling them properly + + // sort inputs + const assetHelpers = new AssetHelpers(this.wrappedNativeAsset); + const [sortedTokens, sortedAmounts] = assetHelpers.sortTokens( + tokensOut, + amountsOut + ) as [string[], string[]]; + + let userData: string; + if (node.type === PoolType.Weighted) { + userData = WeightedPoolEncoder.exitExactBPTInForTokensOut(amountIn); + } else if (node.type === PoolType.ComposableStable) { + userData = + ComposableStablePoolEncoder.exitExactBPTInForAllTokensOut(amountIn); + } else { + // TODO: double check if it's ok to set the Stable Pool Encoder as the default/else case + userData = StablePoolEncoder.exitExactBPTInForTokensOut(amountIn); + } + + const outputReferences = node.children.map((child) => { + return { + index: sortedTokens + .map((t) => t.toLowerCase()) + .indexOf(child.address.toLowerCase()), + key: Relayer.toChainedReference(this.getOutputRef(0, child.index)), + }; + }); + + // console.log( + // `${node.type} ${node.address} prop: ${formatFixed( + // node.proportionOfParent, + // 18 + // )} + // ${node.exitAction}( + // poolId: ${node.id}, + // tokensOut: ${sortedTokens}, + // tokenOut: ${sortedTokens[sortedTokens.indexOf(tokenOut)].toString()}, + // amountOut: ${sortedAmounts[sortedTokens.indexOf(tokenOut)].toString()}, + // amountIn: ${amountIn}, + // minAmountOut: ${minAmountOut}, + // outputRef: ${this.getOutputRef(exitPathIndex, exitChild.index)}, + // sender: ${sender}, + // recipient: ${recipient} + // )` + // ); + + // We have to use correct pool type based off following from Relayer: + // enum PoolKind { WEIGHTED, LEGACY_STABLE, COMPOSABLE_STABLE, COMPOSABLE_STABLE_V2 } + // (note only Weighted and COMPOSABLE_STABLE_V2 will support proportional exits) + let kind = 0; + if (node.type === PoolType.ComposableStable) { + kind = 3; + } + + const call = Relayer.formatExitPoolInput({ + poolId: node.id, + poolKind: kind, + sender, + recipient, + outputReferences, + exitPoolRequest: {} as ExitPoolRequest, + assets: sortedTokens, + minAmountsOut: sortedAmounts, + userData, + toInternalBalance: false, + }); + const encodedCall = Relayer.encodeExitPool(call); + const modelRequest = VaultModel.mapExitPoolRequest(call); + + const userAmountTokensOut = sortedAmounts.map((a) => + Relayer.isChainedReference(a) ? '0' : Zero.sub(a).toString() + ); + const userBptIn = Relayer.isChainedReference(amountIn) ? '0' : amountIn; + // If current node is the root node the exit the delta BPT in should be considered for user deltas + const deltaBptIn = isRootNode ? userBptIn : Zero.toString(); + // If the respective child node is an output, it should be considered for user deltas + const deltaTokensOut = sortedTokens.filter((t) => + node.children + .filter((c) => c.exitAction === 'output') + .map((c) => c.address) + .includes(t) + ); + const deltaAmountsOut = userAmountTokensOut.filter((_, i) => + deltaTokensOut.includes(sortedTokens[i]) + ); + + return { + modelRequest, + encodedCall, + bptIn: deltaBptIn, + tokensOut: deltaTokensOut, + amountsOut: deltaAmountsOut, + }; + } + private getOutputRef = (exitPathIndex: number, nodeIndex: string): number => { return exitPathIndex * 100 + parseInt(nodeIndex); }; diff --git a/balancer-js/src/modules/exits/exitsProportional.module.integration.spec.ts b/balancer-js/src/modules/exits/exitsProportional.module.integration.spec.ts new file mode 100644 index 000000000..5c417fb52 --- /dev/null +++ b/balancer-js/src/modules/exits/exitsProportional.module.integration.spec.ts @@ -0,0 +1,265 @@ +// yarn test:only ./src/modules/exits/exitsProportional.module.integration.spec.ts +import dotenv from 'dotenv'; +import { expect } from 'chai'; + +import { BigNumber, parseFixed } from '@ethersproject/bignumber'; +import { JsonRpcProvider, JsonRpcSigner } from '@ethersproject/providers'; + +import { BalancerSDK, GraphQLQuery, GraphQLArgs, Network } from '@/.'; +import { Relayer } from '@/modules/relayer/relayer.module'; +import { accuracy, forkSetup, getBalances } from '@/test/lib/utils'; +import { ADDRESSES } from '@/test/lib/constants'; +import { SimulationType } from '../simulation/simulation.module'; + +dotenv.config(); + +const network = Network.MAINNET; +const blockNumber = 17116836; +const { ALCHEMY_URL: jsonRpcUrl } = process.env; +const rpcUrl = 'http://127.0.0.1:8545'; + +const addresses = ADDRESSES[network]; + +// Set tenderly config blockNumber and use default values for other parameters +const tenderlyConfig = { + blockNumber, +}; + +/** + * Example of subgraph query that allows filtering pools. + * Might be useful to reduce the response time by limiting the amount of pool + * data that will be queried by the SDK. Specially when on chain data is being + * fetched as well. + */ +const poolAddresses = Object.values(addresses).map( + (address) => address.address +); +const subgraphArgs: GraphQLArgs = { + where: { + swapEnabled: { + eq: true, + }, + totalShares: { + gt: 0.000000000001, + }, + address: { + in: poolAddresses, + }, + }, + orderBy: 'totalLiquidity', + orderDirection: 'desc', + block: { number: blockNumber }, +}; +const subgraphQuery: GraphQLQuery = { args: subgraphArgs, attrs: {} }; + +const sdk = new BalancerSDK({ + network, + rpcUrl, + tenderly: tenderlyConfig, + subgraphQuery, +}); +const { pools, balancerContracts } = sdk; +const provider = new JsonRpcProvider(rpcUrl, network); +const signer = provider.getSigner(1); +const { contracts, contractAddresses } = balancerContracts; +const relayerAddress = contractAddresses.relayer as string; + +interface Test { + signer: JsonRpcSigner; + description: string; + pool: { + id: string; + address: string; + }; + amount: string; + authorisation: string | undefined; + simulationType?: SimulationType; +} + +const runTests = async (tests: Test[]) => { + for (let i = 0; i < tests.length; i++) { + const test = tests[i]; + it(test.description, async () => { + const signerAddress = await test.signer.getAddress(); + const authorisation = await Relayer.signRelayerApproval( + relayerAddress, + signerAddress, + test.signer, + contracts.vault + ); + await testFlow( + test.signer, + signerAddress, + test.pool, + test.amount, + authorisation, + test.simulationType + ); + }).timeout(120000); + } +}; + +const testFlow = async ( + signer: JsonRpcSigner, + signerAddress: string, + pool: { id: string; address: string }, + amount: string, + authorisation: string | undefined, + simulationType = SimulationType.VaultModel +) => { + const gasLimit = 8e6; + const slippage = '10'; // 10 bps = 0.1% + + const { to, encodedCall, tokensOut, expectedAmountsOut, minAmountsOut } = + await pools.generalisedExit( + pool.id, + amount, + signerAddress, + slippage, + signer, + simulationType, + authorisation + ); + + const [bptBalanceBefore, ...tokensOutBalanceBefore] = await getBalances( + [pool.address, ...tokensOut], + signer, + signerAddress + ); + + const response = await signer.sendTransaction({ + to, + data: encodedCall, + gasLimit, + }); + + const receipt = await response.wait(); + console.log('Gas used', receipt.gasUsed.toString()); + + const [bptBalanceAfter, ...tokensOutBalanceAfter] = await getBalances( + [pool.address, ...tokensOut], + signer, + signerAddress + ); + + console.table({ + tokensOut: tokensOut.map((t) => `${t.slice(0, 6)}...${t.slice(38, 42)}`), + minOut: minAmountsOut, + expectedOut: expectedAmountsOut, + balanceAfter: tokensOutBalanceAfter.map((b) => b.toString()), + }); + + expect(receipt.status).to.eql(1); + minAmountsOut.forEach((minAmountOut) => { + expect(BigNumber.from(minAmountOut).gte('0')).to.be.true; + }); + expectedAmountsOut.forEach((expectedAmountOut, i) => { + expect( + BigNumber.from(expectedAmountOut).gte(BigNumber.from(minAmountsOut[i])) + ).to.be.true; + }); + expect(bptBalanceAfter.eq(bptBalanceBefore.sub(amount))).to.be.true; + tokensOutBalanceBefore.forEach((b) => expect(b.eq(0)).to.be.true); + tokensOutBalanceAfter.forEach((balanceAfter, i) => { + const minOut = BigNumber.from(minAmountsOut[i]); + expect(balanceAfter.gte(minOut)).to.be.true; + const expectedOut = BigNumber.from(expectedAmountsOut[i]); + expect(accuracy(balanceAfter, expectedOut)).to.be.closeTo(1, 1e-2); // inaccuracy should not be over to 1% + }); +}; + +describe('generalised exit execution', async () => { + context('composable stable pool - non-boosted', async () => { + let authorisation: string | undefined; + const testPool = addresses.wstETH_rETH_sfrxETH; + + beforeEach(async () => { + const tokens = [testPool.address]; + const slots = [testPool.slot]; + const balances = [parseFixed('0.02', testPool.decimals).toString()]; + await forkSetup( + signer, + tokens, + slots, + balances, + jsonRpcUrl as string, + blockNumber + ); + }); + + await runTests([ + { + signer, + description: 'exit pool', + pool: { + id: testPool.id, + address: testPool.address, + }, + amount: parseFixed('0.01', testPool.decimals).toString(), + authorisation, + }, + ]); + }); + context('composable stable pool - boosted', async () => { + let authorisation: string | undefined; + const testPool = addresses.bbgusd; + + beforeEach(async () => { + const tokens = [testPool.address]; + const slots = [testPool.slot]; + const balances = [parseFixed('0.02', testPool.decimals).toString()]; + await forkSetup( + signer, + tokens, + slots, + balances, + jsonRpcUrl as string, + blockNumber + ); + }); + + await runTests([ + { + signer, + description: 'exit pool', + pool: { + id: testPool.id, + address: testPool.address, + }, + amount: parseFixed('0.01', testPool.decimals).toString(), + authorisation, + }, + ]); + }); + context('weighted with boosted', async () => { + let authorisation: string | undefined; + const testPool = addresses.STG_BBAUSD; + + beforeEach(async () => { + const tokens = [testPool.address]; + const slots = [testPool.slot]; + const balances = [parseFixed('25.111', testPool.decimals).toString()]; + await forkSetup( + signer, + tokens, + slots, + balances, + jsonRpcUrl as string, + blockNumber + ); + }); + + await runTests([ + { + signer, + description: 'exit pool', + pool: { + id: testPool.id, + address: testPool.address, + }, + amount: parseFixed('25.111', testPool.decimals).toString(), + authorisation, + }, + ]); + }); +}); diff --git a/balancer-js/src/modules/graph/graph.ts b/balancer-js/src/modules/graph/graph.ts index b0b815f73..def10ab68 100644 --- a/balancer-js/src/modules/graph/graph.ts +++ b/balancer-js/src/modules/graph/graph.ts @@ -14,6 +14,7 @@ export interface Node { id: string; joinAction: JoinAction; exitAction: ExitAction; + isProportionalExit: boolean; type: string; children: Node[]; marked: boolean; @@ -40,7 +41,7 @@ joinActions.set(PoolType.StablePhantom, 'batchSwap'); joinActions.set(PoolType.Weighted, 'joinPool'); joinActions.set(PoolType.ComposableStable, 'joinPool'); -type ExitAction = 'output' | 'batchSwap' | 'exitPool'; +type ExitAction = 'output' | 'batchSwap' | 'exitPool' | 'exitPoolProportional'; const exitActions = new Map(); supportedPoolTypes.forEach((type) => { if (type.includes('Linear') && supportedPoolTypes.includes(type)) @@ -149,6 +150,7 @@ export class PoolGraph { type: pool.poolType, joinAction, exitAction, + isProportionalExit: false, children: [], marked: false, index: nodeIndex.toString(), @@ -158,6 +160,7 @@ export class PoolGraph { spotPrices, decimals, }; + this.updateNodeIfProportionalExit(pool, poolNode); nodeIndex++; if (pool.poolType.toString().includes('Linear')) { [poolNode, nodeIndex] = this.createLinearNodeChildren( @@ -196,6 +199,20 @@ export class PoolGraph { return [poolNode, nodeIndex]; } + /** + * Updates isProportionalExit for Node if the pool supports it + * @param pool + * @param node + */ + updateNodeIfProportionalExit(pool: Pool, node: Node): void { + if (pool.poolType === PoolType.Weighted) node.isProportionalExit = true; + else if ( + pool.poolType === PoolType.ComposableStable && + pool.poolTypeVersion > 2 + ) + node.isProportionalExit = true; + } + createLinearNodeChildren( linearPoolNode: Node, nodeIndex: number, @@ -236,6 +253,7 @@ export class PoolGraph { marked: false, joinAction: 'input', exitAction: 'output', + isProportionalExit: false, index: nodeIndex.toString(), // This will be updated with real amounts in join construction. parent, proportionOfParent, @@ -271,6 +289,18 @@ export class PoolGraph { return nodes.filter((n) => n.isLeaf).map((n) => n.address); } + /** + * Checks if list of Nodes only contains pools that support proportional exits + * @param nodes + * @returns + */ + static isProportionalPools(nodes: Node[]): boolean { + return nodes.every((node) => { + if (node.exitAction === 'exitPool') return node.isProportionalExit; + else return true; + }); + } + // Get full graph from root pool and return ordered nodes getGraphNodes = async (isJoin: boolean, poolId: string): Promise => { const rootPool = await this.pools.find(poolId); diff --git a/balancer-js/src/modules/joins/joins.module.integration.arbitrum.spec.ts b/balancer-js/src/modules/joins/joins.module.integration.arbitrum.spec.ts new file mode 100644 index 000000000..1fef053aa --- /dev/null +++ b/balancer-js/src/modules/joins/joins.module.integration.arbitrum.spec.ts @@ -0,0 +1,225 @@ +// yarn test:only ./src/modules/joins/joins.module.integration.arbitrum.spec.ts +import dotenv from 'dotenv'; +import { expect } from 'chai'; + +import { BalancerSDK, GraphQLQuery, GraphQLArgs, Network } from '@/.'; +import { BigNumber, parseFixed } from '@ethersproject/bignumber'; +import { JsonRpcProvider } from '@ethersproject/providers'; +import { Contracts } from '@/modules/contracts/contracts.module'; +import { accuracy, forkSetup, getBalances } from '@/test/lib/utils'; +import { ADDRESSES } from '@/test/lib/constants'; +import { Relayer } from '@/modules/relayer/relayer.module'; +import { JsonRpcSigner } from '@ethersproject/providers'; +import { SimulationType } from '../simulation/simulation.module'; + +/** + * -- Integration tests for generalisedJoin -- + * + * It compares results from local fork transactions with simulated results from + * the Simulation module, which can be of 3 different types: + * 1. Tenderly: uses Tenderly Simulation API (third party service) + * 2. VaultModel: uses TS math, which may be less accurate (min. 99% accuracy) + * 3. Static: uses staticCall, which is 100% accurate but requires vault approval + */ + +dotenv.config(); + +const TEST_BOOSTED = true; + +/* + * Testing on ARBITRUM + * - Make sure ALCHEMY_URL_ARBITRUM is set on .env with a arbitrum api key + * - Run node on terminal: yarn run node:arbitrum + * - Uncomment section below: + */ +const network = Network.ARBITRUM; +const blockNumber = 79069597; +const { ALCHEMY_URL_ARBITRUM: jsonRpcUrl } = process.env; +const rpcUrl = 'http://127.0.0.1:8161'; + +const addresses = ADDRESSES[network]; + +// Set tenderly config blockNumber and use default values for other parameters +const tenderlyConfig = { + blockNumber, +}; + +/** + * Example of subgraph query that allows filtering pools. + * Might be useful to reduce the response time by limiting the amount of pool + * data that will be queried by the SDK. Specially when on chain data is being + * fetched as well. + */ +const poolAddresses = Object.values(addresses).map( + (address) => address.address +); +const subgraphArgs: GraphQLArgs = { + where: { + swapEnabled: { + eq: true, + }, + totalShares: { + gt: 0.000000000001, + }, + address: { + in: poolAddresses, + }, + }, + orderBy: 'totalLiquidity', + orderDirection: 'desc', + block: { number: blockNumber }, +}; +const subgraphQuery: GraphQLQuery = { args: subgraphArgs, attrs: {} }; + +const sdk = new BalancerSDK({ + network, + rpcUrl, + tenderly: tenderlyConfig, + subgraphQuery, +}); +const { pools } = sdk; +const provider = new JsonRpcProvider(rpcUrl, network); +const signer = provider.getSigner(); +const { contracts, contractAddresses } = new Contracts( + network as number, + provider +); +const relayer = contractAddresses.relayer as string; + +interface Test { + signer: JsonRpcSigner; + description: string; + pool: { + id: string; + address: string; + }; + tokensIn: string[]; + amountsIn: string[]; + authorisation: string | undefined; + wrapMainTokens: boolean; + simulationType?: SimulationType; +} + +const runTests = async (tests: Test[]) => { + for (let i = 0; i < tests.length; i++) { + const test = tests[i]; + it(test.description, async () => { + const userAddress = await test.signer.getAddress(); + const authorisation = await Relayer.signRelayerApproval( + relayer, + userAddress, + signer, + contracts.vault + ); + await testFlow( + userAddress, + test.pool, + test.tokensIn, + test.amountsIn, + test.wrapMainTokens, + authorisation, + test.simulationType + ); + }).timeout(360000); + } +}; + +const testFlow = async ( + userAddress: string, + pool: { id: string; address: string }, + tokensIn: string[], + amountsIn: string[], + wrapMainTokens: boolean, + authorisation: string | undefined, + simulationType = SimulationType.VaultModel +) => { + const [bptBalanceBefore, ...tokensInBalanceBefore] = await getBalances( + [pool.address, ...tokensIn], + signer, + userAddress + ); + + const gasLimit = 8e6; + const slippage = '10'; // 10 bps = 0.1% + + const query = await pools.generalisedJoin( + pool.id, + tokensIn, + amountsIn, + userAddress, + slippage, + signer, + simulationType, + authorisation + ); + + const response = await signer.sendTransaction({ + to: query.to, + data: query.encodedCall, + gasLimit, + }); + + const receipt = await response.wait(); + console.log('Gas used', receipt.gasUsed.toString()); + + const [bptBalanceAfter, ...tokensInBalanceAfter] = await getBalances( + [pool.address, ...tokensIn], + signer, + userAddress + ); + + console.table({ + minOut: query.minOut, + expectedOut: query.expectedOut, + balanceAfter: bptBalanceAfter.toString(), + }); + + expect(receipt.status).to.eql(1); + expect(BigNumber.from(query.minOut).gte('0')).to.be.true; + expect(BigNumber.from(query.expectedOut).gt(query.minOut)).to.be.true; + tokensInBalanceAfter.forEach((balanceAfter, i) => { + expect(balanceAfter.toString()).to.eq( + tokensInBalanceBefore[i].sub(amountsIn[i]).toString() + ); + }); + expect(bptBalanceBefore.eq(0)).to.be.true; + expect(bptBalanceAfter.gte(query.minOut)).to.be.true; + expect( + accuracy(bptBalanceAfter, BigNumber.from(query.expectedOut)) + ).to.be.closeTo(1, 1e-2); // inaccuracy should not be over to 1% +}; + +describe.skip('generalised join execution', async () => { + context('boosted', async () => { + if (!TEST_BOOSTED) return true; + let authorisation: string | undefined; + const testPool = addresses.bbrfusd; + beforeEach(async () => { + const tokens = [addresses.USDT.address]; + const balances = [parseFixed('5', addresses.USDT.decimals).toString()]; + await forkSetup( + signer, + tokens, + undefined, // slots + balances, + jsonRpcUrl as string, + blockNumber + ); + }); + + await runTests([ + { + signer, + description: 'join with one leaf token', + pool: { + id: testPool.id, + address: testPool.address, + }, + tokensIn: [addresses.USDT.address], + amountsIn: [parseFixed('5', addresses.USDT.decimals).toString()], + authorisation, + wrapMainTokens: false, + }, + ]); + }); +}); diff --git a/balancer-js/src/modules/joins/joins.module.integration.spec.ts b/balancer-js/src/modules/joins/joins.module.integration.spec.ts index 180eea7b2..46f5276cb 100644 --- a/balancer-js/src/modules/joins/joins.module.integration.spec.ts +++ b/balancer-js/src/modules/joins/joins.module.integration.spec.ts @@ -108,7 +108,7 @@ const { contracts, contractAddresses } = new Contracts( network as number, provider ); -const relayer = contractAddresses.relayerV5 as string; +const relayer = contractAddresses.relayer; interface Test { signer: JsonRpcSigner; diff --git a/balancer-js/src/modules/joins/joins.module.ts b/balancer-js/src/modules/joins/joins.module.ts index b1a0c643e..1c4e6d01a 100644 --- a/balancer-js/src/modules/joins/joins.module.ts +++ b/balancer-js/src/modules/joins/joins.module.ts @@ -30,7 +30,9 @@ import { Requests, VaultModel } from '../vaultModel/vaultModel.module'; import { SwapRequest } from '../vaultModel/poolModel/swap'; import { JoinPoolRequest as JoinPoolModelRequest } from '../vaultModel/poolModel/join'; import { JsonRpcSigner } from '@ethersproject/providers'; -import { RelayerV5__factory } from '@/contracts'; +import { BalancerRelayer__factory } from '@/contracts/factories/BalancerRelayer__factory'; + +const balancerRelayerInterface = BalancerRelayer__factory.createInterface(); export class Join { private relayer: string; @@ -41,7 +43,7 @@ export class Join { private simulationService: Simulation ) { const { tokens, contracts } = networkAddresses(networkConfig.chainId); - this.relayer = contracts.relayerV5 as string; + this.relayer = contracts.relayer; this.wrappedNativeAsset = tokens.wrappedNativeAsset; } @@ -349,11 +351,10 @@ export class Join { if (authorisation) { encodedCalls.unshift(this.createSetRelayerApproval(authorisation)); } - - const relayerInterface = RelayerV5__factory.createInterface(); - const encodedCall = relayerInterface.encodeFunctionData('multicall', [ - encodedCalls, - ]); + const encodedCall = balancerRelayerInterface.encodeFunctionData( + 'multicall', + [encodedCalls] + ); return { multiRequests, diff --git a/balancer-js/src/modules/liquidity-managment/migrations.integrations.spec.ts b/balancer-js/src/modules/liquidity-managment/migrations.integrations.spec.ts index 63e34d4b0..bcce554a4 100644 --- a/balancer-js/src/modules/liquidity-managment/migrations.integrations.spec.ts +++ b/balancer-js/src/modules/liquidity-managment/migrations.integrations.spec.ts @@ -1,9 +1,9 @@ +// yarn test:only ./src/modules/liquidity-managment/migrations.integrations.spec.ts import { impersonateAccount, reset } from '@/test/lib/utils'; import { expect } from 'chai'; -import { Vault__factory } from '@/contracts'; +import { ERC20__factory, Vault__factory } from '@/contracts'; import { BALANCER_NETWORK_CONFIG } from '@/lib/constants/config'; import { JsonRpcProvider, JsonRpcSigner } from '@ethersproject/providers'; -import { ERC20 } from '@/modules/contracts/implementations/ERC20'; import { vitaDao1, vitaDao2, @@ -16,12 +16,13 @@ import { } from './migrations/builder.spec-helpers'; import { Migrations } from './migrations'; -describe('Migrations', () => { +describe('Migrations', function () { + this.timeout(30000); context('mainnet', () => { const { addresses: { contracts }, } = BALANCER_NETWORK_CONFIG[1]; - const relayerAddress = contracts.relayerV5 as string; + const relayerAddress = contracts.relayer; const provider = new JsonRpcProvider('http://127.0.0.1:8545'); const vault = Vault__factory.connect(contracts.vault, provider); let signer: JsonRpcSigner; @@ -54,7 +55,11 @@ describe('Migrations', () => { }); it('joins a new pool with an limit', async () => { - const balance = await ERC20(from.address, signer).balanceOf(address); + const balance = ( + await ERC20__factory.connect(from.address, signer).balanceOf( + address + ) + ).toString(); const peek = await migrations.pool2pool( address, from.id, @@ -74,11 +79,11 @@ describe('Migrations', () => { await (await signer.sendTransaction(txParams)).wait(); - const balanceAfter = await ERC20(to.address, signer).balanceOf( - address - ); + const balanceAfter = ( + await ERC20__factory.connect(to.address, signer).balanceOf(address) + ).toString(); - expect(String(balanceAfter)).to.be.eq(expectedBptOut); + expect(balanceAfter).to.be.eq(expectedBptOut); }); }); @@ -91,7 +96,9 @@ describe('Migrations', () => { const gauge = (await gaugesRepository.findBy('poolId', from.id)) as { id: string; }; - const balance = await ERC20(gauge.id, signer).balanceOf(address); + const balance = ( + await ERC20__factory.connect(gauge.id, signer).balanceOf(address) + ).toString(); const peek = await migrations.pool2poolWithGauges( address, @@ -112,9 +119,11 @@ describe('Migrations', () => { await (await signer.sendTransaction(txParams)).wait(); - const balanceAfter = await ERC20(gauge.id, signer).balanceOf(address); + const balanceAfter = ( + await ERC20__factory.connect(gauge.id, signer).balanceOf(address) + ).toString(); - expect(String(balanceAfter)).to.be.eq(expectedBptOut); + expect(balanceAfter).to.be.eq(expectedBptOut); }); }); }); @@ -126,7 +135,9 @@ describe('Migrations', () => { it('should build a migration using exit / join', async () => { const pool = composableStable; - const balance = await ERC20(pool.address, signer).balanceOf(address); + const balance = ( + await ERC20__factory.connect(pool.address, signer).balanceOf(address) + ).toString(); const peek = await migrations.pool2pool( address, @@ -154,9 +165,9 @@ describe('Migrations', () => { await (await signer.sendTransaction(txParams)).wait(); - const balanceAfter = await ERC20(pool.address, signer).balanceOf( - address - ); + const balanceAfter = ( + await ERC20__factory.connect(pool.address, signer).balanceOf(address) + ).toString(); // NOTICE: We don't know the exact amount of BPT that will be minted, // because swaps from the linear pool are not deterministic due to external rates @@ -174,7 +185,9 @@ describe('Migrations', () => { it('should build a migration using exit / join', async () => { const from = vitaDao1; const to = vitaDao2; - const balance = await ERC20(from.address, signer).balanceOf(address); + const balance = ( + await ERC20__factory.connect(from.address, signer).balanceOf(address) + ).toString(); const peek = await migrations.pool2pool( address, from.id, @@ -194,9 +207,11 @@ describe('Migrations', () => { await (await signer.sendTransaction(txParams)).wait(); - const balanceAfter = await ERC20(to.address, signer).balanceOf(address); + const balanceAfter = ( + await ERC20__factory.connect(to.address, signer).balanceOf(address) + ).toString(); - expect(String(balanceAfter)).to.be.eq(expectedBptOut); + expect(balanceAfter).to.be.eq(expectedBptOut); }); }); @@ -208,7 +223,9 @@ describe('Migrations', () => { it('should build a migration using exit / join and stake tokens in the gauge', async () => { const from = '0xa6468eca7633246dcb24e5599681767d27d1f978'; const to = '0x57ab3b673878c3feab7f8ff434c40ab004408c4c'; - const balance = await ERC20(from, provider).balanceOf(address); + const balance = ( + await ERC20__factory.connect(from, provider).balanceOf(address) + ).toString(); const txParams = await migrations.gauge2gauge( address, @@ -219,7 +236,9 @@ describe('Migrations', () => { await (await signer.sendTransaction(txParams)).wait(); - const balanceAfter = await ERC20(to, provider).balanceOf(address); + const balanceAfter = ( + await ERC20__factory.connect(to, provider).balanceOf(address) + ).toString(); expect(balanceAfter).to.be.eql(balance); }); @@ -230,7 +249,7 @@ describe('Migrations', () => { const { addresses: { contracts }, } = BALANCER_NETWORK_CONFIG[137]; - const relayerAddress = contracts.relayerV5 as string; + const relayerAddress = contracts.relayer; const provider = new JsonRpcProvider('http://127.0.0.1:8137'); const vault = Vault__factory.connect(contracts.vault, provider); let signer: JsonRpcSigner; @@ -260,7 +279,9 @@ describe('Migrations', () => { it('should build a migration using exit / join', async () => { const pool = polygonComposableStable; - const balance = await ERC20(pool.address, signer).balanceOf(address); + const balance = ( + await ERC20__factory.connect(pool.address, signer).balanceOf(address) + ).toString(); const peek = await migrations.pool2pool( address, @@ -288,9 +309,9 @@ describe('Migrations', () => { await (await signer.sendTransaction(txParams)).wait(); - const balanceAfter = await ERC20(pool.address, signer).balanceOf( - address - ); + const balanceAfter = ( + await ERC20__factory.connect(pool.address, signer).balanceOf(address) + ).toString(); // NOTICE: We don't know the exact amount of BPT that will be minted, // because swaps from the linear pool are not deterministic due to external rates diff --git a/balancer-js/src/modules/liquidity-managment/migrations/helpers.ts b/balancer-js/src/modules/liquidity-managment/migrations/helpers.ts index 2bae07756..b052b024c 100644 --- a/balancer-js/src/modules/liquidity-managment/migrations/helpers.ts +++ b/balancer-js/src/modules/liquidity-managment/migrations/helpers.ts @@ -1,8 +1,8 @@ import { Findable, Pool, PoolAttribute } from '@/types'; -import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; -import { Interface } from '@ethersproject/abi'; +import { BalancerRelayer__factory } from '@/contracts'; -export const balancerRelayerInterface = new Interface(balancerRelayerAbi); +export const balancerRelayerInterface = + BalancerRelayer__factory.createInterface(); /** * Using array of objects to preserve the tokens order diff --git a/balancer-js/src/modules/pools/factory/composable-stable/composable-stable.factory.integration.spec.ts b/balancer-js/src/modules/pools/factory/composable-stable/composable-stable.factory.integration.spec.ts index c5319e77e..fab0da075 100644 --- a/balancer-js/src/modules/pools/factory/composable-stable/composable-stable.factory.integration.spec.ts +++ b/balancer-js/src/modules/pools/factory/composable-stable/composable-stable.factory.integration.spec.ts @@ -9,7 +9,7 @@ import { OldBigNumber, StableMaths } from '@balancer-labs/sor'; import { Network, PoolType, - ComposableStable__factory, + ComposableStablePool__factory, BalancerSDK, ComposableStable, ComposableStableCreatePoolParameters, @@ -82,7 +82,7 @@ describe('ComposableStable Factory', async () => { provider, transactionReceipt )); - pool = ComposableStable__factory.connect(poolAddress, provider); + pool = ComposableStablePool__factory.connect(poolAddress, provider); const id = await pool.getPoolId(); const owner = await pool.getOwner(); const swapFee = await pool.getSwapFeePercentage(); diff --git a/balancer-js/src/modules/pools/factory/composable-stable/composable-stable.factory.ts b/balancer-js/src/modules/pools/factory/composable-stable/composable-stable.factory.ts index 266466506..a4cb92c21 100644 --- a/balancer-js/src/modules/pools/factory/composable-stable/composable-stable.factory.ts +++ b/balancer-js/src/modules/pools/factory/composable-stable/composable-stable.factory.ts @@ -13,8 +13,8 @@ import { PoolFactory } from '@/modules/pools/factory/pool-factory'; import { ComposableStablePoolEncoder } from '@/pool-composable-stable'; import { BalancerNetworkConfig } from '@/types'; import { - ComposableStable__factory, - ComposableStableFactory__factory, + ComposableStablePool__factory, + ComposableStablePoolFactory__factory, } from '@/contracts'; import { JsonRpcProvider, TransactionReceipt } from '@ethersproject/providers'; import { LogDescription } from '@ethersproject/abi'; @@ -22,7 +22,7 @@ import { findEventInReceiptLogs } from '@/lib/utils'; import { Contract } from '@ethersproject/contracts'; import { ContractInstances } from '@/modules/contracts/contracts.module'; import { BytesLike } from '@ethersproject/bytes'; -import { ComposableStableInterface } from '@/contracts/ComposableStable'; +import { ComposableStablePoolInterface } from '@/contracts/ComposableStablePool'; export class ComposableStableFactory implements PoolFactory { private wrappedNativeAsset: string; @@ -183,7 +183,7 @@ export class ComposableStableFactory implements PoolFactory { ] ): string => { const composablePoolFactoryInterface = - ComposableStableFactory__factory.createInterface(); + ComposableStablePoolFactory__factory.createInterface(); return composablePoolFactoryInterface.encodeFunctionData('create', params); }; @@ -317,7 +317,7 @@ export class ComposableStableFactory implements PoolFactory { const poolCreationEvent: LogDescription = findEventInReceiptLogs({ receipt, to: this.contracts.composableStablePoolFactory?.address || '', - contractInterface: ComposableStableFactory__factory.createInterface(), + contractInterface: ComposableStablePoolFactory__factory.createInterface(), logName: 'PoolCreated', }); @@ -335,7 +335,7 @@ export class ComposableStableFactory implements PoolFactory { }; }; - getPoolInterface(): ComposableStableInterface { - return ComposableStable__factory.createInterface(); + getPoolInterface(): ComposableStablePoolInterface { + return ComposableStablePool__factory.createInterface(); } } diff --git a/balancer-js/src/modules/pools/factory/pool-factory.ts b/balancer-js/src/modules/pools/factory/pool-factory.ts index d593e1e00..b26b01924 100644 --- a/balancer-js/src/modules/pools/factory/pool-factory.ts +++ b/balancer-js/src/modules/pools/factory/pool-factory.ts @@ -8,7 +8,7 @@ import { } from '@/modules/pools/factory/types'; import { JsonRpcProvider, TransactionReceipt } from '@ethersproject/providers'; import { WeightedPoolInterface } from '@/contracts/WeightedPool'; -import { ComposableStableInterface } from '@/contracts/ComposableStable'; +import { ComposableStablePoolInterface } from '@/contracts/ComposableStablePool'; import { ERC4626LinearPoolInterface } from '@/contracts/ERC4626LinearPool'; import { EulerLinearPoolInterface } from '@/contracts/EulerLinearPool'; import { AaveLinearPoolInterface } from '@/contracts/AaveLinearPool'; @@ -33,7 +33,7 @@ export interface PoolFactory { getPoolInterface(): | WeightedPoolInterface - | ComposableStableInterface + | ComposableStablePoolInterface | ERC4626LinearPoolInterface | EulerLinearPoolInterface | AaveLinearPoolInterface diff --git a/balancer-js/src/modules/pools/index.ts b/balancer-js/src/modules/pools/index.ts index 6f1548495..33a4b6872 100644 --- a/balancer-js/src/modules/pools/index.ts +++ b/balancer-js/src/modules/pools/index.ts @@ -141,7 +141,8 @@ export class Pools implements Findable { bptIn: string, slippage: string, shouldUnwrapNativeAsset = false, - singleTokenOut?: string + singleTokenOut?: string, + toInternalBalance = false ) => { if (concerns.exit.buildExitExactBPTIn) { return concerns.exit.buildExitExactBPTIn({ @@ -152,6 +153,7 @@ export class Pools implements Findable { shouldUnwrapNativeAsset, wrappedNativeAsset, singleTokenOut, + toInternalBalance, }); } else { throw 'ExitExactBPTIn not supported'; @@ -161,7 +163,8 @@ export class Pools implements Findable { exiter: string, tokensOut: string[], amountsOut: string[], - slippage: string + slippage: string, + toInternalBalance = false ) => concerns.exit.buildExitExactTokensOut({ exiter, @@ -170,13 +173,20 @@ export class Pools implements Findable { amountsOut, slippage, wrappedNativeAsset, + toInternalBalance, }), - buildRecoveryExit: (exiter: string, bptIn: string, slippage: string) => + buildRecoveryExit: ( + exiter: string, + bptIn: string, + slippage: string, + toInternalBalance = false + ) => concerns.exit.buildRecoveryExit({ exiter, pool, bptIn, slippage, + toInternalBalance, }), // TODO: spotPrice fails, because it needs a subgraphType, diff --git a/balancer-js/src/modules/pools/pool-type-concerns.ts b/balancer-js/src/modules/pools/pool-type-concerns.ts index 6597f6074..774c798bd 100644 --- a/balancer-js/src/modules/pools/pool-type-concerns.ts +++ b/balancer-js/src/modules/pools/pool-type-concerns.ts @@ -7,6 +7,7 @@ import { StablePhantom } from './pool-types/stablePhantom.module'; import { Linear } from './pool-types/linear.module'; import { BalancerError, BalancerErrorCode } from '@/balancerErrors'; import { isLinearish } from '@/lib/utils'; +import { FX } from '@/modules/pools/pool-types/fx.module'; /** * Wrapper around pool type specific methods. @@ -52,6 +53,9 @@ export class PoolTypeConcerns { case 'StablePhantom': { return new StablePhantom(); } + case 'FX': { + return new FX(); + } default: { // Handles all Linear pool types if (isLinearish(poolType)) return new Linear(); diff --git a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.spec.ts index 4b85956d6..23660cefb 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.spec.ts @@ -37,6 +37,7 @@ describe('Composable Stable Pool exits', () => { slippage: '100', shouldUnwrapNativeAsset: false, wrappedNativeAsset, + toInternalBalance: false, }; }); @@ -86,6 +87,7 @@ describe('Composable Stable Pool exits', () => { amountsOut: tokensOut.map((_, i) => String(parseEther(`${i * 100}`))), slippage: '100', wrappedNativeAsset, + toInternalBalance: false, }; }); diff --git a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.ts index 98574631c..c7e9d1b52 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.ts @@ -69,7 +69,10 @@ type SortValuesExactTokensOutParams = SortValuesParams & { tokensOut: string[]; }; -type EncodeExitParams = Pick & { +type EncodeExitParams = Pick< + ExitExactBPTInParameters, + 'exiter' | 'toInternalBalance' +> & { poolTokens: string[]; poolId: string; userData: string; @@ -85,6 +88,7 @@ export class ComposableStablePoolExit implements ExitConcern { shouldUnwrapNativeAsset, wrappedNativeAsset, singleTokenOut, + toInternalBalance, }: ExitExactBPTInParameters): ExitExactBPTInAttributes => { this.checkInputsExactBPTIn({ bptIn, @@ -133,6 +137,7 @@ export class ComposableStablePoolExit implements ExitConcern { exiter, userData, minAmountsOut: minAmountsOutWithBpt, + toInternalBalance, }); const priceImpactConcern = new StablePoolPriceImpact(); @@ -158,6 +163,7 @@ export class ComposableStablePoolExit implements ExitConcern { amountsOut, slippage, wrappedNativeAsset, + toInternalBalance, }: ExitExactTokensOutParameters): ExitExactTokensOutAttributes => { this.checkInputsExactTokensOut(tokensOut, amountsOut, pool); const sortedValues = this.sortValuesExitExactTokensOut({ @@ -184,6 +190,7 @@ export class ComposableStablePoolExit implements ExitConcern { userData, exiter, poolId: pool.id, + toInternalBalance, }); const priceImpactConcern = new StablePoolPriceImpact(); @@ -207,9 +214,10 @@ export class ComposableStablePoolExit implements ExitConcern { pool, bptIn, slippage, + toInternalBalance, }: Pick< ExitExactBPTInParameters, - 'exiter' | 'pool' | 'bptIn' | 'slippage' + 'exiter' | 'pool' | 'bptIn' | 'slippage' | 'toInternalBalance' >): ExitExactBPTInAttributes => { this.checkInputsRecoveryExit({ bptIn, @@ -239,6 +247,7 @@ export class ComposableStablePoolExit implements ExitConcern { exiter, userData, minAmountsOut: minAmountsOutWithBpt, + toInternalBalance, }); const priceImpactConcern = new StablePoolPriceImpact(); @@ -566,7 +575,14 @@ export class ComposableStablePoolExit implements ExitConcern { * @param params */ encodeExitPool = (params: EncodeExitParams): ExitPoolAttributes => { - const { exiter, poolId, minAmountsOut, userData, poolTokens } = params; + const { + exiter, + poolId, + minAmountsOut, + userData, + poolTokens, + toInternalBalance, + } = params; const to = balancerVault; const functionName = 'exitPool'; @@ -578,7 +594,7 @@ export class ComposableStablePoolExit implements ExitConcern { assets: poolTokens, minAmountsOut, userData, - toInternalBalance: false, + toInternalBalance, }, }; diff --git a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exitV1.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exitV1.concern.integration.spec.ts index 44dd2979d..de3b87e73 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exitV1.concern.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exitV1.concern.integration.spec.ts @@ -86,5 +86,10 @@ describe('ComposableStableV1 Exits', () => { const bptIn = parseFixed('10', 18).toString(); await testRecoveryExit(pool, signer, bptIn); }); + + it('proportional exit - to internal balance', async () => { + const bptIn = parseFixed('10', 18).toString(); + await testRecoveryExit(pool, signer, bptIn, true); + }); }); }); diff --git a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/join.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/join.concern.integration.spec.ts index 25a4fea46..ee3fee103 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/join.concern.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/join.concern.integration.spec.ts @@ -25,7 +25,7 @@ const { ALCHEMY_URL_POLYGON: jsonRpcUrl } = process.env; const rpcUrl = 'http://127.0.0.1:8137'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const signer = provider.getSigner(); -const blockNumber = 41029487; +const blockNumber = 41400000; const testPoolId = '0x02d2e2d7a89d6c5cb3681cfcb6f7dac02a55eda400000000000000000000088f'; @@ -33,7 +33,6 @@ describe('ComposableStable Pool - Join Functions', async () => { let signerAddress: string; let pool: PoolWithMethods; let testPoolHelper: TestPoolHelper; - before(async () => { signerAddress = await signer.getAddress(); diff --git a/balancer-js/src/modules/pools/pool-types/concerns/fx/exit.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/fx/exit.concern.ts new file mode 100644 index 000000000..ad9c77e23 --- /dev/null +++ b/balancer-js/src/modules/pools/pool-types/concerns/fx/exit.concern.ts @@ -0,0 +1,41 @@ +import { + ExitConcern, + ExitExactBPTInAttributes, + ExitExactBPTInParameters, + ExitExactTokensOutAttributes, + ExitExactTokensOutParameters, +} from '@/modules/pools/pool-types/concerns/types'; + +export class FXExitConcern implements ExitConcern { + buildExitExactTokensOut({ + exiter, + pool, + tokensOut, + amountsOut, + slippage, + wrappedNativeAsset, + }: ExitExactTokensOutParameters): ExitExactTokensOutAttributes { + console.log( + exiter, + pool, + tokensOut, + amountsOut, + slippage, + wrappedNativeAsset + ); + throw new Error('Not implemented'); + } + + buildRecoveryExit({ + exiter, + pool, + bptIn, + slippage, + }: Pick< + ExitExactBPTInParameters, + 'exiter' | 'pool' | 'bptIn' | 'slippage' + >): ExitExactBPTInAttributes { + console.log(exiter, pool, bptIn, slippage); + throw new Error('Not implemented'); + } +} diff --git a/balancer-js/src/modules/pools/pool-types/concerns/fx/join.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/fx/join.concern.ts new file mode 100644 index 000000000..146728d3e --- /dev/null +++ b/balancer-js/src/modules/pools/pool-types/concerns/fx/join.concern.ts @@ -0,0 +1,26 @@ +import { + JoinConcern, + JoinPoolAttributes, + JoinPoolParameters, +} from '@/modules/pools/pool-types/concerns/types'; + +export class FXJoinConcern implements JoinConcern { + buildJoin({ + joiner, + pool, + tokensIn, + amountsIn, + slippage, + wrappedNativeAsset, + }: JoinPoolParameters): JoinPoolAttributes { + console.log( + joiner, + pool, + tokensIn, + amountsIn, + slippage, + wrappedNativeAsset + ); + throw new Error('Not implemented'); + } +} diff --git a/balancer-js/src/modules/pools/pool-types/concerns/fx/liquidity.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/fx/liquidity.concern.integration.spec.ts new file mode 100644 index 000000000..8446a0bb4 --- /dev/null +++ b/balancer-js/src/modules/pools/pool-types/concerns/fx/liquidity.concern.integration.spec.ts @@ -0,0 +1,72 @@ +// yarn test:only ./src/modules/pools/pool-types/concerns/fx/liquidity.concern.integration.spec.ts +import dotenv from 'dotenv'; +import { Network, PoolWithMethods } from '@/types'; +import { forkSetup, TestPoolHelper } from '@/test/lib/utils'; +import { ethers } from 'hardhat'; +import { BalancerSDK } from '@/modules/sdk.module'; +import { FXPool__factory } from '@/contracts'; +import { Contract } from '@ethersproject/contracts'; +import { expect } from 'chai'; +import { formatFixed, parseFixed } from '@ethersproject/bignumber'; +import { SolidityMaths } from '@/lib/utils/solidityMaths'; + +dotenv.config(); + +const network = Network.POLYGON; +const { ALCHEMY_URL_POLYGON: rpcUrlArchive } = process.env; +const rpcUrlLocal = 'http://127.0.0.1:8137'; + +const provider = new ethers.providers.JsonRpcProvider(rpcUrlLocal, network); +const signer = provider.getSigner(); +const testPoolId = + '0x726e324c29a1e49309672b244bdc4ff62a270407000200000000000000000702'; +let pool: PoolWithMethods; +const blockNumber = 41400000; + +describe('FX Pool - Calculate Liquidity', () => { + const sdkConfig = { + network, + rpcUrl: rpcUrlLocal, + }; + const balancer = new BalancerSDK(sdkConfig); + before(async () => { + const testPool = new TestPoolHelper( + testPoolId, + network, + rpcUrlLocal, + blockNumber + ); + // Gets initial pool info from Subgraph + pool = await testPool.getPool(); + + // Setup forked network, set initial token balances and allowances + await forkSetup(signer, [], [], [], rpcUrlArchive as string, undefined); + + // Update pool info with onchain state from fork block no + pool = await testPool.getPool(); + }); + it('calculating liquidity', async () => { + const liquidity = await balancer.pools.liquidity(pool); + const poolInterface = FXPool__factory.createInterface(); + const poolContract = new Contract(pool.address, poolInterface, provider); + const liquidityFromContract = ( + await poolContract.liquidity() + ).total_.toBigInt(); + const liquidityBigInt = parseFixed(liquidity, 18).toBigInt(); + // expecting 5% of margin error + console.log( + formatFixed( + SolidityMaths.divDownFixed(liquidityBigInt, liquidityFromContract), + 18 + ).toString() + ); + expect( + parseFloat( + formatFixed( + SolidityMaths.divDownFixed(liquidityBigInt, liquidityFromContract), + 18 + ).toString() + ) + ).to.be.closeTo(1, 0.05); + }); +}); diff --git a/balancer-js/src/modules/pools/pool-types/concerns/fx/liquidity.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/fx/liquidity.concern.ts new file mode 100644 index 000000000..a115508b4 --- /dev/null +++ b/balancer-js/src/modules/pools/pool-types/concerns/fx/liquidity.concern.ts @@ -0,0 +1,54 @@ +import { LiquidityConcern } from '../types'; +import { PoolToken } from '@/types'; +import { formatFixed } from '@ethersproject/bignumber'; +import { parseFixed } from '@/lib/utils/math'; +import { SolidityMaths } from '@/lib/utils/solidityMaths'; + +const SCALING_FACTOR = 18; + +export class FXLiquidityConcern implements LiquidityConcern { + calcTotal(tokens: PoolToken[]): string { + let sumBalance = BigInt(0); + let sumValue = BigInt(0); + + for (let i = 0; i < tokens.length; i++) { + const token = tokens[i]; + + // if a token's price is unknown, ignore it + // it will be computed at the next step + if (!token.price?.usd) { + continue; + } + + const price = parseFixed( + token.price.usd.toString(), + SCALING_FACTOR + ).toBigInt(); + const balance = parseFixed(token.balance, SCALING_FACTOR).toBigInt(); + + const value = SolidityMaths.mulDownFixed(balance, price); + sumValue = SolidityMaths.add(sumValue, value); + sumBalance = SolidityMaths.add(sumBalance, balance); + } + // if at least the partial value of the pool is known + // then compute the rest of the value of tokens with unknown prices + if (sumBalance > BigInt(0)) { + const avgPrice = SolidityMaths.divDownFixed(sumValue, sumBalance); + + for (let i = 0; i < tokens.length; i++) { + const token = tokens[i]; + + if (token.price?.usd) { + continue; + } + + const balance = parseFixed(token.balance, SCALING_FACTOR).toBigInt(); + + const value = SolidityMaths.mulDownFixed(balance, avgPrice); + sumValue = SolidityMaths.add(sumValue, value); + sumBalance = SolidityMaths.add(sumBalance, balance); + } + } + return formatFixed(sumValue.toString(), SCALING_FACTOR).toString(); + } +} diff --git a/balancer-js/src/modules/pools/pool-types/concerns/fx/priceImpact.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/fx/priceImpact.concern.ts new file mode 100644 index 000000000..7d321ff5d --- /dev/null +++ b/balancer-js/src/modules/pools/pool-types/concerns/fx/priceImpact.concern.ts @@ -0,0 +1,19 @@ +import { PriceImpactConcern } from '@/modules/pools/pool-types/concerns/types'; +import { Pool } from '@/types'; + +export class FXPriceImpactConcern implements PriceImpactConcern { + bptZeroPriceImpact(pool: Pool, tokenAmounts: bigint[]): bigint { + console.log(pool, tokenAmounts); + throw new Error('Not implemented'); + } + + calcPriceImpact( + pool: Pool, + tokenAmounts: bigint[], + bptAmount: bigint, + isJoin: boolean + ): string { + console.log(pool, tokenAmounts, bptAmount, isJoin); + throw new Error('Not implemented'); + } +} diff --git a/balancer-js/src/modules/pools/pool-types/concerns/fx/spotPrice.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/fx/spotPrice.concern.ts new file mode 100644 index 000000000..404b296d7 --- /dev/null +++ b/balancer-js/src/modules/pools/pool-types/concerns/fx/spotPrice.concern.ts @@ -0,0 +1,9 @@ +import { SpotPriceConcern } from '@/modules/pools/pool-types/concerns/types'; +import { Pool } from '@/types'; + +export class FXSpotPriceConcern implements SpotPriceConcern { + calcPoolSpotPrice(tokenIn: string, tokenOut: string, pool: Pool): string { + console.log(tokenIn, tokenOut, pool); + throw new Error('Not implemented'); + } +} diff --git a/balancer-js/src/modules/pools/pool-types/concerns/linear/exit.concern.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/linear/exit.concern.spec.ts new file mode 100644 index 000000000..36d57e595 --- /dev/null +++ b/balancer-js/src/modules/pools/pool-types/concerns/linear/exit.concern.spec.ts @@ -0,0 +1,58 @@ +// yarn test:only ./src/modules/pools/pool-types/concerns/linear/exit.concern.spec.ts +import { expect } from 'chai'; +import { parseEther } from '@ethersproject/units'; +import { AddressZero } from '@ethersproject/constants'; + +import { insert, Pool } from '@/.'; + +import { ExitExactBPTInParameters } from '../types'; +import { getPoolFromFile } from '@/test/lib/utils'; +import { LinearPoolExit } from './exit.concern'; + +const testPoolId = + '0x3c640f0d3036ad85afa2d5a9e32be651657b874f00000000000000000000046b'; +let pool: Pool; +let bptIndex: number; +const exiter = AddressZero; +const concern = new LinearPoolExit(); + +describe('Linear Pool exits', () => { + before(async () => { + pool = await getPoolFromFile(testPoolId, 1); + bptIndex = pool.tokensList.indexOf(pool.address); + }); + + context('Recovery Exit', async () => { + let defaultParams: Pick< + ExitExactBPTInParameters, + 'exiter' | 'pool' | 'bptIn' | 'slippage' | 'toInternalBalance' + >; + + before(() => { + defaultParams = { + exiter, + pool, + bptIn: String(parseEther('10')), + slippage: '100', + toInternalBalance: false, + }; + }); + + it('should return correct attributes for exiting', async () => { + const { attributes, functionName, minAmountsOut } = + concern.buildRecoveryExit({ + ...defaultParams, + }); + + expect(functionName).to.eq('exitPool'); + expect(attributes.poolId).to.eq(testPoolId); + expect(attributes.recipient).to.eq(exiter); + expect(attributes.sender).to.eq(exiter); + expect(attributes.exitPoolRequest.assets).to.deep.eq(pool.tokensList); + expect(attributes.exitPoolRequest.toInternalBalance).to.be.false; + expect(attributes.exitPoolRequest.minAmountsOut).to.deep.eq( + insert(minAmountsOut, bptIndex, '0') + ); + }); + }); +}); diff --git a/balancer-js/src/modules/pools/pool-types/concerns/linear/exit.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/linear/exit.concern.ts index a54876a79..fab93215f 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/linear/exit.concern.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/linear/exit.concern.ts @@ -5,7 +5,7 @@ import { BigNumber } from '@ethersproject/bignumber'; import { BalancerError, BalancerErrorCode } from '@/balancerErrors'; import { Vault__factory } from '@/contracts'; import { balancerVault } from '@/lib/constants/config'; -import { parsePoolInfo } from '@/lib/utils'; +import { insert, parsePoolInfo, removeItem } from '@/lib/utils'; import { _downscaleDownArray } from '@/lib/utils/solidityMaths'; import { subSlippage } from '@/lib/utils/slippageHelper'; import { BasePoolEncoder } from '@/pool-base'; @@ -33,7 +33,10 @@ type ExactBPTInSortedValues = SortedValues & { scalingFactors: bigint[]; }; -type EncodeExitParams = Pick & { +type EncodeExitParams = Pick< + ExitExactBPTInParameters, + 'exiter' | 'toInternalBalance' +> & { poolTokens: string[]; poolId: string; userData: string; @@ -49,6 +52,7 @@ export class LinearPoolExit implements ExitConcern { shouldUnwrapNativeAsset, wrappedNativeAsset, singleTokenOut, + toInternalBalance, }: ExitExactBPTInParameters): ExitExactBPTInAttributes => { throw new Error('Exit type not supported'); }; @@ -60,6 +64,7 @@ export class LinearPoolExit implements ExitConcern { amountsOut, slippage, wrappedNativeAsset, + toInternalBalance, }: ExitExactTokensOutParameters): ExitExactTokensOutAttributes => { throw new Error('Exit type not supported'); }; @@ -69,9 +74,10 @@ export class LinearPoolExit implements ExitConcern { pool, bptIn, slippage, + toInternalBalance, }: Pick< ExitExactBPTInParameters, - 'exiter' | 'pool' | 'bptIn' | 'slippage' + 'exiter' | 'pool' | 'bptIn' | 'slippage' | 'toInternalBalance' >): ExitExactBPTInAttributes => { this.checkInputsExactBPTIn({ bptIn, @@ -89,12 +95,20 @@ export class LinearPoolExit implements ExitConcern { const userData = BasePoolEncoder.recoveryModeExit(bptIn); + // MinAmounts needs a value for BPT for encoding + const minAmountsOutWithBpt = insert( + minAmountsOut, + sortedValues.bptIndex, + '0' + ); + const encodedData = this.encodeExitPool({ poolTokens: sortedValues.poolTokens, poolId: pool.id, exiter, - minAmountsOut, + minAmountsOut: minAmountsOutWithBpt, userData, + toInternalBalance, }); const priceImpactConcern = new LinearPriceImpact(); @@ -161,11 +175,11 @@ export class LinearPoolExit implements ExitConcern { scalingFactors ); - const expectedAmountsOut = amountsOutScaledDown.map((amount) => - amount.toString() + const expectedAmountsOut = removeItem(amountsOutScaledDown, bptIndex).map( + (amount) => amount.toString() ); // Apply slippage tolerance - const minAmountsOut = amountsOutScaledDown.map((amount) => { + const minAmountsOut = expectedAmountsOut.map((amount) => { const minAmount = subSlippage( BigNumber.from(amount), BigNumber.from(slippage) @@ -180,7 +194,14 @@ export class LinearPoolExit implements ExitConcern { * @param params */ encodeExitPool = (params: EncodeExitParams): ExitPoolAttributes => { - const { exiter, poolId, minAmountsOut, userData, poolTokens } = params; + const { + exiter, + poolId, + minAmountsOut, + userData, + poolTokens, + toInternalBalance, + } = params; const to = balancerVault; const functionName = 'exitPool'; @@ -192,7 +213,7 @@ export class LinearPoolExit implements ExitConcern { assets: poolTokens, minAmountsOut, userData, - toInternalBalance: false, + toInternalBalance, }, }; diff --git a/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.ts index e858e9d85..bfb54ca3a 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.ts @@ -60,7 +60,10 @@ type SortValuesExactTokensOutParams = SortValuesParams & { tokensOut: string[]; }; -type EncodeExitParams = Pick & { +type EncodeExitParams = Pick< + ExitExactBPTInParameters, + 'exiter' | 'toInternalBalance' +> & { poolTokens: string[]; poolId: string; userData: string; @@ -76,6 +79,7 @@ export class StablePoolExit implements ExitConcern { shouldUnwrapNativeAsset, wrappedNativeAsset, singleTokenOut, + toInternalBalance, }: ExitExactBPTInParameters): ExitExactBPTInAttributes => { this.checkInputsExactBPTIn({ bptIn, @@ -116,6 +120,7 @@ export class StablePoolExit implements ExitConcern { exiter, minAmountsOut, userData, + toInternalBalance, }); const priceImpactConcern = new StablePoolPriceImpact(); @@ -141,6 +146,7 @@ export class StablePoolExit implements ExitConcern { amountsOut, slippage, wrappedNativeAsset, + toInternalBalance, }: ExitExactTokensOutParameters): ExitExactTokensOutAttributes => { this.checkInputsExactTokensOut(amountsOut, tokensOut, pool); @@ -166,6 +172,7 @@ export class StablePoolExit implements ExitConcern { poolTokens, minAmountsOut: downScaledAmountsOut, exiter, + toInternalBalance, }); const priceImpactConcern = new StablePoolPriceImpact(); @@ -189,9 +196,10 @@ export class StablePoolExit implements ExitConcern { pool, bptIn, slippage, + toInternalBalance, }: Pick< ExitExactBPTInParameters, - 'exiter' | 'pool' | 'bptIn' | 'slippage' + 'exiter' | 'pool' | 'bptIn' | 'slippage' | 'toInternalBalance' >): ExitExactBPTInAttributes => { this.checkInputsExactBPTIn({ bptIn, @@ -216,6 +224,7 @@ export class StablePoolExit implements ExitConcern { exiter, minAmountsOut, userData, + toInternalBalance, }); const priceImpactConcern = new StablePoolPriceImpact(); @@ -478,6 +487,7 @@ export class StablePoolExit implements ExitConcern { poolTokens, minAmountsOut, userData, + toInternalBalance, }: EncodeExitParams): ExitPoolAttributes => { const to = balancerVault; const functionName = 'exitPool'; @@ -489,7 +499,7 @@ export class StablePoolExit implements ExitConcern { assets: poolTokens, minAmountsOut, userData, - toInternalBalance: false, + toInternalBalance, }, }; // Encode transaction data into an ABI byte string which can be sent to the network to be executed diff --git a/balancer-js/src/modules/pools/pool-types/concerns/stablePhantom/exit.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/stablePhantom/exit.concern.ts index 9bd9c29be..570ce6d85 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/stablePhantom/exit.concern.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/stablePhantom/exit.concern.ts @@ -16,6 +16,7 @@ export class StablePhantomPoolExit implements ExitConcern { shouldUnwrapNativeAsset, wrappedNativeAsset, singleTokenOut, + toInternalBalance, }: ExitExactBPTInParameters): ExitExactBPTInAttributes => { /** * Exit type only supported when pool is in paused state and pause window @@ -31,6 +32,7 @@ export class StablePhantomPoolExit implements ExitConcern { amountsOut, slippage, wrappedNativeAsset, + toInternalBalance, }: ExitExactTokensOutParameters): ExitExactTokensOutAttributes => { throw new Error('Exit type not supported'); }; @@ -40,9 +42,10 @@ export class StablePhantomPoolExit implements ExitConcern { pool, bptIn, slippage, + toInternalBalance, }: Pick< ExitExactBPTInParameters, - 'exiter' | 'pool' | 'bptIn' | 'slippage' + 'exiter' | 'pool' | 'bptIn' | 'slippage' | 'toInternalBalance' >): ExitExactBPTInAttributes => { throw new Error('Exit type not supported'); }; diff --git a/balancer-js/src/modules/pools/pool-types/concerns/types.ts b/balancer-js/src/modules/pools/pool-types/concerns/types.ts index c1270a818..9539275f3 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/types.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/types.ts @@ -83,6 +83,7 @@ export interface ExitConcern { shouldUnwrapNativeAsset, wrappedNativeAsset, singleTokenOut, + toInternalBalance, }: ExitExactBPTInParameters) => ExitExactBPTInAttributes; /** @@ -102,6 +103,7 @@ export interface ExitConcern { amountsOut, slippage, wrappedNativeAsset, + toInternalBalance, }: ExitExactTokensOutParameters) => ExitExactTokensOutAttributes; /** @@ -117,9 +119,10 @@ export interface ExitConcern { pool, bptIn, slippage, + toInternalBalance, }: Pick< ExitExactBPTInParameters, - 'exiter' | 'pool' | 'bptIn' | 'slippage' + 'exiter' | 'pool' | 'bptIn' | 'slippage' | 'toInternalBalance' >) => ExitExactBPTInAttributes; } @@ -215,6 +218,7 @@ export interface ExitExactBPTInParameters { shouldUnwrapNativeAsset: boolean; wrappedNativeAsset: string; singleTokenOut?: string; + toInternalBalance: boolean; } export interface ExitExactBPTInSingleTokenOutParameters { @@ -234,4 +238,5 @@ export interface ExitExactTokensOutParameters { amountsOut: string[]; slippage: string; wrappedNativeAsset: string; + toInternalBalance: boolean; } diff --git a/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.ts index 63639eaff..62cae623e 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.ts @@ -60,7 +60,10 @@ type SortValuesExactTokensOutParams = SortValuesParams & { tokensOut: string[]; }; -type EncodeExitParams = Pick & { +type EncodeExitParams = Pick< + ExitExactBPTInParameters, + 'exiter' | 'toInternalBalance' +> & { poolTokens: string[]; poolId: string; userData: string; @@ -76,6 +79,7 @@ export class WeightedPoolExit implements ExitConcern { shouldUnwrapNativeAsset, wrappedNativeAsset, singleTokenOut, + toInternalBalance, }: ExitExactBPTInParameters): ExitExactBPTInAttributes => { this.checkInputsExactBPTIn({ bptIn, @@ -116,6 +120,7 @@ export class WeightedPoolExit implements ExitConcern { exiter, minAmountsOut, userData, + toInternalBalance, }); const priceImpactConcern = new WeightedPoolPriceImpact(); @@ -141,6 +146,7 @@ export class WeightedPoolExit implements ExitConcern { amountsOut, slippage, wrappedNativeAsset, + toInternalBalance, }: ExitExactTokensOutParameters): ExitExactTokensOutAttributes => { this.checkInputsExactTokensOut(amountsOut, tokensOut, pool); @@ -166,6 +172,7 @@ export class WeightedPoolExit implements ExitConcern { poolTokens, minAmountsOut: downScaledAmountsOut, exiter, + toInternalBalance, }); const priceImpactConcern = new WeightedPoolPriceImpact(); @@ -189,9 +196,10 @@ export class WeightedPoolExit implements ExitConcern { pool, bptIn, slippage, + toInternalBalance, }: Pick< ExitExactBPTInParameters, - 'exiter' | 'pool' | 'bptIn' | 'slippage' + 'exiter' | 'pool' | 'bptIn' | 'slippage' | 'toInternalBalance' >): ExitExactBPTInAttributes => { this.checkInputsExactBPTIn({ bptIn, @@ -216,6 +224,7 @@ export class WeightedPoolExit implements ExitConcern { exiter, minAmountsOut, userData, + toInternalBalance, }); const priceImpactConcern = new WeightedPoolPriceImpact(); @@ -476,6 +485,7 @@ export class WeightedPoolExit implements ExitConcern { poolTokens, minAmountsOut, userData, + toInternalBalance, }: EncodeExitParams): ExitPoolAttributes => { const to = balancerVault; const functionName = 'exitPool'; @@ -487,7 +497,7 @@ export class WeightedPoolExit implements ExitConcern { assets: poolTokens, minAmountsOut, userData, - toInternalBalance: false, + toInternalBalance, }, }; // Encode transaction data into an ABI byte string which can be sent to the network to be executed diff --git a/balancer-js/src/modules/pools/pool-types/fx.module.ts b/balancer-js/src/modules/pools/pool-types/fx.module.ts new file mode 100644 index 000000000..f94bcebe1 --- /dev/null +++ b/balancer-js/src/modules/pools/pool-types/fx.module.ts @@ -0,0 +1,23 @@ +import { PoolType } from './pool-type.interface'; +import { + ExitConcern, + JoinConcern, + LiquidityConcern, + PriceImpactConcern, + SpotPriceConcern, +} from '@/modules/pools/pool-types/concerns/types'; +import { FXExitConcern } from '@/modules/pools/pool-types/concerns/fx/exit.concern'; +import { FXLiquidityConcern } from '@/modules/pools/pool-types/concerns/fx/liquidity.concern'; +import { FXSpotPriceConcern } from '@/modules/pools/pool-types/concerns/fx/spotPrice.concern'; +import { FXPriceImpactConcern } from '@/modules/pools/pool-types/concerns/fx/priceImpact.concern'; +import { FXJoinConcern } from '@/modules/pools/pool-types/concerns/fx/join.concern'; + +export class FX implements PoolType { + constructor( + public exit: ExitConcern = new FXExitConcern(), + public liquidity: LiquidityConcern = new FXLiquidityConcern(), + public spotPriceCalculator: SpotPriceConcern = new FXSpotPriceConcern(), + public priceImpactCalculator: PriceImpactConcern = new FXPriceImpactConcern(), + public join: JoinConcern = new FXJoinConcern() + ) {} +} diff --git a/balancer-js/src/modules/relayer/relayer.module.ts b/balancer-js/src/modules/relayer/relayer.module.ts index 214860108..c41a15118 100644 --- a/balancer-js/src/modules/relayer/relayer.module.ts +++ b/balancer-js/src/modules/relayer/relayer.module.ts @@ -1,8 +1,8 @@ import { JsonRpcSigner } from '@ethersproject/providers'; import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; -import { Interface } from '@ethersproject/abi'; import { MaxUint256 } from '@ethersproject/constants'; -import { Vault } from '@/contracts/Vault'; +import { BatchRelayerLibrary__factory } from '@/contracts'; +import { IVault, Vault } from '@/contracts/Vault'; import { EncodeBatchSwapInput, EncodeExitPoolInput, @@ -13,12 +13,12 @@ import { import { ExitPoolRequest, JoinPoolRequest } from '@/types'; import { Swap } from '../swaps/types'; import { RelayerAuthorization } from '@/lib/utils'; - -import relayerLibraryAbi from '@/lib/abi/BatchRelayerLibrary.json'; +import FundManagementStruct = IVault.FundManagementStruct; +import SingleSwapStruct = IVault.SingleSwapStruct; export * from './types'; -const relayerLibrary = new Interface(relayerLibraryAbi); +const relayerLibrary = BatchRelayerLibrary__factory.createInterface(); export class Relayer { static CHAINED_REFERENCE_TEMP_PREFIX = 'ba10'; // Temporary reference: it is deleted after a read. @@ -73,12 +73,12 @@ export class Relayer { static encodeSwap(params: Swap): string { return relayerLibrary.encodeFunctionData('swap', [ - params.request, - params.funds, + params.request as SingleSwapStruct, + params.funds as FundManagementStruct, params.limit, - params.deadline, - params.value, - params.outputReference, + params.deadline as BigNumberish, + params.value as BigNumberish, + params.outputReference as BigNumberish, ]); } diff --git a/balancer-js/src/modules/sdk.module.ts b/balancer-js/src/modules/sdk.module.ts index dd001bec0..3d07e506b 100644 --- a/balancer-js/src/modules/sdk.module.ts +++ b/balancer-js/src/modules/sdk.module.ts @@ -7,7 +7,6 @@ import { Sor } from './sor/sor.module'; import { getNetworkConfig } from './sdk.helpers'; import { Pricing } from './pricing/pricing.module'; import { ContractInstances, Contracts } from './contracts/contracts.module'; -import { Zaps } from './zaps/zaps.module'; import { Pools } from './pools'; import { Data } from './data'; import { VaultModel } from './vaultModel/vaultModel.module'; @@ -34,7 +33,6 @@ export class BalancerSDK implements BalancerSDKRoot { readonly pools: Pools; readonly data: Data; balancerContracts: Contracts; - zaps: Zaps; vaultModel: VaultModel; readonly networkConfig: BalancerNetworkConfig; readonly provider: JsonRpcProvider; @@ -69,7 +67,6 @@ export class BalancerSDK implements BalancerSDKRoot { this.balancerContracts ); - this.zaps = new Zaps(this.networkConfig.chainId); if (this.data.liquidityGauges) { this.claimService = new ClaimService( this.data.liquidityGauges, @@ -81,7 +78,7 @@ export class BalancerSDK implements BalancerSDKRoot { this.networkConfig.addresses.contracts.balancerMinterAddress ); this.migrationService = new Migrations( - this.networkConfig.addresses.contracts.relayerV5 as string, + this.networkConfig.addresses.contracts.relayer, this.data.pools, this.data.liquidityGauges.subgraph, this.provider diff --git a/balancer-js/src/modules/simulation/simulation.module.ts b/balancer-js/src/modules/simulation/simulation.module.ts index 46dcb1690..016a21db9 100644 --- a/balancer-js/src/modules/simulation/simulation.module.ts +++ b/balancer-js/src/modules/simulation/simulation.module.ts @@ -156,15 +156,13 @@ export class Simulation { throw new Error('Missing Vault Model Config.'); // make one multicall for each exitPath // take only bptOut/tokenOut delta into account - // -- works only with single bpt/token out -- const amountsOut: string[] = []; for (const [i, requests] of multiRequests.entries()) { const deltas = await this.vaultModel.multicall(requests, i === 0); - const tokenOutDelta = Object.values(deltas) - .find((d) => d.lt(0)) - ?.mul(-1); - if (!tokenOutDelta) throw new Error('No delta found for token out.'); - amountsOut.push(tokenOutDelta.toString()); + const tokenOutDeltas = Object.values(deltas).filter((d) => d.lt(0)); + if (tokenOutDeltas.length === 0) + throw new Error('No delta found for token out.'); + amountsOut.push(...tokenOutDeltas.map((d) => d.mul(-1).toString())); } return amountsOut; }; diff --git a/balancer-js/src/modules/sor/pool-data/onChainData.ts b/balancer-js/src/modules/sor/pool-data/onChainData.ts index 449ca2103..94bcea1da 100644 --- a/balancer-js/src/modules/sor/pool-data/onChainData.ts +++ b/balancer-js/src/modules/sor/pool-data/onChainData.ts @@ -7,13 +7,15 @@ import { Vault__factory } from '@/contracts/factories/Vault__factory'; import { Pool, PoolToken, PoolType } from '@/types'; // TODO: decide whether we want to trim these ABIs down to the relevant functions -import aTokenRateProvider from '@/lib/abi/StaticATokenRateProvider.json'; - -import weightedPoolAbi from '@/lib/abi/WeightedPool.json'; -import stablePoolAbi from '@/lib/abi/StablePool.json'; -import elementPoolAbi from '@/lib/abi/ConvergentCurvePool.json'; -import linearPoolAbi from '@/lib/abi/LinearPool.json'; -import composableStableAbi from '@/lib/abi/ComposableStable.json'; +import { + ComposableStablePool__factory, + ConvergentCurvePool__factory, + LinearPool__factory, + StablePool__factory, + StaticATokenRateProvider__factory, + WeightedPool__factory, +} from '@/contracts'; +import { JsonFragment } from '@ethersproject/abi'; export async function getOnChainBalances< GenericPool extends Omit & { @@ -32,14 +34,13 @@ export async function getOnChainBalances< // Remove duplicate entries using their names Object.fromEntries( [ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ...(Vault__factory.abi as any), - ...aTokenRateProvider, - ...weightedPoolAbi, - ...stablePoolAbi, - ...elementPoolAbi, - ...linearPoolAbi, - ...composableStableAbi, + ...(Vault__factory.abi as readonly JsonFragment[]), + ...(StaticATokenRateProvider__factory.abi as readonly JsonFragment[]), + ...(WeightedPool__factory.abi as readonly JsonFragment[]), + ...(StablePool__factory.abi as readonly JsonFragment[]), + ...(ConvergentCurvePool__factory.abi as readonly JsonFragment[]), + ...(LinearPool__factory.abi as readonly JsonFragment[]), + ...(ComposableStablePool__factory.abi as readonly JsonFragment[]), ].map((row) => [row.name, row]) ) ); @@ -176,7 +177,7 @@ export async function getOnChainBalances< } >; } catch (err) { - throw `Issue with multicall execution.`; + throw new Error(`Issue with multicall execution.`); } const onChainPools: GenericPool[] = []; @@ -275,7 +276,7 @@ export async function getOnChainBalances< onChainPools.push(subgraphPools[index]); } catch (err) { - throw `Issue with pool onchain data: ${err}`; + throw new Error(`Issue with pool onchain data: ${err}`); } }); diff --git a/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts b/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts index 345394f92..cba0af8b7 100644 --- a/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts +++ b/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts @@ -75,6 +75,7 @@ export class SubgraphPoolDataService implements PoolDataService { const pools = await this.getSubgraphPools(); const filteredPools = pools.filter((p) => { + if (p.poolType === 'FX') return false; if (!this.network.poolsToIgnore) return true; const index = this.network.poolsToIgnore.findIndex((addr) => isSameAddress(addr, p.address) diff --git a/balancer-js/src/modules/subgraph/balancer-v2/Pools.graphql b/balancer-js/src/modules/subgraph/balancer-v2/Pools.graphql index f58520a71..70f052a3f 100644 --- a/balancer-js/src/modules/subgraph/balancer-v2/Pools.graphql +++ b/balancer-js/src/modules/subgraph/balancer-v2/Pools.graphql @@ -105,6 +105,7 @@ fragment SubgraphPool on Pool { sqrtBeta root3Alpha isInRecoveryMode + isPaused alpha beta c diff --git a/balancer-js/src/modules/subgraph/generated/balancer-subgraph-schema.graphql b/balancer-js/src/modules/subgraph/generated/balancer-subgraph-schema.graphql index 66e349836..65662aee4 100644 --- a/balancer-js/src/modules/subgraph/generated/balancer-subgraph-schema.graphql +++ b/balancer-js/src/modules/subgraph/generated/balancer-subgraph-schema.graphql @@ -119,6 +119,7 @@ enum AmpUpdate_orderBy { poolId__isInRecoveryMode poolId__isPaused poolId__lambda + poolId__lastPostJoinExitInvariant poolId__lowerTarget poolId__mainIndex poolId__managementFee @@ -471,6 +472,7 @@ enum GradualWeightUpdate_orderBy { poolId__isInRecoveryMode poolId__isPaused poolId__lambda + poolId__lastPostJoinExitInvariant poolId__lowerTarget poolId__mainIndex poolId__managementFee @@ -656,6 +658,7 @@ enum JoinExit_orderBy { pool__isInRecoveryMode pool__isPaused pool__lambda + pool__lastPostJoinExitInvariant pool__lowerTarget pool__mainIndex pool__managementFee @@ -807,6 +810,7 @@ enum LatestPrice_orderBy { poolId__isInRecoveryMode poolId__isPaused poolId__lambda + poolId__lastPostJoinExitInvariant poolId__lowerTarget poolId__mainIndex poolId__managementFee @@ -938,6 +942,7 @@ enum ManagementOperation_orderBy { poolTokenId__isExemptFromYieldProtocolFee poolTokenId__managedBalance poolTokenId__name + poolTokenId__oldPriceRate poolTokenId__priceRate poolTokenId__symbol poolTokenId__weight @@ -976,6 +981,7 @@ type Pool { isInRecoveryMode: Boolean isPaused: Boolean lambda: BigDecimal + lastPostJoinExitInvariant: BigDecimal lowerTarget: BigDecimal mainIndex: Int managementFee: BigDecimal @@ -988,6 +994,7 @@ type Pool { principalToken: Bytes protocolAumFeeCache: BigDecimal protocolId: Int + protocolIdData: ProtocolIdData protocolSwapFeeCache: BigDecimal protocolYieldFeeCache: BigDecimal root3Alpha: BigDecimal @@ -1086,6 +1093,7 @@ enum PoolContract_orderBy { pool__isInRecoveryMode pool__isPaused pool__lambda + pool__lastPostJoinExitInvariant pool__lowerTarget pool__mainIndex pool__managementFee @@ -1236,6 +1244,7 @@ enum PoolHistoricalLiquidity_orderBy { poolId__isInRecoveryMode poolId__isPaused poolId__lambda + poolId__lastPostJoinExitInvariant poolId__lowerTarget poolId__mainIndex poolId__managementFee @@ -1374,6 +1383,7 @@ enum PoolShare_orderBy { poolId__isInRecoveryMode poolId__isPaused poolId__lambda + poolId__lastPostJoinExitInvariant poolId__lowerTarget poolId__mainIndex poolId__managementFee @@ -1551,6 +1561,7 @@ enum PoolSnapshot_orderBy { pool__isInRecoveryMode pool__isPaused pool__lambda + pool__lastPostJoinExitInvariant pool__lowerTarget pool__mainIndex pool__managementFee @@ -1609,6 +1620,7 @@ type PoolToken { managedBalance: BigDecimal! managements(first: Int = 100, orderBy: ManagementOperation_orderBy, orderDirection: OrderDirection, skip: Int = 0, where: ManagementOperation_filter): [ManagementOperation!] name: String! + oldPriceRate: BigDecimal poolId: Pool priceRate: BigDecimal! symbol: String! @@ -1723,6 +1735,14 @@ input PoolToken_filter { name_not_starts_with_nocase: String name_starts_with: String name_starts_with_nocase: String + oldPriceRate: BigDecimal + oldPriceRate_gt: BigDecimal + oldPriceRate_gte: BigDecimal + oldPriceRate_in: [BigDecimal!] + oldPriceRate_lt: BigDecimal + oldPriceRate_lte: BigDecimal + oldPriceRate_not: BigDecimal + oldPriceRate_not_in: [BigDecimal!] or: [PoolToken_filter] poolId: String poolId_: Pool_filter @@ -1816,6 +1836,7 @@ enum PoolToken_orderBy { managedBalance managements name + oldPriceRate poolId poolId__address poolId__alpha @@ -1834,6 +1855,7 @@ enum PoolToken_orderBy { poolId__isInRecoveryMode poolId__isPaused poolId__lambda + poolId__lastPostJoinExitInvariant poolId__lowerTarget poolId__mainIndex poolId__managementFee @@ -1881,6 +1903,7 @@ enum PoolToken_orderBy { token__id token__latestFXPrice token__latestUSDPrice + token__latestUSDPriceTimestamp token__name token__symbol token__totalBalanceNotional @@ -2030,6 +2053,14 @@ input Pool_filter { lambda_lte: BigDecimal lambda_not: BigDecimal lambda_not_in: [BigDecimal!] + lastPostJoinExitInvariant: BigDecimal + lastPostJoinExitInvariant_gt: BigDecimal + lastPostJoinExitInvariant_gte: BigDecimal + lastPostJoinExitInvariant_in: [BigDecimal!] + lastPostJoinExitInvariant_lt: BigDecimal + lastPostJoinExitInvariant_lte: BigDecimal + lastPostJoinExitInvariant_not: BigDecimal + lastPostJoinExitInvariant_not_in: [BigDecimal!] lowerTarget: BigDecimal lowerTarget_gt: BigDecimal lowerTarget_gte: BigDecimal @@ -2137,6 +2168,27 @@ input Pool_filter { protocolAumFeeCache_not: BigDecimal protocolAumFeeCache_not_in: [BigDecimal!] protocolId: Int + protocolIdData: String + protocolIdData_: ProtocolIdData_filter + protocolIdData_contains: String + protocolIdData_contains_nocase: String + protocolIdData_ends_with: String + protocolIdData_ends_with_nocase: String + protocolIdData_gt: String + protocolIdData_gte: String + protocolIdData_in: [String!] + protocolIdData_lt: String + protocolIdData_lte: String + protocolIdData_not: String + protocolIdData_not_contains: String + protocolIdData_not_contains_nocase: String + protocolIdData_not_ends_with: String + protocolIdData_not_ends_with_nocase: String + protocolIdData_not_in: [String!] + protocolIdData_not_starts_with: String + protocolIdData_not_starts_with_nocase: String + protocolIdData_starts_with: String + protocolIdData_starts_with_nocase: String protocolId_gt: Int protocolId_gte: Int protocolId_in: [Int!] @@ -2431,6 +2483,7 @@ enum Pool_orderBy { isInRecoveryMode isPaused lambda + lastPostJoinExitInvariant lowerTarget mainIndex managementFee @@ -2443,6 +2496,9 @@ enum Pool_orderBy { principalToken protocolAumFeeCache protocolId + protocolIdData + protocolIdData__id + protocolIdData__name protocolSwapFeeCache protocolYieldFeeCache root3Alpha @@ -2620,6 +2676,7 @@ enum PriceRateProvider_orderBy { poolId__isInRecoveryMode poolId__isPaused poolId__lambda + poolId__lastPostJoinExitInvariant poolId__lowerTarget poolId__mainIndex poolId__managementFee @@ -2671,11 +2728,57 @@ enum PriceRateProvider_orderBy { token__isExemptFromYieldProtocolFee token__managedBalance token__name + token__oldPriceRate token__priceRate token__symbol token__weight } +type ProtocolIdData { + id: ID! + name: String! +} + +input ProtocolIdData_filter { + """Filter for the block changed event.""" + _change_block: BlockChangedFilter + and: [ProtocolIdData_filter] + id: ID + id_gt: ID + id_gte: ID + id_in: [ID!] + id_lt: ID + id_lte: ID + id_not: ID + id_not_in: [ID!] + name: String + name_contains: String + name_contains_nocase: String + name_ends_with: String + name_ends_with_nocase: String + name_gt: String + name_gte: String + name_in: [String!] + name_lt: String + name_lte: String + name_not: String + name_not_contains: String + name_not_contains_nocase: String + name_not_ends_with: String + name_not_ends_with_nocase: String + name_not_in: [String!] + name_not_starts_with: String + name_not_starts_with_nocase: String + name_starts_with: String + name_starts_with_nocase: String + or: [ProtocolIdData_filter] +} + +enum ProtocolIdData_orderBy { + id + name +} + type Query { """Access to subgraph metadata""" _meta(block: Block_height): _Meta_ @@ -3071,6 +3174,34 @@ type Query { subgraphError: _SubgraphErrorPolicy_! = deny where: PriceRateProvider_filter ): [PriceRateProvider!]! + protocolIdData( + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + id: ID! + + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): ProtocolIdData + protocolIdDatas( + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + first: Int = 100 + orderBy: ProtocolIdData_orderBy + orderDirection: OrderDirection + skip: Int = 0 + + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + where: ProtocolIdData_filter + ): [ProtocolIdData!]! swap( """ The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. @@ -3720,6 +3851,34 @@ type Subscription { subgraphError: _SubgraphErrorPolicy_! = deny where: PriceRateProvider_filter ): [PriceRateProvider!]! + protocolIdData( + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + id: ID! + + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + ): ProtocolIdData + protocolIdDatas( + """ + The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. + """ + block: Block_height + first: Int = 100 + orderBy: ProtocolIdData_orderBy + orderDirection: OrderDirection + skip: Int = 0 + + """ + Set to `allow` to receive data even if the subgraph has skipped over errors while syncing. + """ + subgraphError: _SubgraphErrorPolicy_! = deny + where: ProtocolIdData_filter + ): [ProtocolIdData!]! swap( """ The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted. @@ -4098,6 +4257,7 @@ enum SwapFeeUpdate_orderBy { pool__isInRecoveryMode pool__isPaused pool__lambda + pool__lastPostJoinExitInvariant pool__lowerTarget pool__mainIndex pool__managementFee @@ -4332,6 +4492,7 @@ enum Swap_orderBy { poolId__isInRecoveryMode poolId__isPaused poolId__lambda + poolId__lastPostJoinExitInvariant poolId__lowerTarget poolId__mainIndex poolId__managementFee @@ -4391,6 +4552,7 @@ type Token { latestFXPrice: BigDecimal latestPrice: LatestPrice latestUSDPrice: BigDecimal + latestUSDPriceTimestamp: BigInt name: String pool: Pool symbol: String @@ -4523,6 +4685,7 @@ enum TokenPrice_orderBy { poolId__isInRecoveryMode poolId__isPaused poolId__lambda + poolId__lastPostJoinExitInvariant poolId__lowerTarget poolId__mainIndex poolId__managementFee @@ -4671,6 +4834,7 @@ enum TokenSnapshot_orderBy { token__id token__latestFXPrice token__latestUSDPrice + token__latestUSDPriceTimestamp token__name token__symbol token__totalBalanceNotional @@ -4755,6 +4919,14 @@ input Token_filter { latestPrice_starts_with: String latestPrice_starts_with_nocase: String latestUSDPrice: BigDecimal + latestUSDPriceTimestamp: BigInt + latestUSDPriceTimestamp_gt: BigInt + latestUSDPriceTimestamp_gte: BigInt + latestUSDPriceTimestamp_in: [BigInt!] + latestUSDPriceTimestamp_lt: BigInt + latestUSDPriceTimestamp_lte: BigInt + latestUSDPriceTimestamp_not: BigInt + latestUSDPriceTimestamp_not_in: [BigInt!] latestUSDPrice_gt: BigDecimal latestUSDPrice_gte: BigDecimal latestUSDPrice_in: [BigDecimal!] @@ -4878,6 +5050,7 @@ enum Token_orderBy { latestPrice__price latestPrice__pricingAsset latestUSDPrice + latestUSDPriceTimestamp name pool pool__address @@ -4897,6 +5070,7 @@ enum Token_orderBy { pool__isInRecoveryMode pool__isPaused pool__lambda + pool__lastPostJoinExitInvariant pool__lowerTarget pool__mainIndex pool__managementFee @@ -5113,6 +5287,7 @@ enum TradePair_orderBy { token0__id token0__latestFXPrice token0__latestUSDPrice + token0__latestUSDPriceTimestamp token0__name token0__symbol token0__totalBalanceNotional @@ -5126,6 +5301,7 @@ enum TradePair_orderBy { token1__id token1__latestFXPrice token1__latestUSDPrice + token1__latestUSDPriceTimestamp token1__name token1__symbol token1__totalBalanceNotional diff --git a/balancer-js/src/modules/subgraph/generated/balancer-subgraph-types.ts b/balancer-js/src/modules/subgraph/generated/balancer-subgraph-types.ts index f837bf473..7787c788b 100644 --- a/balancer-js/src/modules/subgraph/generated/balancer-subgraph-types.ts +++ b/balancer-js/src/modules/subgraph/generated/balancer-subgraph-types.ts @@ -127,6 +127,7 @@ export enum AmpUpdate_OrderBy { PoolIdIsInRecoveryMode = 'poolId__isInRecoveryMode', PoolIdIsPaused = 'poolId__isPaused', PoolIdLambda = 'poolId__lambda', + PoolIdLastPostJoinExitInvariant = 'poolId__lastPostJoinExitInvariant', PoolIdLowerTarget = 'poolId__lowerTarget', PoolIdMainIndex = 'poolId__mainIndex', PoolIdManagementFee = 'poolId__managementFee', @@ -485,6 +486,7 @@ export enum GradualWeightUpdate_OrderBy { PoolIdIsInRecoveryMode = 'poolId__isInRecoveryMode', PoolIdIsPaused = 'poolId__isPaused', PoolIdLambda = 'poolId__lambda', + PoolIdLastPostJoinExitInvariant = 'poolId__lastPostJoinExitInvariant', PoolIdLowerTarget = 'poolId__lowerTarget', PoolIdMainIndex = 'poolId__mainIndex', PoolIdManagementFee = 'poolId__managementFee', @@ -671,6 +673,7 @@ export enum JoinExit_OrderBy { PoolIsInRecoveryMode = 'pool__isInRecoveryMode', PoolIsPaused = 'pool__isPaused', PoolLambda = 'pool__lambda', + PoolLastPostJoinExitInvariant = 'pool__lastPostJoinExitInvariant', PoolLowerTarget = 'pool__lowerTarget', PoolMainIndex = 'pool__mainIndex', PoolManagementFee = 'pool__managementFee', @@ -823,6 +826,7 @@ export enum LatestPrice_OrderBy { PoolIdIsInRecoveryMode = 'poolId__isInRecoveryMode', PoolIdIsPaused = 'poolId__isPaused', PoolIdLambda = 'poolId__lambda', + PoolIdLastPostJoinExitInvariant = 'poolId__lastPostJoinExitInvariant', PoolIdLowerTarget = 'poolId__lowerTarget', PoolIdMainIndex = 'poolId__mainIndex', PoolIdManagementFee = 'poolId__managementFee', @@ -955,6 +959,7 @@ export enum ManagementOperation_OrderBy { PoolTokenIdIsExemptFromYieldProtocolFee = 'poolTokenId__isExemptFromYieldProtocolFee', PoolTokenIdManagedBalance = 'poolTokenId__managedBalance', PoolTokenIdName = 'poolTokenId__name', + PoolTokenIdOldPriceRate = 'poolTokenId__oldPriceRate', PoolTokenIdPriceRate = 'poolTokenId__priceRate', PoolTokenIdSymbol = 'poolTokenId__symbol', PoolTokenIdWeight = 'poolTokenId__weight', @@ -994,6 +999,7 @@ export type Pool = { isInRecoveryMode?: Maybe; isPaused?: Maybe; lambda?: Maybe; + lastPostJoinExitInvariant?: Maybe; lowerTarget?: Maybe; mainIndex?: Maybe; managementFee?: Maybe; @@ -1006,6 +1012,7 @@ export type Pool = { principalToken?: Maybe; protocolAumFeeCache?: Maybe; protocolId?: Maybe; + protocolIdData?: Maybe; protocolSwapFeeCache?: Maybe; protocolYieldFeeCache?: Maybe; root3Alpha?: Maybe; @@ -1168,6 +1175,7 @@ export enum PoolContract_OrderBy { PoolIsInRecoveryMode = 'pool__isInRecoveryMode', PoolIsPaused = 'pool__isPaused', PoolLambda = 'pool__lambda', + PoolLastPostJoinExitInvariant = 'pool__lastPostJoinExitInvariant', PoolLowerTarget = 'pool__lowerTarget', PoolMainIndex = 'pool__mainIndex', PoolManagementFee = 'pool__managementFee', @@ -1319,6 +1327,7 @@ export enum PoolHistoricalLiquidity_OrderBy { PoolIdIsInRecoveryMode = 'poolId__isInRecoveryMode', PoolIdIsPaused = 'poolId__isPaused', PoolIdLambda = 'poolId__lambda', + PoolIdLastPostJoinExitInvariant = 'poolId__lastPostJoinExitInvariant', PoolIdLowerTarget = 'poolId__lowerTarget', PoolIdMainIndex = 'poolId__mainIndex', PoolIdManagementFee = 'poolId__managementFee', @@ -1458,6 +1467,7 @@ export enum PoolShare_OrderBy { PoolIdIsInRecoveryMode = 'poolId__isInRecoveryMode', PoolIdIsPaused = 'poolId__isPaused', PoolIdLambda = 'poolId__lambda', + PoolIdLastPostJoinExitInvariant = 'poolId__lastPostJoinExitInvariant', PoolIdLowerTarget = 'poolId__lowerTarget', PoolIdMainIndex = 'poolId__mainIndex', PoolIdManagementFee = 'poolId__managementFee', @@ -1636,6 +1646,7 @@ export enum PoolSnapshot_OrderBy { PoolIsInRecoveryMode = 'pool__isInRecoveryMode', PoolIsPaused = 'pool__isPaused', PoolLambda = 'pool__lambda', + PoolLastPostJoinExitInvariant = 'pool__lastPostJoinExitInvariant', PoolLowerTarget = 'pool__lowerTarget', PoolMainIndex = 'pool__mainIndex', PoolManagementFee = 'pool__managementFee', @@ -1695,6 +1706,7 @@ export type PoolToken = { managedBalance: Scalars['BigDecimal']; managements?: Maybe>; name: Scalars['String']; + oldPriceRate?: Maybe; poolId?: Maybe; priceRate: Scalars['BigDecimal']; symbol: Scalars['String']; @@ -1818,6 +1830,14 @@ export type PoolToken_Filter = { name_not_starts_with_nocase?: InputMaybe; name_starts_with?: InputMaybe; name_starts_with_nocase?: InputMaybe; + oldPriceRate?: InputMaybe; + oldPriceRate_gt?: InputMaybe; + oldPriceRate_gte?: InputMaybe; + oldPriceRate_in?: InputMaybe>; + oldPriceRate_lt?: InputMaybe; + oldPriceRate_lte?: InputMaybe; + oldPriceRate_not?: InputMaybe; + oldPriceRate_not_in?: InputMaybe>; or?: InputMaybe>>; poolId?: InputMaybe; poolId_?: InputMaybe; @@ -1911,6 +1931,7 @@ export enum PoolToken_OrderBy { ManagedBalance = 'managedBalance', Managements = 'managements', Name = 'name', + OldPriceRate = 'oldPriceRate', PoolId = 'poolId', PoolIdAddress = 'poolId__address', PoolIdAlpha = 'poolId__alpha', @@ -1929,6 +1950,7 @@ export enum PoolToken_OrderBy { PoolIdIsInRecoveryMode = 'poolId__isInRecoveryMode', PoolIdIsPaused = 'poolId__isPaused', PoolIdLambda = 'poolId__lambda', + PoolIdLastPostJoinExitInvariant = 'poolId__lastPostJoinExitInvariant', PoolIdLowerTarget = 'poolId__lowerTarget', PoolIdMainIndex = 'poolId__mainIndex', PoolIdManagementFee = 'poolId__managementFee', @@ -1976,6 +1998,7 @@ export enum PoolToken_OrderBy { TokenId = 'token__id', TokenLatestFxPrice = 'token__latestFXPrice', TokenLatestUsdPrice = 'token__latestUSDPrice', + TokenLatestUsdPriceTimestamp = 'token__latestUSDPriceTimestamp', TokenName = 'token__name', TokenSymbol = 'token__symbol', TokenTotalBalanceNotional = 'token__totalBalanceNotional', @@ -2125,6 +2148,14 @@ export type Pool_Filter = { lambda_lte?: InputMaybe; lambda_not?: InputMaybe; lambda_not_in?: InputMaybe>; + lastPostJoinExitInvariant?: InputMaybe; + lastPostJoinExitInvariant_gt?: InputMaybe; + lastPostJoinExitInvariant_gte?: InputMaybe; + lastPostJoinExitInvariant_in?: InputMaybe>; + lastPostJoinExitInvariant_lt?: InputMaybe; + lastPostJoinExitInvariant_lte?: InputMaybe; + lastPostJoinExitInvariant_not?: InputMaybe; + lastPostJoinExitInvariant_not_in?: InputMaybe>; lowerTarget?: InputMaybe; lowerTarget_gt?: InputMaybe; lowerTarget_gte?: InputMaybe; @@ -2232,6 +2263,27 @@ export type Pool_Filter = { protocolAumFeeCache_not?: InputMaybe; protocolAumFeeCache_not_in?: InputMaybe>; protocolId?: InputMaybe; + protocolIdData?: InputMaybe; + protocolIdData_?: InputMaybe; + protocolIdData_contains?: InputMaybe; + protocolIdData_contains_nocase?: InputMaybe; + protocolIdData_ends_with?: InputMaybe; + protocolIdData_ends_with_nocase?: InputMaybe; + protocolIdData_gt?: InputMaybe; + protocolIdData_gte?: InputMaybe; + protocolIdData_in?: InputMaybe>; + protocolIdData_lt?: InputMaybe; + protocolIdData_lte?: InputMaybe; + protocolIdData_not?: InputMaybe; + protocolIdData_not_contains?: InputMaybe; + protocolIdData_not_contains_nocase?: InputMaybe; + protocolIdData_not_ends_with?: InputMaybe; + protocolIdData_not_ends_with_nocase?: InputMaybe; + protocolIdData_not_in?: InputMaybe>; + protocolIdData_not_starts_with?: InputMaybe; + protocolIdData_not_starts_with_nocase?: InputMaybe; + protocolIdData_starts_with?: InputMaybe; + protocolIdData_starts_with_nocase?: InputMaybe; protocolId_gt?: InputMaybe; protocolId_gte?: InputMaybe; protocolId_in?: InputMaybe>; @@ -2526,6 +2578,7 @@ export enum Pool_OrderBy { IsInRecoveryMode = 'isInRecoveryMode', IsPaused = 'isPaused', Lambda = 'lambda', + LastPostJoinExitInvariant = 'lastPostJoinExitInvariant', LowerTarget = 'lowerTarget', MainIndex = 'mainIndex', ManagementFee = 'managementFee', @@ -2538,6 +2591,9 @@ export enum Pool_OrderBy { PrincipalToken = 'principalToken', ProtocolAumFeeCache = 'protocolAumFeeCache', ProtocolId = 'protocolId', + ProtocolIdData = 'protocolIdData', + ProtocolIdDataId = 'protocolIdData__id', + ProtocolIdDataName = 'protocolIdData__name', ProtocolSwapFeeCache = 'protocolSwapFeeCache', ProtocolYieldFeeCache = 'protocolYieldFeeCache', Root3Alpha = 'root3Alpha', @@ -2716,6 +2772,7 @@ export enum PriceRateProvider_OrderBy { PoolIdIsInRecoveryMode = 'poolId__isInRecoveryMode', PoolIdIsPaused = 'poolId__isPaused', PoolIdLambda = 'poolId__lambda', + PoolIdLastPostJoinExitInvariant = 'poolId__lastPostJoinExitInvariant', PoolIdLowerTarget = 'poolId__lowerTarget', PoolIdMainIndex = 'poolId__mainIndex', PoolIdManagementFee = 'poolId__managementFee', @@ -2767,11 +2824,58 @@ export enum PriceRateProvider_OrderBy { TokenIsExemptFromYieldProtocolFee = 'token__isExemptFromYieldProtocolFee', TokenManagedBalance = 'token__managedBalance', TokenName = 'token__name', + TokenOldPriceRate = 'token__oldPriceRate', TokenPriceRate = 'token__priceRate', TokenSymbol = 'token__symbol', TokenWeight = 'token__weight' } +export type ProtocolIdData = { + __typename?: 'ProtocolIdData'; + id: Scalars['ID']; + name: Scalars['String']; +}; + +export type ProtocolIdData_Filter = { + /** Filter for the block changed event. */ + _change_block?: InputMaybe; + and?: InputMaybe>>; + id?: InputMaybe; + id_gt?: InputMaybe; + id_gte?: InputMaybe; + id_in?: InputMaybe>; + id_lt?: InputMaybe; + id_lte?: InputMaybe; + id_not?: InputMaybe; + id_not_in?: InputMaybe>; + name?: InputMaybe; + name_contains?: InputMaybe; + name_contains_nocase?: InputMaybe; + name_ends_with?: InputMaybe; + name_ends_with_nocase?: InputMaybe; + name_gt?: InputMaybe; + name_gte?: InputMaybe; + name_in?: InputMaybe>; + name_lt?: InputMaybe; + name_lte?: InputMaybe; + name_not?: InputMaybe; + name_not_contains?: InputMaybe; + name_not_contains_nocase?: InputMaybe; + name_not_ends_with?: InputMaybe; + name_not_ends_with_nocase?: InputMaybe; + name_not_in?: InputMaybe>; + name_not_starts_with?: InputMaybe; + name_not_starts_with_nocase?: InputMaybe; + name_starts_with?: InputMaybe; + name_starts_with_nocase?: InputMaybe; + or?: InputMaybe>>; +}; + +export enum ProtocolIdData_OrderBy { + Id = 'id', + Name = 'name' +} + export type Query = { __typename?: 'Query'; /** Access to subgraph metadata */ @@ -2804,6 +2908,8 @@ export type Query = { pools: Array; priceRateProvider?: Maybe; priceRateProviders: Array; + protocolIdData?: Maybe; + protocolIdDatas: Array; swap?: Maybe; swapFeeUpdate?: Maybe; swapFeeUpdates: Array; @@ -3082,6 +3188,24 @@ export type QueryPriceRateProvidersArgs = { }; +export type QueryProtocolIdDataArgs = { + block?: InputMaybe; + id: Scalars['ID']; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type QueryProtocolIdDatasArgs = { + block?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; + where?: InputMaybe; +}; + + export type QuerySwapArgs = { block?: InputMaybe; id: Scalars['ID']; @@ -3275,6 +3399,8 @@ export type Subscription = { pools: Array; priceRateProvider?: Maybe; priceRateProviders: Array; + protocolIdData?: Maybe; + protocolIdDatas: Array; swap?: Maybe; swapFeeUpdate?: Maybe; swapFeeUpdates: Array; @@ -3553,6 +3679,24 @@ export type SubscriptionPriceRateProvidersArgs = { }; +export type SubscriptionProtocolIdDataArgs = { + block?: InputMaybe; + id: Scalars['ID']; + subgraphError?: _SubgraphErrorPolicy_; +}; + + +export type SubscriptionProtocolIdDatasArgs = { + block?: InputMaybe; + first?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; + subgraphError?: _SubgraphErrorPolicy_; + where?: InputMaybe; +}; + + export type SubscriptionSwapArgs = { block?: InputMaybe; id: Scalars['ID']; @@ -3840,6 +3984,7 @@ export enum SwapFeeUpdate_OrderBy { PoolIsInRecoveryMode = 'pool__isInRecoveryMode', PoolIsPaused = 'pool__isPaused', PoolLambda = 'pool__lambda', + PoolLastPostJoinExitInvariant = 'pool__lastPostJoinExitInvariant', PoolLowerTarget = 'pool__lowerTarget', PoolMainIndex = 'pool__mainIndex', PoolManagementFee = 'pool__managementFee', @@ -4074,6 +4219,7 @@ export enum Swap_OrderBy { PoolIdIsInRecoveryMode = 'poolId__isInRecoveryMode', PoolIdIsPaused = 'poolId__isPaused', PoolIdLambda = 'poolId__lambda', + PoolIdLastPostJoinExitInvariant = 'poolId__lastPostJoinExitInvariant', PoolIdLowerTarget = 'poolId__lowerTarget', PoolIdMainIndex = 'poolId__mainIndex', PoolIdManagementFee = 'poolId__managementFee', @@ -4134,6 +4280,7 @@ export type Token = { latestFXPrice?: Maybe; latestPrice?: Maybe; latestUSDPrice?: Maybe; + latestUSDPriceTimestamp?: Maybe; name?: Maybe; pool?: Maybe; symbol?: Maybe; @@ -4267,6 +4414,7 @@ export enum TokenPrice_OrderBy { PoolIdIsInRecoveryMode = 'poolId__isInRecoveryMode', PoolIdIsPaused = 'poolId__isPaused', PoolIdLambda = 'poolId__lambda', + PoolIdLastPostJoinExitInvariant = 'poolId__lastPostJoinExitInvariant', PoolIdLowerTarget = 'poolId__lowerTarget', PoolIdMainIndex = 'poolId__mainIndex', PoolIdManagementFee = 'poolId__managementFee', @@ -4416,6 +4564,7 @@ export enum TokenSnapshot_OrderBy { TokenId = 'token__id', TokenLatestFxPrice = 'token__latestFXPrice', TokenLatestUsdPrice = 'token__latestUSDPrice', + TokenLatestUsdPriceTimestamp = 'token__latestUSDPriceTimestamp', TokenName = 'token__name', TokenSymbol = 'token__symbol', TokenTotalBalanceNotional = 'token__totalBalanceNotional', @@ -4500,6 +4649,14 @@ export type Token_Filter = { latestPrice_starts_with?: InputMaybe; latestPrice_starts_with_nocase?: InputMaybe; latestUSDPrice?: InputMaybe; + latestUSDPriceTimestamp?: InputMaybe; + latestUSDPriceTimestamp_gt?: InputMaybe; + latestUSDPriceTimestamp_gte?: InputMaybe; + latestUSDPriceTimestamp_in?: InputMaybe>; + latestUSDPriceTimestamp_lt?: InputMaybe; + latestUSDPriceTimestamp_lte?: InputMaybe; + latestUSDPriceTimestamp_not?: InputMaybe; + latestUSDPriceTimestamp_not_in?: InputMaybe>; latestUSDPrice_gt?: InputMaybe; latestUSDPrice_gte?: InputMaybe; latestUSDPrice_in?: InputMaybe>; @@ -4623,6 +4780,7 @@ export enum Token_OrderBy { LatestPricePrice = 'latestPrice__price', LatestPricePricingAsset = 'latestPrice__pricingAsset', LatestUsdPrice = 'latestUSDPrice', + LatestUsdPriceTimestamp = 'latestUSDPriceTimestamp', Name = 'name', Pool = 'pool', PoolAddress = 'pool__address', @@ -4642,6 +4800,7 @@ export enum Token_OrderBy { PoolIsInRecoveryMode = 'pool__isInRecoveryMode', PoolIsPaused = 'pool__isPaused', PoolLambda = 'pool__lambda', + PoolLastPostJoinExitInvariant = 'pool__lastPostJoinExitInvariant', PoolLowerTarget = 'pool__lowerTarget', PoolMainIndex = 'pool__mainIndex', PoolManagementFee = 'pool__managementFee', @@ -4860,6 +5019,7 @@ export enum TradePair_OrderBy { Token0Id = 'token0__id', Token0LatestFxPrice = 'token0__latestFXPrice', Token0LatestUsdPrice = 'token0__latestUSDPrice', + Token0LatestUsdPriceTimestamp = 'token0__latestUSDPriceTimestamp', Token0Name = 'token0__name', Token0Symbol = 'token0__symbol', Token0TotalBalanceNotional = 'token0__totalBalanceNotional', @@ -4873,6 +5033,7 @@ export enum TradePair_OrderBy { Token1Id = 'token1__id', Token1LatestFxPrice = 'token1__latestFXPrice', Token1LatestUsdPrice = 'token1__latestUSDPrice', + Token1LatestUsdPriceTimestamp = 'token1__latestUSDPriceTimestamp', Token1Name = 'token1__name', Token1Symbol = 'token1__symbol', Token1TotalBalanceNotional = 'token1__totalBalanceNotional', @@ -5080,7 +5241,7 @@ export type PoolsQueryVariables = Exact<{ }>; -export type PoolsQuery = { __typename?: 'Query', pools: Array<{ __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null }> }; +export type PoolsQuery = { __typename?: 'Query', pools: Array<{ __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, isPaused?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null }> }; export type AllPoolsQueryVariables = Exact<{ skip?: InputMaybe; @@ -5092,7 +5253,7 @@ export type AllPoolsQueryVariables = Exact<{ }>; -export type AllPoolsQuery = { __typename?: 'Query', pool0: Array<{ __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null }>, pool1000: Array<{ __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null }>, pool2000: Array<{ __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null }> }; +export type AllPoolsQuery = { __typename?: 'Query', pool0: Array<{ __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, isPaused?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null }>, pool1000: Array<{ __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, isPaused?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null }>, pool2000: Array<{ __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, isPaused?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null }> }; export type PoolQueryVariables = Exact<{ id: Scalars['ID']; @@ -5100,9 +5261,9 @@ export type PoolQueryVariables = Exact<{ }>; -export type PoolQuery = { __typename?: 'Query', pool?: { __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null } | null }; +export type PoolQuery = { __typename?: 'Query', pool?: { __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, isPaused?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null } | null }; -export type SubgraphPoolFragment = { __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null }; +export type SubgraphPoolFragment = { __typename?: 'Pool', id: string, address: string, poolType?: string | null, poolTypeVersion?: number | null, factory?: string | null, strategyType: number, symbol?: string | null, name?: string | null, swapEnabled: boolean, swapFee: string, protocolYieldFeeCache?: string | null, protocolSwapFeeCache?: string | null, owner?: string | null, totalWeight?: string | null, totalSwapVolume: string, totalSwapFee: string, totalLiquidity: string, totalShares: string, swapsCount: string, holdersCount: string, tokensList: Array, amp?: string | null, expiryTime?: string | null, unitSeconds?: string | null, createTime: number, principalToken?: string | null, baseToken?: string | null, wrappedIndex?: number | null, mainIndex?: number | null, lowerTarget?: string | null, upperTarget?: string | null, sqrtAlpha?: string | null, sqrtBeta?: string | null, root3Alpha?: string | null, isInRecoveryMode?: boolean | null, isPaused?: boolean | null, alpha?: string | null, beta?: string | null, c?: string | null, s?: string | null, lambda?: string | null, tauAlphaX?: string | null, tauAlphaY?: string | null, tauBetaX?: string | null, tauBetaY?: string | null, u?: string | null, v?: string | null, w?: string | null, z?: string | null, dSq?: string | null, delta?: string | null, epsilon?: string | null, tokens?: Array<{ __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }> | null, priceRateProviders?: Array<{ __typename?: 'PriceRateProvider', address: string, token: { __typename?: 'PoolToken', address: string } }> | null }; export type SubgraphPoolTokenFragment = { __typename?: 'PoolToken', id: string, symbol: string, name: string, decimals: number, address: string, balance: string, managedBalance: string, weight?: string | null, priceRate: string, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, latestFXPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null, tokens?: Array<{ __typename?: 'PoolToken', address: string, balance: string, weight?: string | null, priceRate: string, symbol: string, decimals: number, isExemptFromYieldProtocolFee?: boolean | null, token: { __typename?: 'Token', latestUSDPrice?: string | null, pool?: { __typename?: 'Pool', id: string, totalShares: string, address: string, poolType?: string | null, mainIndex?: number | null } | null } }> | null } | null } }> | null } | null } }; @@ -5356,6 +5517,7 @@ export const SubgraphPoolFragmentDoc = gql` sqrtBeta root3Alpha isInRecoveryMode + isPaused alpha beta c diff --git a/balancer-js/src/modules/swaps/joinAndExit.integration.spec.ts b/balancer-js/src/modules/swaps/joinAndExit.integration.spec.ts index 9fe4d6f10..4f5c32957 100644 --- a/balancer-js/src/modules/swaps/joinAndExit.integration.spec.ts +++ b/balancer-js/src/modules/swaps/joinAndExit.integration.spec.ts @@ -10,7 +10,12 @@ import { TokenPriceService, SwapTypes, } from '@balancer-labs/sor'; -import { BalancerSDK, Network, RelayerAuthorization } from '@/index'; +import { + BalancerSDK, + Network, + RelayerAuthorization, + BALANCER_NETWORK_CONFIG, +} from '@/index'; import { buildRelayerCalls, someJoinExit } from './joinAndExit'; import { BAL_WETH, @@ -23,7 +28,6 @@ import { MockPoolDataService } from '@/test/lib/mockPool'; import { ADDRESSES } from '@/test/lib/constants'; import { Contracts } from '../contracts/contracts.module'; import { forkSetup, getBalances } from '@/test/lib/utils'; -import { networkAddresses } from '@/lib/constants/config'; dotenv.config(); const { ALCHEMY_URL: jsonRpcUrl } = process.env; @@ -34,11 +38,12 @@ const gasLimit = 8e6; let sor: SOR; const { contracts } = new Contracts(networkId, provider); -const { tokens, contracts: contractAddresses } = networkAddresses(networkId); const signer = provider.getSigner(); -const relayerAddress = contractAddresses.relayerV5 as string; -const wrappedNativeAsset = tokens.wrappedNativeAsset; +const relayerAddress = + BALANCER_NETWORK_CONFIG[networkId].addresses.contracts.relayer; +const wrappedNativeAsset = + BALANCER_NETWORK_CONFIG[networkId].addresses.tokens.wrappedNativeAsset; describe('join and exit integration tests', async () => { await testFlow( diff --git a/balancer-js/src/modules/swaps/joinAndExit.ts b/balancer-js/src/modules/swaps/joinAndExit.ts index e4144b2fb..dde0c890e 100644 --- a/balancer-js/src/modules/swaps/joinAndExit.ts +++ b/balancer-js/src/modules/swaps/joinAndExit.ts @@ -9,7 +9,6 @@ import { } from '@balancer-labs/sor'; import { BalancerError, BalancerErrorCode } from '@/balancerErrors'; -import { RelayerV5__factory } from '@/contracts'; import { AssetHelpers, subSlippage } from '@/lib/utils'; import { Relayer, @@ -20,6 +19,7 @@ import { } from '@/modules/relayer/relayer.module'; import { getPoolAddress } from '@/pool-utils'; import { WeightedPoolEncoder } from '@/pool-weighted'; +import { BalancerRelayer__factory } from '@/contracts/factories/BalancerRelayer__factory'; import { ExitPoolRequest } from '@/types'; import { FundManagement, SwapType } from './types'; @@ -114,7 +114,7 @@ const EMPTY_BATCHSWAP_ACTION: BatchSwapAction = { type Actions = JoinAction | ExitAction | SwapAction | BatchSwapAction; type OrderedActions = JoinAction | ExitAction | BatchSwapAction; -const balancerRelayerInterface = RelayerV5__factory.createInterface(); +const balancerRelayerInterface = BalancerRelayer__factory.createInterface(); function getOutputRef(key: number, index: number): OutputReference { const keyRef = Relayer.toChainedReference(key); diff --git a/balancer-js/src/modules/swaps/swap_builder/batch_swap_builder.spec.ts b/balancer-js/src/modules/swaps/swap_builder/batch_swap_builder.spec.ts index d30128dde..beab44765 100644 --- a/balancer-js/src/modules/swaps/swap_builder/batch_swap_builder.spec.ts +++ b/balancer-js/src/modules/swaps/swap_builder/batch_swap_builder.spec.ts @@ -5,8 +5,8 @@ import { expect } from 'chai'; import { BigNumber } from '@ethersproject/bignumber'; describe('SwapBuilder', () => { - const swapAmountForSwaps = BigNumber.from('1000'); - const returnAmountFromSwaps = BigNumber.from('2000'); + const swapAmountForSwaps = BigNumber.from('10000'); + const returnAmountFromSwaps = BigNumber.from('10000'); const swapInfo = factories.swapInfo.build({ swapAmountForSwaps, returnAmountFromSwaps, @@ -18,14 +18,7 @@ describe('SwapBuilder', () => { it('for 1 bsp 0.01%', () => { const maxSlippage = 1; builder.setLimits(maxSlippage); - expect(builder.limits).to.eql([ - swapAmountForSwaps.toString(), - returnAmountFromSwaps - .mul(1e3 - maxSlippage) - .div(1e3) - .mul(-1) - .toString(), - ]); + expect(builder.limits).to.eql(['10000', '-9999']); }); }); @@ -35,13 +28,7 @@ describe('SwapBuilder', () => { it('for 1 bsp 0.01%', () => { const maxSlippage = 1; builder.setLimits(maxSlippage); - expect(builder.limits).to.eql([ - returnAmountFromSwaps - .mul(1e3 + maxSlippage) - .div(1e3) - .toString(), - swapAmountForSwaps.mul(-1).toString(), - ]); + expect(builder.limits).to.eql(['10001', '-10000']); }); }); }); diff --git a/balancer-js/src/modules/swaps/swap_builder/swap_info_decorator.ts b/balancer-js/src/modules/swaps/swap_builder/swap_info_decorator.ts index b3b48cf88..a1b344c5b 100644 --- a/balancer-js/src/modules/swaps/swap_builder/swap_info_decorator.ts +++ b/balancer-js/src/modules/swaps/swap_builder/swap_info_decorator.ts @@ -26,10 +26,10 @@ function amountForLimit(amount: BigNumber): AmountForLimit { return { amount, max: (maxSlippage: number): BigNumber => { - return amount.mul(1e3 + maxSlippage).div(1e3); + return amount.mul(1e4 + maxSlippage).div(1e4); }, min: (maxSlippage: number): BigNumber => { - return amount.mul(1e3 - maxSlippage).div(1e3); + return amount.mul(1e4 - maxSlippage).div(1e4); }, }; } diff --git a/balancer-js/src/modules/swaps/swap_builder/swap_utils.ts b/balancer-js/src/modules/swaps/swap_builder/swap_utils.ts index cefe29ccb..5e0c66907 100644 --- a/balancer-js/src/modules/swaps/swap_builder/swap_utils.ts +++ b/balancer-js/src/modules/swaps/swap_builder/swap_utils.ts @@ -1,7 +1,7 @@ import { Vault__factory } from '@/contracts/factories/Vault__factory'; -import BatchRelayerLibraryAbi from '@/lib/abi/BatchRelayerLibrary.json'; import { JsonFragment } from '@ethersproject/abi'; import { networkAddresses } from '@/lib/constants/config'; +import { BatchRelayerLibrary__factory } from '@/contracts'; /** * Maps SOR data to get the tokenIn used in swaps. @@ -86,8 +86,11 @@ function relayerResolver( function swapFragment(relayer: SwapRelayer): JsonFragment[] { if (relayer.id === Relayers.lido) - return BatchRelayerLibraryAbi.filter( - (fn) => fn.name && ['swap', 'batchSwap'].includes(fn.name) + return BatchRelayerLibrary__factory.abi.filter( + (f) => + f.type === 'function' && + f.name && + ['swap', 'batchSwap'].includes(f.name) ); else return Vault__factory.abi.filter( @@ -106,8 +109,8 @@ function batchSwapFragment( const { tokens, contracts } = networkAddresses(chainId); if (tokens.stETH && contracts.lidoRelayer) { if ([assetIn, assetOut].includes(tokens.stETH)) { - const relayerSignaturesForSwaps = BatchRelayerLibraryAbi.filter( - (fn) => fn.name && ['batchSwap'].includes(fn.name) + const relayerSignaturesForSwaps = BatchRelayerLibrary__factory.abi.filter( + (f) => f.type === 'function' && f.name === 'batchSwap' ); return relayerSignaturesForSwaps; } diff --git a/balancer-js/src/modules/swaps/swaps.module.spec.ts b/balancer-js/src/modules/swaps/swaps.module.spec.ts index cd1af1fea..1dfb8291a 100644 --- a/balancer-js/src/modules/swaps/swaps.module.spec.ts +++ b/balancer-js/src/modules/swaps/swaps.module.spec.ts @@ -9,13 +9,12 @@ import { BalancerSDK, Swaps, BALANCER_NETWORK_CONFIG, + BatchRelayerLibrary__factory, } from '@/.'; import { getNetworkConfig } from '@/modules/sdk.helpers'; import { mockPool, mockPoolDataService } from '@/test/lib/mockPool'; import { SwapTransactionRequest, SwapType } from './types'; import { Vault__factory } from '@/contracts/factories/Vault__factory'; -import BatchRelayerLibraryAbi from '@/lib/abi/BatchRelayerLibrary.json'; -import { Interface } from '@ethersproject/abi'; import { BigNumber } from '@ethersproject/bignumber'; import { AddressZero, MaxUint256 } from '@ethersproject/constants'; import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; @@ -37,7 +36,7 @@ const sdkConfig: BalancerSdkConfig = { }; const vaultInterface = Vault__factory.createInterface(); -const vaultActions = new Interface(BatchRelayerLibraryAbi); +const vaultActions = BatchRelayerLibrary__factory.createInterface(); const funds = { fromInternalBalance: false, diff --git a/balancer-js/src/modules/vaultModel/poolModel/exit.ts b/balancer-js/src/modules/vaultModel/poolModel/exit.ts index 24aa819c7..eb8a7130b 100644 --- a/balancer-js/src/modules/vaultModel/poolModel/exit.ts +++ b/balancer-js/src/modules/vaultModel/poolModel/exit.ts @@ -59,6 +59,11 @@ export class ExitModel { ComposableStablePoolExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT ) return WeightedPoolExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT; + if ( + exitKind.toNumber() === + ComposableStablePoolExitKind.EXACT_BPT_IN_FOR_ALL_TOKENS_OUT + ) + return WeightedPoolExitKind.EXACT_BPT_IN_FOR_TOKENS_OUT; else { return WeightedPoolExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT; } diff --git a/balancer-js/src/modules/vaultModel/vaultModel.module.integration.spec.ts b/balancer-js/src/modules/vaultModel/vaultModel.module.integration.spec.ts index 2eaa4b141..34011a0fe 100644 --- a/balancer-js/src/modules/vaultModel/vaultModel.module.integration.spec.ts +++ b/balancer-js/src/modules/vaultModel/vaultModel.module.integration.spec.ts @@ -10,7 +10,12 @@ import { TokenPriceService, SwapTypes, } from '@balancer-labs/sor'; -import { BalancerSDK, Network, RelayerAuthorization } from '@/index'; +import { + BalancerSDK, + Network, + RelayerAuthorization, + BALANCER_NETWORK_CONFIG, +} from '@/index'; import { buildRelayerCalls, someJoinExit } from '@/modules/swaps/joinAndExit'; import { BAL_WETH, @@ -45,8 +50,10 @@ let sor: SOR; const { contracts } = new Contracts(networkId, provider); const signer = provider.getSigner(); -const relayerV4Address = '0x2536dfeeCB7A0397CF98eDaDA8486254533b1aFA'; -const wrappedNativeAsset = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; +const relayerAddress = + BALANCER_NETWORK_CONFIG[networkId].addresses.contracts.relayer; +const wrappedNativeAsset = + BALANCER_NETWORK_CONFIG[networkId].addresses.tokens.wrappedNativeAsset; describe('join and exit integration tests', async () => { await testFlow( @@ -152,7 +159,7 @@ async function testFlow( slots, balances, jsonRpcUrl as string, - 15624161 + 16940624 ); [sor, vaultModel] = await setUp(networkId, provider, pools); await sor.fetchPools(); @@ -169,7 +176,7 @@ async function testFlow( ); const signerAddr = await signer.getAddress(); const authorisation = await signRelayerApproval( - ADDRESSES[networkId].BatchRelayerV4.address, + relayerAddress, signerAddr, signer ); @@ -181,7 +188,7 @@ async function testFlow( swapInfo, pools, signerAddr, - relayerV4Address, + relayerAddress, wrappedNativeAsset, slippage, authorisation diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts deleted file mode 100644 index d911d7f50..000000000 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ /dev/null @@ -1,203 +0,0 @@ -export const ADDRESSES = { - 1: { - relayer: '0x886A3Ec7bcC508B8795990B60Fa21f85F9dB7948', - staBal3: { - id: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063', - address: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42', - gauge: '0x34f33cdaed8ba0e1ceece80e5f4a73bcf234cfac', - assetOrder: ['DAI', 'USDC', 'USDT'], - }, - bbausd1: { - id: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb20000000000000000000000fe', - address: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb2', - gauge: '0x68d019f64a7aa97e2d4e7363aee42251d08124fb', - assetOrder: ['bb-a-USDT', 'bb-a-DAI', 'bb-a-USDC'], - }, - bbausd2: { - id: '0xa13a9247ea42d743238089903570127dda72fe4400000000000000000000035d', - address: '0xa13a9247ea42d743238089903570127dda72fe44', - gauge: '0xa6325e799d266632d347e41265a69af111b05403', - }, - linearUsdc1: { - id: '0x9210f1204b5a24742eba12f710636d76240df3d00000000000000000000000fc', - address: '0x9210F1204b5a24742Eba12f710636D76240dF3d0', - }, - linearDai1: { - id: '0x804cdb9116a10bb78768d3252355a1b18067bf8f0000000000000000000000fb', - address: '0x804CdB9116a10bB78768D3252355a1b18067bF8f', - }, - linearUsdt1: { - id: '0x2bbf681cc4eb09218bee85ea2a5d3d13fa40fc0c0000000000000000000000fd', - address: '0x2BBf681cC4eb09218BEe85EA2a5d3D13Fa40fC0C', - }, - linearUsdc2: { - id: '0x82698AECC9E28E9BB27608BD52CF57F704BD1B83000000000000000000000336', - address: '0x82698aeCc9E28e9Bb27608Bd52cF57f704BD1B83', - }, - linearDai2: { - id: '0xAE37D54AE477268B9997D4161B96B8200755935C000000000000000000000337', - address: '0xae37D54Ae477268B9997d4161B96b8200755935c', - }, - linearUsdt2: { - id: '0x2F4EB100552EF93840D5ADC30560E5513DFFFACB000000000000000000000334', - address: '0x2F4eb100552ef93840d5aDC30560E5513DFfFACb', - }, - maiusd: { - id: '', - address: '', - gauge: '', - assetOrder: ['USDT', 'miMATIC', 'DAI', 'USDC'], - }, - maibbausd: { - id: '', - address: '', - gauge: '', - assetOrder: ['bb-a-USD', 'miMATIC'], - }, - DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', - USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', - waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', - waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', - waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', - miMATIC: '', - }, - 5: { - relayer: '0x7b9B6f094DC2Bd1c12024b0D9CC63d6993Be1888', - staBal3: { - id: '0xdcdd4a3d36dec8d57594e89763d069a7e9b223e2000000000000000000000062', - address: '0xdcdd4a3d36dec8d57594e89763d069a7e9b223e2', - gauge: '0xfd364cda96bb7db06b65706182c448a73f0a5f9a', - assetOrder: ['USDT', 'DAI', 'USDC'], - }, - staBal3_2: { - id: '0xff9d677474d4344379924e10b68c8fea67e03294000000000000000000000072', - address: '0xff9d677474d4344379924e10b68c8fea67e03294', - gauge: '0x4e4ebf2aa90e41174d716a5168895357762d68af', - assetOrder: ['USDT', 'DAI', 'USDC'], - }, - staBal3_3: { - id: '0x3bfc8a0509f1a68aefd446f6c19bf37b3c75a8fc0000000000000000000000a5', - address: '0x3bfc8a0509f1a68aefd446f6c19bf37b3c75a8fc', - gauge: '0x7776e1008d7c20ab54aa57a7c44fc7de602de29a', - assetOrder: ['USDT', 'DAI', 'USDC'], - }, - bbausd1: { - id: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd00000000000000000000005f', - address: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd', - gauge: '0xa2d0ea81a47d68598922cd54c59249ff58c2a3ff', - assetOrder: ['bb-a-USDC', 'bb-a-DAI', 'bb-a-USDT'], - }, - bbausd2: { - id: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd00000000000000000000005f', - address: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd', - gauge: '0xa2d0ea81a47d68598922cd54c59249ff58c2a3ff', - }, - linearUsdc1: { - id: '0x0595d1df64279ddb51f1bdc405fe2d0b4cc8668100000000000000000000005c', - address: '0x0595d1df64279ddb51f1bdc405fe2d0b4cc86681', - }, - linearDai1: { - id: '0x5cea6a84ed13590ed14903925fa1a73c36297d9900000000000000000000005d', - address: '0x5cea6a84ed13590ed14903925fa1a73c36297d99', - }, - linearUsdt1: { - id: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f00000000000000000000005e', - address: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f', - }, - linearUsdc2: { - id: '0x0595d1df64279ddb51f1bdc405fe2d0b4cc8668100000000000000000000005c', - address: '0x0595d1df64279ddb51f1bdc405fe2d0b4cc86681', - }, - linearDai2: { - id: '0x5cea6a84ed13590ed14903925fa1a73c36297d9900000000000000000000005d', - address: '0x5cea6a84ed13590ed14903925fa1a73c36297d99', - }, - linearUsdt2: { - id: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f00000000000000000000005e', - address: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f', - }, - maiusd: { - id: '0x6a8f9ab364b85725973d2a33cb9aae2dac43b5e30000000000000000000000a6', - address: '0x6a8f9ab364b85725973d2a33cb9aae2dac43b5e3', - gauge: '0x58141bdcecb7fbae006964f4131cf6f65c948357', - assetOrder: ['USDT', 'miMATIC', 'DAI', 'USDC'], - }, - maibbausd: { - id: '0xb04b03b78cf79788a1931545bd2744161029648f0000000000000000000000a8', - address: '0xb04b03b78cf79788a1931545bd2744161029648f', - gauge: '0xdc3f6fc8898830e53c777543fe252b14f22680d4', - assetOrder: ['bb-a-USD', 'miMATIC', 'MAI BSP'], - }, - USDT: '0x1f1f156e0317167c11aa412e3d1435ea29dc3cce', - DAI: '0x8c9e6c40d3402480ace624730524facc5482798c', - USDC: '0xe0c9275e44ea80ef17579d33c55136b7da269aeb', - waDAI: '0x89534a24450081aa267c79b07411e9617d984052', - waUSDC: '0x811151066392fd641fe74a9b55a712670572d161', - waUSDT: '0x4cb1892fddf14f772b2e39e299f44b2e5da90d04', - miMATIC: '0x398106564948feeb1fedea0709ae7d969d62a391', - }, - 137: { - relayer: '0xcf6a66E32dCa0e26AcC3426b851FD8aCbF12Dac7', - staBal3: { - id: '', - address: '', - gauge: '', - assetOrder: ['USDT', 'DAI', 'USDC'], - }, - bbausd1: { - id: '', - address: '', - gauge: '', - assetOrder: ['bb-a-USDC', 'bb-a-DAI', 'bb-a-USDT'], - }, - bbausd2: { - id: '0x48e6b98ef6329f8f0a30ebb8c7c960330d64808500000000000000000000075b', - address: '0x48e6b98ef6329f8f0a30ebb8c7c960330d648085', - gauge: '', - }, - linearUsdc1: { - id: '', - address: '', - }, - linearDai1: { - id: '', - address: '', - }, - linearUsdt1: { - id: '', - address: '', - }, - linearUsdc2: { - id: '0xf93579002dbe8046c43fefe86ec78b1112247bb8000000000000000000000759', - address: '0xf93579002dbe8046c43fefe86ec78b1112247bb8', - }, - linearDai2: { - id: '0x178e029173417b1f9c8bc16dcec6f697bc323746000000000000000000000758', - address: '0x178e029173417b1f9c8bc16dcec6f697bc323746', - }, - linearUsdt2: { - id: '0xff4ce5aaab5a627bf82f4a571ab1ce94aa365ea600000000000000000000075a', - address: '0xff4ce5aaab5a627bf82f4a571ab1ce94aa365ea6', - }, - maiusd: { - id: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000012', - address: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42', - gauge: '0x72843281394e68de5d55bcf7072bb9b2ebc24150', - assetOrder: ['USDC', 'DAI', 'miMATIC', 'USDT'], - }, - maibbausd: { - id: '0xb54b2125b711cd183edd3dd09433439d5396165200000000000000000000075e', - address: '0xb54b2125b711cd183edd3dd09433439d53961652', - gauge: '0x9a105ef22a59484aa2731c357049f6a13d0891f5', - assetOrder: ['bb-a-USD', 'miMATIC'], - }, - USDT: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', - DAI: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', - USDC: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', - waDAI: '0xEE029120c72b0607344f35B17cdD90025e647B00', - waUSDC: '0x221836a597948Dce8F3568E044fF123108aCc42A', - waUSDT: '0x19C60a251e525fa88Cd6f3768416a8024e98fC19', - miMATIC: '0xa3fa99a148fa48d14ed51d610c367c61876997f1', - }, -}; diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts deleted file mode 100644 index f79241f9c..000000000 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ /dev/null @@ -1,272 +0,0 @@ -import dotenv from 'dotenv'; -import { expect } from 'chai'; -import hardhat from 'hardhat'; -import { - BalancerError, - BalancerErrorCode, - BalancerSDK, - Network, - RelayerAuthorization, - PoolWithMethods, -} from '@/.'; -import { BigNumber, parseFixed } from '@ethersproject/bignumber'; -import { Contracts } from '@/modules/contracts/contracts.module'; -import { ADDRESSES } from './addresses'; -import { JsonRpcSigner } from '@ethersproject/providers'; -import { MaxUint256, WeiPerEther } from '@ethersproject/constants'; -import { Migrations } from '../migrations'; -import { getErc20Balance, move, stake } from '@/test/lib/utils'; - -dotenv.config(); - -/* - * Testing on GOERLI - * - Run node on terminal: yarn run node:goerli - * - Uncomment section below - */ -// const network = Network.GOERLI; -// const blockNumber = 7277540; -// const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; -// const { ALCHEMY_URL_GOERLI: jsonRpcUrl } = process.env; -// const rpcUrl = 'http://127.0.0.1:8000'; - -/* - * Testing on MAINNET - * - Run node on terminal: yarn run node - * - Uncomment section below - */ -const network = Network.MAINNET; -const blockNumber = 15496800; -const holderAddress = '0xec576a26335de1c360d2fc9a68cba6ba37af4a13'; -const { ALCHEMY_URL: jsonRpcUrl } = process.env; -const rpcUrl = 'http://127.0.0.1:8545'; - -const { ethers } = hardhat; -const MAX_GAS_LIMIT = 8e6; -const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); -const addresses = ADDRESSES[network]; -const fromPool = { - id: addresses.bbausd1.id, - address: addresses.bbausd1.address, - gauge: addresses.bbausd1.gauge, -}; -const toPool = { - id: addresses.bbausd2.id, - address: addresses.bbausd2.address, - gauge: addresses.bbausd2.gauge, -}; -const { contracts } = new Contracts(network as number, provider); -const migrations = new Migrations(network); - -const relayer = addresses.relayer; - -const signRelayerApproval = async ( - relayerAddress: string, - signerAddress: string, - signer: JsonRpcSigner -): Promise => { - const approval = contracts.vault.interface.encodeFunctionData( - 'setRelayerApproval', - [signerAddress, relayerAddress, true] - ); - - const signature = - await RelayerAuthorization.signSetRelayerApprovalAuthorization( - contracts.vault, - signer, - relayerAddress, - approval - ); - - const calldata = RelayerAuthorization.encodeCalldataAuthorization( - '0x', - MaxUint256, - signature - ); - - return calldata; -}; - -const reset = async () => - provider.send('hardhat_reset', [ - { - forking: { - jsonRpcUrl, - blockNumber, - }, - }, - ]); - -describe.skip('bbausd migration execution', async function () { - this.timeout(40000); - - let signer: JsonRpcSigner; - let signerAddress: string; - let authorisation: string; - let balance: BigNumber; - let pool: PoolWithMethods; - - beforeEach(async function () { - await reset(); - - signer = provider.getSigner(); - signerAddress = await signer.getAddress(); - authorisation = await signRelayerApproval(relayer, signerAddress, signer); - // Transfer tokens from existing user account to signer - // We need that to test signatures, because hardhat doesn't have impersonated accounts private keys - balance = await move( - fromPool.address, - holderAddress, - signerAddress, - provider - ); - - const sdk = new BalancerSDK({ - network, - rpcUrl, - }); - const { pools } = sdk; - await pools.findBy('address', fromPool.address).then((res) => { - if (!res) throw new BalancerError(BalancerErrorCode.POOL_DOESNT_EXIST); - pool = res; - }); - }); - - async function testFlow( - staked: boolean, - authorised = true, - minOutBuffer: string - ): Promise { - const addressIn = staked ? fromPool.gauge : fromPool.address; - const addressOut = staked ? toPool.gauge : toPool.address; - // Store balance before migration - const before = { - from: await getErc20Balance(addressIn, provider, signerAddress), - to: await getErc20Balance(addressOut, provider, signerAddress), - }; - - const amount = before.from; - - let query = migrations.bbaUsd( - signerAddress, - amount.toString(), - '0', - staked, - pool.tokens - .filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed - .map((token) => { - const parsedBalance = parseFixed(token.balance, token.decimals); - const parsedPriceRate = parseFixed(token.priceRate as string, 18); - return parsedBalance.mul(WeiPerEther).div(parsedPriceRate).toString(); - }), - authorisation - ); - - const gasLimit = MAX_GAS_LIMIT; - - // Static call can be used to simulate tx and get expected BPT in/out deltas - const staticResult = await signer.call({ - to: query.to, - data: query.data, - gasLimit, - }); - - const bptOut = query.decode(staticResult, staked); - - query = migrations.bbaUsd( - signerAddress, - amount.toString(), - BigNumber.from(bptOut).add(minOutBuffer).toString(), - staked, - pool.tokens - .filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed - .map((token) => { - const parsedBalance = parseFixed(token.balance, token.decimals); - const parsedPriceRate = parseFixed(token.priceRate as string, 18); - return parsedBalance.mul(WeiPerEther).div(parsedPriceRate).toString(); - }), - authorised ? authorisation : undefined - ); - - const response = await signer.sendTransaction({ - to: query.to, - data: query.data, - gasLimit, - }); - - const receipt = await response.wait(); - console.log('Gas used', receipt.gasUsed.toString()); - - const after = { - from: await getErc20Balance(addressIn, provider, signerAddress), - to: await getErc20Balance(addressOut, provider, signerAddress), - }; - expect(BigNumber.from(bptOut).gt(0)).to.be.true; - expect(after.from.toString()).to.eq('0'); - expect(after.to.gte(bptOut)).to.be.true; - return bptOut; - } - - context('staked', async () => { - beforeEach(async function () { - // Stake them - await stake(signer, fromPool.address, fromPool.gauge, balance); - }); - - it('should transfer tokens from stable to boosted - using exact bbausd2AmountOut from static call', async () => { - await testFlow(true, undefined, '0'); - }); - - it('should transfer tokens from stable to boosted - limit should fail', async () => { - let errorMessage = ''; - try { - await testFlow(true, true, '1000000000000000000'); - } catch (error) { - errorMessage = (error as Error).message; - } - expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }); - }); - - context('not staked', async () => { - it('should transfer tokens from stable to boosted - using exact bbausd2AmountOut from static call', async () => { - await testFlow(false, undefined, '0'); - }); - - it('should transfer tokens from stable to boosted - limit should fail', async () => { - let errorMessage = ''; - try { - await testFlow(false, true, '1000000000000000000'); - } catch (error) { - errorMessage = (error as Error).message; - } - expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }); - }); - - context('authorisation', async () => { - // authorisation wihtin relayer is the default case and is already tested on previous scenarios - - it('should transfer tokens from stable to boosted - pre authorised', async () => { - const approval = contracts.vault.interface.encodeFunctionData( - 'setRelayerApproval', - [signerAddress, relayer, true] - ); - await signer.sendTransaction({ - to: contracts.vault.address, - data: approval, - }); - await testFlow(false, false, '0'); - }); - - it('should transfer tokens from stable to boosted - auhtorisation should fail', async () => { - let errorMessage = ''; - try { - await testFlow(false, false, '0'); - } catch (error) { - errorMessage = (error as Error).message; - } - expect(errorMessage).to.contain('BAL#503'); // USER_DOESNT_ALLOW_RELAYER - Relayers must be allowed by both governance and the user account - }); - }); -}); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts deleted file mode 100644 index a198d53b9..000000000 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ /dev/null @@ -1,316 +0,0 @@ -import { ADDRESSES } from './addresses'; -import { Relayer } from '@/modules/relayer/relayer.module'; -import { BatchSwapStep, FundManagement, SwapType } from '@/modules/swaps/types'; -import { Interface } from '@ethersproject/abi'; -// TODO - Ask Nico to update Typechain? -import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; -import { BigNumber } from '@ethersproject/bignumber'; -import { Zero } from '@ethersproject/constants'; -import { BalancerError, BalancerErrorCode } from '@/balancerErrors'; -const balancerRelayerInterface = new Interface(balancerRelayerAbi); - -const SWAP_RESULT_BBAUSD = Relayer.toChainedReference('24'); -export class BbaUsd1Builder { - private addresses; - - constructor(networkId: 1 | 5 | 137) { - this.addresses = ADDRESSES[networkId]; - } - - /** - * Builds migration call data. - * Migrates tokens from bbausd1 to bbausd2 pool. - * Tokens that are initially staked are re-staked at the end of migration. Non-staked are not. - * - * @param userAddress User address. - * @param bbausd1Amount Amount of BPT tokens to migrate. - * @param minBbausd2Out Minimum of expected BPT out ot the migration flow. - * @param staked Indicates whether tokens are initially staked or not. - * @param tokenBalances Token balances in EVM scale. Array must have the same length and order as tokens in pool being migrated from. Refer to [getPoolTokens](https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/interfaces/contracts/vault/IVault.sol#L334). - * @param authorisation Encoded authorisation call. - * @returns Migration transaction request ready to send with signer.sendTransaction - */ - calldata( - userAddress: string, - bbausd1Amount: string, - minBbausd2Out: string, - staked: boolean, - tokenBalances: string[], - authorisation?: string - ): { - to: string; - data: string; - } { - if (BigNumber.from(bbausd1Amount).lte(0)) - throw new BalancerError(BalancerErrorCode.INPUT_ZERO_NOT_ALLOWED); - const relayer = this.addresses.relayer; - let calls: string[] = []; - - if (authorisation) { - calls = [this.buildSetRelayerApproval(authorisation)]; - } - - if (staked) { - calls = [ - ...calls, - this.buildWithdraw(userAddress, bbausd1Amount), - this.buildSwap( - bbausd1Amount, - minBbausd2Out, - relayer, - relayer, - tokenBalances - ), - this.buildDeposit(userAddress), - ]; - } else { - calls = [ - ...calls, - this.buildSwap( - bbausd1Amount, - minBbausd2Out, - userAddress, - userAddress, - tokenBalances - ), - ]; - } - - const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ - calls, - ]); - - return { - to: this.addresses.relayer, - data: callData, - }; - } - - /** - * Creates encoded batchSwap function with following swaps: boosted -> linears -> stables -> linears -> boosted - * outputreferences should contain the amount of resulting BPT. - * - * @param bbausd1Amount Amount of BPT tokens to migrate. - * @param minBbausd2Out Minimum of expected BPT out ot the migration flow. - * @param sender Sender address. - * @param recipient Recipient address. - * @param tokenBalances Token balances in EVM scale. - * @returns Encoded batchSwap call. Output references. - */ - buildSwap( - bbausd1Amount: string, - minBbausd2Out: string, - sender: string, - recipient: string, - tokenBalances: string[] - ): string { - const assets = [ - this.addresses.bbausd2.address, - this.addresses.waDAI, - this.addresses.linearDai1.address, - this.addresses.linearDai2.address, - this.addresses.waUSDC, - this.addresses.linearUsdc1.address, - this.addresses.linearUsdc2.address, - this.addresses.waUSDT, - this.addresses.linearUsdt1.address, - this.addresses.linearUsdt2.address, - this.addresses.bbausd1.address, - ]; - - const outputReferences = [{ index: 0, key: SWAP_RESULT_BBAUSD }]; - - // Calculate proportional token amounts - - // Assuming 1:1 exchange rates between tokens - // TODO: Fetch current prices, or use price or priceRate from subgraph? - const totalLiquidity = tokenBalances.reduce( - (sum, tokenBalance) => sum.add(BigNumber.from(tokenBalance)), - Zero - ); - - // bbausd1[bbausd1]blinear1[linear1]stable[linear2]blinear2[bbausd2]bbausd2 and then do that proportionally for each underlying stable. - // Split BPT amount proportionally: - const { assetOrder } = this.addresses.bbausd1; - const usdcBptAmt = BigNumber.from(bbausd1Amount) - .mul(tokenBalances[assetOrder.indexOf('bb-a-USDC')]) - .div(totalLiquidity) - .toString(); - const daiBptAmt = BigNumber.from(bbausd1Amount) - .mul(tokenBalances[assetOrder.indexOf('bb-a-DAI')]) - .div(totalLiquidity) - .toString(); - const usdtBptAmt = BigNumber.from(bbausd1Amount) - .sub(usdcBptAmt) - .sub(daiBptAmt) - .toString(); - - const swaps: BatchSwapStep[] = [ - { - poolId: this.addresses.bbausd1.id, - assetInIndex: 10, - assetOutIndex: 2, - amount: daiBptAmt, - userData: '0x', - }, - { - poolId: this.addresses.linearDai1.id, - assetInIndex: 2, - assetOutIndex: 1, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.linearDai2.id, - assetInIndex: 1, - assetOutIndex: 3, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.bbausd2.id, - assetInIndex: 3, - assetOutIndex: 0, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.bbausd1.id, - assetInIndex: 10, - assetOutIndex: 5, - amount: usdcBptAmt, - userData: '0x', - }, - { - poolId: this.addresses.linearUsdc1.id, - assetInIndex: 5, - assetOutIndex: 4, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.linearUsdc2.id, - assetInIndex: 4, - assetOutIndex: 6, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.bbausd2.id, - assetInIndex: 6, - assetOutIndex: 0, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.bbausd1.id, - assetInIndex: 10, - assetOutIndex: 8, - amount: usdtBptAmt, - userData: '0x', - }, - { - poolId: this.addresses.linearUsdt1.id, - assetInIndex: 8, - assetOutIndex: 7, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.linearUsdt2.id, - assetInIndex: 7, - assetOutIndex: 9, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.bbausd2.id, - assetInIndex: 9, - assetOutIndex: 0, - amount: '0', - userData: '0x', - }, - ]; - - // For tokens going in to the Vault, the limit shall be a positive number. For tokens going out of the Vault, the limit shall be a negative number. - const limits = [ - BigNumber.from(minBbausd2Out).mul(-1).toString(), // bbausd2 - '0', - '0', - '0', - '0', - '0', - '0', - '0', - '0', - '0', - bbausd1Amount, // Max in should be bbausd1 amount - ]; - - // Swap to/from Relayer - const funds: FundManagement = { - sender, - recipient, - fromInternalBalance: false, - toInternalBalance: false, - }; - - const encodedBatchSwap = Relayer.encodeBatchSwap({ - swapType: SwapType.SwapExactIn, - swaps, - assets, - funds, - limits, - deadline: BigNumber.from(Math.ceil(Date.now() / 1000) + 3600), // 1 hour from now - value: '0', - outputReferences, - }); - - return encodedBatchSwap; - } - - /** - * Uses relayer to withdraw staked BPT from gauge and send to relayer - * - * @param sender Sender address. - * @param amount Amount of BPT to exit with. - * @returns withdraw call - */ - buildWithdraw(sender: string, amount: string): string { - return Relayer.encodeGaugeWithdraw( - this.addresses.bbausd1.gauge, - sender, - this.addresses.relayer, - amount - ); - } - - /** - * Uses relayer to deposit user's BPT to gauge and sends to recipient - * - * @param recipient Recipient address. - * @returns deposit call - */ - buildDeposit(recipient: string): string { - return Relayer.encodeGaugeDeposit( - this.addresses.bbausd2.gauge, - this.addresses.relayer, - recipient, - SWAP_RESULT_BBAUSD.toString() - ); - } - - /** - * Uses relayer to approve itself to act in behalf of the user - * - * @param authorisation Encoded authorisation call. - * @returns relayer approval call - */ - buildSetRelayerApproval(authorisation: string): string { - return Relayer.encodeSetRelayerApproval( - this.addresses.relayer, - true, - authorisation - ); - } -} diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts deleted file mode 100644 index 94ffa467f..000000000 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts +++ /dev/null @@ -1,255 +0,0 @@ -// import dotenv from 'dotenv'; -// import { expect } from 'chai'; -// import hardhat from 'hardhat'; -// import { Network, RelayerAuthorization } from '@/.'; -// import { BigNumber } from '@ethersproject/bignumber'; -// import { Contracts } from '@/modules/contracts/contracts.module'; -// import { ADDRESSES } from './addresses'; -// import { JsonRpcSigner } from '@ethersproject/providers'; -// import { MaxUint256 } from '@ethersproject/constants'; -// import { Migrations } from '../migrations'; -// import { getErc20Balance, move, stake } from '@/test/lib/utils'; - -// dotenv.config(); - -// /* -// * Testing on GOERLI -// * - Run node on terminal: yarn run node:goerli -// * - Uncomment section below -// */ -// const network = Network.GOERLI; -// const blockNumber = 7376670; -// const holderAddress = '0x8fe3a2a5ae6baa201c26fc7830eb713f33d6b313'; -// const { ALCHEMY_URL_GOERLI: jsonRpcUrl } = process.env; -// const rpcUrl = 'http://127.0.0.1:8000'; - -// /* -// * Testing on POLYGON -// * - Run node on terminal: yarn run node:polygon -// * - Uncomment section below -// */ -// // const network = Network.POLYGON; -// // const blockNumber = 32856000; -// // const holderAddress = '0xfb0272990728a967ecaf702a1291fcd64c38ed25'; -// // const { ALCHEMY_URL_POLYGON: jsonRpcUrl } = process.env; -// // const rpcUrl = 'http://127.0.0.1:8545'; - -// const { ethers } = hardhat; -// const MAX_GAS_LIMIT = 8e6; - -// const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); -// const addresses = ADDRESSES[network]; -// const fromPool = { -// id: addresses.maiusd.id, -// address: addresses.maiusd.address, -// gauge: addresses.maiusd.gauge, -// }; -// const toPool = { -// id: addresses.maibbausd.id, -// address: addresses.maibbausd.address, -// gauge: addresses.maibbausd.gauge, -// }; -// const { contracts } = new Contracts(network as number, provider); -// const migrations = new Migrations(network); - -// const relayer = addresses.relayer; - -// const signRelayerApproval = async ( -// relayerAddress: string, -// signerAddress: string, -// signer: JsonRpcSigner -// ): Promise => { -// const approval = contracts.vault.interface.encodeFunctionData( -// 'setRelayerApproval', -// [signerAddress, relayerAddress, true] -// ); - -// const signature = -// await RelayerAuthorization.signSetRelayerApprovalAuthorization( -// contracts.vault, -// signer, -// relayerAddress, -// approval -// ); - -// const calldata = RelayerAuthorization.encodeCalldataAuthorization( -// '0x', -// MaxUint256, -// signature -// ); - -// return calldata; -// }; - -// const reset = () => -// provider.send('hardhat_reset', [ -// { -// forking: { -// jsonRpcUrl, -// blockNumber, -// }, -// }, -// ]); - -// describe('maiusd migration execution', async () => { -// let signer: JsonRpcSigner; -// let signerAddress: string; -// let authorisation: string; -// let balance: BigNumber; - -// before(async function () { -// try { -// const currentNetwork = await provider.getNetwork(); -// if (currentNetwork.chainId != network) { -// this.skip(); -// } -// } catch (err) { -// console.log(err); -// this.skip(); -// } -// }); - -// beforeEach(async function () { -// await reset(); - -// signer = provider.getSigner(); -// signerAddress = await signer.getAddress(); -// authorisation = await signRelayerApproval(relayer, signerAddress, signer); - -// // Transfer tokens from existing user account to signer -// // We need that to test signatures, because hardhat doesn't have impersonated accounts private keys -// balance = await move( -// fromPool.address, -// holderAddress, -// signerAddress, -// provider -// ); -// }); - -// async function testFlow( -// staked: boolean, -// authorised = true, -// minBptOut: undefined | string = undefined -// ): Promise { -// const addressIn = staked ? fromPool.gauge : fromPool.address; -// const addressOut = staked ? toPool.gauge : toPool.address; -// // Store balance before migration -// const before = { -// from: await getErc20Balance(addressIn, provider, signerAddress), -// to: await getErc20Balance(addressOut, provider, signerAddress), -// }; - -// const amount = before.from; - -// let query = migrations.maiusd( -// signerAddress, -// amount.toString(), -// '0', -// staked, -// authorisation -// ); -// const gasLimit = MAX_GAS_LIMIT; - -// // Static call can be used to simulate tx and get expected BPT in/out deltas -// const staticResult = await signer.call({ -// to: query.to, -// data: query.data, -// gasLimit, -// }); -// const bptOut = query.decode(staticResult, staked); - -// query = migrations.maiusd( -// signerAddress, -// amount.toString(), -// minBptOut ? minBptOut : bptOut, -// staked, -// authorised ? authorisation : undefined -// ); - -// const response = await signer.sendTransaction({ -// to: query.to, -// data: query.data, -// gasLimit, -// }); - -// const receipt = await response.wait(); -// console.log('Gas used', receipt.gasUsed.toString()); - -// const after = { -// from: await getErc20Balance(addressIn, provider, signerAddress), -// to: await getErc20Balance(addressOut, provider, signerAddress), -// }; - -// console.log(bptOut); - -// expect(BigNumber.from(bptOut).gt(0)).to.be.true; -// expect(after.from.toString()).to.eq('0'); -// expect(after.to.toString()).to.eq(bptOut); -// return bptOut; -// } - -// let bptOut: string; - -// context('staked', async () => { -// beforeEach(async function () { -// // Stake them -// await stake(signer, fromPool.address, fromPool.gauge, balance); -// }); - -// it('should transfer tokens from stable to boosted', async () => { -// bptOut = await testFlow(true); -// }); - -// it('should transfer tokens from stable to boosted - limit should fail', async () => { -// let errorMessage = ''; -// try { -// await testFlow(true, true, BigNumber.from(bptOut).add(1).toString()); -// } catch (error) { -// errorMessage = (error as Error).message; -// } -// expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) -// }); -// }); - -// context('not staked', async () => { -// it('should transfer tokens from stable to boosted', async () => { -// bptOut = await testFlow(false); -// }); - -// it('should transfer tokens from stable to boosted - limit should fail', async () => { -// let errorMessage = ''; -// try { -// await testFlow(false, true, BigNumber.from(bptOut).add(1).toString()); -// } catch (error) { -// errorMessage = (error as Error).message; -// } -// expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) -// }); -// }); - -// context('authorisation', async () => { -// // authorisation wihtin relayer is the default case and is already tested on previous scenarios - -// it('should transfer tokens from stable to boosted - pre authorised', async () => { -// const approval = contracts.vault.interface.encodeFunctionData( -// 'setRelayerApproval', -// [signerAddress, relayer, true] -// ); -// await signer.sendTransaction({ -// to: contracts.vault.address, -// data: approval, -// }); -// await testFlow(false, false); -// }); - -// it('should transfer tokens from stable to boosted - auhtorisation should fail', async () => { -// let errorMessage = ''; -// try { -// await testFlow(false, false); -// } catch (error) { -// errorMessage = (error as Error).message; -// } -// expect(errorMessage).to.contain('BAL#503'); // USER_DOESNT_ALLOW_RELAYER - Relayers must be allowed by both governance and the user account -// }); -// }); -// }); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts deleted file mode 100644 index 4a81f9edd..000000000 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts +++ /dev/null @@ -1,305 +0,0 @@ -import { StablePoolEncoder } from '@/pool-stable/encoder'; -import { ADDRESSES } from './addresses'; -import { Relayer } from '@/modules/relayer/relayer.module'; -import { ExitPoolRequest } from '@/types'; -import { BatchSwapStep, FundManagement, SwapType } from '@/modules/swaps/types'; -import { Interface } from '@ethersproject/abi'; -import { BigNumber } from '@ethersproject/bignumber'; -import { MaxInt256 } from '@ethersproject/constants'; -import { BalancerError, BalancerErrorCode } from '@/balancerErrors'; -// TODO - Ask Nico to update Typechain? -import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; -const balancerRelayerInterface = new Interface(balancerRelayerAbi); - -const EXIT_MIMATIC = Relayer.toChainedReference('20'); -const EXIT_DAI = Relayer.toChainedReference('21'); -const EXIT_USDC = Relayer.toChainedReference('22'); -const EXIT_USDT = Relayer.toChainedReference('23'); -const SWAP_RESULT = Relayer.toChainedReference('24'); - -export class MaiusdBuilder { - private addresses; - - constructor(networkId: 1 | 5 | 137) { - this.addresses = ADDRESSES[networkId]; - } - - /** - * Builds migration call data. - * Migrates tokens from maiusd to maibbausd pool. - * Tokens that are initially staked are re-staked at the end of migration. Non-staked are not. - * - * @param userAddress User address. - * @param bptIn Amount of BPT tokens to migrate. - * @param minBptOut Minimum of expected BPT out ot the migration flow. - * @param staked Indicates whether tokens are initially staked or not. - * @param authorisation Encoded authorisation call. - * @returns Migration transaction request ready to send with signer.sendTransaction - */ - calldata( - userAddress: string, - bptIn: string, - minBptOut: string, - staked: boolean, - authorisation?: string - ): { - to: string; - data: string; - } { - if (BigNumber.from(bptIn).lte(0)) - throw new BalancerError(BalancerErrorCode.INPUT_ZERO_NOT_ALLOWED); - - const relayer = this.addresses.relayer; - let calls: string[] = []; - - if (authorisation) { - calls = [this.buildSetRelayerApproval(authorisation)]; - } - - if (staked) { - calls = [ - ...calls, - this.buildWithdraw(userAddress, bptIn), - this.buildExit(relayer, bptIn), - this.buildSwap(relayer, minBptOut), - this.buildDeposit(userAddress), - ]; - } else { - calls = [ - ...calls, - this.buildExit(userAddress, bptIn), - this.buildSwap(userAddress, minBptOut), - ]; - } - - const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ - calls, - ]); - - return { - to: relayer, - data: callData, - }; - } - - /** - * Encodes exitPool callData. - * Exit maiusd pool proportionally to underlying stables. Exits to relayer. - * Outputreferences are used to store exit amounts for next transaction. - * - * @param sender Sender address. - * @param amount Amount of BPT to exit with. - * @returns Encoded exitPool call. Output references. - */ - buildExit(sender: string, amount: string): string { - const { assetOrder } = this.addresses.maiusd; - const assets = assetOrder.map( - (key) => this.addresses[key as keyof typeof this.addresses] as string - ); - - // Assume gaugeWithdraw returns same amount value - const userData = StablePoolEncoder.exitExactBPTInForTokensOut(amount); - - // Store exit outputs to be used as swaps inputs - const outputReferences = [ - { index: assetOrder.indexOf('miMATIC'), key: EXIT_MIMATIC }, - { index: assetOrder.indexOf('DAI'), key: EXIT_DAI }, - { index: assetOrder.indexOf('USDC'), key: EXIT_USDC }, - { index: assetOrder.indexOf('USDT'), key: EXIT_USDT }, - ]; - - const minAmountsOut = Array(assets.length).fill('0'); - - const exitPoolInput = Relayer.formatExitPoolInput({ - assets, - minAmountsOut, - userData, - toInternalBalance: true, - poolId: this.addresses.maiusd.id, - poolKind: 0, // This will always be 0 to match supported Relayer types - sender, - recipient: this.addresses.relayer, - outputReferences, - exitPoolRequest: {} as ExitPoolRequest, - }); - const callData = Relayer.encodeExitPool(exitPoolInput); - - return callData; - } - - /** - * Creates encoded batchSwap function with following swaps: stables -> linear pools -> boosted pool - * outputreferences should contain the amount of resulting BPT. - * - * @param recipient Sender address. - * @param minBptOut Minimum BPT out expected from the join transaction. - * @returns Encoded batchSwap call. Output references. - */ - buildSwap(recipient: string, minBptOut: string): string { - const assets = [ - this.addresses.bbausd2.address, - this.addresses.DAI, - this.addresses.linearDai2.address, - this.addresses.USDC, - this.addresses.linearUsdc2.address, - this.addresses.USDT, - this.addresses.linearUsdt2.address, - this.addresses.miMATIC, - this.addresses.maibbausd.address, - ]; - - const outputReferences = [{ index: 8, key: SWAP_RESULT }]; - - const swaps: BatchSwapStep[] = [ - { - poolId: this.addresses.linearDai2.id, - assetInIndex: 1, - assetOutIndex: 2, - amount: EXIT_DAI.toString(), - userData: '0x', - }, - { - poolId: this.addresses.bbausd2.id, - assetInIndex: 2, - assetOutIndex: 0, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.maibbausd.id, - assetInIndex: 0, - assetOutIndex: 8, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.linearUsdc2.id, - assetInIndex: 3, - assetOutIndex: 4, - amount: EXIT_USDC.toString(), - userData: '0x', - }, - { - poolId: this.addresses.bbausd2.id, - assetInIndex: 4, - assetOutIndex: 0, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.maibbausd.id, - assetInIndex: 0, - assetOutIndex: 8, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.linearUsdt2.id, - assetInIndex: 5, - assetOutIndex: 6, - amount: EXIT_USDT.toString(), - userData: '0x', - }, - { - poolId: this.addresses.bbausd2.id, - assetInIndex: 6, - assetOutIndex: 0, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.maibbausd.id, - assetInIndex: 0, - assetOutIndex: 8, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.maibbausd.id, - assetInIndex: 7, - assetOutIndex: 8, - amount: EXIT_MIMATIC.toString(), - userData: '0x', - }, - ]; - - // For tokens going in to the Vault, the limit shall be a positive number. For tokens going out of the Vault, the limit shall be a negative number. - const limits = [ - '0', - MaxInt256.toString(), - '0', - MaxInt256.toString(), - '0', - MaxInt256.toString(), - '0', - MaxInt256.toString(), - BigNumber.from(minBptOut).mul(-1).toString(), - ]; - - // Swap to/from Relayer - const funds: FundManagement = { - sender: this.addresses.relayer, - recipient, - fromInternalBalance: true, - toInternalBalance: false, - }; - - const encodedBatchSwap = Relayer.encodeBatchSwap({ - swapType: SwapType.SwapExactIn, - swaps, - assets, - funds, - limits, - deadline: BigNumber.from(Math.ceil(Date.now() / 1000) + 3600), // 1 hour from now - value: '0', - outputReferences, - }); - - return encodedBatchSwap; - } - - /** - * Uses relayer to withdraw staked BPT from gauge and send to relayer - * - * @param sender Sender address. - * @param amount Amount of BPT to exit with. - * @returns withdraw call - */ - buildWithdraw(sender: string, amount: string): string { - return Relayer.encodeGaugeWithdraw( - this.addresses.maiusd.gauge, - sender, - this.addresses.relayer, - amount - ); - } - - /** - * Uses relayer to deposit user's BPT to gauge and sends to recipient - * - * @param recipient Recipient address. - * @returns deposit call - */ - buildDeposit(recipient: string): string { - return Relayer.encodeGaugeDeposit( - this.addresses.maibbausd.gauge, - this.addresses.relayer, - recipient, - SWAP_RESULT.toString() - ); - } - - /** - * Uses relayer to approve itself to act in behalf of the user - * - * @param authorisation Encoded authorisation call. - * @returns relayer approval call - */ - buildSetRelayerApproval(authorisation: string): string { - return Relayer.encodeSetRelayerApproval( - this.addresses.relayer, - true, - authorisation - ); - } -} diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts deleted file mode 100644 index 51a79087b..000000000 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ /dev/null @@ -1,249 +0,0 @@ -import dotenv from 'dotenv'; -import { expect } from 'chai'; -import hardhat from 'hardhat'; -import { Network, RelayerAuthorization } from '@/.'; -import { BigNumber } from '@ethersproject/bignumber'; -import { Contracts } from '@/modules/contracts/contracts.module'; -import { ADDRESSES } from './addresses'; -import { JsonRpcSigner } from '@ethersproject/providers'; -import { MaxUint256 } from '@ethersproject/constants'; -import { Migrations } from '../migrations'; -import { getErc20Balance, move, stake } from '@/test/lib/utils'; -import { subSlippage } from '@/lib/utils/slippageHelper'; - -dotenv.config(); -const { ALCHEMY_URL: jsonRpcUrl } = process.env; - -// /* -// * Testing on GOERLI -// * - Update hardhat.config.js with chainId = 5 -// * - Update ALCHEMY_URL on .env with a goerli api key -// * - Run node on terminal: yarn run node -// * - Uncomment this section -// */ -// const network = Network.GOERLI; -// const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; // GOERLI -// const blockNumber = 7277540; - -/* - * Testing on MAINNET - * - Update hardhat.config.js with chainId = 1 - * - Update ALCHEMY_URL on .env with a mainnet api key - * - Run node on terminal: yarn run node - * - Uncomment this section - */ -const network = Network.MAINNET; -const holderAddress = '0xf346592803eb47cb8d8fa9f90b0ef17a82f877e0'; -const blockNumber = 15526452; - -const { ethers } = hardhat; -const MAX_GAS_LIMIT = 8e6; - -const rpcUrl = 'http://127.0.0.1:8545'; -const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); -const addresses = ADDRESSES[network]; -const fromPool = { - id: addresses.staBal3.id, - address: addresses.staBal3.address, - gauge: addresses.staBal3.gauge, -}; -const toPool = { - id: addresses.bbausd2.id, - address: addresses.bbausd2.address, - gauge: addresses.bbausd2.gauge, -}; -const { contracts } = new Contracts(network as number, provider); -const migrations = new Migrations(network); - -const relayer = addresses.relayer; - -const signRelayerApproval = async ( - relayerAddress: string, - signerAddress: string, - signer: JsonRpcSigner -): Promise => { - const approval = contracts.vault.interface.encodeFunctionData( - 'setRelayerApproval', - [signerAddress, relayerAddress, true] - ); - - const signature = - await RelayerAuthorization.signSetRelayerApprovalAuthorization( - contracts.vault, - signer, - relayerAddress, - approval - ); - - const calldata = RelayerAuthorization.encodeCalldataAuthorization( - '0x', - MaxUint256, - signature - ); - - return calldata; -}; - -const reset = () => - provider.send('hardhat_reset', [ - { - forking: { - jsonRpcUrl, - blockNumber, - }, - }, - ]); - -describe.skip('stabal3 migration execution', async () => { - let signer: JsonRpcSigner; - let signerAddress: string; - let authorisation: string; - let balance: BigNumber; - - beforeEach(async function () { - await reset(); - - signer = provider.getSigner(); - signerAddress = await signer.getAddress(); - authorisation = await signRelayerApproval(relayer, signerAddress, signer); - - // Transfer tokens from existing user account to signer - // We need that to test signatures, because hardhat doesn't have impersonated accounts private keys - balance = await move( - fromPool.address, - holderAddress, - signerAddress, - provider - ); - }); - - async function testFlow( - staked: boolean, - authorised = true, - minBptOut: undefined | string = undefined - ): Promise { - const addressIn = staked ? fromPool.gauge : fromPool.address; - const addressOut = staked ? toPool.gauge : toPool.address; - // Store balance before migration - const before = { - from: await getErc20Balance(addressIn, provider, signerAddress), - to: await getErc20Balance(addressOut, provider, signerAddress), - }; - - const amount = before.from; - - let query = migrations.stabal3( - signerAddress, - amount.toString(), - '0', - staked, - authorisation - ); - const gasLimit = MAX_GAS_LIMIT; - - // Static call can be used to simulate tx and get expected BPT in/out deltas - const staticResult = await signer.call({ - to: query.to, - data: query.data, - gasLimit, - }); - const expectedBptOut = query.decode(staticResult, staked); - const slippageAsBasisPoints = BigNumber.from('1'); // 0.01% - const expectedWithSlippage = subSlippage( - BigNumber.from(expectedBptOut), - slippageAsBasisPoints - ); - - query = migrations.stabal3( - signerAddress, - amount.toString(), - minBptOut ? minBptOut : expectedWithSlippage.toString(), - staked, - authorised ? authorisation : undefined - ); - - const response = await signer.sendTransaction({ - to: query.to, - data: query.data, - gasLimit, - }); - - const receipt = await response.wait(); - console.log('Gas used', receipt.gasUsed.toString()); - - const after = { - from: await getErc20Balance(addressIn, provider, signerAddress), - to: await getErc20Balance(addressOut, provider, signerAddress), - }; - - expect(BigNumber.from(expectedBptOut).gt(0)).to.be.true; - expect(after.from.toString()).to.eq('0'); - expect(after.to.gte(expectedWithSlippage)).to.be.true; - return expectedBptOut; - } - - let bptOut: string; - - context('staked', async () => { - beforeEach(async function () { - // Stake them - await stake(signer, fromPool.address, fromPool.gauge, balance); - }); - - it('should transfer tokens from stable to boosted', async () => { - bptOut = await testFlow(true); - }); - - it('should transfer tokens from stable to boosted - limit should fail', async () => { - let errorMessage = ''; - try { - await testFlow(true, true, BigNumber.from(bptOut).add(1).toString()); - } catch (error) { - errorMessage = (error as Error).message; - } - expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }); - }); - - context('not staked', async () => { - it('should transfer tokens from stable to boosted', async () => { - bptOut = await testFlow(false); - }); - - it('should transfer tokens from stable to boosted - limit should fail', async () => { - let errorMessage = ''; - try { - await testFlow(false, true, BigNumber.from(bptOut).add(1).toString()); - } catch (error) { - errorMessage = (error as Error).message; - } - expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }); - }); - - context('authorisation', async () => { - // authorisation wihtin relayer is the default case and is already tested on previous scenarios - - it('should transfer tokens from stable to boosted - pre authorised', async () => { - const approval = contracts.vault.interface.encodeFunctionData( - 'setRelayerApproval', - [signerAddress, relayer, true] - ); - await signer.sendTransaction({ - to: contracts.vault.address, - data: approval, - }); - await testFlow(false, false); - }); - - it('should transfer tokens from stable to boosted - auhtorisation should fail', async () => { - let errorMessage = ''; - try { - await testFlow(false, false); - } catch (error) { - errorMessage = (error as Error).message; - } - expect(errorMessage).to.contain('BAL#503'); // USER_DOESNT_ALLOW_RELAYER - Relayers must be allowed by both governance and the user account - }); - }); -}); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts deleted file mode 100644 index 65058a59c..000000000 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ /dev/null @@ -1,276 +0,0 @@ -import { StablePoolEncoder } from '@/pool-stable/encoder'; -import { ADDRESSES } from './addresses'; -import { Relayer } from '@/modules/relayer/relayer.module'; -import { ExitPoolRequest } from '@/types'; -import { BatchSwapStep, FundManagement, SwapType } from '@/modules/swaps/types'; -import { Interface } from '@ethersproject/abi'; -import { BigNumber } from '@ethersproject/bignumber'; -import { MaxInt256 } from '@ethersproject/constants'; -import { BalancerError, BalancerErrorCode } from '@/balancerErrors'; -// TODO - Ask Nico to update Typechain? -import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; -const balancerRelayerInterface = new Interface(balancerRelayerAbi); - -const EXIT_DAI = Relayer.toChainedReference('21'); -const EXIT_USDC = Relayer.toChainedReference('22'); -const EXIT_USDT = Relayer.toChainedReference('23'); -const SWAP_RESULT_BBAUSD = Relayer.toChainedReference('24'); - -export class StaBal3Builder { - private addresses; - - constructor(networkId: 1 | 5 | 137) { - this.addresses = ADDRESSES[networkId]; - } - - /** - * Builds migration call data. - * Migrates tokens from staBal3 to bbausd2 pool. - * Tokens that are initially staked are re-staked at the end of migration. Non-staked are not. - * - * @param userAddress User address. - * @param staBal3Amount Amount of BPT tokens to migrate. - * @param minBbausd2Out Minimum of expected BPT out ot the migration flow. - * @param staked Indicates whether tokens are initially staked or not. - * @param authorisation Encoded authorisation call. - * @returns Migration transaction request ready to send with signer.sendTransaction - */ - calldata( - userAddress: string, - staBal3Amount: string, - minBbausd2Out: string, - staked: boolean, - authorisation?: string - ): { - to: string; - data: string; - } { - if (BigNumber.from(staBal3Amount).lte(0)) - throw new BalancerError(BalancerErrorCode.INPUT_ZERO_NOT_ALLOWED); - const relayer = this.addresses.relayer; - let calls: string[] = []; - - if (authorisation) { - calls = [this.buildSetRelayerApproval(authorisation)]; - } - - if (staked) { - calls = [ - ...calls, - this.buildWithdraw(userAddress, staBal3Amount), - this.buildExit(relayer, staBal3Amount), - this.buildSwap(minBbausd2Out, relayer), - this.buildDeposit(userAddress), - ]; - } else { - calls = [ - ...calls, - this.buildExit(userAddress, staBal3Amount), - this.buildSwap(minBbausd2Out, userAddress), - ]; - } - - const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ - calls, - ]); - - return { - to: relayer, - data: callData, - }; - } - - /** - * Encodes exitPool callData. - * Exit staBal3 pool proportionally to underlying stables. Exits to relayer. - * Outputreferences are used to store exit amounts for next transaction. - * - * @param sender Sender address. - * @param amount Amount of staBal3 BPT to exit with. - * @returns Encoded exitPool call. Output references. - */ - buildExit(sender: string, amount: string): string { - // Goerli and Mainnet has different assets ordering - const { assetOrder } = this.addresses.staBal3; - const assets = assetOrder.map( - (key) => this.addresses[key as keyof typeof this.addresses] as string - ); - - // Assume gaugeWithdraw returns same amount value - const userData = StablePoolEncoder.exitExactBPTInForTokensOut(amount); - // const userData = StablePoolEncoder.exitExactBPTInForOneTokenOut( - // amount, - // assetOrder.indexOf('DAI') - // ); - - // Ask to store exit outputs for batchSwap of exit is used as input to swaps - const outputReferences = [ - { index: assetOrder.indexOf('DAI'), key: EXIT_DAI }, - { index: assetOrder.indexOf('USDC'), key: EXIT_USDC }, - { index: assetOrder.indexOf('USDT'), key: EXIT_USDT }, - ]; - - const exitPoolInput = Relayer.formatExitPoolInput({ - assets, - minAmountsOut: ['0', '0', '0'], - userData, - toInternalBalance: true, - poolId: this.addresses.staBal3.id, - poolKind: 0, // This will always be 0 to match supported Relayer types - sender, - recipient: this.addresses.relayer, - outputReferences, - exitPoolRequest: {} as ExitPoolRequest, - }); - const callData = Relayer.encodeExitPool(exitPoolInput); - - return callData; - } - - /** - * Creates encoded batchSwap function with following swaps: stables -> linear pools -> boosted pool - * outputreferences should contain the amount of resulting BPT. - * - * @param expectedBptReturn BPT amount expected out of the swap. - * @param recipient Recipient address. - * @returns Encoded batchSwap call. Output references. - */ - buildSwap(expectedBptReturn: string, recipient: string): string { - const assets = [ - this.addresses.bbausd2.address, - this.addresses.DAI, - this.addresses.linearDai2.address, - this.addresses.USDC, - this.addresses.linearUsdc2.address, - this.addresses.USDT, - this.addresses.linearUsdt2.address, - ]; - - const outputReferences = [{ index: 0, key: SWAP_RESULT_BBAUSD }]; - - // for each linear pool swap - - // linear1Bpt[linear1]stable[linear2]linear2bpt[bbausd2]bbausd2 Uses chainedReference from previous action for amount. - // TO DO - Will swap order matter here? John to ask Fernando. - const swaps: BatchSwapStep[] = [ - { - poolId: this.addresses.linearDai2.id, - assetInIndex: 1, - assetOutIndex: 2, - amount: EXIT_DAI.toString(), - userData: '0x', - }, - { - poolId: this.addresses.bbausd2.id, - assetInIndex: 2, - assetOutIndex: 0, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.linearUsdc2.id, - assetInIndex: 3, - assetOutIndex: 4, - amount: EXIT_USDC.toString(), - userData: '0x', - }, - { - poolId: this.addresses.bbausd2.id, - assetInIndex: 4, - assetOutIndex: 0, - amount: '0', - userData: '0x', - }, - { - poolId: this.addresses.linearUsdt2.id, - assetInIndex: 5, - assetOutIndex: 6, - amount: EXIT_USDT.toString(), - userData: '0x', - }, - { - poolId: this.addresses.bbausd2.id, - assetInIndex: 6, - assetOutIndex: 0, - amount: '0', - userData: '0x', - }, - ]; - - // For tokens going in to the Vault, the limit shall be a positive number. For tokens going out of the Vault, the limit shall be a negative number. - const limits = [ - BigNumber.from(expectedBptReturn).mul(-1).toString(), - MaxInt256.toString(), - '0', - MaxInt256.toString(), - '0', - MaxInt256.toString(), - '0', - ]; - - // Swap to/from Relayer - const funds: FundManagement = { - sender: this.addresses.relayer, - recipient, - fromInternalBalance: true, - toInternalBalance: false, - }; - - const encodedBatchSwap = Relayer.encodeBatchSwap({ - swapType: SwapType.SwapExactIn, - swaps, - assets, - funds, - limits, - deadline: BigNumber.from(Math.ceil(Date.now() / 1000) + 3600), // 1 hour from now - value: '0', - outputReferences, - }); - - return encodedBatchSwap; - } - - /** - * Uses relayer to withdraw staked BPT from gauge and send to relayer - * - * @param sender Sender address. - * @param amount Amount of BPT to exit with. - * @returns withdraw call - */ - buildWithdraw(sender: string, amount: string): string { - return Relayer.encodeGaugeWithdraw( - this.addresses.staBal3.gauge, - sender, - this.addresses.relayer, - amount - ); - } - - /** - * Uses relayer to deposit user's BPT to gauge and sends to recipient - * - * @param recipient Recipient address. - * @returns deposit call - */ - buildDeposit(recipient: string): string { - return Relayer.encodeGaugeDeposit( - this.addresses.bbausd2.gauge, - this.addresses.relayer, - recipient, - SWAP_RESULT_BBAUSD.toString() - ); - } - - /** - * Uses relayer to approve itself to act in behalf of the user - * - * @param authorisation Encoded authorisation call. - * @returns relayer approval call - */ - buildSetRelayerApproval(authorisation: string): string { - return Relayer.encodeSetRelayerApproval( - this.addresses.relayer, - true, - authorisation - ); - } -} diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts deleted file mode 100644 index 5b8430ba4..000000000 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ /dev/null @@ -1,302 +0,0 @@ -import dotenv from 'dotenv'; -import { expect } from 'chai'; -import hardhat from 'hardhat'; -import { Network, RelayerAuthorization } from '@/.'; -import { BigNumber } from '@ethersproject/bignumber'; -import { Contracts } from '@/modules/contracts/contracts.module'; -import { ADDRESSES } from './addresses'; -import { JsonRpcSigner } from '@ethersproject/providers'; -import { MaxUint256 } from '@ethersproject/constants'; -import { Migrations } from '../migrations'; -import { getErc20Balance, move, stake } from '@/test/lib/utils'; - -dotenv.config(); - -/* - * Testing on GOERLI - * - Run node on terminal: yarn run node:goerli - * - Uncomment section below - */ -const network = Network.GOERLI; -const addresses = ADDRESSES[network]; -const blockNumber = 7300090; -const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; -const { ALCHEMY_URL_GOERLI: jsonRpcUrl } = process.env; -const rpcUrl = 'http://127.0.0.1:8000'; -// stabal3 -const fromPool = { - id: addresses.staBal3.id, - address: addresses.staBal3.address, - gauge: addresses.staBal3.gauge, -}; -// new stabal3 -const toPool = { - id: addresses.staBal3_2.id, - address: addresses.staBal3_2.address, - gauge: addresses.staBal3_2.gauge, -}; -const tokens = [addresses.USDT, addresses.DAI, addresses.USDC]; // this order only works for testing with Goerli - change order to test on Mainnet - -/* - * Testing on POLYGON - * - Run node on terminal: yarn run node - * - Uncomment section below - */ -// const network = Network.POLYGON; -// const addresses = ADDRESSES[network]; -// const blockNumber = 32856000; -// const holderAddress = '0x8df33a75e5cc9d71db97fb1248cc8bdac316fe09'; -// // MaticX -// const fromPool = { -// id: '0xc17636e36398602dd37bb5d1b3a9008c7629005f0002000000000000000004c4', -// address: '0xc17636e36398602dd37bb5d1b3a9008c7629005f', -// gauge: '0x48534d027f8962692122db440714ffe88ab1fa85', -// }; -// // new MaticX -// const toPool = { -// id: '0xb20fc01d21a50d2c734c4a1262b4404d41fa7bf000000000000000000000075c', -// address: '0xb20fc01d21a50d2c734c4a1262b4404d41fa7bf0', -// gauge: '0xdffe97094394680362ec9706a759eb9366d804c2', -// }; -// const tokens = [ -// '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', // wMATIC -// '0xfa68FB4628DFF1028CFEc22b4162FCcd0d45efb6', // MaticX -// ]; -// const holderAddress = '0x70d04384b5c3a466ec4d8cfb8213efc31c6a9d15'; -// // stMATIC -// const fromPool = { -// id: '0xaf5e0b5425de1f5a630a8cb5aa9d97b8141c908d000200000000000000000366', -// address: '0xaf5e0b5425de1f5a630a8cb5aa9d97b8141c908d', -// gauge: '0x9928340f9e1aaad7df1d95e27bd9a5c715202a56', -// }; -// // new stMATIC -// const toPool = { -// id: '0x8159462d255c1d24915cb51ec361f700174cd99400000000000000000000075d', -// address: '0x8159462d255c1d24915cb51ec361f700174cd994', -// gauge: '0x2aa6fb79efe19a3fce71c46ae48efc16372ed6dd', -// }; -// const tokens = [ -// '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', // wMATIC -// '0x3a58a54c066fdc0f2d55fc9c89f0415c92ebf3c4', // stMATIC -// ]; -// const { ALCHEMY_URL: jsonRpcUrl } = process.env; -// const rpcUrl = 'http://127.0.0.1:8545'; - -const { ethers } = hardhat; -const MAX_GAS_LIMIT = 8e6; - -const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); -const relayer = addresses.relayer; -const { contracts } = new Contracts(network as number, provider); -const migrations = new Migrations(network); - -const signRelayerApproval = async ( - relayerAddress: string, - signerAddress: string, - signer: JsonRpcSigner -): Promise => { - const approval = contracts.vault.interface.encodeFunctionData( - 'setRelayerApproval', - [signerAddress, relayerAddress, true] - ); - - const signature = - await RelayerAuthorization.signSetRelayerApprovalAuthorization( - contracts.vault, - signer, - relayerAddress, - approval - ); - - const calldata = RelayerAuthorization.encodeCalldataAuthorization( - '0x', - MaxUint256, - signature - ); - - return calldata; -}; - -const reset = () => - provider.send('hardhat_reset', [ - { - forking: { - jsonRpcUrl, - blockNumber, - }, - }, - ]); - -describe.skip('stables migration execution', async () => { - let signer: JsonRpcSigner; - let signerAddress: string; - let authorisation: string; - let balance: BigNumber; - - before(async function () { - try { - const currentNetwork = await provider.getNetwork(); - if (currentNetwork.chainId != network) { - this.skip(); - } - } catch (err) { - console.log(err); - this.skip(); - } - }); - - beforeEach(async function () { - await reset(); - - signer = provider.getSigner(); - signerAddress = await signer.getAddress(); - authorisation = await signRelayerApproval(relayer, signerAddress, signer); - - // Transfer tokens from existing user account to signer - // We need that to test signatures, because hardhat doesn't have impersonated accounts private keys - balance = await move( - fromPool.address, - holderAddress, - signerAddress, - provider - ); - }); - - const testFlow = async ( - staked: boolean, - authorised = true, - minBptOut: undefined | string = undefined - ) => { - const addressIn = staked ? fromPool.gauge : fromPool.address; - const addressOut = staked ? toPool.gauge : toPool.address; - // Store balance before migration - const before = { - from: await getErc20Balance(addressIn, provider, signerAddress), - to: await getErc20Balance(addressOut, provider, signerAddress), - }; - - let query = migrations.stables( - signerAddress, - fromPool, - toPool, - before.from.toString(), - '0', - staked, - tokens, - authorisation - ); - - const gasLimit = MAX_GAS_LIMIT; - - // Static call can be used to simulate tx and get expected BPT in/out deltas - const staticResult = await signer.call({ - to: query.to, - data: query.data, - gasLimit, - }); - const bptOut = query.decode(staticResult, staked); - - query = migrations.stables( - signerAddress, - fromPool, - toPool, - before.from.toString(), - minBptOut ? minBptOut : bptOut, - staked, - tokens, - authorised ? authorisation : undefined - ); - - const response = await signer.sendTransaction({ - to: query.to, - data: query.data, - gasLimit, - }); - - const receipt = await response.wait(); - console.log('Gas used', receipt.gasUsed.toString()); - - const after = { - from: await getErc20Balance(addressIn, provider, signerAddress), - to: await getErc20Balance(addressOut, provider, signerAddress), - }; - - const diffs = { - from: after.from.sub(before.from), - to: after.to.sub(before.to), - }; - - console.log(diffs.from, diffs.to); - - expect(BigNumber.from(bptOut).gt(0)).to.be.true; - expect(after.from.toString()).to.eq('0'); - expect(after.to.toString()).to.eq(bptOut); - return bptOut; - }; - - let bptOut: string; - - context('staked', async () => { - beforeEach(async function () { - // Stake them - await stake(signer, fromPool.address, fromPool.gauge, balance); - }); - - it('should transfer tokens from stable to boosted', async () => { - bptOut = await testFlow(true); - }); - - it('should transfer tokens from stable to boosted - limit should fail', async () => { - let errorMessage = ''; - try { - await testFlow(true, true, BigNumber.from(bptOut).add(1).toString()); - } catch (error) { - errorMessage = (error as Error).message; - } - expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }); - }); - - context('not staked', async () => { - it('should transfer tokens from stable to boosted', async () => { - // Store balance before migration - bptOut = await testFlow(false); - }); - - it('should transfer tokens from stable to boosted - limit should fail', async () => { - let errorMessage = ''; - try { - await testFlow(false, true, BigNumber.from(bptOut).add(1).toString()); - } catch (error) { - errorMessage = (error as Error).message; - } - expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }); - }); - - context('authorisation', async () => { - // authorisation wihtin relayer is the default case and is already tested on previous scenarios - - it('should transfer tokens from stable to boosted - pre authorised', async () => { - const approval = contracts.vault.interface.encodeFunctionData( - 'setRelayerApproval', - [signerAddress, relayer, true] - ); - await signer.sendTransaction({ - to: contracts.vault.address, - data: approval, - }); - await testFlow(false, false); - }); - - it('should transfer tokens from stable to boosted - auhtorisation should fail', async () => { - let errorMessage = ''; - try { - await testFlow(false, false); - } catch (error) { - errorMessage = (error as Error).message; - } - expect(errorMessage).to.contain('BAL#503'); // USER_DOESNT_ALLOW_RELAYER - Relayers must be allowed by both governance and the user account - }); - }); -}); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts deleted file mode 100644 index abae189b8..000000000 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ /dev/null @@ -1,252 +0,0 @@ -import { StablePoolEncoder } from '@/pool-stable/encoder'; -import { ADDRESSES } from './addresses'; -import { Relayer } from '@/modules/relayer/relayer.module'; -import { ExitPoolRequest } from '@/types'; -import { BatchSwapStep, FundManagement, SwapType } from '@/modules/swaps/types'; -import { Interface } from '@ethersproject/abi'; -import { BigNumber } from '@ethersproject/bignumber'; -import { MaxInt256 } from '@ethersproject/constants'; -// TODO - Ask Nico to update Typechain? -import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; -const balancerRelayerInterface = new Interface(balancerRelayerAbi); - -const SWAP_RESULT = Relayer.toChainedReference('0'); -const EXIT_RESULTS: BigNumber[] = []; - -export class StablesBuilder { - private addresses; - - constructor(networkId: 1 | 5 | 137) { - this.addresses = ADDRESSES[networkId]; - } - - /** - * Builds migration call data. - * Migrates tokens from old stable to new stable phantom pools with the same underlying tokens. - * Tokens that are initially staked are re-staked at the end of migration. Non-staked are not. - * - * @param userAddress User address. - * @param from Pool info being migrated from - * @param to Pool info being migrated to - * @param bptIn Amount of BPT tokens to migrate. - * @param minBptOut Minimum of expected BPT out ot the migration flow. - * @param staked Indicates whether tokens are initially staked or not. - * @param underlyingTokens Underlying token addresses. Array must have the same length and order as underlying tokens in pool being migrated from. Refer to [getPoolTokens](https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/interfaces/contracts/vault/IVault.sol#L334). - * @param authorisation Encoded authorisation call. - * @returns Migration transaction request ready to send with signer.sendTransaction - */ - calldata( - userAddress: string, - from: { id: string; address: string; gauge?: string }, - to: { id: string; address: string; gauge?: string }, - bptIn: string, - minBptOut: string, - staked: boolean, - underlyingTokens: string[], - authorisation?: string - ): { - to: string; - data: string; - } { - if (staked && (from.gauge == undefined || to.gauge == undefined)) - throw new Error( - 'Staked flow migration requires gauge addresses to be provided' - ); - - const relayer = this.addresses.relayer; - let calls: string[] = []; - - if (authorisation) { - calls = [this.buildSetRelayerApproval(authorisation)]; - } - - if (staked) { - calls = [ - ...calls, - this.buildWithdraw(userAddress, bptIn, from.gauge as string), - this.buildExit(from.id, relayer, bptIn, underlyingTokens), - this.buildSwap(minBptOut, relayer, to.id, to.address, underlyingTokens), - this.buildDeposit(userAddress, to.gauge as string), - ]; - } else { - calls = [ - ...calls, - this.buildExit(from.id, userAddress, bptIn, underlyingTokens), - this.buildSwap( - minBptOut, - userAddress, - to.id, - to.address, - underlyingTokens - ), - ]; - } - - const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ - calls, - ]); - - return { - to: this.addresses.relayer, - data: callData, - }; - } - - /** - * Encodes exitPool call data. - * Exit stable pool proportionally to underlying stables. Exits to relayer. - * Outputreferences are used to store exit amounts for next transaction. - * - * @param poolId Pool id. - * @param sender Sender address. - * @param amount Amount of BPT to exit with. - * @param underlyingTokens Token addresses to exit to. - * @returns Encoded exitPool call. Output references. - */ - buildExit( - poolId: string, - sender: string, - amount: string, - underlyingTokens: string[] - ): string { - // Assume gaugeWithdraw returns same amount value - const userData = StablePoolEncoder.exitExactBPTInForTokensOut(amount); - - // Store exit outputs to be used as swaps inputs - const outputReferences = []; - for (let i = 0; i < underlyingTokens.length; i++) { - outputReferences[i] = { - index: i, - key: Relayer.toChainedReference(`${i + 1}`), // index 0 will be used by swap result - }; - EXIT_RESULTS.push(outputReferences[i].key); - } - - const minAmountsOut = Array(underlyingTokens.length).fill('0'); - - const exitPoolInput = Relayer.formatExitPoolInput({ - assets: underlyingTokens, - minAmountsOut, - userData, - toInternalBalance: true, - poolId, - poolKind: 0, // This will always be 0 to match supported Relayer types - sender, - recipient: this.addresses.relayer, - outputReferences, - exitPoolRequest: {} as ExitPoolRequest, - }); - const callData = Relayer.encodeExitPool(exitPoolInput); - - return callData; - } - - /** - * Creates encoded batchSwap function to swap stables to new phantom stable pool BPT. - * outputreferences should contain the amount of resulting BPT. - * - * @param expectedBptReturn BPT amount expected out of the swap. - * @param recipient Recipient address. - * @param poolId Pool id - * @param poolAddress Pool address - * @param tokens Token addresses to swap from. - * @returns BatchSwap call. - */ - buildSwap( - expectedBptReturn: string, - recipient: string, - poolId: string, - poolAddress: string, - tokens: string[] - ): string { - const assets = [poolAddress, ...tokens]; - - const outputReferences = [{ index: 0, key: SWAP_RESULT }]; - - const swaps: BatchSwapStep[] = []; - // Add a swap flow for each token provided - for (let i = 0; i < tokens.length; i++) { - swaps.push({ - poolId, - assetInIndex: i + 1, - assetOutIndex: 0, - amount: EXIT_RESULTS[i].toString(), - userData: '0x', - }); - } - - // For tokens going in to the Vault, the limit shall be a positive number. For tokens going out of the Vault, the limit shall be a negative number. - const limits = [BigNumber.from(expectedBptReturn).mul(-1).toString()]; - for (let i = 0; i < tokens.length; i++) { - limits.push(MaxInt256.toString()); - } - - // Swap to/from Relayer - const funds: FundManagement = { - sender: this.addresses.relayer, - recipient, - fromInternalBalance: true, - toInternalBalance: false, - }; - - const encodedBatchSwap = Relayer.encodeBatchSwap({ - swapType: SwapType.SwapExactIn, - swaps, - assets, - funds, - limits, - deadline: BigNumber.from(Math.ceil(Date.now() / 1000) + 3600), // 1 hour from now - value: '0', - outputReferences, - }); - - return encodedBatchSwap; - } - - /** - * Uses relayer to withdraw staked BPT from gauge and send to relayer - * - * @param sender Sender address. - * @param amount Amount of BPT to exit with. - * @param gaugeAddress Gauge address. - * @returns withdraw call - */ - buildWithdraw(sender: string, amount: string, gaugeAddress: string): string { - return Relayer.encodeGaugeWithdraw( - gaugeAddress, - sender, - this.addresses.relayer, - amount - ); - } - - /** - * Uses relayer to deposit user's BPT to gauge and sends to recipient - * - * @param recipient Recipient address. - * @param gaugeAddress Gauge address. - * @returns deposit call - */ - buildDeposit(recipient: string, gaugeAddress: string): string { - return Relayer.encodeGaugeDeposit( - gaugeAddress, - this.addresses.relayer, - recipient, - SWAP_RESULT.toString() - ); - } - - /** - * Uses relayer to approve itself to act in behalf of the user - * - * @param authorisation Encoded authorisation call. - * @returns relayer approval call - */ - buildSetRelayerApproval(authorisation: string): string { - return Relayer.encodeSetRelayerApproval( - this.addresses.relayer, - true, - authorisation - ); - } -} diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts deleted file mode 100644 index 29dfb9816..000000000 --- a/balancer-js/src/modules/zaps/migrations.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { defaultAbiCoder } from '@ethersproject/abi'; -import { StaBal3Builder } from './bbausd2-migrations/stabal3'; -import { BbaUsd1Builder } from './bbausd2-migrations/bbausd1'; -import { StablesBuilder } from './bbausd2-migrations/stables'; -import { MaiusdBuilder } from './bbausd2-migrations/maiusd'; - -export class Migrations { - constructor(private network: 1 | 5 | 137) {} - - /** - * Builds migration call data. - * Migrates tokens from staBal3 to bbausd2 pool. - * Tokens that are initially staked are re-staked at the end of migration. Non-staked are not. - * - * @param userAddress User address. - * @param staBal3Amount Amount of BPT tokens to migrate. - * @param minBbausd2Out Minimum of expected BPT out ot the migration flow. - * @param staked Indicates whether tokens are initially staked or not. - * @param authorisation Encoded authorisation call. - * @returns Migration transaction request ready to send with signer.sendTransaction - */ - stabal3( - userAddress: string, - staBal3Amount: string, - minBbausd2Out: string, - staked: boolean, - authorisation?: string - ): { - to: string; - data: string; - decode: (output: string, staked: boolean) => string; - } { - const builder = new StaBal3Builder(this.network); - const request = builder.calldata( - userAddress, - staBal3Amount, - minBbausd2Out, - staked, - authorisation - ); - - return { - to: request.to, - data: request.data, - decode: (output, staked) => { - let swapIndex = staked ? 2 : 1; - if (authorisation) swapIndex += 1; - const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); - const swapDeltas = defaultAbiCoder.decode( - ['int256[]'], - multicallResult[0][swapIndex] - ); - // bbausd2AmountOut - return swapDeltas[0][0].abs().toString(); - }, - }; - } - - /** - * Builds migration call data. - * Migrates tokens from bbausd1 to bbausd2 pool. - * Tokens that are initially staked are re-staked at the end of migration. Non-staked are not. - * - * @param userAddress User address. - * @param bbausd1Amount Amount of BPT tokens to migrate. - * @param minBbausd2Out Minimum of expected BPT out ot the migration flow. - * @param staked Indicates whether tokens are initially staked or not. - * @param tokenBalances Token balances in EVM scale. Array must have the same length and order as tokens in pool being migrated from. Refer to [getPoolTokens](https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/interfaces/contracts/vault/IVault.sol#L334). - * @param authorisation Encoded authorisation call. - * @returns Migration transaction request ready to send with signer.sendTransaction - */ - bbaUsd( - userAddress: string, - bbausd1Amount: string, - minBbausd2Out: string, - staked: boolean, - tokenBalances: string[], - authorisation?: string - ): { - to: string; - data: string; - decode: (output: string, staked: boolean) => string; - } { - const builder = new BbaUsd1Builder(this.network); - const request = builder.calldata( - userAddress, - bbausd1Amount, - minBbausd2Out, - staked, - tokenBalances, - authorisation - ); - - return { - to: request.to, - data: request.data, - decode: (output, staked) => { - let swapIndex = staked ? 1 : 0; - if (authorisation) swapIndex += 1; - const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); - const swapDeltas = defaultAbiCoder.decode( - ['int256[]'], - multicallResult[0][swapIndex] - ); - return swapDeltas[0][0].abs().toString(); // bptOut - }, - }; - } - - /** - * Builds migration call data. - * Migrates tokens from old stable to new stable phantom pools with the same underlying tokens. - * Tokens that are initially staked are re-staked at the end of migration. Non-staked are not. - * - * @param userAddress User address. - * @param from Pool info being migrated from - * @param to Pool info being migrated to - * @param bptIn Amount of BPT tokens to migrate. - * @param minBptOut Minimum of expected BPT out ot the migration flow. - * @param staked Indicates whether tokens are initially staked or not. - * @param underlyingTokens Underlying token addresses. Array must have the same length and order as tokens in pool being migrated from. Refer to [getPoolTokens](https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/interfaces/contracts/vault/IVault.sol#L334). - * @param authorisation Encoded authorisation call. - * @returns Migration transaction request ready to send with signer.sendTransaction - */ - stables( - userAddress: string, - from: { id: string; address: string; gauge?: string }, - to: { id: string; address: string; gauge?: string }, - bptIn: string, - minBptOut: string, - staked: boolean, - underlyingTokens: string[], - authorisation?: string - ): { - to: string; - data: string; - decode: (output: string, staked: boolean) => string; - } { - const builder = new StablesBuilder(this.network); - const request = builder.calldata( - userAddress, - from, - to, - bptIn, - minBptOut, - staked, - underlyingTokens, - authorisation - ); - - return { - to: request.to, - data: request.data, - decode: (output, staked) => { - let swapIndex = staked ? 2 : 1; - if (authorisation) swapIndex += 1; - const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); - const swapDeltas = defaultAbiCoder.decode( - ['int256[]'], - multicallResult[0][swapIndex] - ); - // bbausd2AmountOut - return swapDeltas[0][0].abs().toString(); - }, - }; - } - - /** - * Builds migration call data. - * Migrates tokens from staBal3 to bbausd2 pool. - * Tokens that are initially staked are re-staked at the end of migration. Non-staked are not. - * - * @param userAddress User address. - * @param bptIn Amount of BPT tokens to migrate. - * @param minBptOut Minimum of expected BPT out ot the migration flow. - * @param staked Indicates whether tokens are initially staked or not. - * @param authorisation Encoded authorisation call. - * @returns Migration transaction request ready to send with signer.sendTransaction - */ - maiusd( - userAddress: string, - bptIn: string, - minBptOut: string, - staked: boolean, - authorisation?: string - ): { - to: string; - data: string; - decode: (output: string, staked: boolean) => string; - } { - const builder = new MaiusdBuilder(this.network); - const request = builder.calldata( - userAddress, - bptIn, - minBptOut, - staked, - authorisation - ); - - return { - to: request.to, - data: request.data, - decode: (output, staked) => { - let swapIndex = staked ? 2 : 1; - if (authorisation) swapIndex += 1; - const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); - const swapDeltas = defaultAbiCoder.decode( - ['int256[]'], - multicallResult[0][swapIndex] - ); - const bptOut = swapDeltas[0][8].abs().toString(); - return bptOut; - }, - }; - } -} diff --git a/balancer-js/src/modules/zaps/zaps.module.spec.ts b/balancer-js/src/modules/zaps/zaps.module.spec.ts deleted file mode 100644 index cdfbb1d14..000000000 --- a/balancer-js/src/modules/zaps/zaps.module.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { expect } from 'chai'; -import { Network, BalancerSDK } from '@/.'; -import { Zaps } from './zaps.module'; - -const sdkConfig = { - network: Network.MAINNET, - rpcUrl: '', -}; - -describe('zaps module', () => { - context('instantiation', () => { - it('instantiate via module', async () => { - const zaps = new Zaps(Network.MAINNET); - expect(zaps.network).to.deep.eq(Network.MAINNET); - }); - - it('instantiate via SDK', async () => { - const balancer = new BalancerSDK(sdkConfig); - expect(balancer.zaps.network).to.deep.eq(Network.MAINNET); - }); - }); -}); diff --git a/balancer-js/src/modules/zaps/zaps.module.ts b/balancer-js/src/modules/zaps/zaps.module.ts deleted file mode 100644 index 66a603d22..000000000 --- a/balancer-js/src/modules/zaps/zaps.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Network } from '@/lib/constants/network'; -import { Migrations } from './migrations'; - -export class Zaps { - public migrations: Migrations; - - constructor(public network: Network) { - this.migrations = new Migrations(network as 1 | 5); - } -} diff --git a/balancer-js/src/pool-stable/decoder.ts b/balancer-js/src/pool-stable/decoder.ts index 137ce797a..addc19ba1 100644 --- a/balancer-js/src/pool-stable/decoder.ts +++ b/balancer-js/src/pool-stable/decoder.ts @@ -1,6 +1,6 @@ import { defaultAbiCoder, Result } from '@ethersproject/abi'; -export class StablePoolEncoder { +export class StablePoolDecoder { /** * Cannot be constructed. */ diff --git a/balancer-js/src/test/lib/constants.ts b/balancer-js/src/test/lib/constants.ts index 10bf1d0e2..4d9ed1320 100644 --- a/balancer-js/src/test/lib/constants.ts +++ b/balancer-js/src/test/lib/constants.ts @@ -24,12 +24,6 @@ export const ADDRESSES = { decimals: 18, slot: 3, }, - BatchRelayer: { - address: '0xdcdbf71A870cc60C6F9B621E28a7D3Ffd6Dd4965', - }, - BatchRelayerV4: { - address: '0x2536dfeeCB7A0397CF98eDaDA8486254533b1aFA', - }, ETH: { address: AddressZero, decimals: 18, @@ -115,6 +109,13 @@ export const ADDRESSES = { symbol: 'bbausd2', slot: 0, }, + bbausd3: { + id: '0xfebb0bbf162e64fb9d0dfe186e517d84c395f016000000000000000000000502', + address: '0xfebb0bbf162e64fb9d0dfe186e517d84c395f016', + decimals: 18, + symbol: 'bbausd3', + slot: 0, + }, bbausdcOld: { address: '0x9210F1204b5a24742Eba12f710636D76240dF3d0', decimals: 18, @@ -174,6 +175,23 @@ export const ADDRESSES = { symbol: 'bbadai', slot: 0, }, + bbausdc3: { + address: '0xcbfa4532d8b2ade2c261d3dd5ef2a2284f792692'.toLowerCase(), + decimals: 18, + symbol: 'bbausdc', + slot: 0, + }, + bbausdt3: { + address: '0xa1697f9af0875b63ddc472d6eebada8c1fab8568'.toLowerCase(), + decimals: 18, + symbol: 'bbausdt', + }, + bbadai3: { + address: '0x6667c6fa9f2b3fc1cc8d85320b62703d938e4385'.toLowerCase(), + decimals: 18, + symbol: 'bbadai', + slot: 0, + }, wstETH_bbaUSD: { id: '0x25accb7943fd73dda5e23ba6329085a3c24bfb6a000200000000000000000387', address: '0x25accb7943fd73dda5e23ba6329085a3c24bfb6a', @@ -181,6 +199,40 @@ export const ADDRESSES = { symbol: 'wstETH_bbaUSD', slot: 0, }, + wstETH_bbeUSD: { + id: '0x4fd4687ec38220f805b6363c3c1e52d0df3b5023000200000000000000000473', + address: '0x4fd4687ec38220f805b6363c3c1e52d0df3b5023', + decimals: 18, + symbol: '50wstETH-50bb-euler-USD', + slot: 0, + }, + bbeUSD: { + id: '0x50cf90b954958480b8df7958a9e965752f62712400000000000000000000046f', + address: '0x50cf90b954958480b8df7958a9e965752f627124', + decimals: 18, + symbol: 'bb-e-USD', + slot: 0, + }, + bbeUSDT: { + id: '0x3c640f0d3036ad85afa2d5a9e32be651657b874f00000000000000000000046b', + address: '0x3C640f0d3036Ad85Afa2D5A9E32bE651657B874F', + decimals: 18, + symbol: 'bb-e-USDT', + slot: 0, + }, + bbeUSDC: { + id: '0xd4e7c1f3da1144c9e2cfd1b015eda7652b4a439900000000000000000000046a', + address: '0xD4e7C1F3DA1144c9E2CfD1b015eDA7652b4a4399', + decimals: 18, + symbol: 'bb-e-USDC', + slot: 0, + }, + bbeDAI: { + id: '0xeb486af868aeb3b6e53066abc9623b1041b42bc000000000000000000000046c', + address: '0xeB486AF868AeB3b6e53066abc9623b1041b42bc0', + decimals: 18, + symbol: 'bb-e-DAI', + }, temple_bbeusd: { id: '0xa718042e5622099e5f0ace4e7122058ab39e1bbe000200000000000000000475', address: '0xa718042e5622099e5f0ace4e7122058ab39e1bbe', @@ -216,12 +268,64 @@ export const ADDRESSES = { symbol: 'bbedai', slot: 0, }, + wstETH_rETH_sfrxETH: { + id: '0x5aee1e99fe86960377de9f88689616916d5dcabe000000000000000000000467', + address: '0x5aee1e99fe86960377de9f88689616916d5dcabe', + decimals: 18, + symbol: 'wstETH-rETH-sfrxETH-BPT', + slot: 0, + }, + rETH: { + id: '', + address: '0xac3e018457b222d93114458476f3e3416abbe38f', + decimals: 18, + symbol: 'rETH', + slot: 0, + }, + sfrxETH: { + id: '', + address: '0xae78736cd615f374d3085123a210448e74fc6393', + decimals: 18, + symbol: 'sfrxETH', + slot: 0, + }, + bbgusd: { + id: '0x99c88ad7dc566616548adde8ed3effa730eb6c3400000000000000000000049a', + address: '0x99c88ad7dc566616548adde8ed3effa730eb6c34', + decimals: 18, + symbol: 'bb-g-USD', + slot: 0, + }, + bbgusdc: { + id: '0x4a82b580365cff9b146281ab72500957a849abdc000000000000000000000494', + address: '0x4a82b580365cff9b146281ab72500957a849abdc', + decimals: 18, + symbol: 'bb-g-USDC', + slot: 0, + }, + bbgdai: { + id: '0xe03af00fabe8401560c1ff7d242d622a5b601573000000000000000000000493', + address: '0xe03af00fabe8401560c1ff7d242d622a5b601573', + decimals: 18, + symbol: 'bb-g-DAI', + slot: 0, + }, + STG_BBAUSD: { + id: '0x639883476960a23b38579acfd7d71561a0f408cf000200000000000000000505', + address: '0x639883476960a23b38579acfd7d71561a0f408cf', + decimals: 18, + symbol: 'stg-bbausd', + slot: 0, + }, + STG: { + address: '0xAf5191B0De278C7286d6C7CC6ab6BB8A73bA2Cd6'.toLowerCase(), + decimals: 18, + symbol: 'STG', + slot: 0, + }, }, [Network.KOVAN]: { // Visit https://balancer-faucet.on.fleek.co/#/faucet for test tokens - BatchRelayer: { - address: '0x41B953164995c11C81DA73D212ED8Af25741b7Ac', - }, ETH: { address: AddressZero, decimals: 18, @@ -469,12 +573,12 @@ export const ADDRESSES = { symbol: 'USDT', }, STETH: { - address: 'N/A', + address: '', decimals: 18, symbol: 'STETH', }, bbausd: { - address: 'N/A', + address: '', decimals: 18, symbol: 'bbausd', }, @@ -496,6 +600,31 @@ export const ADDRESSES = { symbol: 'waUSDT', slot: 52, }, + bbrfusd: { + id: '0x077794c30afeccdf5ad2abc0588e8cee7197b71a000000000000000000000352', + address: '0x077794c30afeccdf5ad2abc0588e8cee7197b71a', + decimals: 18, + symbol: 'bb-rf-usd', + slot: 52, + }, + bbrfusdc: { + address: '0x5bae72b75caab1f260d21bc028c630140607d6e8', + decimals: 18, + symbol: 'bb-rf-usdc', + slot: 52, + }, + bbrfusdt: { + address: '0x894c82800526e0391e709c0983a5aea3718b7f6d', + decimals: 18, + symbol: 'bb-rf-usdt', + slot: 52, + }, + bbrfdai: { + address: '0xe1fb90d0d3b47e551d494d7ebe8f209753526b01', + decimals: 18, + symbol: 'bb-rf-dai', + slot: 52, + }, }, [Network.GNOSIS]: { WETH: { diff --git a/balancer-js/src/test/lib/exitHelper.ts b/balancer-js/src/test/lib/exitHelper.ts index b605de00d..6951a9311 100644 --- a/balancer-js/src/test/lib/exitHelper.ts +++ b/balancer-js/src/test/lib/exitHelper.ts @@ -4,23 +4,30 @@ import { BigNumber } from '@ethersproject/bignumber'; import { expect } from 'chai'; import { formatFixed } from '@ethersproject/bignumber'; import { addSlippage, subSlippage } from '@/lib/utils/slippageHelper'; -import { sendTransactionGetBalances } from '@/test/lib/utils'; +import { accuracy, sendTransactionGetBalances } from '@/test/lib/utils'; import { insert } from '@/lib/utils'; -import { formatEther } from '@ethersproject/units'; export const testExactBptIn = async ( pool: PoolWithMethods, signer: JsonRpcSigner, bptIn: string, - tokenOut?: string + tokenOut?: string, + toInternalBalance = false ): Promise => { const slippage = '20'; // 20 bps = 0.2% - this is a high slippage to differences between static call and actual transaction const signerAddress = await signer.getAddress(); const { to, data, minAmountsOut, expectedAmountsOut, priceImpact } = - pool.buildExitExactBPTIn(signerAddress, bptIn, slippage, false, tokenOut); + pool.buildExitExactBPTIn( + signerAddress, + bptIn, + slippage, + false, + tokenOut, + toInternalBalance + ); - const { transactionReceipt, balanceDeltas } = + const { transactionReceipt, balanceDeltas, internalBalanceDeltas } = await sendTransactionGetBalances( pool.tokensList, signer, @@ -31,10 +38,13 @@ export const testExactBptIn = async ( expect(transactionReceipt.status).to.eq(1); const expectedDeltas = insert(expectedAmountsOut, pool.bptIndex, bptIn); - // Allow for rounding errors - this has to be fixed on the SOR side in order to be 100% accurate expectedDeltas.forEach((expectedDelta, i) => { - const delta = Number(formatEther(balanceDeltas[i].sub(expectedDelta))); - expect(delta).to.be.closeTo(0, 1); + const balanceDelta = toInternalBalance + ? balanceDeltas[i].add(internalBalanceDeltas[i]) + : balanceDeltas[i]; + // Allow up to 1% error due to protocol fees not being considered on SOR math + const deltaAccuracy = accuracy(balanceDelta, BigNumber.from(expectedDelta)); + expect(deltaAccuracy).to.be.closeTo(1, 1e-2); }); const expectedMins = expectedAmountsOut.map((a) => subSlippage(BigNumber.from(a), BigNumber.from(slippage)).toString() @@ -50,7 +60,8 @@ export const testExactTokensOut = async ( pool: PoolWithMethods, signer: JsonRpcSigner, tokensOut: string[], - amountsOut: string[] + amountsOut: string[], + toInternalBalance = false ): Promise => { const slippage = '20'; // 20 bps = 0.2% - below it prediction fails with 207 - not enough bptIn const signerAddress = await signer.getAddress(); @@ -60,7 +71,8 @@ export const testExactTokensOut = async ( signerAddress, tokensOut, amountsOut, - slippage + slippage, + toInternalBalance ); const tokensToBeChecked = @@ -68,7 +80,7 @@ export const testExactTokensOut = async ( ? insert(tokensOut, pool.bptIndex, pool.address) : tokensOut; - const { transactionReceipt, balanceDeltas } = + const { transactionReceipt, balanceDeltas, internalBalanceDeltas } = await sendTransactionGetBalances( tokensToBeChecked, signer, @@ -81,8 +93,12 @@ export const testExactTokensOut = async ( const expectedDeltas = insert(amountsOut, pool.bptIndex, expectedBPTIn); // Allow for rounding errors - this has to be fixed on the SOR side in order to be 100% accurate expectedDeltas.forEach((expectedDelta, i) => { - const delta = Number(formatEther(balanceDeltas[i].sub(expectedDelta))); - expect(delta).to.be.closeTo(0, 1); + const balanceDelta = toInternalBalance + ? balanceDeltas[i].add(internalBalanceDeltas[i]) + : balanceDeltas[i]; + // Allow up to 1% error due to protocol fees not being considered on SOR math + const deltaAccuracy = accuracy(balanceDelta, BigNumber.from(expectedDelta)); + expect(deltaAccuracy).to.be.closeTo(1, 1e-2); }); const expectedMaxBpt = addSlippage( BigNumber.from(expectedBPTIn), @@ -98,15 +114,16 @@ export const testExactTokensOut = async ( export const testRecoveryExit = async ( pool: PoolWithMethods, signer: JsonRpcSigner, - bptIn: string + bptIn: string, + toInternalBalance = false ): Promise => { const slippage = '10'; // 10 bps = 0.1% const signerAddress = await signer.getAddress(); const { to, data, minAmountsOut, expectedAmountsOut, priceImpact } = - pool.buildRecoveryExit(signerAddress, bptIn, slippage); + pool.buildRecoveryExit(signerAddress, bptIn, slippage, toInternalBalance); - const { transactionReceipt, balanceDeltas } = + const { transactionReceipt, balanceDeltas, internalBalanceDeltas } = await sendTransactionGetBalances( pool.tokensList, signer, @@ -119,7 +136,11 @@ export const testRecoveryExit = async ( const expectedDeltas = insert(expectedAmountsOut, pool.bptIndex, bptIn); // Allow for rounding errors - this has to be fixed on the SOR side in order to be 100% accurate expectedDeltas.forEach((expectedDelta, i) => { - expect(balanceDeltas[i].sub(expectedDelta).toNumber()).to.be.closeTo(0, 1); + const balanceDelta = toInternalBalance + ? balanceDeltas[i].add(internalBalanceDeltas[i]) + : balanceDeltas[i]; + const delta = balanceDelta.sub(expectedDelta).toNumber(); + expect(delta).to.be.closeTo(0, 1); }); const expectedMins = expectedAmountsOut.map((a) => subSlippage(BigNumber.from(a), BigNumber.from(slippage)).toString() diff --git a/balancer-js/src/test/lib/utils.ts b/balancer-js/src/test/lib/utils.ts index 0dbbd10bd..6dce020ce 100644 --- a/balancer-js/src/test/lib/utils.ts +++ b/balancer-js/src/test/lib/utils.ts @@ -24,10 +24,10 @@ import { PoolsSubgraphRepository, Pool, BALANCER_NETWORK_CONFIG, + ERC20__factory, } from '@/.'; import { balancerVault } from '@/lib/constants/config'; import { parseEther } from '@ethersproject/units'; -import { ERC20 } from '@/modules/contracts/implementations/ERC20'; import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; import { defaultAbiCoder, Interface } from '@ethersproject/abi'; @@ -38,6 +38,7 @@ import { Pools as PoolsProvider } from '@/modules/pools'; import mainnetPools from '../fixtures/pools-mainnet.json'; import polygonPools from '../fixtures/pools-polygon.json'; import { PoolsJsonRepository } from './pools-json-repository'; +import { Contracts } from '@/modules/contracts/contracts.module'; const jsonPools = { [Network.MAINNET]: mainnetPools, @@ -166,8 +167,11 @@ export const approveToken = async ( amount: string, signer: JsonRpcSigner ): Promise => { - const tokenContract = ERC20(token, signer.provider); - return await tokenContract.connect(signer).approve(balancerVault, amount); + const tokenContract = ERC20__factory.connect(token, signer); + const txReceipt = await ( + await tokenContract.approve(balancerVault, amount) + ).wait(); + return txReceipt.status === 1; }; export const setupPool = async ( @@ -183,7 +187,8 @@ export const getErc20Balance = ( token: string, provider: JsonRpcProvider, holder: string -): Promise => ERC20(token, provider).balanceOf(holder); +): Promise => + ERC20__factory.connect(token, provider).balanceOf(holder); export const getBalances = async ( tokens: string[], @@ -201,6 +206,16 @@ export const getBalances = async ( return Promise.all(balances); }; +export const getBalancesInternal = async ( + tokens: string[], + signer: JsonRpcSigner, + signerAddress: string +): Promise> => { + const chainId = await signer.getChainId(); + const { vault } = new Contracts(chainId, signer.provider).contracts; + return vault.getInternalBalance(signerAddress, tokens); +}; + export const formatAddress = (text: string): string => { if (text.match(/^(0x)?[0-9a-fA-F]{40}$/)) return text; // Return text if it's already a valid address return formatBytes32String(text).slice(0, 42); @@ -219,7 +234,9 @@ export const move = async ( ): Promise => { const holder = await impersonateAccount(from, provider); const balance = await getErc20Balance(token, provider, from); - await ERC20(token, provider).connect(holder).transfer(to, balance); + await ERC20__factory.connect(token, provider) + .connect(holder) + .transfer(to, balance); return balance; }; @@ -244,9 +261,7 @@ export const stake = async ( balance: BigNumber ): Promise => { await ( - await ERC20(pool, signer.provider) - .connect(signer) - .approve(gauge, MaxUint256) + await ERC20__factory.connect(pool, signer).approve(gauge, MaxUint256) ).wait(); await ( @@ -366,6 +381,7 @@ export async function sendTransactionGetBalances( ): Promise<{ transactionReceipt: TransactionReceipt; balanceDeltas: BigNumber[]; + internalBalanceDeltas: BigNumber[]; gasUsed: BigNumber; }> { const balanceBefore = await getBalances( @@ -373,6 +389,11 @@ export async function sendTransactionGetBalances( signer, signerAddress ); + const balancesBeforeInternal = await getBalancesInternal( + tokensForBalanceCheck, + signer, + signerAddress + ); // Send transaction to local fork const transactionResponse = await signer.sendTransaction({ to, @@ -389,17 +410,28 @@ export async function sendTransactionGetBalances( signer, signerAddress ); - const balanceDeltas = balancesAfter.map((balAfter, i) => { + const balancesAfterInternal = await getBalancesInternal( + tokensForBalanceCheck, + signer, + signerAddress + ); + + const balanceDeltas = balancesAfter.map((balanceAfter, i) => { // ignore ETH delta from gas cost if (tokensForBalanceCheck[i] === AddressZero) { - balAfter = balAfter.add(gasPrice); + balanceAfter = balanceAfter.add(gasPrice); } - return balAfter.sub(balanceBefore[i]).abs(); + return balanceAfter.sub(balanceBefore[i]).abs(); + }); + + const internalBalanceDeltas = balancesAfterInternal.map((b, i) => { + return b.sub(balancesBeforeInternal[i]).abs(); }); return { transactionReceipt, balanceDeltas, + internalBalanceDeltas, gasUsed, }; } diff --git a/balancer-js/src/types.ts b/balancer-js/src/types.ts index 9b662f787..6d7944df9 100644 --- a/balancer-js/src/types.ts +++ b/balancer-js/src/types.ts @@ -70,9 +70,7 @@ export interface ContractAddresses { balancerHelpers: string; balancerMinterAddress?: string; lidoRelayer?: string; - relayerV3?: string; - relayerV4?: string; - relayerV5?: string; + relayer: string; gaugeController?: string; feeDistributor?: string; veBal?: string; @@ -331,6 +329,7 @@ export interface Pool { priceRateProviders?: PriceRateProvider[]; lastJoinExitInvariant?: string; isInRecoveryMode?: boolean; + isPaused?: boolean; } export interface PriceRateProvider { @@ -386,7 +385,8 @@ export interface PoolWithMethods extends Pool, Queries.ParamsBuilder { bptIn: string, slippage: string, shouldUnwrapNativeAsset?: boolean, - singleTokenOut?: string + singleTokenOut?: string, + toInternalBalance?: boolean ) => ExitExactBPTInAttributes; /** @@ -401,7 +401,8 @@ export interface PoolWithMethods extends Pool, Queries.ParamsBuilder { exiter: string, tokensOut: string[], amountsOut: string[], - slippage: string + slippage: string, + toInternalBalance?: boolean ) => ExitExactTokensOutAttributes; /** @@ -414,7 +415,8 @@ export interface PoolWithMethods extends Pool, Queries.ParamsBuilder { buildRecoveryExit: ( exiter: string, bptIn: string, - slippage: string + slippage: string, + toInternalBalance?: boolean ) => ExitExactBPTInAttributes; /** diff --git a/balancer-js/yarn.lock b/balancer-js/yarn.lock index a2e545d0e..823763377 100644 --- a/balancer-js/yarn.lock +++ b/balancer-js/yarn.lock @@ -507,10 +507,10 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" -"@balancer-labs/sor@^4.1.1-beta.7": - version "4.1.1-beta.7" - resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.1.1-beta.7.tgz#709a12e4ea9543f6af2b2cd5746f46c799233497" - integrity sha512-pb/IVYVeQXCvOZ06qoVJ2KGUTHeL4go9Je7Z5VSTYg26SYx8PNWEKeF9bdg/mo8TOweu4upcLj78PTNBLPF/fQ== +"@balancer-labs/sor@^4.1.1-beta.8": + version "4.1.1-beta.8" + resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.1.1-beta.8.tgz#75b2f40d8083499a1552900c0e2489f6e0a16452" + integrity sha512-By0k3apw/8MLu7UJAsV1xj3kxp9WON8cZI3REFKfOl4xvJq+yB1qR7BHbtR0p7bYZSwUucdiPMevSAlcAXNAsA== dependencies: isomorphic-fetch "^2.2.1"