From e8fec644c5c43521fdd43ed05512dc5bd64d1729 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Sun, 17 Jul 2022 13:26:12 +0100 Subject: [PATCH 001/104] Add Zap skeleton. --- balancer-js/src/modules/sdk.module.ts | 4 ++- .../src/modules/zaps/zaps.module.spec.ts | 25 +++++++++++++++++++ balancer-js/src/modules/zaps/zaps.module.ts | 15 +++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 balancer-js/src/modules/zaps/zaps.module.spec.ts create mode 100644 balancer-js/src/modules/zaps/zaps.module.ts diff --git a/balancer-js/src/modules/sdk.module.ts b/balancer-js/src/modules/sdk.module.ts index 9d8830493..0efb2fc19 100644 --- a/balancer-js/src/modules/sdk.module.ts +++ b/balancer-js/src/modules/sdk.module.ts @@ -9,6 +9,7 @@ import { Pricing } from './pricing/pricing.module'; import { ContractInstances, Contracts } from './contracts/contracts.module'; import { PoolsProvider } from './pools/provider'; import { SubgraphPoolRepository } from './data/pool/subgraph'; +import { Zaps } from './zaps/zaps.module'; export interface BalancerSDKRoot { config: BalancerSdkConfig; @@ -34,7 +35,8 @@ export class BalancerSDK implements BalancerSDKRoot { public poolsProvider = new PoolsProvider( config, new SubgraphPoolRepository(subgraph.client) - ) + ), + public zaps = new Zaps(config) ) { this.swaps = new Swaps(this.config); this.relayer = new Relayer(this.swaps); diff --git a/balancer-js/src/modules/zaps/zaps.module.spec.ts b/balancer-js/src/modules/zaps/zaps.module.spec.ts new file mode 100644 index 000000000..faa88929f --- /dev/null +++ b/balancer-js/src/modules/zaps/zaps.module.spec.ts @@ -0,0 +1,25 @@ +import dotenv from 'dotenv'; +import { expect } from 'chai'; +import { BalancerSdkConfig, Network, BalancerSDK } from '@/.'; +import { Zaps } from './zaps.module'; + +dotenv.config(); + +const sdkConfig: BalancerSdkConfig = { + network: Network.MAINNET, + rpcUrl: `https://mainnet.infura.io/v3/${process.env.INFURA}`, +}; + +describe('zaps module', () => { + context('instantiation', () => { + it('instantiate via module', async () => { + const zaps = new Zaps(sdkConfig); + expect(zaps.config.network).to.deep.eq(Network.MAINNET); + }); + + it('instantiate via SDK', async () => { + const balancer = new BalancerSDK(sdkConfig); + expect(balancer.zaps.config.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 new file mode 100644 index 000000000..215761296 --- /dev/null +++ b/balancer-js/src/modules/zaps/zaps.module.ts @@ -0,0 +1,15 @@ +import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; +import { Interface } from '@ethersproject/abi'; +import { MaxUint256, WeiPerEther, Zero } from '@ethersproject/constants'; +import { BalancerError, BalancerErrorCode } from '@/balancerErrors'; +import { BalancerSdkConfig } from '@/types'; + +/** +TO DOS + +Update typechain Relayer and use this. + */ + +export class Zaps { + constructor(public config: BalancerSdkConfig) {} +} From b395efe5b4fe7e834bc2f270757af9913b1aecdb Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Sun, 17 Jul 2022 20:01:18 +0100 Subject: [PATCH 002/104] WIP migrateStaBal3. --- balancer-js/src/modules/sdk.module.ts | 5 +- .../src/modules/zaps/migrateStaBal3.ts | 421 ++++++++++++++++++ .../src/modules/zaps/zaps.module.spec.ts | 9 +- balancer-js/src/modules/zaps/zaps.module.ts | 10 +- 4 files changed, 438 insertions(+), 7 deletions(-) create mode 100644 balancer-js/src/modules/zaps/migrateStaBal3.ts diff --git a/balancer-js/src/modules/sdk.module.ts b/balancer-js/src/modules/sdk.module.ts index 0efb2fc19..238f879d9 100644 --- a/balancer-js/src/modules/sdk.module.ts +++ b/balancer-js/src/modules/sdk.module.ts @@ -26,6 +26,7 @@ export class BalancerSDK implements BalancerSDKRoot { readonly relayer: Relayer; readonly pricing: Pricing; balancerContracts: Contracts; + zaps: Zaps; constructor( public config: BalancerSdkConfig, @@ -35,8 +36,7 @@ export class BalancerSDK implements BalancerSDKRoot { public poolsProvider = new PoolsProvider( config, new SubgraphPoolRepository(subgraph.client) - ), - public zaps = new Zaps(config) + ) ) { this.swaps = new Swaps(this.config); this.relayer = new Relayer(this.swaps); @@ -46,6 +46,7 @@ export class BalancerSDK implements BalancerSDKRoot { networkConfig.addresses.contracts, sor.provider ); + this.zaps = new Zaps(networkConfig.chainId, this.relayer); } get networkConfig(): BalancerNetworkConfig { diff --git a/balancer-js/src/modules/zaps/migrateStaBal3.ts b/balancer-js/src/modules/zaps/migrateStaBal3.ts new file mode 100644 index 000000000..25dacff45 --- /dev/null +++ b/balancer-js/src/modules/zaps/migrateStaBal3.ts @@ -0,0 +1,421 @@ +import { MaxUint256 } from '@ethersproject/constants'; +import { ExitPoolRequest } from '@/types'; +import { Network } from '@/lib/constants/network'; +import { Relayer, OutputReference } from '../relayer/relayer.module'; +import { StablePoolEncoder } from '@/pool-stable'; +import { SwapType, FundManagement, BatchSwapStep } from '../swaps/types'; + +export const CONSTANTS: NewtorkConstants = { + Mainnet: { + relayer: 'TODO', + staBal3: { + id: '', + address: '0x8fd162f338b770f7e879030830cde9173367f301', + }, + staBal3Gauge: '0x8fd162f338b770f7e879030830cde9173367f301', + linearUsdc1: { + id: '', + address: 'N/A', + }, + linearDai1: { + id: '', + + address: 'N/A', + }, + linearUsdt1: { + id: '', + + address: 'N/A', + }, + linearUsdc2: { + id: '', + + address: 'N/A', + }, + linearDai2: { + id: '', + + address: 'N/A', + }, + linearUsdt2: { + id: '', + + address: 'N/A', + }, + bbausd2Gauge: '0x8fd162f338b770f7e879030830cde9173367f301', + DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', + USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + }, + Goerli: { + relayer: 'TODO', + staBal3Gauge: '0x8fd162f338b770f7e879030830cde9173367f301', + staBal3: { + id: '', + address: '0x8fd162f338b770f7e879030830cde9173367f301', + }, + linearUsdc1: { + id: '', + address: 'N/A', + }, + linearDai1: { + id: '', + address: 'N/A', + }, + linearUsdt1: { + id: '', + address: 'N/A', + }, + linearUsdc2: { + id: '', + address: 'N/A', + }, + linearDai2: { + id: '', + address: 'N/A', + }, + linearUsdt2: { + id: '', + address: 'N/A', + }, + bbausd2Gauge: '0x8fd162f338b770f7e879030830cde9173367f301', + DAI: '', + USDC: '', + USDT: '', + }, +}; + +interface Pool { + id: string; + address: string; +} + +interface Constants { + relayer: string; + staBal3: Pool; + staBal3Gauge: string; + linearUsdc1: Pool; + linearDai1: Pool; + linearUsdt1: Pool; + linearUsdc2: Pool; + linearDai2: Pool; + linearUsdt2: Pool; + bbausd2Gauge: string; + DAI: string; + USDC: string; + USDT: string; +} + +interface NewtorkConstants { + Mainnet: Constants; + Goerli: Constants; +} + +type GaugeWithDraw = string; +type ExitPool = string; +type BatchSwap = string; +type JoinPool = string; +type GaugeDeposit = string; + +type CallData = [GaugeWithDraw, ExitPool, BatchSwap, JoinPool, GaugeDeposit]; + +export interface MigrationAttributes { + to: string; + functionName: string; + calldata: CallData; +} + +export class MigrateStaBal3 { + public constants: Constants; + constructor(public network: Network, public relayer: Relayer) { + if (!(network === Network.MAINNET || network === Network.GOERLI)) + throw new Error('This is not a supported network'); + + this.constants = + this.network === Network.MAINNET ? CONSTANTS.Mainnet : CONSTANTS.Goerli; + } + + buildWithdraw(migrator: string, amount: string): GaugeWithDraw { + /* + a) relayer uses allowance to transfer staked bpt from user to itself + b) relayer returns staked bpt to get bpt back + (steps a) and b) are done automatically by the relayer) + TO DO - + See relayer GaugeActions.sol + Encode gaugeWithdraw + GaugeActions gaugeWithdraw( + IStakingLiquidityGauge gauge, + address sender, + address recipient, + uint256 amount + ) + gaugeWithdraw( + this.constants.staBal3Gauge, + migrator, + this.constants.relayer, + amount + ); + */ + return ''; + } + + /** + * Creates encoded exitPool function. + * Exit staBal3 pool proportionally to underlying Linear BPTs. Exits to relayer. + * Outputreferences are used to store exit amounts for next transaction. + * @param migrator Migrator address. + * @param amount Amount of staBal3 BPT to exit with. + * @returns Encoded exitPool call. Output references. + */ + buildPoolExit( + migrator: string, + amount: string + ): { call: ExitPool; oldLinearAmountsReferences: OutputReference[] } { + // Assume gaugeWithdraw returns same amount value + const userData = StablePoolEncoder.exitExactBPTInForTokensOut(amount); + + // TO DO - Tokens have to be in correct order - might not be. + const exitTokens = [ + this.constants.linearDai1.address, + this.constants.linearUsdc1.address, + this.constants.linearUsdt1.address, + ]; + // Output of exit is used as input to swaps + const exitOutputReferences: OutputReference[] = []; + exitTokens.forEach((asset, i) => { + const key = Relayer.toChainedReference(i); + exitOutputReferences.push({ + index: i, + key: key, + }); + }); + + const call = Relayer.constructExitCall({ + assets: exitTokens, + minAmountsOut: ['0', '0', '0'], + userData: userData, + toInternalBalance: false, + poolId: this.constants.staBal3.id, + poolKind: 0, // This will always be 0 to match supported Relayer types + sender: migrator, + recipient: this.constants.relayer, + outputReferences: exitOutputReferences, + exitPoolRequest: {} as ExitPoolRequest, + }); + + return { + call, + oldLinearAmountsReferences: exitOutputReferences, + }; + } + + /** + * Creates encoded batchSwap function to swap Linear BPTs to underlying stables. + * outputreferences should contain the amounts of each new Linear BPT. + * @param outputReferences References from previous exit call. + * @returns BatchSwap call. + */ + buildSwap(outputReferences: OutputReference[]): { + call: BatchSwap; + newLinearAmountsReferences: OutputReference[]; + } { + // for each linear pool swap - + // linear1Bpt[linear1]stable[linear2]linear2bpt Uses chainedReference from previous action for amount. + // TO DO - Will swap order matter here? John to ask Fernando. + const swaps: BatchSwapStep[] = [ + { + poolId: this.constants.linearDai1.id, + assetInIndex: 0, + assetOutIndex: 1, + amount: outputReferences[0].key.toString(), + userData: '0x', + }, + { + poolId: this.constants.linearDai2.id, + assetInIndex: 1, + assetOutIndex: 2, + amount: '0', + userData: '0x', + }, + { + poolId: this.constants.linearUsdc1.id, + assetInIndex: 3, + assetOutIndex: 4, + amount: outputReferences[1].key.toString(), + userData: '0x', + }, + { + poolId: this.constants.linearUsdc2.id, + assetInIndex: 4, + assetOutIndex: 5, + amount: '0', + userData: '0x', + }, + { + poolId: this.constants.linearUsdt1.id, + assetInIndex: 6, + assetOutIndex: 7, + amount: outputReferences[2].key.toString(), + userData: '0x', + }, + { + poolId: this.constants.linearUsdt2.id, + assetInIndex: 7, + assetOutIndex: 8, + amount: '0', + userData: '0x', + }, + ]; + const assets = [ + this.constants.linearDai1.address, + this.constants.DAI, + this.constants.linearDai2.address, + this.constants.linearUsdc1.address, + this.constants.USDC, + this.constants.linearUsdc2.address, + this.constants.linearUsdt1.address, + this.constants.USDT, + this.constants.linearUsdt2.address, + ]; + // For now assuming ref amounts will be safe - should we add more accurate? + const limits = [ + MaxUint256.toString(), + '0', + '0', + MaxUint256.toString(), + '0', + '0', + MaxUint256.toString(), + '0', + '0', + ]; + + // Swap to/from Relayer + const funds: FundManagement = { + sender: this.constants.relayer, + recipient: this.constants.relayer, + fromInternalBalance: false, + toInternalBalance: false, + }; + + // Output of exit is used as input to swaps + // This should have a value for each delta returned by batchSwap + const swapOutputReferences: OutputReference[] = []; + assets.forEach((asset, i) => { + const key = Relayer.toChainedReference(i); + swapOutputReferences.push({ + index: i, + key: key, + }); + }); + + const encodedBatchSwap = Relayer.encodeBatchSwap({ + swapType: SwapType.SwapExactIn, + swaps: swaps, + assets: assets, + funds: funds, + limits, + deadline: MaxUint256, + value: '0', + outputReferences: swapOutputReferences, + }); + + // We only need the deltas/amounts of the new Linear pools (matches assets index) + // Final order should match token order required for joinPool + const linearDai2OutputRef = swapOutputReferences[2]; + const linearUsdc2OutputRef = swapOutputReferences[5]; + const linearUsdt2OutputRef = swapOutputReferences[8]; + + return { + call: encodedBatchSwap, + newLinearAmountsReferences: [ + linearDai2OutputRef, + linearUsdc2OutputRef, + linearUsdt2OutputRef, + ], + }; + } + + buildPoolJoin(joinAmounts: OutputReference[]): { + call: JoinPool; + bptOutputReference: OutputReference; + } { + /* + Create encoded joinPool. + join bbausd2 pool using Linear2 BPT tokens. + The join amounts should be stored in previous reference + Needs to set output references for next step - this will be the amount of bpt returned by join + */ + return { + call: '', + bptOutputReference: {} as OutputReference, + }; + } + + buildDeposit(migrator: string, bptAmount: OutputReference): GaugeDeposit { + /* + f) relayer stakes bb-a-usd-bpt + g) relayer sends staked bpt to user + (steps f) and g) are done automatically by the relayer) + TO DO - + Encode gaugeDeposit + GaugeActions gaugeDeposit( + IStakingLiquidityGauge gauge, + address sender, + address recipient, + uint256 amount + ) + Uses chainedReference from previous action for amount + gaugeDeposit( + this.constants.bbausd2Gauge, + this.constants.relayer, + migrator, + bptAmount + ) + */ + return ''; + } + + buildMigration(migrator: string, amount: string): MigrationAttributes { + /* + From Nico - + the flow is: + a) relayer uses allowance to transfer staked bpt from user to itself + b) relayer returns staked bpt to get bpt back + (steps a) and b) are done automatically by the relayer) + c) relayer uses the bpt it got to exit the pool + d) relayer swaps linear bpt into stables, and stables into linear v2 bpt + e) relayer joins bb-a-usd 2 + f) relayer stakes bb-a-usd-bpt + g) relayer sends staked bpt to user + (steps f) and g) are done automatically by the relayer) + (if the relayer is not yet approved by the user, there's one more step at the beginning where the relayer submits the user signature to approve itself) + */ + const gaugeWithdraw = this.buildWithdraw(migrator, amount); + + const poolExit = this.buildPoolExit(migrator, amount); + + const swaps = this.buildSwap(poolExit.oldLinearAmountsReferences); + + const poolJoin = this.buildPoolJoin(swaps.newLinearAmountsReferences); + + const gaugeDeposit = this.buildDeposit( + migrator, + poolJoin.bptOutputReference + ); + + const calls: CallData = [ + gaugeWithdraw, + poolExit.call, + swaps.call, + poolJoin.call, + gaugeDeposit, + ]; + + return { + to: this.constants.relayer, + functionName: 'multicall', + calldata: calls, + }; + } +} diff --git a/balancer-js/src/modules/zaps/zaps.module.spec.ts b/balancer-js/src/modules/zaps/zaps.module.spec.ts index faa88929f..f6cf6fe68 100644 --- a/balancer-js/src/modules/zaps/zaps.module.spec.ts +++ b/balancer-js/src/modules/zaps/zaps.module.spec.ts @@ -1,6 +1,6 @@ import dotenv from 'dotenv'; import { expect } from 'chai'; -import { BalancerSdkConfig, Network, BalancerSDK } from '@/.'; +import { BalancerSdkConfig, Network, BalancerSDK, Relayer } from '@/.'; import { Zaps } from './zaps.module'; dotenv.config(); @@ -13,13 +13,14 @@ const sdkConfig: BalancerSdkConfig = { describe('zaps module', () => { context('instantiation', () => { it('instantiate via module', async () => { - const zaps = new Zaps(sdkConfig); - expect(zaps.config.network).to.deep.eq(Network.MAINNET); + const relayer = new Relayer(sdkConfig); + const zaps = new Zaps(Network.MAINNET, relayer); + expect(zaps.network).to.deep.eq(Network.MAINNET); }); it('instantiate via SDK', async () => { const balancer = new BalancerSDK(sdkConfig); - expect(balancer.zaps.config.network).to.deep.eq(Network.MAINNET); + 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 index 215761296..5b17be28e 100644 --- a/balancer-js/src/modules/zaps/zaps.module.ts +++ b/balancer-js/src/modules/zaps/zaps.module.ts @@ -3,6 +3,9 @@ import { Interface } from '@ethersproject/abi'; import { MaxUint256, WeiPerEther, Zero } from '@ethersproject/constants'; import { BalancerError, BalancerErrorCode } from '@/balancerErrors'; import { BalancerSdkConfig } from '@/types'; +import { Network } from '@/lib/constants/network'; +import { MigrateStaBal3, MigrationAttributes } from './migrateStaBal3'; +import { Relayer } from '../relayer/relayer.module'; /** TO DOS @@ -11,5 +14,10 @@ Update typechain Relayer and use this. */ export class Zaps { - constructor(public config: BalancerSdkConfig) {} + constructor(public network: Network, public relayer: Relayer) {} + + migrateStaBal3(migrator: string, amount: string): MigrationAttributes { + const migrate = new MigrateStaBal3(this.network, this.relayer); + return migrate.buildMigration(migrator, amount); + } } From 3600671dd52201c494cc653a98fc558d430b3eb3 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Mon, 18 Jul 2022 08:37:23 +0100 Subject: [PATCH 003/104] Added query function. --- .../src/modules/zaps/migrateStaBal3.ts | 52 +++++++++++++++++-- balancer-js/src/modules/zaps/zaps.module.ts | 29 ++++++++--- 2 files changed, 71 insertions(+), 10 deletions(-) diff --git a/balancer-js/src/modules/zaps/migrateStaBal3.ts b/balancer-js/src/modules/zaps/migrateStaBal3.ts index 25dacff45..bce1acdbc 100644 --- a/balancer-js/src/modules/zaps/migrateStaBal3.ts +++ b/balancer-js/src/modules/zaps/migrateStaBal3.ts @@ -1,3 +1,5 @@ +import { Contract } from '@ethersproject/contracts'; +import { defaultAbiCoder } from '@ethersproject/abi'; import { MaxUint256 } from '@ethersproject/constants'; import { ExitPoolRequest } from '@/types'; import { Network } from '@/lib/constants/network'; @@ -5,6 +7,10 @@ import { Relayer, OutputReference } from '../relayer/relayer.module'; import { StablePoolEncoder } from '@/pool-stable'; import { SwapType, FundManagement, BatchSwapStep } from '../swaps/types'; +// TO DO - Ask Nico to update Typechain? +import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; +import { JsonRpcProvider } from '@ethersproject/providers'; + export const CONSTANTS: NewtorkConstants = { Mainnet: { relayer: 'TODO', @@ -336,13 +342,18 @@ export class MigrateStaBal3 { }; } - buildPoolJoin(joinAmounts: OutputReference[]): { + buildPoolJoin( + joinAmounts: OutputReference[], + expectedBptReturn: string, + slippage: string + ): { call: JoinPool; bptOutputReference: OutputReference; } { /* Create encoded joinPool. join bbausd2 pool using Linear2 BPT tokens. + Use expectedBptReturn and slippage to set minAmount out The join amounts should be stored in previous reference Needs to set output references for next step - this will be the amount of bpt returned by join */ @@ -376,7 +387,12 @@ export class MigrateStaBal3 { return ''; } - buildMigration(migrator: string, amount: string): MigrationAttributes { + buildMigration( + migrator: string, + amount: string, + expectedBptReturn: string, + slippage: string + ): MigrationAttributes { /* From Nico - the flow is: @@ -397,7 +413,11 @@ export class MigrateStaBal3 { const swaps = this.buildSwap(poolExit.oldLinearAmountsReferences); - const poolJoin = this.buildPoolJoin(swaps.newLinearAmountsReferences); + const poolJoin = this.buildPoolJoin( + swaps.newLinearAmountsReferences, + expectedBptReturn, + slippage + ); const gaugeDeposit = this.buildDeposit( migrator, @@ -418,4 +438,30 @@ export class MigrateStaBal3 { calldata: calls, }; } + + /** + * Statically calls migration action to find final BPT amount returned. + * @param migrator Migrator address. + * @param amount Amount of staBal3 BPT. + * @param provider Provider. + * @returns BPT amount from poolJoin call. + */ + async queryMigration( + migrator: string, + amount: string, + provider: JsonRpcProvider + ): Promise { + const migrationData = this.buildMigration(migrator, amount, '0', '0'); + const relayerContract = new Contract( + this.constants.relayer, + balancerRelayerAbi, + provider + ); + // Returns result of each call in an array + const tx = await relayerContract.callStatic[migrationData.functionName]( + migrationData.calldata + ); + // BPT amount from poolJoin call + return defaultAbiCoder.decode(['int256[]'], tx[3]).toString(); + } } diff --git a/balancer-js/src/modules/zaps/zaps.module.ts b/balancer-js/src/modules/zaps/zaps.module.ts index 5b17be28e..275d9d183 100644 --- a/balancer-js/src/modules/zaps/zaps.module.ts +++ b/balancer-js/src/modules/zaps/zaps.module.ts @@ -1,11 +1,7 @@ -import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; -import { Interface } from '@ethersproject/abi'; -import { MaxUint256, WeiPerEther, Zero } from '@ethersproject/constants'; -import { BalancerError, BalancerErrorCode } from '@/balancerErrors'; -import { BalancerSdkConfig } from '@/types'; import { Network } from '@/lib/constants/network'; import { MigrateStaBal3, MigrationAttributes } from './migrateStaBal3'; import { Relayer } from '../relayer/relayer.module'; +import { JsonRpcProvider } from '@ethersproject/providers'; /** TO DOS @@ -16,8 +12,27 @@ Update typechain Relayer and use this. export class Zaps { constructor(public network: Network, public relayer: Relayer) {} - migrateStaBal3(migrator: string, amount: string): MigrationAttributes { + async queryMigrateStaBal3( + migrator: string, + amount: string, + provider: JsonRpcProvider + ): Promise { const migrate = new MigrateStaBal3(this.network, this.relayer); - return migrate.buildMigration(migrator, amount); + return await migrate.queryMigration(migrator, amount, provider); + } + + migrateStaBal3( + migrator: string, + amount: string, + expectedBptReturn: string, + slippage: string + ): MigrationAttributes { + const migrate = new MigrateStaBal3(this.network, this.relayer); + return migrate.buildMigration( + migrator, + amount, + expectedBptReturn, + slippage + ); } } From 309d5c5a6c130598ab7bae9fd30150918c86b653 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Mon, 18 Jul 2022 10:16:25 +0100 Subject: [PATCH 004/104] Pseudo code for bbausd migration. --- .../src/modules/zaps/migrateBbausd1.ts | 314 ++++++++++++++++++ .../src/modules/zaps/migrateStaBal3.ts | 2 +- 2 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 balancer-js/src/modules/zaps/migrateBbausd1.ts diff --git a/balancer-js/src/modules/zaps/migrateBbausd1.ts b/balancer-js/src/modules/zaps/migrateBbausd1.ts new file mode 100644 index 000000000..6b659925f --- /dev/null +++ b/balancer-js/src/modules/zaps/migrateBbausd1.ts @@ -0,0 +1,314 @@ +import { Contract } from '@ethersproject/contracts'; +import { defaultAbiCoder } from '@ethersproject/abi'; +import { MaxUint256 } from '@ethersproject/constants'; +import { Network } from '@/lib/constants/network'; +import { Relayer, OutputReference } from '../relayer/relayer.module'; +import { SwapType, FundManagement, BatchSwapStep } from '../swaps/types'; + +// TO DO - Ask Nico to update Typechain? +import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; +import { JsonRpcProvider } from '@ethersproject/providers'; + +import { Constants, CONSTANTS } from './migrateStaBal3'; + +type GaugeWithDraw = string; +type BatchSwap = string; +type GaugeDeposit = string; +type CallData = [GaugeWithDraw, BatchSwap, GaugeDeposit]; + +export interface MigrationAttributes { + to: string; + functionName: string; + calldata: CallData; +} + +export class MigrateBbausd1 { + public constants: Constants; + constructor(public network: Network, public relayer: Relayer) { + if (!(network === Network.MAINNET || network === Network.GOERLI)) + throw new Error('This is not a supported network'); + + this.constants = + this.network === Network.MAINNET ? CONSTANTS.Mainnet : CONSTANTS.Goerli; + } + + buildWithdraw(migrator: string, amount: string): GaugeWithDraw { + /* + a) relayer uses allowance to transfer staked bpt from user to itself + b) relayer returns staked bpt to get bpt back + (steps a) and b) are done automatically by the relayer) + TO DO - + See relayer GaugeActions.sol + Encode gaugeWithdraw + GaugeActions gaugeWithdraw( + IStakingLiquidityGauge gauge, + address sender, + address recipient, + uint256 amount + ) + gaugeWithdraw( + this.constants.bbausd1Gauge, + migrator, + this.constants.relayer, + amount + ); + */ + return ''; + } + + buildDeposit(migrator: string, bptAmount: OutputReference): GaugeDeposit { + /* + f) relayer stakes bb-a-usd-bpt + g) relayer sends staked bpt to user + (steps f) and g) are done automatically by the relayer) + TO DO - + Encode gaugeDeposit + GaugeActions gaugeDeposit( + IStakingLiquidityGauge gauge, + address sender, + address recipient, + uint256 amount + ) + Uses chainedReference from previous action for amount + gaugeDeposit( + this.constants.bbausd2Gauge, + this.constants.relayer, + migrator, + bptAmount + ) + */ + return ''; + } + + /** + * Creates encoded batchSwap function to swap Linear BPTs to underlying stables. + * outputreferences should contain the amounts of each new Linear BPT. + * @param outputReferences References from previous exit call. + * @returns BatchSwap call. + */ + buildSwap( + bptAmount: string, + expectedBptReturn: string, + slippage: string + ): { + call: BatchSwap; + bbausd2AmountsReference: OutputReference; + } { + // bbausd1[bbausd1]blinear1[linear1]stable[linear2]blinear2[bbausd2]bbausd2 and then do that proportionally for each underlying stable. + // TO DO - Will swap order matter here? John to ask Fernando. + // TO DO - Need to split BPT amount proportionally + const daiBptAmt = ''; + const usdcBptAmt = ''; + const usdtBptAmt = ''; + + const swaps: BatchSwapStep[] = [ + { + poolId: this.constants.bbausd1.id, + assetInIndex: 0, + assetOutIndex: 1, + amount: daiBptAmt, + userData: '0x', + }, + { + poolId: this.constants.linearDai1.id, + assetInIndex: 1, + assetOutIndex: 2, + amount: '0', + userData: '0x', + }, + { + poolId: this.constants.linearDai2.id, + assetInIndex: 2, + assetOutIndex: 3, + amount: '0', + userData: '0x', + }, + { + poolId: this.constants.bbausd2.id, + assetInIndex: 3, + assetOutIndex: 4, + amount: '0', + userData: '0x', + }, + { + poolId: this.constants.bbausd1.id, + assetInIndex: 0, + assetOutIndex: 5, + amount: usdcBptAmt, + userData: '0x', + }, + { + poolId: this.constants.linearUsdc1.id, + assetInIndex: 5, + assetOutIndex: 6, + amount: '0', + userData: '0x', + }, + { + poolId: this.constants.linearUsdc2.id, + assetInIndex: 6, + assetOutIndex: 7, + amount: '0', + userData: '0x', + }, + { + poolId: this.constants.bbausd2.id, + assetInIndex: 7, + assetOutIndex: 4, + amount: '0', + userData: '0x', + }, + { + poolId: this.constants.bbausd1.id, + assetInIndex: 0, + assetOutIndex: 8, + amount: usdtBptAmt, + userData: '0x', + }, + { + poolId: this.constants.linearUsdt1.id, + assetInIndex: 8, + assetOutIndex: 9, + amount: '0', + userData: '0x', + }, + { + poolId: this.constants.linearUsdt2.id, + assetInIndex: 9, + assetOutIndex: 10, + amount: '0', + userData: '0x', + }, + { + poolId: this.constants.bbausd2.id, + assetInIndex: 10, + assetOutIndex: 4, + amount: '0', + userData: '0x', + }, + ]; + const assets = [ + this.constants.bbausd1.address, + this.constants.linearDai1.address, + this.constants.DAI, + this.constants.linearDai2.address, + this.constants.bbausd2.address, + this.constants.linearUsdc1.address, + this.constants.USDC, + this.constants.linearUsdc2.address, + this.constants.linearUsdt1.address, + this.constants.USDT, + this.constants.linearUsdt2.address, + ]; + // For now assuming ref amounts will be safe - should we add more accurate? + const limits = [ + bptAmount, + '0', + '0', + '0', + '0', // Can use expectedBpt amount and slippage to set this limit + '0', + '0', + '0', + '0', + '0', + '0', + '0', + ]; + + // Swap to/from Relayer + const funds: FundManagement = { + sender: this.constants.relayer, + recipient: this.constants.relayer, + fromInternalBalance: false, + toInternalBalance: false, + }; + + // Output of exit is used as input to swaps + // This should have a value for each delta returned by batchSwap + const swapOutputReferences: OutputReference[] = []; + assets.forEach((asset, i) => { + const key = Relayer.toChainedReference(i); + swapOutputReferences.push({ + index: i, + key: key, + }); + }); + + const encodedBatchSwap = Relayer.encodeBatchSwap({ + swapType: SwapType.SwapExactIn, + swaps: swaps, + assets: assets, + funds: funds, + limits, + deadline: MaxUint256, + value: '0', + outputReferences: swapOutputReferences, + }); + + // We only need the deltas/amounts of the new bbausd2 pools (matches assets index) + // Final order should match token order required for joinPool + const bbausd2AmountsReference = swapOutputReferences[4]; + + return { + call: encodedBatchSwap, + bbausd2AmountsReference: bbausd2AmountsReference, + }; + } + + buildMigration( + migrator: string, + amount: string, + expectedBptReturn: string, + slippage: string + ): MigrationAttributes { + /* + the flow is: + withdraw from gauge + swap bbausd1 > bbausd2 via proportional underlying. + deposit into gauge + */ + const gaugeWithdraw = this.buildWithdraw(migrator, amount); + + const swaps = this.buildSwap(amount, expectedBptReturn, slippage); + + const gaugeDeposit = this.buildDeposit( + migrator, + swaps.bbausd2AmountsReference + ); + + const calls: CallData = [gaugeWithdraw, swaps.call, gaugeDeposit]; + + return { + to: this.constants.relayer, + functionName: 'multicall', + calldata: calls, + }; + } + + /** + * Statically calls migration action to find final bbausd2 BPT amount returned. + * @param migrator Migrator address. + * @param amount Amount of bbausd1 BPT. + * @param provider Provider. + * @returns BPT amount from poolJoin call. + */ + async queryMigration( + migrator: string, + amount: string, + provider: JsonRpcProvider + ): Promise { + const migrationData = this.buildMigration(migrator, amount, '0', '0'); + const relayerContract = new Contract( + this.constants.relayer, + balancerRelayerAbi, + provider + ); + // Returns result of each call in an array + const tx = await relayerContract.callStatic[migrationData.functionName]( + migrationData.calldata + ); + // bbausd2 delta amount from batchSwap call + return defaultAbiCoder.decode(['int256[]'], tx[1])[4].toString(); + } +} diff --git a/balancer-js/src/modules/zaps/migrateStaBal3.ts b/balancer-js/src/modules/zaps/migrateStaBal3.ts index bce1acdbc..b4dd1c98a 100644 --- a/balancer-js/src/modules/zaps/migrateStaBal3.ts +++ b/balancer-js/src/modules/zaps/migrateStaBal3.ts @@ -96,7 +96,7 @@ interface Pool { address: string; } -interface Constants { +export interface Constants { relayer: string; staBal3: Pool; staBal3Gauge: string; From 1af7b9284fba733600751876a95af26bbb07c197 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Tue, 19 Jul 2022 14:40:50 +0100 Subject: [PATCH 005/104] Change to use swap instead of join. Use queryBatchSwap to find amount for UI and limits. --- .../src/modules/zaps/migrateBbausd1.ts | 9 +- .../src/modules/zaps/migrateStaBal3.ts | 89 +++++++++---------- 2 files changed, 45 insertions(+), 53 deletions(-) diff --git a/balancer-js/src/modules/zaps/migrateBbausd1.ts b/balancer-js/src/modules/zaps/migrateBbausd1.ts index 6b659925f..9dd8b2ebd 100644 --- a/balancer-js/src/modules/zaps/migrateBbausd1.ts +++ b/balancer-js/src/modules/zaps/migrateBbausd1.ts @@ -206,7 +206,7 @@ export class MigrateBbausd1 { '0', '0', '0', - '0', // Can use expectedBpt amount and slippage to set this limit + expectedBptReturn, // Can use expectedBpt amount and slippage to set this limit '0', '0', '0', @@ -259,7 +259,6 @@ export class MigrateBbausd1 { buildMigration( migrator: string, amount: string, - expectedBptReturn: string, slippage: string ): MigrationAttributes { /* @@ -270,7 +269,9 @@ export class MigrateBbausd1 { */ const gaugeWithdraw = this.buildWithdraw(migrator, amount); - const swaps = this.buildSwap(amount, expectedBptReturn, slippage); + // Fernando - final bbausd2 amount should equal bbausd1 input amount + // Use this to set final swap limit + const swaps = this.buildSwap(amount, amount, slippage); const gaugeDeposit = this.buildDeposit( migrator, @@ -298,7 +299,7 @@ export class MigrateBbausd1 { amount: string, provider: JsonRpcProvider ): Promise { - const migrationData = this.buildMigration(migrator, amount, '0', '0'); + const migrationData = this.buildMigration(migrator, amount, '0'); const relayerContract = new Contract( this.constants.relayer, balancerRelayerAbi, diff --git a/balancer-js/src/modules/zaps/migrateStaBal3.ts b/balancer-js/src/modules/zaps/migrateStaBal3.ts index b4dd1c98a..0834f2ca3 100644 --- a/balancer-js/src/modules/zaps/migrateStaBal3.ts +++ b/balancer-js/src/modules/zaps/migrateStaBal3.ts @@ -120,10 +120,9 @@ interface NewtorkConstants { type GaugeWithDraw = string; type ExitPool = string; type BatchSwap = string; -type JoinPool = string; type GaugeDeposit = string; -type CallData = [GaugeWithDraw, ExitPool, BatchSwap, JoinPool, GaugeDeposit]; +type CallData = [GaugeWithDraw, ExitPool, BatchSwap, GaugeDeposit]; export interface MigrationAttributes { to: string; @@ -221,12 +220,15 @@ export class MigrateStaBal3 { * @param outputReferences References from previous exit call. * @returns BatchSwap call. */ - buildSwap(outputReferences: OutputReference[]): { + buildSwap( + outputReferences: OutputReference[], + expectedBptReturn: string + ): { call: BatchSwap; - newLinearAmountsReferences: OutputReference[]; + bptAmountOut: OutputReference; } { // for each linear pool swap - - // linear1Bpt[linear1]stable[linear2]linear2bpt Uses chainedReference from previous action for amount. + // 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[] = [ { @@ -243,6 +245,13 @@ export class MigrateStaBal3 { amount: '0', userData: '0x', }, + { + poolId: this.constants.bbausd2.id, + assetInIndex: 2, + assetOutIndex: 3, + amount: '0', + userData: '0x', + }, { poolId: this.constants.linearUsdc1.id, assetInIndex: 3, @@ -257,6 +266,13 @@ export class MigrateStaBal3 { amount: '0', userData: '0x', }, + { + poolId: this.constants.bbausd2.id, + assetInIndex: 5, + assetOutIndex: 3, + amount: '0', + userData: '0x', + }, { poolId: this.constants.linearUsdt1.id, assetInIndex: 6, @@ -271,11 +287,19 @@ export class MigrateStaBal3 { amount: '0', userData: '0x', }, + { + poolId: this.constants.bbausd2.id, + assetInIndex: 8, + assetOutIndex: 3, + amount: '0', + userData: '0x', + } ]; const assets = [ this.constants.linearDai1.address, this.constants.DAI, this.constants.linearDai2.address, + this.constants.bbausd2.address, this.constants.linearUsdc1.address, this.constants.USDC, this.constants.linearUsdc2.address, @@ -288,6 +312,7 @@ export class MigrateStaBal3 { MaxUint256.toString(), '0', '0', + expectedBptReturn.toString(), MaxUint256.toString(), '0', '0', @@ -326,40 +351,12 @@ export class MigrateStaBal3 { outputReferences: swapOutputReferences, }); - // We only need the deltas/amounts of the new Linear pools (matches assets index) - // Final order should match token order required for joinPool - const linearDai2OutputRef = swapOutputReferences[2]; - const linearUsdc2OutputRef = swapOutputReferences[5]; - const linearUsdt2OutputRef = swapOutputReferences[8]; + // We only need the deltas/amounts of the bbausd2 (matches assets index) + const bptOut = swapOutputReferences[3]; return { call: encodedBatchSwap, - newLinearAmountsReferences: [ - linearDai2OutputRef, - linearUsdc2OutputRef, - linearUsdt2OutputRef, - ], - }; - } - - buildPoolJoin( - joinAmounts: OutputReference[], - expectedBptReturn: string, - slippage: string - ): { - call: JoinPool; - bptOutputReference: OutputReference; - } { - /* - Create encoded joinPool. - join bbausd2 pool using Linear2 BPT tokens. - Use expectedBptReturn and slippage to set minAmount out - The join amounts should be stored in previous reference - Needs to set output references for next step - this will be the amount of bpt returned by join - */ - return { - call: '', - bptOutputReference: {} as OutputReference, + bptAmountOut: bptOut, }; } @@ -411,24 +408,18 @@ export class MigrateStaBal3 { const poolExit = this.buildPoolExit(migrator, amount); - const swaps = this.buildSwap(poolExit.oldLinearAmountsReferences); - - const poolJoin = this.buildPoolJoin( - swaps.newLinearAmountsReferences, - expectedBptReturn, - slippage + // We can swap to bbausd2 instead of join as swap fees will be 0 + const swaps = this.buildSwap( + poolExit.oldLinearAmountsReferences, + expectedBptReturn ); - const gaugeDeposit = this.buildDeposit( - migrator, - poolJoin.bptOutputReference - ); + const gaugeDeposit = this.buildDeposit(migrator, swaps.bptAmountOut); const calls: CallData = [ gaugeWithdraw, poolExit.call, swaps.call, - poolJoin.call, gaugeDeposit, ]; @@ -461,7 +452,7 @@ export class MigrateStaBal3 { const tx = await relayerContract.callStatic[migrationData.functionName]( migrationData.calldata ); - // BPT amount from poolJoin call - return defaultAbiCoder.decode(['int256[]'], tx[3]).toString(); + // BPT amount from batchSwap call + return defaultAbiCoder.decode(['int256[]'], tx[2])[3].toString(); } } From d0570ef31783003820a5c5fadb1ffb3be31d3184 Mon Sep 17 00:00:00 2001 From: bronco Date: Wed, 20 Jul 2022 14:06:33 +0200 Subject: [PATCH 006/104] flow wip added GaugeRelayer deposit / withdrawal interface calculate token proportions in bbaUSD pool --- .../src/modules/zaps/migrateBbausd1.ts | 116 +++++++------ .../src/modules/zaps/migrateStaBal3.ts | 161 ++++++++---------- 2 files changed, 134 insertions(+), 143 deletions(-) diff --git a/balancer-js/src/modules/zaps/migrateBbausd1.ts b/balancer-js/src/modules/zaps/migrateBbausd1.ts index 9dd8b2ebd..3025c5af7 100644 --- a/balancer-js/src/modules/zaps/migrateBbausd1.ts +++ b/balancer-js/src/modules/zaps/migrateBbausd1.ts @@ -1,15 +1,18 @@ import { Contract } from '@ethersproject/contracts'; import { defaultAbiCoder } from '@ethersproject/abi'; -import { MaxUint256 } from '@ethersproject/constants'; +import { MaxUint256, Zero } from '@ethersproject/constants'; import { Network } from '@/lib/constants/network'; import { Relayer, OutputReference } from '../relayer/relayer.module'; import { SwapType, FundManagement, BatchSwapStep } from '../swaps/types'; // TO DO - Ask Nico to update Typechain? import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; +// we are missing encodeGaugeDeposit / Withdraw functions import { JsonRpcProvider } from '@ethersproject/providers'; -import { Constants, CONSTANTS } from './migrateStaBal3'; +import { CONSTANTS, gaugeActionsInterface } from './migrateStaBal3'; +import { Pool } from '@/types'; +import { BigNumber } from '@ethersproject/bignumber'; type GaugeWithDraw = string; type BatchSwap = string; @@ -23,8 +26,13 @@ export interface MigrationAttributes { } export class MigrateBbausd1 { - public constants: Constants; - constructor(public network: Network, public relayer: Relayer) { + public constants; + + constructor( + public network: Network, + public relayer: Relayer, + private from: Pool + ) { if (!(network === Network.MAINNET || network === Network.GOERLI)) throw new Error('This is not a supported network'); @@ -32,52 +40,32 @@ export class MigrateBbausd1 { this.network === Network.MAINNET ? CONSTANTS.Mainnet : CONSTANTS.Goerli; } + /** + * Is using gauge relayer to withdraw staked BPT from user to itself + * + * @returns withdraw call + */ buildWithdraw(migrator: string, amount: string): GaugeWithDraw { - /* - a) relayer uses allowance to transfer staked bpt from user to itself - b) relayer returns staked bpt to get bpt back - (steps a) and b) are done automatically by the relayer) - TO DO - - See relayer GaugeActions.sol - Encode gaugeWithdraw - GaugeActions gaugeWithdraw( - IStakingLiquidityGauge gauge, - address sender, - address recipient, - uint256 amount - ) - gaugeWithdraw( - this.constants.bbausd1Gauge, - migrator, - this.constants.relayer, - amount - ); - */ - return ''; + return gaugeActionsInterface.encodeFunctionData('gaugeWithdraw', [ + this.constants.bbausd1.gauge, + migrator, + this.constants.relayer, + amount, + ]); } - buildDeposit(migrator: string, bptAmount: OutputReference): GaugeDeposit { - /* - f) relayer stakes bb-a-usd-bpt - g) relayer sends staked bpt to user - (steps f) and g) are done automatically by the relayer) - TO DO - - Encode gaugeDeposit - GaugeActions gaugeDeposit( - IStakingLiquidityGauge gauge, - address sender, - address recipient, - uint256 amount - ) - Uses chainedReference from previous action for amount - gaugeDeposit( - this.constants.bbausd2Gauge, - this.constants.relayer, - migrator, - bptAmount - ) - */ - return ''; + /** + * Is using gauge relayer to deposit user's BPT to itself + * + * @returns deposit call + */ + buildDeposit(migrator: string, amount: OutputReference): GaugeDeposit { + return gaugeActionsInterface.encodeFunctionData('gaugeDeposit', [ + this.constants.bbausd2.gauge, + this.constants.relayer, + migrator, + amount, + ]); } /** @@ -94,12 +82,35 @@ export class MigrateBbausd1 { call: BatchSwap; bbausd2AmountsReference: OutputReference; } { + const { tokens } = this.from; + + // Assuming 1:1 exchange rates between tokens + // TODO: Fetch current prices, or use price or priceRate from subgraph? + const totalLiquidity = tokens.reduce( + (sum, token) => sum.add(BigNumber.from(token.balance)), + Zero + ); + + const weights = Object.fromEntries( + tokens.map((token) => [ + token.symbol, + BigNumber.from(token.balance).div(totalLiquidity), + ]) + ); + // bbausd1[bbausd1]blinear1[linear1]stable[linear2]blinear2[bbausd2]bbausd2 and then do that proportionally for each underlying stable. // TO DO - Will swap order matter here? John to ask Fernando. - // TO DO - Need to split BPT amount proportionally - const daiBptAmt = ''; - const usdcBptAmt = ''; - const usdtBptAmt = ''; + + // Split BPT amount proportionally: + const daiBptAmt = BigNumber.from(bptAmount) + .mul(weights['bb-a-DAI']) + .toString(); + const usdcBptAmt = BigNumber.from(bptAmount) + .mul(weights['bb-a-USDC']) + .toString(); + const usdtBptAmt = BigNumber.from(bptAmount) + .mul(weights['bb-a-USDT']) + .toString(); const swaps: BatchSwapStep[] = [ { @@ -187,6 +198,7 @@ export class MigrateBbausd1 { userData: '0x', }, ]; + const assets = [ this.constants.bbausd1.address, this.constants.linearDai1.address, @@ -200,6 +212,7 @@ export class MigrateBbausd1 { this.constants.USDT, this.constants.linearUsdt2.address, ]; + // For now assuming ref amounts will be safe - should we add more accurate? const limits = [ bptAmount, @@ -297,6 +310,7 @@ export class MigrateBbausd1 { async queryMigration( migrator: string, amount: string, + poolData: Pool, provider: JsonRpcProvider ): Promise { const migrationData = this.buildMigration(migrator, amount, '0'); diff --git a/balancer-js/src/modules/zaps/migrateStaBal3.ts b/balancer-js/src/modules/zaps/migrateStaBal3.ts index 0834f2ca3..d5e2ce030 100644 --- a/balancer-js/src/modules/zaps/migrateStaBal3.ts +++ b/balancer-js/src/modules/zaps/migrateStaBal3.ts @@ -1,5 +1,5 @@ import { Contract } from '@ethersproject/contracts'; -import { defaultAbiCoder } from '@ethersproject/abi'; +import { defaultAbiCoder, Interface } from '@ethersproject/abi'; import { MaxUint256 } from '@ethersproject/constants'; import { ExitPoolRequest } from '@/types'; import { Network } from '@/lib/constants/network'; @@ -11,54 +11,73 @@ import { SwapType, FundManagement, BatchSwapStep } from '../swaps/types'; import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; import { JsonRpcProvider } from '@ethersproject/providers'; -export const CONSTANTS: NewtorkConstants = { +export const gaugeActionsInterface = new Interface([ + 'function gaugeDeposit(address gauge, address sender, address recipient, uint amount) payable', + 'function gaugeWithdraw(address gauge, address sender, address recipient, uint amount) payable', +]); + +export const CONSTANTS = { Mainnet: { relayer: 'TODO', staBal3: { + id: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063', + address: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42', + gauge: '0x34f33cdaed8ba0e1ceece80e5f4a73bcf234cfac', + }, + bbausd1: { + id: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb20000000000000000000000fe', + address: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb2', + gauge: '0x68d019f64a7aa97e2d4e7363aee42251d08124fb', + }, + bbausd2: { id: '', - address: '0x8fd162f338b770f7e879030830cde9173367f301', + address: '', + gauge: '', }, - staBal3Gauge: '0x8fd162f338b770f7e879030830cde9173367f301', linearUsdc1: { id: '', address: 'N/A', }, linearDai1: { id: '', - address: 'N/A', }, linearUsdt1: { id: '', - address: 'N/A', }, linearUsdc2: { id: '', - address: 'N/A', }, linearDai2: { id: '', - address: 'N/A', }, linearUsdt2: { id: '', - address: 'N/A', }, - bbausd2Gauge: '0x8fd162f338b770f7e879030830cde9173367f301', DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', }, Goerli: { relayer: 'TODO', - staBal3Gauge: '0x8fd162f338b770f7e879030830cde9173367f301', staBal3: { + id: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063', + address: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42', + gauge: '0x34f33cdaed8ba0e1ceece80e5f4a73bcf234cfac', + }, + bbausd1: { + id: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb20000000000000000000000fe', + address: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb2', + gauge: '0x68d019f64a7aa97e2d4e7363aee42251d08124fb', + }, + bbausd2: { id: '', - address: '0x8fd162f338b770f7e879030830cde9173367f301', + address: '', + gauge: '', }, linearUsdc1: { id: '', @@ -84,39 +103,12 @@ export const CONSTANTS: NewtorkConstants = { id: '', address: 'N/A', }, - bbausd2Gauge: '0x8fd162f338b770f7e879030830cde9173367f301', - DAI: '', - USDC: '', - USDT: '', + DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', + USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', }, }; -interface Pool { - id: string; - address: string; -} - -export interface Constants { - relayer: string; - staBal3: Pool; - staBal3Gauge: string; - linearUsdc1: Pool; - linearDai1: Pool; - linearUsdt1: Pool; - linearUsdc2: Pool; - linearDai2: Pool; - linearUsdt2: Pool; - bbausd2Gauge: string; - DAI: string; - USDC: string; - USDT: string; -} - -interface NewtorkConstants { - Mainnet: Constants; - Goerli: Constants; -} - type GaugeWithDraw = string; type ExitPool = string; type BatchSwap = string; @@ -131,8 +123,13 @@ export interface MigrationAttributes { } export class MigrateStaBal3 { - public constants: Constants; - constructor(public network: Network, public relayer: Relayer) { + public constants; + + constructor( + public network: Network, + public relayer: Relayer, + private from: Pool + ) { if (!(network === Network.MAINNET || network === Network.GOERLI)) throw new Error('This is not a supported network'); @@ -140,28 +137,32 @@ export class MigrateStaBal3 { this.network === Network.MAINNET ? CONSTANTS.Mainnet : CONSTANTS.Goerli; } + /** + * Is using gauge relayer to withdraw staked BPT from user to itself + * + * @returns withdraw call + */ buildWithdraw(migrator: string, amount: string): GaugeWithDraw { - /* - a) relayer uses allowance to transfer staked bpt from user to itself - b) relayer returns staked bpt to get bpt back - (steps a) and b) are done automatically by the relayer) - TO DO - - See relayer GaugeActions.sol - Encode gaugeWithdraw - GaugeActions gaugeWithdraw( - IStakingLiquidityGauge gauge, - address sender, - address recipient, - uint256 amount - ) - gaugeWithdraw( - this.constants.staBal3Gauge, - migrator, - this.constants.relayer, - amount - ); - */ - return ''; + return gaugeActionsInterface.encodeFunctionData('gaugeWithdraw', [ + this.constants.staBal3.gauge, + migrator, + this.constants.relayer, + amount, + ]); + } + + /** + * Is using gauge relayer to deposit user's BPT to itself + * + * @returns deposit call + */ + buildDeposit(migrator: string, amount: OutputReference): GaugeDeposit { + return gaugeActionsInterface.encodeFunctionData('gaugeDeposit', [ + this.constants.bbausd2.gauge, + this.constants.relayer, + migrator, + amount, + ]); } /** @@ -235,7 +236,7 @@ export class MigrateStaBal3 { poolId: this.constants.linearDai1.id, assetInIndex: 0, assetOutIndex: 1, - amount: outputReferences[0].key.toString(), + amount: outputReferences[0].key.toString(), // exitPool amount of DAI subpool.. userData: '0x', }, { @@ -256,7 +257,7 @@ export class MigrateStaBal3 { poolId: this.constants.linearUsdc1.id, assetInIndex: 3, assetOutIndex: 4, - amount: outputReferences[1].key.toString(), + amount: outputReferences[1].key.toString(), // exitPool amount of DAI subpool.. userData: '0x', }, { @@ -277,7 +278,7 @@ export class MigrateStaBal3 { poolId: this.constants.linearUsdt1.id, assetInIndex: 6, assetOutIndex: 7, - amount: outputReferences[2].key.toString(), + amount: outputReferences[2].key.toString(), // exitPool amount of DAI subpool.. userData: '0x', }, { @@ -360,30 +361,6 @@ export class MigrateStaBal3 { }; } - buildDeposit(migrator: string, bptAmount: OutputReference): GaugeDeposit { - /* - f) relayer stakes bb-a-usd-bpt - g) relayer sends staked bpt to user - (steps f) and g) are done automatically by the relayer) - TO DO - - Encode gaugeDeposit - GaugeActions gaugeDeposit( - IStakingLiquidityGauge gauge, - address sender, - address recipient, - uint256 amount - ) - Uses chainedReference from previous action for amount - gaugeDeposit( - this.constants.bbausd2Gauge, - this.constants.relayer, - migrator, - bptAmount - ) - */ - return ''; - } - buildMigration( migrator: string, amount: string, From e07c8cad5f233dc491b457197fbe16c10db0069d Mon Sep 17 00:00:00 2001 From: bronco Date: Wed, 20 Jul 2022 14:08:56 +0200 Subject: [PATCH 007/104] wip - lint fixes --- balancer-js/src/modules/zaps/migrateStaBal3.ts | 4 ++-- balancer-js/src/modules/zaps/zaps.module.ts | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/balancer-js/src/modules/zaps/migrateStaBal3.ts b/balancer-js/src/modules/zaps/migrateStaBal3.ts index d5e2ce030..42868f2f9 100644 --- a/balancer-js/src/modules/zaps/migrateStaBal3.ts +++ b/balancer-js/src/modules/zaps/migrateStaBal3.ts @@ -1,7 +1,7 @@ import { Contract } from '@ethersproject/contracts'; import { defaultAbiCoder, Interface } from '@ethersproject/abi'; import { MaxUint256 } from '@ethersproject/constants'; -import { ExitPoolRequest } from '@/types'; +import { Pool, ExitPoolRequest } from '@/types'; import { Network } from '@/lib/constants/network'; import { Relayer, OutputReference } from '../relayer/relayer.module'; import { StablePoolEncoder } from '@/pool-stable'; @@ -294,7 +294,7 @@ export class MigrateStaBal3 { assetOutIndex: 3, amount: '0', userData: '0x', - } + }, ]; const assets = [ this.constants.linearDai1.address, diff --git a/balancer-js/src/modules/zaps/zaps.module.ts b/balancer-js/src/modules/zaps/zaps.module.ts index 275d9d183..450e2c79f 100644 --- a/balancer-js/src/modules/zaps/zaps.module.ts +++ b/balancer-js/src/modules/zaps/zaps.module.ts @@ -2,6 +2,7 @@ import { Network } from '@/lib/constants/network'; import { MigrateStaBal3, MigrationAttributes } from './migrateStaBal3'; import { Relayer } from '../relayer/relayer.module'; import { JsonRpcProvider } from '@ethersproject/providers'; +import { Pool } from '@/types'; /** TO DOS @@ -13,21 +14,23 @@ export class Zaps { constructor(public network: Network, public relayer: Relayer) {} async queryMigrateStaBal3( + staBal3: Pool, migrator: string, amount: string, provider: JsonRpcProvider ): Promise { - const migrate = new MigrateStaBal3(this.network, this.relayer); + const migrate = new MigrateStaBal3(this.network, this.relayer, staBal3); return await migrate.queryMigration(migrator, amount, provider); } migrateStaBal3( + staBal3: Pool, migrator: string, amount: string, expectedBptReturn: string, slippage: string ): MigrationAttributes { - const migrate = new MigrateStaBal3(this.network, this.relayer); + const migrate = new MigrateStaBal3(this.network, this.relayer, staBal3); return migrate.buildMigration( migrator, amount, From 10a3257ea5d8ec51575b6369a1ce8e5a03e2b3a2 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 20 Jul 2022 16:31:40 -0300 Subject: [PATCH 008/104] Add integration test setup --- .../zaps/zaps.module.integration.spec.ts | 88 +++++++++++++++++++ balancer-js/src/test/lib/utils.ts | 33 ++++--- 2 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 balancer-js/src/modules/zaps/zaps.module.integration.spec.ts diff --git a/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts b/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts new file mode 100644 index 000000000..8f8bf8f32 --- /dev/null +++ b/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts @@ -0,0 +1,88 @@ +import dotenv from 'dotenv'; +import { expect } from 'chai'; +import { BalancerSDK, BalancerSdkConfig, Network, Relayer } from '@/.'; +import hardhat from 'hardhat'; + +import { BigNumber, parseFixed } from '@ethersproject/bignumber'; + +import { forkSetup } from '@/test/lib/utils'; +import { Zaps } from './zaps.module'; + +/* + * Testing on GOERLI + * + * Run goerli node using the following terminal command line: + * npx hardhat node --fork [GOERLI_ALCHEMY_URL] + * + * Change `network` to Network.GOERLI + */ + +dotenv.config(); + +const { ALCHEMY_URL: jsonRpcUrl } = process.env; +const { ethers } = hardhat; + +let balancer: BalancerSDK; +const network = Network.GOERLI; +const rpcUrl = 'http://127.0.0.1:8545'; +const sdkConfig: BalancerSdkConfig = { + network, + rpcUrl, +}; +const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); +const signer = provider.getSigner(); + +const gaugeSlots = [1]; // Info fetched using npm package slot20 + +// Goerli +const gaugeAddresses = ['0xf0f572ad66baacDd07d8c7ea3e0E5EFA56a76081']; // Balancer B-50WBTC-50WETH Gauge Deposit +// Mainnet +// const gaugeAddresses = ['0x68d019f64a7aa97e2d4e7363aee42251d08124fb']; // Balancer bb-a-USD Gauge Deposit + +const initialBalance = '1000'; +let signerAddress: string; + +// Setup + +const tokenBalance = async (tokenAddress: string) => { + const balance: Promise = balancer.contracts + .ERC20(tokenAddress, signer.provider) + .balanceOf(signerAddress); + return balance; +}; + +const updateBalances = async (addresses: string[]) => { + const balances = []; + for (let i = 0; i < addresses.length; i++) { + balances[i] = tokenBalance(addresses[i]); + } + return Promise.all(balances); +}; + +// Test Scenarios + +describe('zaps execution', async () => { + before(async function () { + this.timeout(20000); + balancer = new BalancerSDK(sdkConfig); + + const isVyperMapping = true; // required for gauge tokens + await forkSetup( + balancer, + signer, + gaugeAddresses, + gaugeSlots, + [parseFixed(initialBalance, 18).toString()], + jsonRpcUrl as string, + isVyperMapping + ); + signerAddress = await signer.getAddress(); + }); + + it('should update balances', async () => { + const balances = await updateBalances(gaugeAddresses); + for (let i = 0; i < balances.length; i++) { + expect(balances[i].eq(parseFixed(initialBalance, 18))).to.be.true; + } + }); +}).timeout(20000); diff --git a/balancer-js/src/test/lib/utils.ts b/balancer-js/src/test/lib/utils.ts index f617c75cf..55f17333f 100644 --- a/balancer-js/src/test/lib/utils.ts +++ b/balancer-js/src/test/lib/utils.ts @@ -1,5 +1,5 @@ import { BalancerSDK } from '@/.'; -import { JsonRpcProvider, JsonRpcSigner } from '@ethersproject/providers'; +import { JsonRpcSigner } from '@ethersproject/providers'; import { BigNumber } from '@ethersproject/bignumber'; import { balancerVault } from '@/lib/constants/config'; import { hexlify, zeroPad } from '@ethersproject/bytes'; @@ -7,14 +7,15 @@ import { keccak256 } from '@ethersproject/solidity'; export const forkSetup = async ( balancer: BalancerSDK, - provider: JsonRpcProvider, + signer: JsonRpcSigner, // it's safer to use signer than provider for this tokens: string[], slots: number[], balances: string[], jsonRpcUrl: string, + isVyperMapping = false, blockNumber?: number ): Promise => { - await provider.send('hardhat_reset', [ + await signer.provider.send('hardhat_reset', [ { forking: { jsonRpcUrl, @@ -26,13 +27,14 @@ export const forkSetup = async ( for (let i = 0; i < tokens.length; i++) { // Set initial account balance for each token that will be used to join pool await setTokenBalance( - provider.getSigner(), + signer, tokens[i], slots[i], - balances[i] + balances[i], + isVyperMapping ); // Approve appropriate allowances so that vault contract can move tokens - await approveToken(balancer, tokens[i], balances[i], provider.getSigner()); + await approveToken(balancer, tokens[i], balances[i], signer); } }; @@ -48,7 +50,8 @@ export const setTokenBalance = async ( signer: JsonRpcSigner, token: string, slot: number, - balance: string + balance: string, + isVyperMapping = false ): Promise => { const toBytes32 = (bn: BigNumber) => { return hexlify(zeroPad(bn.toHexString(), 32)); @@ -62,10 +65,18 @@ export const setTokenBalance = async ( const signerAddress = await signer.getAddress(); // Get storage slot index - const index = keccak256( - ['uint256', 'uint256'], - [signerAddress, slot] // key, slot - ); + let index; + if (isVyperMapping) { + index = keccak256( + ['uint256', 'uint256'], + [slot, signerAddress] // slot, key + ); + } else { + index = keccak256( + ['uint256', 'uint256'], + [signerAddress, slot] // key, slot + ); + } // Manipulate local balance (needs to be bytes32 string) await setStorageAt( From a358b6e0bfd63c448fcaad91c2f275d3348ca2c2 Mon Sep 17 00:00:00 2001 From: bronco Date: Thu, 21 Jul 2022 10:56:18 +0200 Subject: [PATCH 009/104] adding new batch relayer abi --- .../src/lib/abi/BatchRelayerLibrary.json | 1011 +++++++++++++++++ balancer-js/src/lib/abi/VaultActions.json | 428 ------- .../src/modules/relayer/relayer.module.ts | 36 +- .../modules/swaps/swap_builder/swap_utils.ts | 6 +- 4 files changed, 1045 insertions(+), 436 deletions(-) create mode 100644 balancer-js/src/lib/abi/BatchRelayerLibrary.json delete mode 100644 balancer-js/src/lib/abi/VaultActions.json diff --git a/balancer-js/src/lib/abi/BatchRelayerLibrary.json b/balancer-js/src/lib/abi/BatchRelayerLibrary.json new file mode 100644 index 000000000..ca1953a4c --- /dev/null +++ b/balancer-js/src/lib/abi/BatchRelayerLibrary.json @@ -0,0 +1,1011 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "wstETH", + "type": "address" + }, + { + "internalType": "contract IBalancerMinter", + "name": "minter", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approveVault", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum IVault.SwapKind", + "name": "kind", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "assetInIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "assetOutIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IVault.BatchSwapStep[]", + "name": "swaps", + "type": "tuple[]" + }, + { + "internalType": "contract IAsset[]", + "name": "assets", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bool", + "name": "fromInternalBalance", + "type": "bool" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "internalType": "bool", + "name": "toInternalBalance", + "type": "bool" + } + ], + "internalType": "struct IVault.FundManagement", + "name": "funds", + "type": "tuple" + }, + { + "internalType": "int256[]", + "name": "limits", + "type": "int256[]" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "key", + "type": "uint256" + } + ], + "internalType": "struct VaultActions.OutputReference[]", + "name": "outputReferences", + "type": "tuple[]" + } + ], + "name": "batchSwap", + "outputs": [ + { + "internalType": "int256[]", + "name": "", + "type": "int256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "enum VaultActions.PoolKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IAsset[]", + "name": "assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "toInternalBalance", + "type": "bool" + } + ], + "internalType": "struct IVault.ExitPoolRequest", + "name": "request", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "key", + "type": "uint256" + } + ], + "internalType": "struct VaultActions.OutputReference[]", + "name": "outputReferences", + "type": "tuple[]" + } + ], + "name": "exitPool", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IStakingLiquidityGauge[]", + "name": "gauges", + "type": "address[]" + } + ], + "name": "gaugeClaimRewards", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IStakingLiquidityGauge", + "name": "gauge", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "gaugeDeposit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "gauges", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "gaugeMint", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "approval", + "type": "bool" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "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": "gaugeSetMinterApproval", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IStakingLiquidityGauge", + "name": "gauge", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "gaugeWithdraw", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "getEntrypoint", + "outputs": [ + { + "internalType": "contract IBalancerRelayer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "enum VaultActions.PoolKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IAsset[]", + "name": "assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "maxAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "fromInternalBalance", + "type": "bool" + } + ], + "internalType": "struct IVault.JoinPoolRequest", + "name": "request", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "joinPool", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum IVault.UserBalanceOpKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "contract IAsset", + "name": "asset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + } + ], + "internalType": "struct IVault.UserBalanceOp[]", + "name": "ops", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "manageUserBalance", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "relayer", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "authorisation", + "type": "bytes" + } + ], + "name": "setRelayerApproval", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "stakeETH", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "stakeETHAndWrap", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "enum IVault.SwapKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "contract IAsset", + "name": "assetIn", + "type": "address" + }, + { + "internalType": "contract IAsset", + "name": "assetOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IVault.SingleSwap", + "name": "singleSwap", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bool", + "name": "fromInternalBalance", + "type": "bool" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "internalType": "bool", + "name": "toInternalBalance", + "type": "bool" + } + ], + "internalType": "struct IVault.FundManagement", + "name": "funds", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "swap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IStaticATokenLM", + "name": "staticToken", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "toUnderlying", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "unwrapAaveStaticToken", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "unwrapERC4626", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IUnbuttonToken", + "name": "wrapperToken", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "unwrapUnbuttonToken", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "unwrapWstETH", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20Permit", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "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": "vaultPermit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20PermitDAI", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "allowed", + "type": "bool" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "vaultPermitDAI", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IStaticATokenLM", + "name": "staticToken", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "fromUnderlying", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "wrapAaveDynamicToken", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC4626", + "name": "wrappedToken", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "wrapERC4626", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "wrapStETH", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IUnbuttonToken", + "name": "wrapperToken", + "type": "address" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "uAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputReference", + "type": "uint256" + } + ], + "name": "wrapUnbuttonToken", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } +] \ No newline at end of file diff --git a/balancer-js/src/lib/abi/VaultActions.json b/balancer-js/src/lib/abi/VaultActions.json deleted file mode 100644 index e8e007a1e..000000000 --- a/balancer-js/src/lib/abi/VaultActions.json +++ /dev/null @@ -1,428 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "contract IERC20", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approveVault", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "enum IVault.SwapKind", - "name": "kind", - "type": "uint8" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "poolId", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "assetInIndex", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "assetOutIndex", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "userData", - "type": "bytes" - } - ], - "internalType": "struct IVault.BatchSwapStep[]", - "name": "swaps", - "type": "tuple[]" - }, - { - "internalType": "contract IAsset[]", - "name": "assets", - "type": "address[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "bool", - "name": "fromInternalBalance", - "type": "bool" - }, - { - "internalType": "address payable", - "name": "recipient", - "type": "address" - }, - { - "internalType": "bool", - "name": "toInternalBalance", - "type": "bool" - } - ], - "internalType": "struct IVault.FundManagement", - "name": "funds", - "type": "tuple" - }, - { - "internalType": "int256[]", - "name": "limits", - "type": "int256[]" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "index", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "key", - "type": "uint256" - } - ], - "internalType": "struct VaultActions.OutputReference[]", - "name": "outputReferences", - "type": "tuple[]" - } - ], - "name": "batchSwap", - "outputs": [ - { - "internalType": "int256[]", - "name": "", - "type": "int256[]" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "poolId", - "type": "bytes32" - }, - { - "internalType": "enum VaultActions.PoolKind", - "name": "kind", - "type": "uint8" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address payable", - "name": "recipient", - "type": "address" - }, - { - "components": [ - { - "internalType": "contract IAsset[]", - "name": "assets", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "minAmountsOut", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "userData", - "type": "bytes" - }, - { - "internalType": "bool", - "name": "toInternalBalance", - "type": "bool" - } - ], - "internalType": "struct IVault.ExitPoolRequest", - "name": "request", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "index", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "key", - "type": "uint256" - } - ], - "internalType": "struct VaultActions.OutputReference[]", - "name": "outputReferences", - "type": "tuple[]" - } - ], - "name": "exitPool", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "getVault", - "outputs": [ - { - "internalType": "contract IVault", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "poolId", - "type": "bytes32" - }, - { - "internalType": "enum VaultActions.PoolKind", - "name": "kind", - "type": "uint8" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "components": [ - { - "internalType": "contract IAsset[]", - "name": "assets", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "maxAmountsIn", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "userData", - "type": "bytes" - }, - { - "internalType": "bool", - "name": "fromInternalBalance", - "type": "bool" - } - ], - "internalType": "struct IVault.JoinPoolRequest", - "name": "request", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "outputReference", - "type": "uint256" - } - ], - "name": "joinPool", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "enum IVault.UserBalanceOpKind", - "name": "kind", - "type": "uint8" - }, - { - "internalType": "contract IAsset", - "name": "asset", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address payable", - "name": "recipient", - "type": "address" - } - ], - "internalType": "struct IVault.UserBalanceOp[]", - "name": "ops", - "type": "tuple[]" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "manageUserBalance", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "poolId", - "type": "bytes32" - }, - { - "internalType": "enum IVault.SwapKind", - "name": "kind", - "type": "uint8" - }, - { - "internalType": "contract IAsset", - "name": "assetIn", - "type": "address" - }, - { - "internalType": "contract IAsset", - "name": "assetOut", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "userData", - "type": "bytes" - } - ], - "internalType": "struct IVault.SingleSwap", - "name": "singleSwap", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "bool", - "name": "fromInternalBalance", - "type": "bool" - }, - { - "internalType": "address payable", - "name": "recipient", - "type": "address" - }, - { - "internalType": "bool", - "name": "toInternalBalance", - "type": "bool" - } - ], - "internalType": "struct IVault.FundManagement", - "name": "funds", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "limit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "outputReference", - "type": "uint256" - } - ], - "name": "swap", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - } -] diff --git a/balancer-js/src/modules/relayer/relayer.module.ts b/balancer-js/src/modules/relayer/relayer.module.ts index e5086fff2..ad37dc543 100644 --- a/balancer-js/src/modules/relayer/relayer.module.ts +++ b/balancer-js/src/modules/relayer/relayer.module.ts @@ -21,9 +21,11 @@ import { } from '../swaps/types'; import { SubgraphPoolBase } from '@balancer-labs/sor'; -import relayerLibraryAbi from '@/lib/abi/VaultActions.json'; +import relayerLibraryAbi from '@/lib/abi/BatchRelayerLibrary.json'; import aaveWrappingAbi from '@/lib/abi/AaveWrapping.json'; +const relayerLibrary = new Interface(relayerLibraryAbi); + export * from './types'; export class Relayer { @@ -39,9 +41,35 @@ export class Relayer { } } - static encodeBatchSwap(params: EncodeBatchSwapInput): string { - const relayerLibrary = new Interface(relayerLibraryAbi); + static encodeGaugeWithdraw( + gaugeAddress: string, + sender: string, + recipient: string, + amount: string + ): string { + return relayerLibrary.encodeFunctionData('gaugeDeposit', [ + gaugeAddress, + sender, + recipient, + amount, + ]); + } + static encodeGaugeDeposit( + gaugeAddress: string, + sender: string, + recipient: string, + amount: string + ): string { + return relayerLibrary.encodeFunctionData('gaugeDeposit', [ + gaugeAddress, + sender, + recipient, + amount, + ]); + } + + static encodeBatchSwap(params: EncodeBatchSwapInput): string { return relayerLibrary.encodeFunctionData('batchSwap', [ params.swapType, params.swaps, @@ -55,8 +83,6 @@ export class Relayer { } static encodeExitPool(params: EncodeExitPoolInput): string { - const relayerLibrary = new Interface(relayerLibraryAbi); - return relayerLibrary.encodeFunctionData('exitPool', [ params.poolId, params.poolKind, 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 a244d785e..21c9880e4 100644 --- a/balancer-js/src/modules/swaps/swap_builder/swap_utils.ts +++ b/balancer-js/src/modules/swaps/swap_builder/swap_utils.ts @@ -1,5 +1,5 @@ import { Vault__factory } from '@balancer-labs/typechain'; -import vaultActionsAbi from '@/lib/abi/VaultActions.json'; +import BatchRelayerLibraryAbi from '@/lib/abi/BatchRelayerLibrary.json'; import { JsonFragment } from '@ethersproject/abi'; import { networkAddresses } from '@/lib/constants/config'; @@ -86,7 +86,7 @@ function relayerResolver( function swapFragment(relayer: SwapRelayer): JsonFragment[] { let source = Vault__factory.abi; - if (relayer.id === Relayers.lido) source = vaultActionsAbi; + if (relayer.id === Relayers.lido) source = BatchRelayerLibraryAbi; const signatures = source.filter( (fn) => fn.name && ['swap', 'batchSwap'].includes(fn.name) @@ -103,7 +103,7 @@ function batchSwapFragment( const vaultSignaturesForSwaps = Vault__factory.abi.filter( (fn) => fn.name && ['batchSwap'].includes(fn.name) ); - const relayerSignaturesForSwaps = vaultActionsAbi.filter( + const relayerSignaturesForSwaps = BatchRelayerLibraryAbi.filter( (fn) => fn.name && ['batchSwap'].includes(fn.name) ); let returnSignatures = vaultSignaturesForSwaps; From fca4de752a0544cf3fd3b4e121fea5e53de18503 Mon Sep 17 00:00:00 2001 From: bronco Date: Thu, 21 Jul 2022 10:59:08 +0200 Subject: [PATCH 010/104] fix name in gaugeWithdraw --- balancer-js/src/modules/relayer/relayer.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balancer-js/src/modules/relayer/relayer.module.ts b/balancer-js/src/modules/relayer/relayer.module.ts index ad37dc543..7618b4373 100644 --- a/balancer-js/src/modules/relayer/relayer.module.ts +++ b/balancer-js/src/modules/relayer/relayer.module.ts @@ -47,7 +47,7 @@ export class Relayer { recipient: string, amount: string ): string { - return relayerLibrary.encodeFunctionData('gaugeDeposit', [ + return relayerLibrary.encodeFunctionData('gaugeWithdraw', [ gaugeAddress, sender, recipient, From 82355f684306f318ed3f26137b2d9d7cc56da325 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 21 Jul 2022 12:02:49 -0300 Subject: [PATCH 011/104] Add extra instruction steps for testing on goerli --- .../modules/zaps/zaps.module.integration.spec.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts b/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts index 8f8bf8f32..f6ac7774c 100644 --- a/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts +++ b/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts @@ -10,11 +10,11 @@ import { Zaps } from './zaps.module'; /* * Testing on GOERLI - * - * Run goerli node using the following terminal command line: - * npx hardhat node --fork [GOERLI_ALCHEMY_URL] - * - * Change `network` to Network.GOERLI + * - Update hardhat.config.js with chainId = 5 + * - Update ALCHEMY_URL on .env with a goerli api key + * - Run goerli node on terminal: npx hardhat node --fork [ALCHEMY_URL] + * - Change `network` to Network.GOERLI + * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli */ dotenv.config(); @@ -23,7 +23,7 @@ const { ALCHEMY_URL: jsonRpcUrl } = process.env; const { ethers } = hardhat; let balancer: BalancerSDK; -const network = Network.GOERLI; +const network = Network.MAINNET; const rpcUrl = 'http://127.0.0.1:8545'; const sdkConfig: BalancerSdkConfig = { network, @@ -35,9 +35,9 @@ const signer = provider.getSigner(); const gaugeSlots = [1]; // Info fetched using npm package slot20 // Goerli -const gaugeAddresses = ['0xf0f572ad66baacDd07d8c7ea3e0E5EFA56a76081']; // Balancer B-50WBTC-50WETH Gauge Deposit +// const gaugeAddresses = ['0xf0f572ad66baacDd07d8c7ea3e0E5EFA56a76081']; // Balancer B-50WBTC-50WETH Gauge Deposit // Mainnet -// const gaugeAddresses = ['0x68d019f64a7aa97e2d4e7363aee42251d08124fb']; // Balancer bb-a-USD Gauge Deposit +const gaugeAddresses = ['0x68d019f64a7aa97e2d4e7363aee42251d08124fb']; // Balancer bb-a-USD Gauge Deposit const initialBalance = '1000'; let signerAddress: string; From a0017bc6b7c228fd464b8604b2e743bc5a808484 Mon Sep 17 00:00:00 2001 From: bronco Date: Thu, 21 Jul 2022 17:58:17 +0200 Subject: [PATCH 012/104] wip: stabal3 basic flow still missing approvals --- .../zaps/bbausd2-migrations/addresses.ts | 92 ++++ .../zaps/bbausd2-migrations/bbausd1.ts | 0 .../zaps/bbausd2-migrations/stabal3.ts | 220 +++++++++ .../src/modules/zaps/migrateStaBal3.ts | 424 +----------------- 4 files changed, 330 insertions(+), 406 deletions(-) create mode 100644 balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts create mode 100644 balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts create mode 100644 balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts new file mode 100644 index 000000000..069f342b0 --- /dev/null +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -0,0 +1,92 @@ +export const ADDRESSES = { + 1: { + relayer: 'TODO', + staBal3: { + id: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063', + address: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42', + gauge: '0x34f33cdaed8ba0e1ceece80e5f4a73bcf234cfac', + }, + bbausd1: { + id: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb20000000000000000000000fe', + address: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb2', + gauge: '0x68d019f64a7aa97e2d4e7363aee42251d08124fb', + }, + bbausd2: { + id: '', + address: '', + gauge: '', + }, + linearUsdc1: { + id: '', + address: 'N/A', + }, + linearDai1: { + id: '', + address: 'N/A', + }, + linearUsdt1: { + id: '', + address: 'N/A', + }, + linearUsdc2: { + id: '', + address: 'N/A', + }, + linearDai2: { + id: '', + address: 'N/A', + }, + linearUsdt2: { + id: '', + address: 'N/A', + }, + DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', + USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + }, + 5: { + relayer: '0x7b9B6f094DC2Bd1c12024b0D9CC63d6993Be1888', + staBal3: { + id: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063', + address: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42', + gauge: '0x34f33cdaed8ba0e1ceece80e5f4a73bcf234cfac', + }, + bbausd1: { + id: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb20000000000000000000000fe', + address: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb2', + gauge: '0x68d019f64a7aa97e2d4e7363aee42251d08124fb', + }, + bbausd2: { + id: '', + address: '', + gauge: '', + }, + linearUsdc1: { + id: '', + address: 'N/A', + }, + linearDai1: { + id: '', + address: 'N/A', + }, + linearUsdt1: { + id: '', + address: 'N/A', + }, + linearUsdc2: { + id: '', + address: 'N/A', + }, + linearDai2: { + id: '', + address: 'N/A', + }, + linearUsdt2: { + id: '', + address: 'N/A', + }, + DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', + USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + }, +}; diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts new file mode 100644 index 000000000..e69de29bb diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts new file mode 100644 index 000000000..d78483712 --- /dev/null +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -0,0 +1,220 @@ +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 { MaxUint256 } from '@ethersproject/constants'; +// TO DO - Ask Nico to update Typechain? +import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; +const balancerRelayerInterface = new Interface(balancerRelayerAbi); + +const EXIT_DAI = Relayer.toChainedReference('exit_dai'); +const EXIT_USDC = Relayer.toChainedReference('exit_usdc'); +const EXIT_USDT = Relayer.toChainedReference('exit_usdt'); +const SWAP_RESULT_BBAUSD = Relayer.toChainedReference('swap_result_bbausd'); + +export class StaBal3Builder { + private addresses; + + constructor(networkId: 1 | 5) { + this.addresses = ADDRESSES[networkId]; + } + + calldata( + amount: string, + expectedAmount: string, + userAddress: string, + staked: boolean + ): { + to: string; + data: string; + } { + let calls = [ + this.buildExit(userAddress, amount), + this.buildSwap(expectedAmount), + ]; + + if (staked) { + calls = [ + this.buildWithdraw(userAddress, amount), + ...calls, + this.buildDeposit(userAddress), + ]; + } + + const callData = balancerRelayerInterface.encodeFunctionData( + 'multicall', + calls + ); + + return { + to: this.addresses.relayer, + data: callData, + }; + } + + /** + * Encodes exitPool callData. + * Exit staBal3 pool proportionally to underlying Linear BPTs. Exits to relayer. + * Outputreferences are used to store exit amounts for next transaction. + * + * @param migrator Migrator address. + * @param amount Amount of staBal3 BPT to exit with. + * @returns Encoded exitPool call. Output references. + */ + buildExit(migrator: string, amount: string): string { + // Assume gaugeWithdraw returns same amount value + const userData = StablePoolEncoder.exitExactBPTInForTokensOut(amount); + + // TO DO - Tokens have to be in correct order - might not be. + // UPDATE: checked PoolBalanceChanged events after exit in etherscan, order checks out for all the transactions + const assets = [ + this.addresses.DAI, + this.addresses.USDC, + this.addresses.USDT, + ]; + + // Ask to store exit outputs for batchSwap of exit is used as input to swaps + const outputReferences = [ + { index: 0, key: EXIT_DAI }, + { index: 1, key: EXIT_USDC }, + { index: 2, key: EXIT_USDT }, + ]; + + const callData = Relayer.constructExitCall({ + assets, + minAmountsOut: ['0', '0', '0'], + userData, + toInternalBalance: false, + poolId: this.addresses.staBal3.id, + poolKind: 0, // This will always be 0 to match supported Relayer types + sender: migrator, + recipient: this.addresses.relayer, + outputReferences, + exitPoolRequest: {} as ExitPoolRequest, + }); + + return callData; + } + + /** + * Creates encoded batchSwap function to swap Linear BPTs to underlying stables. + * outputreferences should contain the amounts of each new Linear BPT. + * + * @returns BatchSwap call. + */ + buildSwap(expectedBptReturn: string): string { + const assets = [ + this.addresses.DAI, + this.addresses.linearDai2.address, + this.addresses.USDC, + this.addresses.linearUsdc2.address, + this.addresses.USDT, + this.addresses.linearUsdt2.address, + this.addresses.bbausd2.address, + ]; + + const outputReferences = [{ index: 6, 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: 0, + assetOutIndex: 1, + amount: EXIT_DAI.toString(), + userData: '0x', + }, + { + poolId: this.addresses.bbausd2.id, + assetInIndex: 1, + assetOutIndex: 6, + amount: '0', + userData: '0x', + }, + { + poolId: this.addresses.linearUsdc2.id, + assetInIndex: 2, + assetOutIndex: 3, + amount: EXIT_USDC.toString(), + userData: '0x', + }, + { + poolId: this.addresses.bbausd2.id, + assetInIndex: 3, + assetOutIndex: 6, + amount: '0', + userData: '0x', + }, + { + poolId: this.addresses.linearUsdt2.id, + assetInIndex: 4, + assetOutIndex: 5, + amount: EXIT_USDT.toString(), + userData: '0x', + }, + { + poolId: this.addresses.bbausd2.id, + assetInIndex: 5, + assetOutIndex: 6, + amount: '0', + userData: '0x', + }, + ]; + + // For now assuming ref amounts will be safe - should we add more accurate? + const limits = ['0', '0', '0', '0', '0', '0', expectedBptReturn.toString()]; + + // Swap to/from Relayer + const funds: FundManagement = { + sender: this.addresses.relayer, + recipient: this.addresses.relayer, + fromInternalBalance: false, + toInternalBalance: false, + }; + + const encodedBatchSwap = Relayer.encodeBatchSwap({ + swapType: SwapType.SwapExactIn, + swaps, + assets, + funds, + limits, + deadline: MaxUint256, + value: '0', + outputReferences, + }); + + return encodedBatchSwap; + } + + /** + * Is using gauge relayer to withdraw staked BPT from user to itself + * + * @returns withdraw call + */ + buildWithdraw(migrator: string, amount: string): string { + return Relayer.encodeGaugeWithdraw( + this.addresses.staBal3.gauge, + migrator, + this.addresses.relayer, + amount + ); + } + + /** + * Is using gauge relayer to deposit user's BPT to itself + * + * @returns deposit call + */ + buildDeposit(migrator: string): string { + return Relayer.encodeGaugeDeposit( + this.addresses.bbausd2.gauge, + this.addresses.relayer, + migrator, + SWAP_RESULT_BBAUSD.toString() + ); + } +} diff --git a/balancer-js/src/modules/zaps/migrateStaBal3.ts b/balancer-js/src/modules/zaps/migrateStaBal3.ts index 42868f2f9..e6b63017b 100644 --- a/balancer-js/src/modules/zaps/migrateStaBal3.ts +++ b/balancer-js/src/modules/zaps/migrateStaBal3.ts @@ -1,373 +1,15 @@ -import { Contract } from '@ethersproject/contracts'; -import { defaultAbiCoder, Interface } from '@ethersproject/abi'; -import { MaxUint256 } from '@ethersproject/constants'; -import { Pool, ExitPoolRequest } from '@/types'; -import { Network } from '@/lib/constants/network'; -import { Relayer, OutputReference } from '../relayer/relayer.module'; -import { StablePoolEncoder } from '@/pool-stable'; -import { SwapType, FundManagement, BatchSwapStep } from '../swaps/types'; - -// TO DO - Ask Nico to update Typechain? -import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; -import { JsonRpcProvider } from '@ethersproject/providers'; - -export const gaugeActionsInterface = new Interface([ - 'function gaugeDeposit(address gauge, address sender, address recipient, uint amount) payable', - 'function gaugeWithdraw(address gauge, address sender, address recipient, uint amount) payable', -]); - -export const CONSTANTS = { - Mainnet: { - relayer: 'TODO', - staBal3: { - id: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063', - address: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42', - gauge: '0x34f33cdaed8ba0e1ceece80e5f4a73bcf234cfac', - }, - bbausd1: { - id: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb20000000000000000000000fe', - address: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb2', - gauge: '0x68d019f64a7aa97e2d4e7363aee42251d08124fb', - }, - bbausd2: { - id: '', - address: '', - gauge: '', - }, - linearUsdc1: { - id: '', - address: 'N/A', - }, - linearDai1: { - id: '', - address: 'N/A', - }, - linearUsdt1: { - id: '', - address: 'N/A', - }, - linearUsdc2: { - id: '', - address: 'N/A', - }, - linearDai2: { - id: '', - address: 'N/A', - }, - linearUsdt2: { - id: '', - address: 'N/A', - }, - DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', - USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', - }, - Goerli: { - relayer: 'TODO', - staBal3: { - id: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063', - address: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42', - gauge: '0x34f33cdaed8ba0e1ceece80e5f4a73bcf234cfac', - }, - bbausd1: { - id: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb20000000000000000000000fe', - address: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb2', - gauge: '0x68d019f64a7aa97e2d4e7363aee42251d08124fb', - }, - bbausd2: { - id: '', - address: '', - gauge: '', - }, - linearUsdc1: { - id: '', - address: 'N/A', - }, - linearDai1: { - id: '', - address: 'N/A', - }, - linearUsdt1: { - id: '', - address: 'N/A', - }, - linearUsdc2: { - id: '', - address: 'N/A', - }, - linearDai2: { - id: '', - address: 'N/A', - }, - linearUsdt2: { - id: '', - address: 'N/A', - }, - DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', - USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', - }, -}; - -type GaugeWithDraw = string; -type ExitPool = string; -type BatchSwap = string; -type GaugeDeposit = string; - -type CallData = [GaugeWithDraw, ExitPool, BatchSwap, GaugeDeposit]; - -export interface MigrationAttributes { - to: string; - functionName: string; - calldata: CallData; -} +import { defaultAbiCoder } from '@ethersproject/abi'; +import { Provider } from '@ethersproject/providers'; +import { StaBal3Builder } from './bbausd2-migrations/stabal3'; export class MigrateStaBal3 { - public constants; - - constructor( - public network: Network, - public relayer: Relayer, - private from: Pool - ) { - if (!(network === Network.MAINNET || network === Network.GOERLI)) - throw new Error('This is not a supported network'); - - this.constants = - this.network === Network.MAINNET ? CONSTANTS.Mainnet : CONSTANTS.Goerli; - } - - /** - * Is using gauge relayer to withdraw staked BPT from user to itself - * - * @returns withdraw call - */ - buildWithdraw(migrator: string, amount: string): GaugeWithDraw { - return gaugeActionsInterface.encodeFunctionData('gaugeWithdraw', [ - this.constants.staBal3.gauge, - migrator, - this.constants.relayer, - amount, - ]); - } + private builder: StaBal3Builder; - /** - * Is using gauge relayer to deposit user's BPT to itself - * - * @returns deposit call - */ - buildDeposit(migrator: string, amount: OutputReference): GaugeDeposit { - return gaugeActionsInterface.encodeFunctionData('gaugeDeposit', [ - this.constants.bbausd2.gauge, - this.constants.relayer, - migrator, - amount, - ]); + constructor(private network: 1 | 5, private provider: Provider) { + this.builder = new StaBal3Builder(network); } - /** - * Creates encoded exitPool function. - * Exit staBal3 pool proportionally to underlying Linear BPTs. Exits to relayer. - * Outputreferences are used to store exit amounts for next transaction. - * @param migrator Migrator address. - * @param amount Amount of staBal3 BPT to exit with. - * @returns Encoded exitPool call. Output references. - */ - buildPoolExit( - migrator: string, - amount: string - ): { call: ExitPool; oldLinearAmountsReferences: OutputReference[] } { - // Assume gaugeWithdraw returns same amount value - const userData = StablePoolEncoder.exitExactBPTInForTokensOut(amount); - - // TO DO - Tokens have to be in correct order - might not be. - const exitTokens = [ - this.constants.linearDai1.address, - this.constants.linearUsdc1.address, - this.constants.linearUsdt1.address, - ]; - // Output of exit is used as input to swaps - const exitOutputReferences: OutputReference[] = []; - exitTokens.forEach((asset, i) => { - const key = Relayer.toChainedReference(i); - exitOutputReferences.push({ - index: i, - key: key, - }); - }); - - const call = Relayer.constructExitCall({ - assets: exitTokens, - minAmountsOut: ['0', '0', '0'], - userData: userData, - toInternalBalance: false, - poolId: this.constants.staBal3.id, - poolKind: 0, // This will always be 0 to match supported Relayer types - sender: migrator, - recipient: this.constants.relayer, - outputReferences: exitOutputReferences, - exitPoolRequest: {} as ExitPoolRequest, - }); - - return { - call, - oldLinearAmountsReferences: exitOutputReferences, - }; - } - - /** - * Creates encoded batchSwap function to swap Linear BPTs to underlying stables. - * outputreferences should contain the amounts of each new Linear BPT. - * @param outputReferences References from previous exit call. - * @returns BatchSwap call. - */ - buildSwap( - outputReferences: OutputReference[], - expectedBptReturn: string - ): { - call: BatchSwap; - bptAmountOut: OutputReference; - } { - // 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.constants.linearDai1.id, - assetInIndex: 0, - assetOutIndex: 1, - amount: outputReferences[0].key.toString(), // exitPool amount of DAI subpool.. - userData: '0x', - }, - { - poolId: this.constants.linearDai2.id, - assetInIndex: 1, - assetOutIndex: 2, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.bbausd2.id, - assetInIndex: 2, - assetOutIndex: 3, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.linearUsdc1.id, - assetInIndex: 3, - assetOutIndex: 4, - amount: outputReferences[1].key.toString(), // exitPool amount of DAI subpool.. - userData: '0x', - }, - { - poolId: this.constants.linearUsdc2.id, - assetInIndex: 4, - assetOutIndex: 5, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.bbausd2.id, - assetInIndex: 5, - assetOutIndex: 3, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.linearUsdt1.id, - assetInIndex: 6, - assetOutIndex: 7, - amount: outputReferences[2].key.toString(), // exitPool amount of DAI subpool.. - userData: '0x', - }, - { - poolId: this.constants.linearUsdt2.id, - assetInIndex: 7, - assetOutIndex: 8, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.bbausd2.id, - assetInIndex: 8, - assetOutIndex: 3, - amount: '0', - userData: '0x', - }, - ]; - const assets = [ - this.constants.linearDai1.address, - this.constants.DAI, - this.constants.linearDai2.address, - this.constants.bbausd2.address, - this.constants.linearUsdc1.address, - this.constants.USDC, - this.constants.linearUsdc2.address, - this.constants.linearUsdt1.address, - this.constants.USDT, - this.constants.linearUsdt2.address, - ]; - // For now assuming ref amounts will be safe - should we add more accurate? - const limits = [ - MaxUint256.toString(), - '0', - '0', - expectedBptReturn.toString(), - MaxUint256.toString(), - '0', - '0', - MaxUint256.toString(), - '0', - '0', - ]; - - // Swap to/from Relayer - const funds: FundManagement = { - sender: this.constants.relayer, - recipient: this.constants.relayer, - fromInternalBalance: false, - toInternalBalance: false, - }; - - // Output of exit is used as input to swaps - // This should have a value for each delta returned by batchSwap - const swapOutputReferences: OutputReference[] = []; - assets.forEach((asset, i) => { - const key = Relayer.toChainedReference(i); - swapOutputReferences.push({ - index: i, - key: key, - }); - }); - - const encodedBatchSwap = Relayer.encodeBatchSwap({ - swapType: SwapType.SwapExactIn, - swaps: swaps, - assets: assets, - funds: funds, - limits, - deadline: MaxUint256, - value: '0', - outputReferences: swapOutputReferences, - }); - - // We only need the deltas/amounts of the bbausd2 (matches assets index) - const bptOut = swapOutputReferences[3]; - - return { - call: encodedBatchSwap, - bptAmountOut: bptOut, - }; - } - - buildMigration( - migrator: string, - amount: string, - expectedBptReturn: string, - slippage: string - ): MigrationAttributes { - /* + /* From Nico - the flow is: a) relayer uses allowance to transfer staked bpt from user to itself @@ -380,55 +22,25 @@ export class MigrateStaBal3 { g) relayer sends staked bpt to user (steps f) and g) are done automatically by the relayer) (if the relayer is not yet approved by the user, there's one more step at the beginning where the relayer submits the user signature to approve itself) - */ - const gaugeWithdraw = this.buildWithdraw(migrator, amount); - - const poolExit = this.buildPoolExit(migrator, amount); - - // We can swap to bbausd2 instead of join as swap fees will be 0 - const swaps = this.buildSwap( - poolExit.oldLinearAmountsReferences, - expectedBptReturn - ); - - const gaugeDeposit = this.buildDeposit(migrator, swaps.bptAmountOut); - - const calls: CallData = [ - gaugeWithdraw, - poolExit.call, - swaps.call, - gaugeDeposit, - ]; - - return { - to: this.constants.relayer, - functionName: 'multicall', - calldata: calls, - }; - } + */ /** * Statically calls migration action to find final BPT amount returned. - * @param migrator Migrator address. + * + * @param userAddress * @param amount Amount of staBal3 BPT. - * @param provider Provider. - * @returns BPT amount from poolJoin call. + * @param signature Approving relayer to access tokens in vault. + * @returns BPT amount from swap joining a pool. */ async queryMigration( - migrator: string, + userAddress: string, amount: string, - provider: JsonRpcProvider + signature: string, + staked: boolean ): Promise { - const migrationData = this.buildMigration(migrator, amount, '0', '0'); - const relayerContract = new Contract( - this.constants.relayer, - balancerRelayerAbi, - provider - ); - // Returns result of each call in an array - const tx = await relayerContract.callStatic[migrationData.functionName]( - migrationData.calldata - ); + const request = this.builder.calldata(amount, '0', userAddress, staked); + const tx = await this.provider.call(request); + // BPT amount from batchSwap call return defaultAbiCoder.decode(['int256[]'], tx[2])[3].toString(); } From e6bd464de7f787ee239f8a18510857164b02bfe4 Mon Sep 17 00:00:00 2001 From: bronco Date: Thu, 21 Jul 2022 22:02:09 +0200 Subject: [PATCH 013/104] using internal balances --- balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index d78483712..a71eea3d7 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -86,7 +86,7 @@ export class StaBal3Builder { assets, minAmountsOut: ['0', '0', '0'], userData, - toInternalBalance: false, + toInternalBalance: true, poolId: this.addresses.staBal3.id, poolKind: 0, // This will always be 0 to match supported Relayer types sender: migrator, @@ -172,8 +172,8 @@ export class StaBal3Builder { const funds: FundManagement = { sender: this.addresses.relayer, recipient: this.addresses.relayer, - fromInternalBalance: false, - toInternalBalance: false, + fromInternalBalance: true, + toInternalBalance: true, }; const encodedBatchSwap = Relayer.encodeBatchSwap({ From 5c5af2f7453261ee78387892302aeaa610bd1a41 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 09:33:40 +0200 Subject: [PATCH 014/104] remove balancerSdk dependency from utils other parts need to be refactored --- .../zaps/zaps.module.integration.spec.ts | 20 ++++++++----------- balancer-js/src/test/lib/utils.ts | 10 ++++------ 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts b/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts index f6ac7774c..edbc60f14 100644 --- a/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts +++ b/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts @@ -1,6 +1,7 @@ import dotenv from 'dotenv'; import { expect } from 'chai'; -import { BalancerSDK, BalancerSdkConfig, Network, Relayer } from '@/.'; +import { Contracts } from '@/modules/contracts/contracts.module'; +import { Network, Relayer } from '@/.'; import hardhat from 'hardhat'; import { BigNumber, parseFixed } from '@ethersproject/bignumber'; @@ -22,30 +23,27 @@ dotenv.config(); const { ALCHEMY_URL: jsonRpcUrl } = process.env; const { ethers } = hardhat; -let balancer: BalancerSDK; -const network = Network.MAINNET; +const network = Network.GOERLI; const rpcUrl = 'http://127.0.0.1:8545'; -const sdkConfig: BalancerSdkConfig = { - network, - rpcUrl, -}; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const signer = provider.getSigner(); const gaugeSlots = [1]; // Info fetched using npm package slot20 // Goerli -// const gaugeAddresses = ['0xf0f572ad66baacDd07d8c7ea3e0E5EFA56a76081']; // Balancer B-50WBTC-50WETH Gauge Deposit +const gaugeAddresses = ['0xf0f572ad66baacDd07d8c7ea3e0E5EFA56a76081']; // Balancer B-50WBTC-50WETH Gauge Deposit // Mainnet -const gaugeAddresses = ['0x68d019f64a7aa97e2d4e7363aee42251d08124fb']; // Balancer bb-a-USD Gauge Deposit +// const gaugeAddresses = ['0x68d019f64a7aa97e2d4e7363aee42251d08124fb']; // Balancer bb-a-USD Gauge Deposit const initialBalance = '1000'; let signerAddress: string; +const { contracts } = new Contracts(5, provider); + // Setup const tokenBalance = async (tokenAddress: string) => { - const balance: Promise = balancer.contracts + const balance: Promise = contracts .ERC20(tokenAddress, signer.provider) .balanceOf(signerAddress); return balance; @@ -64,11 +62,9 @@ const updateBalances = async (addresses: string[]) => { describe('zaps execution', async () => { before(async function () { this.timeout(20000); - balancer = new BalancerSDK(sdkConfig); const isVyperMapping = true; // required for gauge tokens await forkSetup( - balancer, signer, gaugeAddresses, gaugeSlots, diff --git a/balancer-js/src/test/lib/utils.ts b/balancer-js/src/test/lib/utils.ts index 55f17333f..3ecbd5f76 100644 --- a/balancer-js/src/test/lib/utils.ts +++ b/balancer-js/src/test/lib/utils.ts @@ -1,12 +1,11 @@ -import { BalancerSDK } from '@/.'; -import { JsonRpcSigner } from '@ethersproject/providers'; +import { Provider, JsonRpcSigner } from '@ethersproject/providers'; import { BigNumber } from '@ethersproject/bignumber'; import { balancerVault } from '@/lib/constants/config'; import { hexlify, zeroPad } from '@ethersproject/bytes'; import { keccak256 } from '@ethersproject/solidity'; +import { ERC20 } from '@/modules/contracts/ERC20'; export const forkSetup = async ( - balancer: BalancerSDK, signer: JsonRpcSigner, // it's safer to use signer than provider for this tokens: string[], slots: number[], @@ -34,7 +33,7 @@ export const forkSetup = async ( isVyperMapping ); // Approve appropriate allowances so that vault contract can move tokens - await approveToken(balancer, tokens[i], balances[i], signer); + await approveToken(tokens[i], balances[i], signer); } }; @@ -95,11 +94,10 @@ export const setTokenBalance = async ( * @param {JsonRpcSigner} signer Account that will have tokens approved */ export const approveToken = async ( - balancer: BalancerSDK, token: string, amount: string, signer: JsonRpcSigner ): Promise => { - const tokenContract = balancer.contracts.ERC20(token, signer.provider); + const tokenContract = ERC20(token, signer.provider); return await tokenContract.connect(signer).approve(balancerVault, amount); }; From 8605360ed0a47bf487ee25cf4a76ae4e084f48ec Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 09:33:52 +0200 Subject: [PATCH 015/104] Create stabal3.integration.spec.ts --- .../modules/zaps/stabal3.integration.spec.ts | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 balancer-js/src/modules/zaps/stabal3.integration.spec.ts diff --git a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts new file mode 100644 index 000000000..a727aa5bf --- /dev/null +++ b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts @@ -0,0 +1,79 @@ +import dotenv from 'dotenv'; +import { expect } from 'chai'; +import { Network } from '@/.'; +import hardhat from 'hardhat'; +import { BigNumber, parseFixed } from '@ethersproject/bignumber'; +import { forkSetup } from '@/test/lib/utils'; +import { Contracts } from '@/modules/contracts/contracts.module'; + +/* + * Testing on GOERLI + * - Update hardhat.config.js with chainId = 5 + * - Update ALCHEMY_URL on .env with a goerli api key + * - Run goerli node on terminal: yarn run node + * - Change `network` to Network.GOERLI + * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli + */ + +dotenv.config(); + +const { ALCHEMY_URL: jsonRpcUrl } = process.env; +const { ethers } = hardhat; + +const network = Network.GOERLI; +const rpcUrl = 'http://127.0.0.1:8545'; +const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); +const signer = provider.getSigner(); + +const gaugeSlots = [1]; // Info fetched using npm package slot20 + +// Goerli +const gaugeAddresses = ['0xf0f572ad66baacDd07d8c7ea3e0E5EFA56a76081']; // Balancer B-50WBTC-50WETH Gauge Deposit +// Mainnet +// const gaugeAddresses = ['0x68d019f64a7aa97e2d4e7363aee42251d08124fb']; // Balancer bb-a-USD Gauge Deposit + +const initialBalance = '1000'; +let signerAddress: string; + +const { contracts } = new Contracts(5, provider); +// Setup + +const tokenBalance = async (tokenAddress: string) => { + const balance: Promise = contracts + .ERC20(tokenAddress, signer.provider) + .balanceOf(signerAddress); + return balance; +}; + +const updateBalances = async (addresses: string[]) => { + const balances = []; + for (let i = 0; i < addresses.length; i++) { + balances[i] = tokenBalance(addresses[i]); + } + return Promise.all(balances); +}; + +// Test Scenarios + +describe('execution', async () => { + before(async function () { + this.timeout(20000); + const isVyperMapping = true; // required for gauge tokens + await forkSetup( + signer, + gaugeAddresses, + gaugeSlots, + [parseFixed(initialBalance, 18).toString()], + jsonRpcUrl as string, + isVyperMapping + ); + signerAddress = await signer.getAddress(); + }); + + it('should update balances', async () => { + const balances = await updateBalances(gaugeAddresses); + for (let i = 0; i < balances.length; i++) { + expect(balances[i].eq(parseFixed(initialBalance, 18))).to.be.true; + } + }).timeout(20000); +}).timeout(20000); From fa24e52d51a4d47f305f63b4ab981fd8eb09231c Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 09:33:58 +0200 Subject: [PATCH 016/104] Update package.json --- balancer-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balancer-js/package.json b/balancer-js/package.json index 98dec83d7..169277d42 100644 --- a/balancer-js/package.json +++ b/balancer-js/package.json @@ -28,7 +28,7 @@ "lint:fix": "eslint ./src --ext .ts --max-warnings 0 --fix", "subgraph:generate": "graphql-codegen --config src/modules/subgraph/codegen.yml -r dotenv/config", "examples:run": "TS_NODE_PROJECT='tsconfig.testing.json' ts-node -r tsconfig-paths/register", - "node": "npx hardhat node --fork $(grep ALCHEMY_URL .env | cut -d '=' -f2) --fork-block-number 14828550" + "node": "npx hardhat node --fork $(grep ALCHEMY_URL .env | tail -1 | cut -d '=' -f2) --fork-block-number $(grep FORK_BLOCK_NUMBER .env | tail -1 | cut -d '=' -f2)" }, "devDependencies": { "@ethersproject/abi": "^5.4.0", From 4e93086c3cf91c53366ded6f7efca40b27d90ddf Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 09:34:28 +0200 Subject: [PATCH 017/104] fixing output references type --- .../src/modules/zaps/bbausd2-migrations/stabal3.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index a71eea3d7..39aeba078 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -9,10 +9,10 @@ import { MaxUint256 } from '@ethersproject/constants'; import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; const balancerRelayerInterface = new Interface(balancerRelayerAbi); -const EXIT_DAI = Relayer.toChainedReference('exit_dai'); -const EXIT_USDC = Relayer.toChainedReference('exit_usdc'); -const EXIT_USDT = Relayer.toChainedReference('exit_usdt'); -const SWAP_RESULT_BBAUSD = Relayer.toChainedReference('swap_result_bbausd'); +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; From dcf9599eeae10f0a07547ddf8425a239b97b50ee Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 09:47:31 +0200 Subject: [PATCH 018/104] goerli addresses for testing --- .../zaps/bbausd2-migrations/addresses.ts | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 069f342b0..f6031e322 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -47,46 +47,46 @@ export const ADDRESSES = { 5: { relayer: '0x7b9B6f094DC2Bd1c12024b0D9CC63d6993Be1888', staBal3: { - id: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063', - address: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42', - gauge: '0x34f33cdaed8ba0e1ceece80e5f4a73bcf234cfac', + id: '0xdcdd4a3d36dec8d57594e89763d069a7e9b223e2000000000000000000000062', + address: '0xdcdd4a3d36dec8d57594e89763d069a7e9b223e2', + gauge: '', }, bbausd1: { - id: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb20000000000000000000000fe', - address: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb2', - gauge: '0x68d019f64a7aa97e2d4e7363aee42251d08124fb', + id: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd00000000000000000000005f', + address: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd', + gauge: '', }, bbausd2: { - id: '', - address: '', + id: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd00000000000000000000005f', + address: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd', gauge: '', }, linearUsdc1: { - id: '', - address: 'N/A', + id: '0x0595d1df64279ddb51f1bdc405fe2d0b4cc8668100000000000000000000005c', + address: '0x0595d1df64279ddb51f1bdc405fe2d0b4cc86681', }, linearDai1: { - id: '', - address: 'N/A', + id: '0x5cea6a84ed13590ed14903925fa1a73c36297d9900000000000000000000005d', + address: '0x5cea6a84ed13590ed14903925fa1a73c36297d99', }, linearUsdt1: { - id: '', - address: 'N/A', + id: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f00000000000000000000005e', + address: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f', }, linearUsdc2: { - id: '', - address: 'N/A', + id: '0x0595d1df64279ddb51f1bdc405fe2d0b4cc8668100000000000000000000005c', + address: '0x0595d1df64279ddb51f1bdc405fe2d0b4cc86681', }, linearDai2: { - id: '', - address: 'N/A', + id: '0x5cea6a84ed13590ed14903925fa1a73c36297d9900000000000000000000005d', + address: '0x5cea6a84ed13590ed14903925fa1a73c36297d99', }, linearUsdt2: { - id: '', - address: 'N/A', + id: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f00000000000000000000005e', + address: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f', }, - DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', - USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + DAI: '0x8c9e6c40d3402480ace624730524facc5482798c', + USDC: '0xe0c9275e44ea80ef17579d33c55136b7da269aeb', + USDT: '0x1f1f156e0317167c11aa412e3d1435ea29dc3cce', }, }; From 8181a3a986907d15cfeaeab7d3b3a03c07e34b76 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 16:45:23 +0200 Subject: [PATCH 019/104] adding hardhat helpers --- balancer-js/package.json | 1 + balancer-js/yarn.lock | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/balancer-js/package.json b/balancer-js/package.json index 169277d42..e221be36b 100644 --- a/balancer-js/package.json +++ b/balancer-js/package.json @@ -51,6 +51,7 @@ "@graphql-codegen/typescript-graphql-request": "^4.3.0", "@graphql-codegen/typescript-operations": "^2.2.0", "@graphql-codegen/typescript-resolvers": "2.4.1", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", "@nomiclabs/hardhat-ethers": "^2.0.5", "@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-json": "^4.1.0", diff --git a/balancer-js/yarn.lock b/balancer-js/yarn.lock index 57ba042f0..0684e0d3a 100644 --- a/balancer-js/yarn.lock +++ b/balancer-js/yarn.lock @@ -1472,6 +1472,13 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@nomicfoundation/hardhat-network-helpers@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.3.tgz#3303cf7c8f52e1ef33ff4fc98d85af020d64f083" + integrity sha512-sBeUCzgrcdS8x7Nnr4t6wNpC7GIMMR3gQs8lVaxff5VWVKf7SjdkJ2rvSJsS2ckD8/8KGxeDTLb7XCOqVAjFjA== + dependencies: + ethereumjs-util "^7.1.4" + "@nomiclabs/hardhat-ethers@^2.0.5": version "2.1.0" resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.1.0.tgz#9b7dc94d669ad9dc286b94f6f2f1513118c7027b" From 96ead2427ba3497e3cfe82fad967e94684409fea Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 16:57:47 +0200 Subject: [PATCH 020/104] adding approving actions to the relayer --- .../src/modules/relayer/relayer.module.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/balancer-js/src/modules/relayer/relayer.module.ts b/balancer-js/src/modules/relayer/relayer.module.ts index 7618b4373..43ea48dfb 100644 --- a/balancer-js/src/modules/relayer/relayer.module.ts +++ b/balancer-js/src/modules/relayer/relayer.module.ts @@ -41,6 +41,25 @@ export class Relayer { } } + static encodeApproveVault(tokenAddress: string, maxAmount: string): string { + return relayerLibrary.encodeFunctionData('approveVault', [ + tokenAddress, + maxAmount, + ]); + } + + static encodeSetRelayerApproval( + relayerAdress: string, + approved: boolean, + authorisation: string + ): string { + return relayerLibrary.encodeFunctionData('setRelayerApproval', [ + relayerAdress, + approved, + authorisation, + ]); + } + static encodeGaugeWithdraw( gaugeAddress: string, sender: string, From 453478def463d14445a61bab8ef75285b8526427 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 16:57:59 +0200 Subject: [PATCH 021/104] wip: migration --- .../zaps/bbausd2-migrations/addresses.ts | 4 +- .../zaps/bbausd2-migrations/stabal3.ts | 67 ++++++--- .../{migrateStaBal3.ts => migrate-stabal3.ts} | 30 +++- .../src/modules/zaps/migrateBbausd1.ts | 2 +- .../modules/zaps/stabal3.integration.spec.ts | 136 ++++++++++++------ balancer-js/src/modules/zaps/zaps.module.ts | 2 +- 6 files changed, 173 insertions(+), 68 deletions(-) rename balancer-js/src/modules/zaps/{migrateStaBal3.ts => migrate-stabal3.ts} (69%) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index f6031e322..18c67818a 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -5,6 +5,7 @@ export const ADDRESSES = { id: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063', address: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42', gauge: '0x34f33cdaed8ba0e1ceece80e5f4a73bcf234cfac', + assetOrder: ['DAI', 'USDC', 'USDT'], }, bbausd1: { id: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb20000000000000000000000fe', @@ -50,6 +51,7 @@ export const ADDRESSES = { id: '0xdcdd4a3d36dec8d57594e89763d069a7e9b223e2000000000000000000000062', address: '0xdcdd4a3d36dec8d57594e89763d069a7e9b223e2', gauge: '', + assetOrder: ['USDT', 'DAI', 'USDC'], }, bbausd1: { id: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd00000000000000000000005f', @@ -85,8 +87,8 @@ export const ADDRESSES = { id: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f00000000000000000000005e', address: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f', }, + USDT: '0x1f1f156e0317167c11aa412e3d1435ea29dc3cce', DAI: '0x8c9e6c40d3402480ace624730524facc5482798c', USDC: '0xe0c9275e44ea80ef17579d33c55136b7da269aeb', - USDT: '0x1f1f156e0317167c11aa412e3d1435ea29dc3cce', }, }; diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 39aeba078..e965cf403 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -4,8 +4,8 @@ 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 { MaxUint256 } from '@ethersproject/constants'; -// TO DO - Ask Nico to update Typechain? +import { MaxUint256, MaxInt256 } from '@ethersproject/constants'; +// TODO - Ask Nico to update Typechain? import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; const balancerRelayerInterface = new Interface(balancerRelayerAbi); @@ -25,16 +25,28 @@ export class StaBal3Builder { amount: string, expectedAmount: string, userAddress: string, - staked: boolean + staked: boolean, + authorisation?: string ): { to: string; data: string; } { + const { assetOrder } = this.addresses.staBal3; let calls = [ this.buildExit(userAddress, amount), + ...assetOrder.map((name) => { + const tokenAddress = this.addresses[ + name as keyof typeof this.addresses + ] as string; + return this.buildApproveVault(tokenAddress); + }), this.buildSwap(expectedAmount), ]; + if (authorisation) { + calls = [this.buildSetRelayerApproval(authorisation), ...calls]; + } + if (staked) { calls = [ this.buildWithdraw(userAddress, amount), @@ -43,10 +55,9 @@ export class StaBal3Builder { ]; } - const callData = balancerRelayerInterface.encodeFunctionData( - 'multicall', - calls - ); + const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ + calls, + ]); return { to: this.addresses.relayer, @@ -67,19 +78,17 @@ export class StaBal3Builder { // Assume gaugeWithdraw returns same amount value const userData = StablePoolEncoder.exitExactBPTInForTokensOut(amount); - // TO DO - Tokens have to be in correct order - might not be. - // UPDATE: checked PoolBalanceChanged events after exit in etherscan, order checks out for all the transactions - const assets = [ - this.addresses.DAI, - this.addresses.USDC, - this.addresses.USDT, - ]; + // 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 + ); // Ask to store exit outputs for batchSwap of exit is used as input to swaps const outputReferences = [ - { index: 0, key: EXIT_DAI }, - { index: 1, key: EXIT_USDC }, - { index: 2, key: EXIT_USDT }, + { index: assetOrder.indexOf('DAI'), key: EXIT_DAI }, + { index: assetOrder.indexOf('USDC'), key: EXIT_USDC }, + { index: assetOrder.indexOf('USDT'), key: EXIT_USDT }, ]; const callData = Relayer.constructExitCall({ @@ -89,7 +98,7 @@ export class StaBal3Builder { toInternalBalance: true, poolId: this.addresses.staBal3.id, poolKind: 0, // This will always be 0 to match supported Relayer types - sender: migrator, + sender: migrator, // this.addresses.relayer, recipient: this.addresses.relayer, outputReferences, exitPoolRequest: {} as ExitPoolRequest, @@ -166,7 +175,15 @@ export class StaBal3Builder { ]; // For now assuming ref amounts will be safe - should we add more accurate? - const limits = ['0', '0', '0', '0', '0', '0', expectedBptReturn.toString()]; + const limits = [ + MaxInt256.toString(), + MaxInt256.toString(), + MaxInt256.toString(), + MaxInt256.toString(), + MaxInt256.toString(), + MaxInt256.toString(), + MaxInt256.toString(), // expectedBptReturn.toString()]; + ]; // Swap to/from Relayer const funds: FundManagement = { @@ -217,4 +234,16 @@ export class StaBal3Builder { SWAP_RESULT_BBAUSD.toString() ); } + + buildApproveVault(token: string): string { + return Relayer.encodeApproveVault(token, MaxUint256.toString()); + } + + buildSetRelayerApproval(authorisation: string): string { + return Relayer.encodeSetRelayerApproval( + this.addresses.relayer, + true, + authorisation + ); + } } diff --git a/balancer-js/src/modules/zaps/migrateStaBal3.ts b/balancer-js/src/modules/zaps/migrate-stabal3.ts similarity index 69% rename from balancer-js/src/modules/zaps/migrateStaBal3.ts rename to balancer-js/src/modules/zaps/migrate-stabal3.ts index e6b63017b..2dd319613 100644 --- a/balancer-js/src/modules/zaps/migrateStaBal3.ts +++ b/balancer-js/src/modules/zaps/migrate-stabal3.ts @@ -29,19 +29,37 @@ export class MigrateStaBal3 { * * @param userAddress * @param amount Amount of staBal3 BPT. - * @param signature Approving relayer to access tokens in vault. + * @param authorisation Approving relayer to access tokens in vault. * @returns BPT amount from swap joining a pool. */ async queryMigration( userAddress: string, amount: string, - signature: string, + authorisation: string, staked: boolean - ): Promise { + ): Promise<{ to: string; data: string; decode: (output: string) => string }> { const request = this.builder.calldata(amount, '0', userAddress, staked); - const tx = await this.provider.call(request); - // BPT amount from batchSwap call - return defaultAbiCoder.decode(['int256[]'], tx[2])[3].toString(); + return { + to: request.to, + data: request.data, + decode: (output) => + defaultAbiCoder.decode(['int256[]'], output[2])[3].toString(), + }; + + // const tx = await this.provider.call(request); + + // // BPT amount from batchSwap call + // return defaultAbiCoder.decode(['int256[]'], tx[2])[3].toString(); } + + buildMigration( + userAddress: string, + amount: string, + signature: string, + staked: boolean + ): { + to: string; + data: string; + } {} } diff --git a/balancer-js/src/modules/zaps/migrateBbausd1.ts b/balancer-js/src/modules/zaps/migrateBbausd1.ts index 3025c5af7..6ea2f5ec4 100644 --- a/balancer-js/src/modules/zaps/migrateBbausd1.ts +++ b/balancer-js/src/modules/zaps/migrateBbausd1.ts @@ -10,7 +10,7 @@ import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; // we are missing encodeGaugeDeposit / Withdraw functions import { JsonRpcProvider } from '@ethersproject/providers'; -import { CONSTANTS, gaugeActionsInterface } from './migrateStaBal3'; +import { CONSTANTS, gaugeActionsInterface } from './migrate-stabal3'; import { Pool } from '@/types'; import { BigNumber } from '@ethersproject/bignumber'; diff --git a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts index a727aa5bf..37fbaca38 100644 --- a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts @@ -1,10 +1,16 @@ import dotenv from 'dotenv'; import { expect } from 'chai'; -import { Network } from '@/.'; import hardhat from 'hardhat'; +import { Network, RelayerAuthorization } from '@/.'; import { BigNumber, parseFixed } from '@ethersproject/bignumber'; -import { forkSetup } from '@/test/lib/utils'; import { Contracts } from '@/modules/contracts/contracts.module'; +import { ADDRESSES } from './bbausd2-migrations/addresses'; +import { MigrateStaBal3 as Migration } from './migrate-stabal3'; +import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; +import { parseEther, formatEther } from '@ethersproject/units'; +import { ContractTransaction } from '@ethersproject/contracts'; +import { JsonRpcSigner } from '@ethersproject/providers'; +import { MaxUint256 } from '@ethersproject/constants'; /* * Testing on GOERLI @@ -19,38 +25,56 @@ dotenv.config(); const { ALCHEMY_URL: jsonRpcUrl } = process.env; const { ethers } = hardhat; +const MAX_GAS_LIMIT = 8e6; const network = Network.GOERLI; const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); -const signer = provider.getSigner(); - -const gaugeSlots = [1]; // Info fetched using npm package slot20 - -// Goerli -const gaugeAddresses = ['0xf0f572ad66baacDd07d8c7ea3e0E5EFA56a76081']; // Balancer B-50WBTC-50WETH Gauge Deposit -// Mainnet -// const gaugeAddresses = ['0x68d019f64a7aa97e2d4e7363aee42251d08124fb']; // Balancer bb-a-USD Gauge Deposit - -const initialBalance = '1000'; -let signerAddress: string; - +const addresses = ADDRESSES[network]; const { contracts } = new Contracts(5, provider); -// Setup +const migration = new Migration(network, provider); -const tokenBalance = async (tokenAddress: string) => { - const balance: Promise = contracts - .ERC20(tokenAddress, signer.provider) - .balanceOf(signerAddress); - return balance; +// https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#impersonating-accounts +// WARNING: don't use hardhat SignerWithAddress to sendTransactions!! +// It's not working and we didn't have time to figure out why. +// Use JsonRpcSigner instead +const impersonateAccount = async (account: string) => { + await provider.send('hardhat_impersonateAccount', [account]); + await setBalance(account, parseEther('10000')); + return provider.getSigner(account); }; -const updateBalances = async (addresses: string[]) => { - const balances = []; - for (let i = 0; i < addresses.length; i++) { - balances[i] = tokenBalance(addresses[i]); +const approveRelayer = async ( + address: string, + signer: JsonRpcSigner, + withSignature = false +): Promise => { + let calldata = contracts.vault.interface.encodeFunctionData( + 'setRelayerApproval', + [address, addresses.relayer, true] + ); + + if (withSignature) { + const signature = + await RelayerAuthorization.signSetRelayerApprovalAuthorization( + contracts.vault, + signer, + address, + calldata + ); + calldata = RelayerAuthorization.encodeCalldataAuthorization( + calldata, + MaxUint256, + signature + ); } - return Promise.all(balances); + + // Hardcoding a gas limit prevents (slow) gas estimation + return signer.sendTransaction({ + to: contracts.vault.address, + data: calldata, + gasLimit: MAX_GAS_LIMIT, + }); }; // Test Scenarios @@ -58,22 +82,54 @@ const updateBalances = async (addresses: string[]) => { describe('execution', async () => { before(async function () { this.timeout(20000); - const isVyperMapping = true; // required for gauge tokens - await forkSetup( - signer, - gaugeAddresses, - gaugeSlots, - [parseFixed(initialBalance, 18).toString()], - jsonRpcUrl as string, - isVyperMapping - ); - signerAddress = await signer.getAddress(); + + await provider.send('hardhat_reset', [ + { + forking: { + jsonRpcUrl, + blockNumber: 7269604, + }, + }, + ]); }); - it('should update balances', async () => { - const balances = await updateBalances(gaugeAddresses); - for (let i = 0; i < balances.length; i++) { - expect(balances[i].eq(parseFixed(initialBalance, 18))).to.be.true; - } + it('should transfer tokens from stable to boosted', async () => { + const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; + const holder = await impersonateAccount(holderAddress); + + const balance = await contracts + .ERC20(addresses.staBal3.address, provider) + .balanceOf(holderAddress); + + // Approval + await ( + await contracts.vault + .connect(holder) + .setRelayerApproval(holderAddress, addresses.relayer, true) + ).wait(); + + const query = await migration.queryMigration( + holderAddress, + balance, + '', // can we use signature with relayer? + false + ); + + const response = await holder.sendTransaction({ + to: query.to, + data: query.data, + gasLimit: MAX_GAS_LIMIT, + }); + + const reciept = await response.wait(); + console.log(reciept); + + const balanceAfterExit = await contracts + .ERC20(addresses.staBal3.address, provider) + .balanceOf(holderAddress); + + console.log(balance, balanceAfterExit); + + expect(balanceAfterExit).to.eq(0); }).timeout(20000); }).timeout(20000); diff --git a/balancer-js/src/modules/zaps/zaps.module.ts b/balancer-js/src/modules/zaps/zaps.module.ts index 450e2c79f..3d664acbc 100644 --- a/balancer-js/src/modules/zaps/zaps.module.ts +++ b/balancer-js/src/modules/zaps/zaps.module.ts @@ -1,5 +1,5 @@ import { Network } from '@/lib/constants/network'; -import { MigrateStaBal3, MigrationAttributes } from './migrateStaBal3'; +import { MigrateStaBal3, MigrationAttributes } from './migrate-stabal3'; import { Relayer } from '../relayer/relayer.module'; import { JsonRpcProvider } from '@ethersproject/providers'; import { Pool } from '@/types'; From ab38538e52afc9464060554a66ea3d5311a89223 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 18:24:32 +0200 Subject: [PATCH 022/104] first passing test case --- .../zaps/bbausd2-migrations/stabal3.ts | 9 +- .../src/modules/zaps/migrate-stabal3.ts | 8 +- .../modules/zaps/stabal3.integration.spec.ts | 118 ++++++++++-------- 3 files changed, 78 insertions(+), 57 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index e965cf403..65c2ad9a1 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -32,6 +32,7 @@ export class StaBal3Builder { data: string; } { const { assetOrder } = this.addresses.staBal3; + let calls = [ this.buildExit(userAddress, amount), ...assetOrder.map((name) => { @@ -40,7 +41,7 @@ export class StaBal3Builder { ] as string; return this.buildApproveVault(tokenAddress); }), - this.buildSwap(expectedAmount), + this.buildSwap(expectedAmount, !staked ? userAddress : undefined), ]; if (authorisation) { @@ -113,7 +114,7 @@ export class StaBal3Builder { * * @returns BatchSwap call. */ - buildSwap(expectedBptReturn: string): string { + buildSwap(expectedBptReturn: string, recipient?: string): string { const assets = [ this.addresses.DAI, this.addresses.linearDai2.address, @@ -188,9 +189,9 @@ export class StaBal3Builder { // Swap to/from Relayer const funds: FundManagement = { sender: this.addresses.relayer, - recipient: this.addresses.relayer, + recipient: recipient ? recipient : this.addresses.relayer, fromInternalBalance: true, - toInternalBalance: true, + toInternalBalance: recipient ? false : true, }; const encodedBatchSwap = Relayer.encodeBatchSwap({ diff --git a/balancer-js/src/modules/zaps/migrate-stabal3.ts b/balancer-js/src/modules/zaps/migrate-stabal3.ts index 2dd319613..077979ada 100644 --- a/balancer-js/src/modules/zaps/migrate-stabal3.ts +++ b/balancer-js/src/modules/zaps/migrate-stabal3.ts @@ -38,7 +38,13 @@ export class MigrateStaBal3 { authorisation: string, staked: boolean ): Promise<{ to: string; data: string; decode: (output: string) => string }> { - const request = this.builder.calldata(amount, '0', userAddress, staked); + const request = this.builder.calldata( + amount, + '0', + userAddress, + staked, + authorisation + ); return { to: request.to, diff --git a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts index 37fbaca38..ee67c45fe 100644 --- a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts @@ -2,13 +2,12 @@ import dotenv from 'dotenv'; import { expect } from 'chai'; import hardhat from 'hardhat'; import { Network, RelayerAuthorization } from '@/.'; -import { BigNumber, parseFixed } from '@ethersproject/bignumber'; +import { BigNumber } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; import { ADDRESSES } from './bbausd2-migrations/addresses'; import { MigrateStaBal3 as Migration } from './migrate-stabal3'; import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; import { parseEther, formatEther } from '@ethersproject/units'; -import { ContractTransaction } from '@ethersproject/contracts'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256 } from '@ethersproject/constants'; @@ -27,6 +26,7 @@ const { ALCHEMY_URL: jsonRpcUrl } = process.env; const { ethers } = hardhat; const MAX_GAS_LIMIT = 8e6; +const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; const network = Network.GOERLI; const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); @@ -34,6 +34,9 @@ const addresses = ADDRESSES[network]; const { contracts } = new Contracts(5, provider); const migration = new Migration(network, provider); +const getErc20Balance = (token: string, holder: string): Promise => + contracts.ERC20(token, provider).balanceOf(holder); + // https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#impersonating-accounts // WARNING: don't use hardhat SignerWithAddress to sendTransactions!! // It's not working and we didn't have time to figure out why. @@ -44,42 +47,36 @@ const impersonateAccount = async (account: string) => { return provider.getSigner(account); }; -const approveRelayer = async ( - address: string, - signer: JsonRpcSigner, - withSignature = false -): Promise => { - let calldata = contracts.vault.interface.encodeFunctionData( +const signRelayerApproval = async ( + signerAddress: string, + signer: JsonRpcSigner +): Promise => { + const approval = contracts.vault.interface.encodeFunctionData( 'setRelayerApproval', - [address, addresses.relayer, true] + [signerAddress, addresses.relayer, true] ); - if (withSignature) { - const signature = - await RelayerAuthorization.signSetRelayerApprovalAuthorization( - contracts.vault, - signer, - address, - calldata - ); - calldata = RelayerAuthorization.encodeCalldataAuthorization( - calldata, - MaxUint256, - signature + const signature = + await RelayerAuthorization.signSetRelayerApprovalAuthorization( + contracts.vault, + signer, + addresses.relayer, + approval ); - } - // Hardcoding a gas limit prevents (slow) gas estimation - return signer.sendTransaction({ - to: contracts.vault.address, - data: calldata, - gasLimit: MAX_GAS_LIMIT, - }); -}; + const calldata = RelayerAuthorization.encodeCalldataAuthorization( + '0x', + MaxUint256, + signature + ); -// Test Scenarios + return calldata; +}; describe('execution', async () => { + let signer: JsonRpcSigner; + let signerAddress: string; + before(async function () { this.timeout(20000); @@ -91,45 +88,62 @@ describe('execution', async () => { }, }, ]); - }); - it('should transfer tokens from stable to boosted', async () => { - const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; - const holder = await impersonateAccount(holderAddress); + signer = provider.getSigner(); + signerAddress = await signer.getAddress(); - const balance = await contracts + // Transfer tokens from existing user account to signer + // We need that to test signatures, because hardhat doesn't have access to private keys on impersonated accounts + const holder = await impersonateAccount(holderAddress); + const balance = await getErc20Balance( + addresses.staBal3.address, + holderAddress + ); + await contracts .ERC20(addresses.staBal3.address, provider) - .balanceOf(holderAddress); + .connect(holder) + .transfer(signerAddress, balance); + }); - // Approval - await ( - await contracts.vault - .connect(holder) - .setRelayerApproval(holderAddress, addresses.relayer, true) - ).wait(); + it('should transfer tokens from stable to boosted', async () => { + // Store balancer before migration + const before = { + from: await getErc20Balance(addresses.staBal3.address, signerAddress), + to: await getErc20Balance(addresses.bbausd2.address, signerAddress), + }; + + // Get authorisation + const authorisation = await signRelayerApproval(signerAddress, signer); const query = await migration.queryMigration( - holderAddress, - balance, - '', // can we use signature with relayer? + signerAddress, + before.from.toString(), + authorisation, false ); - const response = await holder.sendTransaction({ + const response = await signer.sendTransaction({ to: query.to, data: query.data, gasLimit: MAX_GAS_LIMIT, }); const reciept = await response.wait(); - console.log(reciept); + console.log('Gas used', reciept.gasUsed.toString()); - const balanceAfterExit = await contracts - .ERC20(addresses.staBal3.address, provider) - .balanceOf(holderAddress); + const after = { + from: await getErc20Balance(addresses.staBal3.address, signerAddress), + to: await getErc20Balance(addresses.bbausd2.address, signerAddress), + }; + + const diffs = { + from: after.from.sub(before.from), + to: after.to.sub(before.to), + }; - console.log(balance, balanceAfterExit); + console.log(diffs.from, diffs.to); - expect(balanceAfterExit).to.eq(0); + expect(diffs.from).to.eql(before.from.mul(-1)); + expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); }).timeout(20000); }).timeout(20000); From 821c59c2753ac0b234cbae002925868ff0552311 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 18:50:39 +0200 Subject: [PATCH 023/104] minor updates --- .../zaps/bbausd2-migrations/stabal3.ts | 2 +- .../src/modules/zaps/migrate-stabal3.ts | 26 +++++++++++++------ .../modules/zaps/stabal3.integration.spec.ts | 13 +++++++--- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 65c2ad9a1..f4d9e92c9 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -183,7 +183,7 @@ export class StaBal3Builder { MaxInt256.toString(), MaxInt256.toString(), MaxInt256.toString(), - MaxInt256.toString(), // expectedBptReturn.toString()]; + expectedBptReturn.toString(), ]; // Swap to/from Relayer diff --git a/balancer-js/src/modules/zaps/migrate-stabal3.ts b/balancer-js/src/modules/zaps/migrate-stabal3.ts index 077979ada..056884866 100644 --- a/balancer-js/src/modules/zaps/migrate-stabal3.ts +++ b/balancer-js/src/modules/zaps/migrate-stabal3.ts @@ -1,5 +1,6 @@ import { defaultAbiCoder } from '@ethersproject/abi'; import { Provider } from '@ethersproject/providers'; +import { MaxInt256 } from '@ethersproject/constants'; import { StaBal3Builder } from './bbausd2-migrations/stabal3'; export class MigrateStaBal3 { @@ -40,7 +41,7 @@ export class MigrateStaBal3 { ): Promise<{ to: string; data: string; decode: (output: string) => string }> { const request = this.builder.calldata( amount, - '0', + MaxInt256.toString(), userAddress, staked, authorisation @@ -52,20 +53,29 @@ export class MigrateStaBal3 { decode: (output) => defaultAbiCoder.decode(['int256[]'], output[2])[3].toString(), }; - - // const tx = await this.provider.call(request); - - // // BPT amount from batchSwap call - // return defaultAbiCoder.decode(['int256[]'], tx[2])[3].toString(); } buildMigration( userAddress: string, amount: string, - signature: string, + expectedBptOut: string, + authorisation: string, staked: boolean ): { to: string; data: string; - } {} + } { + const request = this.builder.calldata( + amount, + expectedBptOut, + userAddress, + staked, + authorisation + ); + + return { + to: request.to, + data: request.data, + }; + } } diff --git a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts index ee67c45fe..a161bbca9 100644 --- a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts @@ -48,19 +48,20 @@ const impersonateAccount = async (account: string) => { }; const signRelayerApproval = async ( + relayerAddress: string, signerAddress: string, signer: JsonRpcSigner ): Promise => { const approval = contracts.vault.interface.encodeFunctionData( 'setRelayerApproval', - [signerAddress, addresses.relayer, true] + [signerAddress, relayerAddress, true] ); const signature = await RelayerAuthorization.signSetRelayerApprovalAuthorization( contracts.vault, signer, - addresses.relayer, + relayerAddress, approval ); @@ -93,7 +94,7 @@ describe('execution', async () => { signerAddress = await signer.getAddress(); // Transfer tokens from existing user account to signer - // We need that to test signatures, because hardhat doesn't have access to private keys on impersonated accounts + // We need that to test signatures, because hardhat doesn't have impersonated accounts private keys const holder = await impersonateAccount(holderAddress); const balance = await getErc20Balance( addresses.staBal3.address, @@ -113,7 +114,11 @@ describe('execution', async () => { }; // Get authorisation - const authorisation = await signRelayerApproval(signerAddress, signer); + const authorisation = await signRelayerApproval( + addresses.relayer, + signerAddress, + signer + ); const query = await migration.queryMigration( signerAddress, From c6ac84384eb9baf8aafd7c70f6d689eb27270dd1 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 18:50:52 +0200 Subject: [PATCH 024/104] adding rest of addresses to goerli --- .../src/modules/zaps/bbausd2-migrations/addresses.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 18c67818a..38eda1f88 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -50,18 +50,18 @@ export const ADDRESSES = { staBal3: { id: '0xdcdd4a3d36dec8d57594e89763d069a7e9b223e2000000000000000000000062', address: '0xdcdd4a3d36dec8d57594e89763d069a7e9b223e2', - gauge: '', + gauge: '0xfd364cda96bb7db06b65706182c448a73f0a5f9a', assetOrder: ['USDT', 'DAI', 'USDC'], }, bbausd1: { id: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd00000000000000000000005f', address: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd', - gauge: '', + gauge: '0xa2d0ea81a47d68598922cd54c59249ff58c2a3ff', }, bbausd2: { id: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd00000000000000000000005f', address: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd', - gauge: '', + gauge: '0xa2d0ea81a47d68598922cd54c59249ff58c2a3ff', }, linearUsdc1: { id: '0x0595d1df64279ddb51f1bdc405fe2d0b4cc8668100000000000000000000005c', From 73537ce81fba46e5435bdc4901cb23736fedf9ce Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 19:08:31 +0200 Subject: [PATCH 025/104] minor stuff --- .../zaps/bbausd2-migrations/stabal3.ts | 25 +++++++++++-------- .../src/modules/zaps/migrate-stabal3.ts | 1 + .../modules/zaps/stabal3.integration.spec.ts | 2 ++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index f4d9e92c9..7fb3562ec 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -32,22 +32,25 @@ export class StaBal3Builder { data: string; } { const { assetOrder } = this.addresses.staBal3; + let calls: string[] = []; - let calls = [ + if (authorisation) { + calls = [this.buildSetRelayerApproval(authorisation)]; + } + + calls = [ + ...calls, this.buildExit(userAddress, amount), - ...assetOrder.map((name) => { - const tokenAddress = this.addresses[ - name as keyof typeof this.addresses - ] as string; - return this.buildApproveVault(tokenAddress); - }), + // TODO: Let's double check with setting approveVault to 0 if we need that or not, or ask Nico ;) + // ...assetOrder.map((name) => { + // const tokenAddress = this.addresses[ + // name as keyof typeof this.addresses + // ] as string; + // return this.buildApproveVault(tokenAddress); + // }), this.buildSwap(expectedAmount, !staked ? userAddress : undefined), ]; - if (authorisation) { - calls = [this.buildSetRelayerApproval(authorisation), ...calls]; - } - if (staked) { calls = [ this.buildWithdraw(userAddress, amount), diff --git a/balancer-js/src/modules/zaps/migrate-stabal3.ts b/balancer-js/src/modules/zaps/migrate-stabal3.ts index 056884866..75fc0a46a 100644 --- a/balancer-js/src/modules/zaps/migrate-stabal3.ts +++ b/balancer-js/src/modules/zaps/migrate-stabal3.ts @@ -31,6 +31,7 @@ export class MigrateStaBal3 { * @param userAddress * @param amount Amount of staBal3 BPT. * @param authorisation Approving relayer to access tokens in vault. + * @param staked BPT are staked. * @returns BPT amount from swap joining a pool. */ async queryMigration( diff --git a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts index a161bbca9..a5c14651e 100644 --- a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts @@ -104,6 +104,8 @@ describe('execution', async () => { .ERC20(addresses.staBal3.address, provider) .connect(holder) .transfer(signerAddress, balance); + + // TODO: Stake them }); it('should transfer tokens from stable to boosted', async () => { From 1364d789deb06ccceb6f2f5f18dc9ad29b7ef388 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 19:33:40 +0200 Subject: [PATCH 026/104] adding single token exit option --- .../zaps/bbausd2-migrations/stabal3.ts | 43 +++++++++++-------- .../modules/zaps/stabal3.integration.spec.ts | 3 +- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 7fb3562ec..0d163a3a6 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -79,15 +79,19 @@ export class StaBal3Builder { * @returns Encoded exitPool call. Output references. */ buildExit(migrator: string, amount: string): string { - // Assume gaugeWithdraw returns same amount value - const userData = StablePoolEncoder.exitExactBPTInForTokensOut(amount); - // 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 }, @@ -102,7 +106,8 @@ export class StaBal3Builder { toInternalBalance: true, poolId: this.addresses.staBal3.id, poolKind: 0, // This will always be 0 to match supported Relayer types - sender: migrator, // this.addresses.relayer, + // sender: this.addresses.relayer, // For staked tokens, because they are sent to relayer first + sender: migrator, recipient: this.addresses.relayer, outputReferences, exitPoolRequest: {} as ExitPoolRequest, @@ -119,16 +124,16 @@ export class StaBal3Builder { */ 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, - this.addresses.bbausd2.address, ]; - const outputReferences = [{ index: 6, key: SWAP_RESULT_BBAUSD }]; + 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. @@ -136,43 +141,43 @@ export class StaBal3Builder { const swaps: BatchSwapStep[] = [ { poolId: this.addresses.linearDai2.id, - assetInIndex: 0, - assetOutIndex: 1, + assetInIndex: 1, + assetOutIndex: 2, amount: EXIT_DAI.toString(), userData: '0x', }, { poolId: this.addresses.bbausd2.id, - assetInIndex: 1, - assetOutIndex: 6, + assetInIndex: 2, + assetOutIndex: 0, amount: '0', userData: '0x', }, { poolId: this.addresses.linearUsdc2.id, - assetInIndex: 2, - assetOutIndex: 3, + assetInIndex: 3, + assetOutIndex: 4, amount: EXIT_USDC.toString(), userData: '0x', }, { poolId: this.addresses.bbausd2.id, - assetInIndex: 3, - assetOutIndex: 6, + assetInIndex: 4, + assetOutIndex: 0, amount: '0', userData: '0x', }, { poolId: this.addresses.linearUsdt2.id, - assetInIndex: 4, - assetOutIndex: 5, + assetInIndex: 5, + assetOutIndex: 6, amount: EXIT_USDT.toString(), userData: '0x', }, { poolId: this.addresses.bbausd2.id, - assetInIndex: 5, - assetOutIndex: 6, + assetInIndex: 6, + assetOutIndex: 0, amount: '0', userData: '0x', }, @@ -180,13 +185,13 @@ export class StaBal3Builder { // For now assuming ref amounts will be safe - should we add more accurate? const limits = [ + expectedBptReturn.toString(), MaxInt256.toString(), MaxInt256.toString(), MaxInt256.toString(), MaxInt256.toString(), MaxInt256.toString(), MaxInt256.toString(), - expectedBptReturn.toString(), ]; // Swap to/from Relayer diff --git a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts index a5c14651e..3a2a2cb14 100644 --- a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts @@ -26,7 +26,8 @@ const { ALCHEMY_URL: jsonRpcUrl } = process.env; const { ethers } = hardhat; const MAX_GAS_LIMIT = 8e6; -const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; +// const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; +const holderAddress = '0xb7d222a710169f42ddff2a9a5122bd7c724dc203'; const network = Network.GOERLI; const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); From 4eeb30517ca5efc7271cf77416e1a948ae104000 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 22 Jul 2022 21:03:23 +0200 Subject: [PATCH 027/104] adding known mainnet addresses --- .../src/modules/zaps/bbausd2-migrations/addresses.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 38eda1f88..43fb05074 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -18,16 +18,16 @@ export const ADDRESSES = { gauge: '', }, linearUsdc1: { - id: '', - address: 'N/A', + id: '0x9210f1204b5a24742eba12f710636d76240df3d00000000000000000000000fc', + address: '0x9210F1204b5a24742Eba12f710636D76240dF3d0', }, linearDai1: { - id: '', - address: 'N/A', + id: '0x804cdb9116a10bb78768d3252355a1b18067bf8f0000000000000000000000fb', + address: '0x804CdB9116a10bB78768D3252355a1b18067bF8f', }, linearUsdt1: { - id: '', - address: 'N/A', + id: '0x2bbf681cc4eb09218bee85ea2a5d3d13fa40fc0c0000000000000000000000fd', + address: '0x2BBf681cC4eb09218BEe85EA2a5d3D13Fa40fC0C', }, linearUsdc2: { id: '', From 5ab97087fb87ab4361c977dd61835e1126454c13 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Fri, 22 Jul 2022 17:43:01 -0300 Subject: [PATCH 028/104] Add test case for staked-stabal3 to staked-bbausd2 migration --- .../zaps/stabal3-staked.integration.spec.ts | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts diff --git a/balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts b/balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts new file mode 100644 index 000000000..9a4c4e0bf --- /dev/null +++ b/balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts @@ -0,0 +1,195 @@ +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 './bbausd2-migrations/addresses'; +import { MigrateStaBal3 as Migration } from './migrate-stabal3'; +import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; +import { parseEther, formatEther } from '@ethersproject/units'; +import { JsonRpcSigner } from '@ethersproject/providers'; +import { MaxUint256 } from '@ethersproject/constants'; + +import { Relayer } from '@/modules/relayer/relayer.module'; +import { Interface } from '@ethersproject/abi'; +import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; +import { Contract } from 'ethers'; +const balancerRelayerInterface = new Interface(balancerRelayerAbi); + +import liquidityGaugeAbi from '@/lib/abi/LiquidityGaugeV5.json'; + +/* + * Testing on GOERLI + * - Update hardhat.config.js with chainId = 5 + * - Update ALCHEMY_URL on .env with a goerli api key + * - Run goerli node on terminal: yarn run node + * - Change `network` to Network.GOERLI + * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli + */ + +dotenv.config(); + +const { ALCHEMY_URL: jsonRpcUrl } = process.env; +const { ethers } = hardhat; +const MAX_GAS_LIMIT = 8e6; + +const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; +const network = Network.GOERLI; +const rpcUrl = 'http://127.0.0.1:8545'; +const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); +const addresses = ADDRESSES[network]; +const { contracts } = new Contracts(network as number, provider); +const migration = new Migration(network, provider); + +const getErc20Balance = (token: string, holder: string): Promise => + contracts.ERC20(token, provider).balanceOf(holder); + +// https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#impersonating-accounts +// WARNING: don't use hardhat SignerWithAddress to sendTransactions!! +// It's not working and we didn't have time to figure out why. +// Use JsonRpcSigner instead +const impersonateAccount = async (account: string) => { + await provider.send('hardhat_impersonateAccount', [account]); + await setBalance(account, parseEther('10000')); + return provider.getSigner(account); +}; + +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; +}; + +describe('execution', async () => { + let signer: JsonRpcSigner; + let signerAddress: string; + + before(async function () { + this.timeout(20000); + + await provider.send('hardhat_reset', [ + { + forking: { + jsonRpcUrl, + blockNumber: 7269604, + }, + }, + ]); + + signer = provider.getSigner(); + signerAddress = await signer.getAddress(); + + // Transfer tokens from existing user account to signer + // We need that to test signatures, because hardhat doesn't have impersonated accounts private keys + const holder = await impersonateAccount(holderAddress); + const balance = await getErc20Balance( + addresses.staBal3.address, + holderAddress + ); + await contracts + .ERC20(addresses.staBal3.address, provider) + .connect(holder) + .transfer(signerAddress, balance); + + // TODO: Stake them + const authorisation = await signRelayerApproval( + addresses.relayer, + signerAddress, + signer + ); + const authorisationCall = Relayer.encodeSetRelayerApproval( + addresses.relayer, + true, + authorisation + ); + const approveTokenCall = Relayer.encodeApproveVault( + addresses.staBal3.address, + MaxUint256.toString() + ); + const depositCall = Relayer.encodeGaugeDeposit( + addresses.staBal3.gauge, + signerAddress, + signerAddress, + balance.toString() + ); + const calls = [authorisationCall, approveTokenCall, depositCall]; + const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ + calls, + ]); + const response = await signer.sendTransaction({ + to: addresses.relayer, + data: callData, + gasLimit: MAX_GAS_LIMIT, + }); + const recepit = await response.wait(); + console.log('receipt status should be 1 -> ', recepit.status); + }); + + it('should transfer tokens from stable to boosted', async () => { + // Store balance before migration + const before = { + from: await getErc20Balance(addresses.staBal3.address, signerAddress), + to: await getErc20Balance(addresses.bbausd2.address, signerAddress), + }; + + // Get authorisation + const authorisation = await signRelayerApproval( + addresses.relayer, + signerAddress, + signer + ); + + const query = await migration.queryMigration( + signerAddress, + before.from.toString(), + authorisation, + true + ); + + const response = await signer.sendTransaction({ + to: query.to, + data: query.data, + gasLimit: MAX_GAS_LIMIT, + }); + + const reciept = await response.wait(); + console.log('Gas used', reciept.gasUsed.toString()); + + const after = { + from: await getErc20Balance(addresses.staBal3.address, signerAddress), + to: await getErc20Balance(addresses.bbausd2.address, signerAddress), + }; + + const diffs = { + from: after.from.sub(before.from), + to: after.to.sub(before.to), + }; + + console.log(diffs.from, diffs.to); + + expect(diffs.from).to.eql(before.from.mul(-1)); + expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + }).timeout(20000); +}).timeout(20000); From 3bf5273d7e0954da130a160359894a54081c15e0 Mon Sep 17 00:00:00 2001 From: bronco Date: Sat, 23 Jul 2022 10:10:52 +0200 Subject: [PATCH 029/104] wip: figuring out staked flow now at least staking setup is working, but gaugeWithdrawal via relayer is failing due to SENDER_NOT_ALLOWED error --- .../zaps/bbausd2-migrations/stabal3.ts | 45 ++++++---- .../zaps/stabal3-staked.integration.spec.ts | 87 +++++++++---------- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 0d163a3a6..b93860e6d 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -31,16 +31,12 @@ export class StaBal3Builder { to: string; data: string; } { + const relayer = this.addresses.relayer; const { assetOrder } = this.addresses.staBal3; let calls: string[] = []; - if (authorisation) { - calls = [this.buildSetRelayerApproval(authorisation)]; - } - calls = [ - ...calls, - this.buildExit(userAddress, amount), + this.buildExit(staked ? relayer : userAddress, relayer, amount), // TODO: Let's double check with setting approveVault to 0 if we need that or not, or ask Nico ;) // ...assetOrder.map((name) => { // const tokenAddress = this.addresses[ @@ -48,17 +44,25 @@ export class StaBal3Builder { // ] as string; // return this.buildApproveVault(tokenAddress); // }), - this.buildSwap(expectedAmount, !staked ? userAddress : undefined), + this.buildSwap( + expectedAmount, + staked ? relayer : userAddress, + staked ? true : false + ), ]; if (staked) { calls = [ this.buildWithdraw(userAddress, amount), ...calls, - this.buildDeposit(userAddress), + // this.buildDeposit(userAddress), ]; } + // if (authorisation) { + // calls = [this.buildSetRelayerApproval(authorisation), ...calls]; + // } + const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ calls, ]); @@ -78,7 +82,7 @@ export class StaBal3Builder { * @param amount Amount of staBal3 BPT to exit with. * @returns Encoded exitPool call. Output references. */ - buildExit(migrator: string, amount: string): string { + buildExit(sender: string, recipient: string, amount: string): string { // Goerli and Mainnet has different assets ordering const { assetOrder } = this.addresses.staBal3; const assets = assetOrder.map( @@ -106,9 +110,8 @@ export class StaBal3Builder { toInternalBalance: true, poolId: this.addresses.staBal3.id, poolKind: 0, // This will always be 0 to match supported Relayer types - // sender: this.addresses.relayer, // For staked tokens, because they are sent to relayer first - sender: migrator, - recipient: this.addresses.relayer, + sender, + recipient, outputReferences, exitPoolRequest: {} as ExitPoolRequest, }); @@ -122,7 +125,11 @@ export class StaBal3Builder { * * @returns BatchSwap call. */ - buildSwap(expectedBptReturn: string, recipient?: string): string { + buildSwap( + expectedBptReturn: string, + recipient: string, + toInternalBalance = false + ): string { const assets = [ this.addresses.bbausd2.address, this.addresses.DAI, @@ -197,9 +204,9 @@ export class StaBal3Builder { // Swap to/from Relayer const funds: FundManagement = { sender: this.addresses.relayer, - recipient: recipient ? recipient : this.addresses.relayer, + recipient, fromInternalBalance: true, - toInternalBalance: recipient ? false : true, + toInternalBalance, }; const encodedBatchSwap = Relayer.encodeBatchSwap({ @@ -221,10 +228,10 @@ export class StaBal3Builder { * * @returns withdraw call */ - buildWithdraw(migrator: string, amount: string): string { + buildWithdraw(sender: string, amount: string): string { return Relayer.encodeGaugeWithdraw( this.addresses.staBal3.gauge, - migrator, + sender, this.addresses.relayer, amount ); @@ -235,11 +242,11 @@ export class StaBal3Builder { * * @returns deposit call */ - buildDeposit(migrator: string): string { + buildDeposit(recipient: string): string { return Relayer.encodeGaugeDeposit( this.addresses.bbausd2.gauge, this.addresses.relayer, - migrator, + recipient, SWAP_RESULT_BBAUSD.toString() ); } diff --git a/balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts b/balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts index 9a4c4e0bf..68728d80d 100644 --- a/balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts +++ b/balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts @@ -1,6 +1,7 @@ import dotenv from 'dotenv'; import { expect } from 'chai'; import hardhat from 'hardhat'; +import { Contract } from 'ethers'; import { Network, RelayerAuthorization } from '@/.'; import { BigNumber } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; @@ -14,10 +15,9 @@ import { MaxUint256 } from '@ethersproject/constants'; import { Relayer } from '@/modules/relayer/relayer.module'; import { Interface } from '@ethersproject/abi'; import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; -import { Contract } from 'ethers'; +const liquidityGaugeAbi = ['function deposit(uint value) payable']; const balancerRelayerInterface = new Interface(balancerRelayerAbi); - -import liquidityGaugeAbi from '@/lib/abi/LiquidityGaugeV5.json'; +const liquidityGauge = new Interface(liquidityGaugeAbi); /* * Testing on GOERLI @@ -30,11 +30,11 @@ import liquidityGaugeAbi from '@/lib/abi/LiquidityGaugeV5.json'; dotenv.config(); -const { ALCHEMY_URL: jsonRpcUrl } = process.env; +const { ALCHEMY_URL: jsonRpcUrl, FORKED_BLOCK_NUMBER: blockNumber } = + process.env; const { ethers } = hardhat; const MAX_GAS_LIMIT = 8e6; -const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; const network = Network.GOERLI; const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); @@ -42,6 +42,12 @@ const addresses = ADDRESSES[network]; const { contracts } = new Contracts(network as number, provider); const migration = new Migration(network, provider); +const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; +const poolAddress = '0x16faf9f73748013155b7bc116a3008b57332d1e6'; +const gaugeAddress = '0xf0f572ad66baacdd07d8c7ea3e0e5efa56a76081'; +// const poolAddress = addresses.staBal3.address; +// const gaugeAddress = addresses.staBal3.gauge; + const getErc20Balance = (token: string, holder: string): Promise => contracts.ERC20(token, provider).balanceOf(holder); @@ -93,7 +99,7 @@ describe('execution', async () => { { forking: { jsonRpcUrl, - blockNumber: 7269604, + blockNumber: blockNumber || 7273825, }, }, ]); @@ -104,55 +110,35 @@ describe('execution', async () => { // Transfer tokens from existing user account to signer // We need that to test signatures, because hardhat doesn't have impersonated accounts private keys const holder = await impersonateAccount(holderAddress); - const balance = await getErc20Balance( - addresses.staBal3.address, - holderAddress - ); + const balance = await getErc20Balance(poolAddress, holderAddress); await contracts - .ERC20(addresses.staBal3.address, provider) + .ERC20(poolAddress, provider) .connect(holder) .transfer(signerAddress, balance); - // TODO: Stake them - const authorisation = await signRelayerApproval( - addresses.relayer, - signerAddress, - signer - ); - const authorisationCall = Relayer.encodeSetRelayerApproval( - addresses.relayer, - true, - authorisation - ); - const approveTokenCall = Relayer.encodeApproveVault( - addresses.staBal3.address, - MaxUint256.toString() - ); - const depositCall = Relayer.encodeGaugeDeposit( - addresses.staBal3.gauge, - signerAddress, - signerAddress, - balance.toString() - ); - const calls = [authorisationCall, approveTokenCall, depositCall]; - const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ - calls, - ]); - const response = await signer.sendTransaction({ - to: addresses.relayer, - data: callData, - gasLimit: MAX_GAS_LIMIT, - }); - const recepit = await response.wait(); - console.log('receipt status should be 1 -> ', recepit.status); + // Stake them + await ( + await contracts + .ERC20(poolAddress, provider) + .connect(signer) + .approve(gaugeAddress, MaxUint256) + ).wait(); + + await ( + await signer.sendTransaction({ + to: gaugeAddress, + data: liquidityGauge.encodeFunctionData('deposit', [balance]), + }) + ).wait(); }); it('should transfer tokens from stable to boosted', async () => { // Store balance before migration const before = { - from: await getErc20Balance(addresses.staBal3.address, signerAddress), - to: await getErc20Balance(addresses.bbausd2.address, signerAddress), + from: await getErc20Balance(gaugeAddress, signerAddress), + to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), }; + // console.log(before); // Get authorisation const authorisation = await signRelayerApproval( @@ -177,11 +163,18 @@ describe('execution', async () => { const reciept = await response.wait(); console.log('Gas used', reciept.gasUsed.toString()); + const internalBalances1 = await contracts.vault.getInternalBalance(addresses.relayer, [addresses.DAI, addresses.USDC]); + const internalBalances2 = await contracts.vault.getInternalBalance(signerAddress, [addresses.DAI, addresses.USDC]); + const internalBalances3 = await contracts.vault.getInternalBalance(gaugeAddress, [addresses.DAI, addresses.USDC]); + console.log(internalBalances1, internalBalances2, internalBalances3); + const after = { - from: await getErc20Balance(addresses.staBal3.address, signerAddress), - to: await getErc20Balance(addresses.bbausd2.address, signerAddress), + from: await getErc20Balance(gaugeAddress, signerAddress), + to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), }; + console.log(before, after); + const diffs = { from: after.from.sub(before.from), to: after.to.sub(before.to), From 8eaad4782b058f7907102527ef4ca66a38b56159 Mon Sep 17 00:00:00 2001 From: bronco Date: Sat, 23 Jul 2022 19:16:37 +0200 Subject: [PATCH 030/104] stabal3 complete --- .../zaps/bbausd2-migrations/stabal3.ts | 50 ++--- .../zaps/stabal3-staked.integration.spec.ts | 188 ---------------- .../modules/zaps/stabal3.integration.spec.ts | 212 ++++++++++++------ 3 files changed, 166 insertions(+), 284 deletions(-) delete mode 100644 balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index b93860e6d..40775a447 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -26,42 +26,38 @@ export class StaBal3Builder { expectedAmount: string, userAddress: string, staked: boolean, - authorisation?: string + authorisation: string ): { to: string; data: string; } { const relayer = this.addresses.relayer; - const { assetOrder } = this.addresses.staBal3; let calls: string[] = []; - calls = [ - this.buildExit(staked ? relayer : userAddress, relayer, amount), - // TODO: Let's double check with setting approveVault to 0 if we need that or not, or ask Nico ;) - // ...assetOrder.map((name) => { - // const tokenAddress = this.addresses[ - // name as keyof typeof this.addresses - // ] as string; - // return this.buildApproveVault(tokenAddress); - // }), - this.buildSwap( - expectedAmount, - staked ? relayer : userAddress, - staked ? true : false - ), - ]; - if (staked) { calls = [ + this.buildSetRelayerApproval(authorisation), this.buildWithdraw(userAddress, amount), - ...calls, - // this.buildDeposit(userAddress), + this.buildExit(relayer, relayer, amount), + this.buildSwap(expectedAmount, relayer), + this.buildDeposit(userAddress), + ]; + } else { + calls = [ + this.buildSetRelayerApproval(authorisation), + this.buildExit(userAddress, relayer, amount), + this.buildSwap(expectedAmount, userAddress), ]; } - // if (authorisation) { - // calls = [this.buildSetRelayerApproval(authorisation), ...calls]; - // } + // TODO: Let's double check with setting approveVault to 0 if we need that or not, or ask Nico ;) + // const { assetOrder } = this.addresses.staBal3; + // ...assetOrder.map((name) => { + // const tokenAddress = this.addresses[ + // name as keyof typeof this.addresses + // ] as string; + // return this.buildApproveVault(tokenAddress); + // }), const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ calls, @@ -125,11 +121,7 @@ export class StaBal3Builder { * * @returns BatchSwap call. */ - buildSwap( - expectedBptReturn: string, - recipient: string, - toInternalBalance = false - ): string { + buildSwap(expectedBptReturn: string, recipient: string): string { const assets = [ this.addresses.bbausd2.address, this.addresses.DAI, @@ -206,7 +198,7 @@ export class StaBal3Builder { sender: this.addresses.relayer, recipient, fromInternalBalance: true, - toInternalBalance, + toInternalBalance: false, }; const encodedBatchSwap = Relayer.encodeBatchSwap({ diff --git a/balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts b/balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts deleted file mode 100644 index 68728d80d..000000000 --- a/balancer-js/src/modules/zaps/stabal3-staked.integration.spec.ts +++ /dev/null @@ -1,188 +0,0 @@ -import dotenv from 'dotenv'; -import { expect } from 'chai'; -import hardhat from 'hardhat'; -import { Contract } from 'ethers'; -import { Network, RelayerAuthorization } from '@/.'; -import { BigNumber } from '@ethersproject/bignumber'; -import { Contracts } from '@/modules/contracts/contracts.module'; -import { ADDRESSES } from './bbausd2-migrations/addresses'; -import { MigrateStaBal3 as Migration } from './migrate-stabal3'; -import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; -import { parseEther, formatEther } from '@ethersproject/units'; -import { JsonRpcSigner } from '@ethersproject/providers'; -import { MaxUint256 } from '@ethersproject/constants'; - -import { Relayer } from '@/modules/relayer/relayer.module'; -import { Interface } from '@ethersproject/abi'; -import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; -const liquidityGaugeAbi = ['function deposit(uint value) payable']; -const balancerRelayerInterface = new Interface(balancerRelayerAbi); -const liquidityGauge = new Interface(liquidityGaugeAbi); - -/* - * Testing on GOERLI - * - Update hardhat.config.js with chainId = 5 - * - Update ALCHEMY_URL on .env with a goerli api key - * - Run goerli node on terminal: yarn run node - * - Change `network` to Network.GOERLI - * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli - */ - -dotenv.config(); - -const { ALCHEMY_URL: jsonRpcUrl, FORKED_BLOCK_NUMBER: blockNumber } = - process.env; -const { ethers } = hardhat; -const MAX_GAS_LIMIT = 8e6; - -const network = Network.GOERLI; -const rpcUrl = 'http://127.0.0.1:8545'; -const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); -const addresses = ADDRESSES[network]; -const { contracts } = new Contracts(network as number, provider); -const migration = new Migration(network, provider); - -const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; -const poolAddress = '0x16faf9f73748013155b7bc116a3008b57332d1e6'; -const gaugeAddress = '0xf0f572ad66baacdd07d8c7ea3e0e5efa56a76081'; -// const poolAddress = addresses.staBal3.address; -// const gaugeAddress = addresses.staBal3.gauge; - -const getErc20Balance = (token: string, holder: string): Promise => - contracts.ERC20(token, provider).balanceOf(holder); - -// https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#impersonating-accounts -// WARNING: don't use hardhat SignerWithAddress to sendTransactions!! -// It's not working and we didn't have time to figure out why. -// Use JsonRpcSigner instead -const impersonateAccount = async (account: string) => { - await provider.send('hardhat_impersonateAccount', [account]); - await setBalance(account, parseEther('10000')); - return provider.getSigner(account); -}; - -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; -}; - -describe('execution', async () => { - let signer: JsonRpcSigner; - let signerAddress: string; - - before(async function () { - this.timeout(20000); - - await provider.send('hardhat_reset', [ - { - forking: { - jsonRpcUrl, - blockNumber: blockNumber || 7273825, - }, - }, - ]); - - signer = provider.getSigner(); - signerAddress = await signer.getAddress(); - - // Transfer tokens from existing user account to signer - // We need that to test signatures, because hardhat doesn't have impersonated accounts private keys - const holder = await impersonateAccount(holderAddress); - const balance = await getErc20Balance(poolAddress, holderAddress); - await contracts - .ERC20(poolAddress, provider) - .connect(holder) - .transfer(signerAddress, balance); - - // Stake them - await ( - await contracts - .ERC20(poolAddress, provider) - .connect(signer) - .approve(gaugeAddress, MaxUint256) - ).wait(); - - await ( - await signer.sendTransaction({ - to: gaugeAddress, - data: liquidityGauge.encodeFunctionData('deposit', [balance]), - }) - ).wait(); - }); - - it('should transfer tokens from stable to boosted', async () => { - // Store balance before migration - const before = { - from: await getErc20Balance(gaugeAddress, signerAddress), - to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), - }; - // console.log(before); - - // Get authorisation - const authorisation = await signRelayerApproval( - addresses.relayer, - signerAddress, - signer - ); - - const query = await migration.queryMigration( - signerAddress, - before.from.toString(), - authorisation, - true - ); - - const response = await signer.sendTransaction({ - to: query.to, - data: query.data, - gasLimit: MAX_GAS_LIMIT, - }); - - const reciept = await response.wait(); - console.log('Gas used', reciept.gasUsed.toString()); - - const internalBalances1 = await contracts.vault.getInternalBalance(addresses.relayer, [addresses.DAI, addresses.USDC]); - const internalBalances2 = await contracts.vault.getInternalBalance(signerAddress, [addresses.DAI, addresses.USDC]); - const internalBalances3 = await contracts.vault.getInternalBalance(gaugeAddress, [addresses.DAI, addresses.USDC]); - console.log(internalBalances1, internalBalances2, internalBalances3); - - const after = { - from: await getErc20Balance(gaugeAddress, signerAddress), - to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), - }; - - console.log(before, after); - - const diffs = { - from: after.from.sub(before.from), - to: after.to.sub(before.to), - }; - - console.log(diffs.from, diffs.to); - - expect(diffs.from).to.eql(before.from.mul(-1)); - expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); - }).timeout(20000); -}).timeout(20000); diff --git a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts index 3a2a2cb14..8dfe796a5 100644 --- a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/stabal3.integration.spec.ts @@ -11,6 +11,10 @@ import { parseEther, formatEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256 } from '@ethersproject/constants'; +import { Interface } from '@ethersproject/abi'; +const liquidityGaugeAbi = ['function deposit(uint value) payable']; +const liquidityGauge = new Interface(liquidityGaugeAbi); + /* * Testing on GOERLI * - Update hardhat.config.js with chainId = 5 @@ -22,19 +26,22 @@ import { MaxUint256 } from '@ethersproject/constants'; dotenv.config(); -const { ALCHEMY_URL: jsonRpcUrl } = process.env; +const { ALCHEMY_URL: jsonRpcUrl, FORK_BLOCK_NUMBER: blockNumber } = process.env; const { ethers } = hardhat; const MAX_GAS_LIMIT = 8e6; -// const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; -const holderAddress = '0xb7d222a710169f42ddff2a9a5122bd7c724dc203'; const network = Network.GOERLI; const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const addresses = ADDRESSES[network]; -const { contracts } = new Contracts(5, provider); +const { contracts } = new Contracts(network as number, provider); const migration = new Migration(network, provider); +const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; +const poolAddress = addresses.staBal3.address; +const gaugeAddress = addresses.staBal3.gauge; +const relayer = addresses.relayer; + const getErc20Balance = (token: string, holder: string): Promise => contracts.ERC20(token, provider).balanceOf(holder); @@ -75,83 +82,154 @@ const signRelayerApproval = async ( return calldata; }; +const reset = () => + provider.send('hardhat_reset', [ + { + forking: { + jsonRpcUrl, + blockNumber: (blockNumber && parseInt(blockNumber)) || 7277540, + }, + }, + ]); + +const move = async ( + token: string, + from: string, + to: string +): Promise => { + const holder = await impersonateAccount(from); + const balance = await getErc20Balance(token, from); + await contracts.ERC20(token, provider).connect(holder).transfer(to, balance); + + return balance; +}; + +const stake = async ( + signer: JsonRpcSigner, + balance: BigNumber +): Promise => { + await ( + await contracts + .ERC20(poolAddress, provider) + .connect(signer) + .approve(gaugeAddress, MaxUint256) + ).wait(); + + await ( + await contracts + .ERC20(addresses.bbausd1.address, provider) + .connect(signer) + .approve(addresses.bbausd1.gauge, MaxUint256) + ).wait(); + + await ( + await signer.sendTransaction({ + to: gaugeAddress, + data: liquidityGauge.encodeFunctionData('deposit', [balance]), + }) + ).wait(); +}; + describe('execution', async () => { let signer: JsonRpcSigner; let signerAddress: string; + let authorisation: string; + let balance: BigNumber; - before(async function () { - this.timeout(20000); - - await provider.send('hardhat_reset', [ - { - forking: { - jsonRpcUrl, - blockNumber: 7269604, - }, - }, - ]); + beforeEach(async () => { + 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 - const holder = await impersonateAccount(holderAddress); - const balance = await getErc20Balance( - addresses.staBal3.address, - holderAddress - ); - await contracts - .ERC20(addresses.staBal3.address, provider) - .connect(holder) - .transfer(signerAddress, balance); - - // TODO: Stake them + balance = await move(poolAddress, holderAddress, signerAddress); }); - it('should transfer tokens from stable to boosted', async () => { - // Store balancer before migration - const before = { - from: await getErc20Balance(addresses.staBal3.address, signerAddress), - to: await getErc20Balance(addresses.bbausd2.address, signerAddress), - }; - - // Get authorisation - const authorisation = await signRelayerApproval( - addresses.relayer, - signerAddress, - signer - ); - - const query = await migration.queryMigration( - signerAddress, - before.from.toString(), - authorisation, - false - ); + context('staked', async () => { + beforeEach(async function () { + this.timeout(20000); - const response = await signer.sendTransaction({ - to: query.to, - data: query.data, - gasLimit: MAX_GAS_LIMIT, + // Stake them + await stake(signer, balance); }); - const reciept = await response.wait(); - console.log('Gas used', reciept.gasUsed.toString()); - - const after = { - from: await getErc20Balance(addresses.staBal3.address, signerAddress), - to: await getErc20Balance(addresses.bbausd2.address, signerAddress), - }; - - const diffs = { - from: after.from.sub(before.from), - to: after.to.sub(before.to), - }; - - console.log(diffs.from, diffs.to); + it('should transfer tokens from stable to boosted', async () => { + // Store balance before migration + const before = { + from: await getErc20Balance(gaugeAddress, signerAddress), + to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), + }; + + const query = await migration.queryMigration( + signerAddress, + before.from.toString(), + authorisation, + true + ); + + const { to, data } = query; + const gasLimit = MAX_GAS_LIMIT; + const response = await signer.sendTransaction({ to, data, gasLimit }); + + const reciept = await response.wait(); + console.log('Gas used', reciept.gasUsed.toString()); + + const after = { + from: await getErc20Balance(gaugeAddress, signerAddress), + to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), + }; + + const diffs = { + from: after.from.sub(before.from), + to: after.to.sub(before.to), + }; + + console.log(diffs.from, diffs.to); + + expect(diffs.from).to.eql(before.from.mul(-1)); + expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + }).timeout(20000); + }); - expect(diffs.from).to.eql(before.from.mul(-1)); - expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); - }).timeout(20000); + context('not staked', async () => { + it('should transfer tokens from stable to boosted', async () => { + // Store balance before migration + const before = { + from: await getErc20Balance(poolAddress, signerAddress), + to: await getErc20Balance(addresses.bbausd2.address, signerAddress), + }; + + const query = await migration.queryMigration( + signerAddress, + before.from.toString(), + authorisation, + false + ); + + const { to, data } = query; + const gasLimit = MAX_GAS_LIMIT; + const response = await signer.sendTransaction({ to, data, gasLimit }); + + const reciept = await response.wait(); + console.log('Gas used', reciept.gasUsed.toString()); + + const after = { + from: await getErc20Balance(poolAddress, signerAddress), + to: await getErc20Balance(addresses.bbausd2.address, signerAddress), + }; + + const diffs = { + from: after.from.sub(before.from), + to: after.to.sub(before.to), + }; + + console.log(diffs.from, diffs.to); + + expect(diffs.from).to.eql(before.from.mul(-1)); + expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + }).timeout(20000); + }); }).timeout(20000); From 769e4bbce6c8a9b3a6d364295eabd3684dd94035 Mon Sep 17 00:00:00 2001 From: bronco Date: Sat, 23 Jul 2022 20:20:53 +0200 Subject: [PATCH 031/104] migrations module --- .../stabal3.integration.spec.ts | 24 +++--- .../zaps/bbausd2-migrations/stabal3.ts | 2 +- .../src/modules/zaps/migrate-stabal3.ts | 82 ------------------- balancer-js/src/modules/zaps/migrations.ts | 31 +++++++ balancer-js/src/modules/zaps/zaps.module.ts | 39 +-------- 5 files changed, 49 insertions(+), 129 deletions(-) rename balancer-js/src/modules/zaps/{ => bbausd2-migrations}/stabal3.integration.spec.ts (95%) delete mode 100644 balancer-js/src/modules/zaps/migrate-stabal3.ts create mode 100644 balancer-js/src/modules/zaps/migrations.ts diff --git a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts similarity index 95% rename from balancer-js/src/modules/zaps/stabal3.integration.spec.ts rename to balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts index 8dfe796a5..3fc623b4b 100644 --- a/balancer-js/src/modules/zaps/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -4,8 +4,8 @@ import hardhat from 'hardhat'; import { Network, RelayerAuthorization } from '@/.'; import { BigNumber } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; -import { ADDRESSES } from './bbausd2-migrations/addresses'; -import { MigrateStaBal3 as Migration } from './migrate-stabal3'; +import { ADDRESSES } from './addresses'; +import { StaBal3Builder as MigrationBuilder } from './stabal3'; import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; import { parseEther, formatEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; @@ -35,7 +35,7 @@ const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const addresses = ADDRESSES[network]; const { contracts } = new Contracts(network as number, provider); -const migration = new Migration(network, provider); +const migration = new MigrationBuilder(network); const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; const poolAddress = addresses.staBal3.address; @@ -163,11 +163,12 @@ describe('execution', async () => { to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), }; - const query = await migration.queryMigration( - signerAddress, + const query = migration.calldata( before.from.toString(), - authorisation, - true + undefined, + signerAddress, + true, + authorisation ); const { to, data } = query; @@ -202,11 +203,12 @@ describe('execution', async () => { to: await getErc20Balance(addresses.bbausd2.address, signerAddress), }; - const query = await migration.queryMigration( - signerAddress, + const query = migration.calldata( before.from.toString(), - authorisation, - false + undefined, + signerAddress, + false, + authorisation ); const { to, data } = query; diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 40775a447..33b8d6cc8 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -23,7 +23,7 @@ export class StaBal3Builder { calldata( amount: string, - expectedAmount: string, + expectedAmount = MaxInt256.toString(), userAddress: string, staked: boolean, authorisation: string diff --git a/balancer-js/src/modules/zaps/migrate-stabal3.ts b/balancer-js/src/modules/zaps/migrate-stabal3.ts deleted file mode 100644 index 75fc0a46a..000000000 --- a/balancer-js/src/modules/zaps/migrate-stabal3.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { defaultAbiCoder } from '@ethersproject/abi'; -import { Provider } from '@ethersproject/providers'; -import { MaxInt256 } from '@ethersproject/constants'; -import { StaBal3Builder } from './bbausd2-migrations/stabal3'; - -export class MigrateStaBal3 { - private builder: StaBal3Builder; - - constructor(private network: 1 | 5, private provider: Provider) { - this.builder = new StaBal3Builder(network); - } - - /* - From Nico - - the flow is: - a) relayer uses allowance to transfer staked bpt from user to itself - b) relayer returns staked bpt to get bpt back - (steps a) and b) are done automatically by the relayer) - c) relayer uses the bpt it got to exit the pool - d) relayer swaps linear bpt into stables, and stables into linear v2 bpt - e) relayer joins bb-a-usd 2 - f) relayer stakes bb-a-usd-bpt - g) relayer sends staked bpt to user - (steps f) and g) are done automatically by the relayer) - (if the relayer is not yet approved by the user, there's one more step at the beginning where the relayer submits the user signature to approve itself) - */ - - /** - * Statically calls migration action to find final BPT amount returned. - * - * @param userAddress - * @param amount Amount of staBal3 BPT. - * @param authorisation Approving relayer to access tokens in vault. - * @param staked BPT are staked. - * @returns BPT amount from swap joining a pool. - */ - async queryMigration( - userAddress: string, - amount: string, - authorisation: string, - staked: boolean - ): Promise<{ to: string; data: string; decode: (output: string) => string }> { - const request = this.builder.calldata( - amount, - MaxInt256.toString(), - userAddress, - staked, - authorisation - ); - - return { - to: request.to, - data: request.data, - decode: (output) => - defaultAbiCoder.decode(['int256[]'], output[2])[3].toString(), - }; - } - - buildMigration( - userAddress: string, - amount: string, - expectedBptOut: string, - authorisation: string, - staked: boolean - ): { - to: string; - data: string; - } { - const request = this.builder.calldata( - amount, - expectedBptOut, - userAddress, - staked, - authorisation - ); - - return { - to: request.to, - data: request.data, - }; - } -} diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts new file mode 100644 index 000000000..c518bdf3e --- /dev/null +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -0,0 +1,31 @@ +import { defaultAbiCoder } from '@ethersproject/abi'; +import { MaxInt256 } from '@ethersproject/constants'; +import { StaBal3Builder } from './bbausd2-migrations/stabal3'; + +export class Migrations { + constructor(private network: 1 | 5) {} + + stabal3( + userAddress: string, + amount: string, + limit = MaxInt256.toString(), + authorisation: string, + staked: boolean + ): { to: string; data: string; decode: (output: string) => string } { + const builder = new StaBal3Builder(this.network); + const request = builder.calldata( + amount, + limit, + userAddress, + staked, + authorisation + ); + + return { + to: request.to, + data: request.data, + decode: (output) => + defaultAbiCoder.decode(['int256[]'], output[2])[3].toString(), + }; + } +} diff --git a/balancer-js/src/modules/zaps/zaps.module.ts b/balancer-js/src/modules/zaps/zaps.module.ts index 3d664acbc..66a603d22 100644 --- a/balancer-js/src/modules/zaps/zaps.module.ts +++ b/balancer-js/src/modules/zaps/zaps.module.ts @@ -1,41 +1,10 @@ import { Network } from '@/lib/constants/network'; -import { MigrateStaBal3, MigrationAttributes } from './migrate-stabal3'; -import { Relayer } from '../relayer/relayer.module'; -import { JsonRpcProvider } from '@ethersproject/providers'; -import { Pool } from '@/types'; - -/** -TO DOS - -Update typechain Relayer and use this. - */ +import { Migrations } from './migrations'; export class Zaps { - constructor(public network: Network, public relayer: Relayer) {} - - async queryMigrateStaBal3( - staBal3: Pool, - migrator: string, - amount: string, - provider: JsonRpcProvider - ): Promise { - const migrate = new MigrateStaBal3(this.network, this.relayer, staBal3); - return await migrate.queryMigration(migrator, amount, provider); - } + public migrations: Migrations; - migrateStaBal3( - staBal3: Pool, - migrator: string, - amount: string, - expectedBptReturn: string, - slippage: string - ): MigrationAttributes { - const migrate = new MigrateStaBal3(this.network, this.relayer, staBal3); - return migrate.buildMigration( - migrator, - amount, - expectedBptReturn, - slippage - ); + constructor(public network: Network) { + this.migrations = new Migrations(network as 1 | 5); } } From f7d8b1ea4ab1ed341daa1bef2225d77138a71bcf Mon Sep 17 00:00:00 2001 From: bronco Date: Sat, 23 Jul 2022 20:21:17 +0200 Subject: [PATCH 032/104] wip: bbaUsd flow --- .../zaps/bbausd2-migrations/bbausd1.ts | 257 ++++++++++++++ .../src/modules/zaps/migrateBbausd1.ts | 329 ------------------ balancer-js/src/modules/zaps/migrations.ts | 28 ++ 3 files changed, 285 insertions(+), 329 deletions(-) delete mode 100644 balancer-js/src/modules/zaps/migrateBbausd1.ts diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index e69de29bb..49ba3b63d 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -0,0 +1,257 @@ +import { ADDRESSES } from './addresses'; +import { Relayer } from '@/modules/relayer/relayer.module'; +import { BatchSwapStep, FundManagement, SwapType } from '@/modules/swaps/types'; +import { Interface } from '@ethersproject/abi'; +import { MaxUint256, MaxInt256, Zero } from '@ethersproject/constants'; +// TODO - Ask Nico to update Typechain? +import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; +import { PoolToken } from '@/types'; +import { BigNumber } from '@ethersproject/bignumber'; +const balancerRelayerInterface = new Interface(balancerRelayerAbi); + +const SWAP_RESULT_BBAUSD = Relayer.toChainedReference('24'); + +export class BbaUsd1Builder { + private addresses; + + constructor(networkId: 1 | 5) { + this.addresses = ADDRESSES[networkId]; + } + + calldata( + amount: string, + expectedAmount = MaxInt256.toString(), + userAddress: string, + staked: boolean, + authorisation: string, + tokens: PoolToken[] + ): { + to: string; + data: string; + } { + const relayer = this.addresses.relayer; + let calls: string[] = []; + + if (staked) { + calls = [ + this.buildSetRelayerApproval(authorisation), + this.buildWithdraw(userAddress, amount), + this.buildSwap(amount, expectedAmount, relayer, tokens), + this.buildDeposit(userAddress), + ]; + } else { + calls = [ + this.buildSetRelayerApproval(authorisation), + this.buildSwap(amount, expectedAmount, userAddress, tokens), + ]; + } + + const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ + calls, + ]); + + return { + to: this.addresses.relayer, + data: callData, + }; + } + + /** + * Creates encoded batchSwap function to swap Linear BPTs to underlying stables. + * outputreferences should contain the amounts of each new Linear BPT. + * + * @returns BatchSwap call. + */ + buildSwap( + bptAmount: string, + expectedBptReturn: string, + recipient: string, + tokens: PoolToken[] + ): string { + const assets = [ + this.addresses.bbausd2.address, + this.addresses.DAI, + this.addresses.linearDai1.address, + this.addresses.linearDai2.address, + this.addresses.USDC, + this.addresses.linearUsdc1.address, + this.addresses.linearUsdc2.address, + this.addresses.USDT, + this.addresses.linearUsdt1.address, + this.addresses.linearUsdt2.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 = tokens.reduce( + (sum, token) => sum.add(BigNumber.from(token.balance)), + Zero + ); + + const weights = Object.fromEntries( + tokens.map((token) => [ + token.symbol, + BigNumber.from(token.balance).div(totalLiquidity), + ]) + ); + + // bbausd1[bbausd1]blinear1[linear1]stable[linear2]blinear2[bbausd2]bbausd2 and then do that proportionally for each underlying stable. + // TO DO - Will swap order matter here? John to ask Fernando. + + // Split BPT amount proportionally: + const daiBptAmt = BigNumber.from(bptAmount) + .mul(weights['bb-a-DAI']) + .toString(); + const usdcBptAmt = BigNumber.from(bptAmount) + .mul(weights['bb-a-USDC']) + .toString(); + const usdtBptAmt = BigNumber.from(bptAmount) + .mul(weights['bb-a-USDT']) + .toString(); + + const swaps: BatchSwapStep[] = [ + { + poolId: this.addresses.linearDai1.id, + assetInIndex: 2, + assetOutIndex: 1, + amount: daiBptAmt, + 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.linearUsdc1.id, + assetInIndex: 5, + assetOutIndex: 4, + amount: usdcBptAmt, + 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.linearUsdt1.id, + assetInIndex: 8, + assetOutIndex: 7, + amount: usdtBptAmt, + 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 now assuming ref amounts will be safe - should we add more accurate? + const limits = [ + expectedBptReturn.toString(), + MaxInt256.toString(), + MaxInt256.toString(), + MaxInt256.toString(), + MaxInt256.toString(), + MaxInt256.toString(), + MaxInt256.toString(), + MaxInt256.toString(), + MaxInt256.toString(), + 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: MaxUint256, + value: '0', + outputReferences, + }); + + return encodedBatchSwap; + } + + /** + * Is using gauge relayer to withdraw staked BPT from user to itself + * + * @returns withdraw call + */ + buildWithdraw(sender: string, amount: string): string { + return Relayer.encodeGaugeWithdraw( + this.addresses.staBal3.gauge, + sender, + this.addresses.relayer, + amount + ); + } + + /** + * Is using gauge relayer to deposit user's BPT to itself + * + * @returns deposit call + */ + buildDeposit(recipient: string): string { + return Relayer.encodeGaugeDeposit( + this.addresses.bbausd2.gauge, + this.addresses.relayer, + recipient, + SWAP_RESULT_BBAUSD.toString() + ); + } + + buildApproveVault(token: string): string { + return Relayer.encodeApproveVault(token, MaxUint256.toString()); + } + + buildSetRelayerApproval(authorisation: string): string { + return Relayer.encodeSetRelayerApproval( + this.addresses.relayer, + true, + authorisation + ); + } +} diff --git a/balancer-js/src/modules/zaps/migrateBbausd1.ts b/balancer-js/src/modules/zaps/migrateBbausd1.ts deleted file mode 100644 index 6ea2f5ec4..000000000 --- a/balancer-js/src/modules/zaps/migrateBbausd1.ts +++ /dev/null @@ -1,329 +0,0 @@ -import { Contract } from '@ethersproject/contracts'; -import { defaultAbiCoder } from '@ethersproject/abi'; -import { MaxUint256, Zero } from '@ethersproject/constants'; -import { Network } from '@/lib/constants/network'; -import { Relayer, OutputReference } from '../relayer/relayer.module'; -import { SwapType, FundManagement, BatchSwapStep } from '../swaps/types'; - -// TO DO - Ask Nico to update Typechain? -import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; -// we are missing encodeGaugeDeposit / Withdraw functions -import { JsonRpcProvider } from '@ethersproject/providers'; - -import { CONSTANTS, gaugeActionsInterface } from './migrate-stabal3'; -import { Pool } from '@/types'; -import { BigNumber } from '@ethersproject/bignumber'; - -type GaugeWithDraw = string; -type BatchSwap = string; -type GaugeDeposit = string; -type CallData = [GaugeWithDraw, BatchSwap, GaugeDeposit]; - -export interface MigrationAttributes { - to: string; - functionName: string; - calldata: CallData; -} - -export class MigrateBbausd1 { - public constants; - - constructor( - public network: Network, - public relayer: Relayer, - private from: Pool - ) { - if (!(network === Network.MAINNET || network === Network.GOERLI)) - throw new Error('This is not a supported network'); - - this.constants = - this.network === Network.MAINNET ? CONSTANTS.Mainnet : CONSTANTS.Goerli; - } - - /** - * Is using gauge relayer to withdraw staked BPT from user to itself - * - * @returns withdraw call - */ - buildWithdraw(migrator: string, amount: string): GaugeWithDraw { - return gaugeActionsInterface.encodeFunctionData('gaugeWithdraw', [ - this.constants.bbausd1.gauge, - migrator, - this.constants.relayer, - amount, - ]); - } - - /** - * Is using gauge relayer to deposit user's BPT to itself - * - * @returns deposit call - */ - buildDeposit(migrator: string, amount: OutputReference): GaugeDeposit { - return gaugeActionsInterface.encodeFunctionData('gaugeDeposit', [ - this.constants.bbausd2.gauge, - this.constants.relayer, - migrator, - amount, - ]); - } - - /** - * Creates encoded batchSwap function to swap Linear BPTs to underlying stables. - * outputreferences should contain the amounts of each new Linear BPT. - * @param outputReferences References from previous exit call. - * @returns BatchSwap call. - */ - buildSwap( - bptAmount: string, - expectedBptReturn: string, - slippage: string - ): { - call: BatchSwap; - bbausd2AmountsReference: OutputReference; - } { - const { tokens } = this.from; - - // Assuming 1:1 exchange rates between tokens - // TODO: Fetch current prices, or use price or priceRate from subgraph? - const totalLiquidity = tokens.reduce( - (sum, token) => sum.add(BigNumber.from(token.balance)), - Zero - ); - - const weights = Object.fromEntries( - tokens.map((token) => [ - token.symbol, - BigNumber.from(token.balance).div(totalLiquidity), - ]) - ); - - // bbausd1[bbausd1]blinear1[linear1]stable[linear2]blinear2[bbausd2]bbausd2 and then do that proportionally for each underlying stable. - // TO DO - Will swap order matter here? John to ask Fernando. - - // Split BPT amount proportionally: - const daiBptAmt = BigNumber.from(bptAmount) - .mul(weights['bb-a-DAI']) - .toString(); - const usdcBptAmt = BigNumber.from(bptAmount) - .mul(weights['bb-a-USDC']) - .toString(); - const usdtBptAmt = BigNumber.from(bptAmount) - .mul(weights['bb-a-USDT']) - .toString(); - - const swaps: BatchSwapStep[] = [ - { - poolId: this.constants.bbausd1.id, - assetInIndex: 0, - assetOutIndex: 1, - amount: daiBptAmt, - userData: '0x', - }, - { - poolId: this.constants.linearDai1.id, - assetInIndex: 1, - assetOutIndex: 2, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.linearDai2.id, - assetInIndex: 2, - assetOutIndex: 3, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.bbausd2.id, - assetInIndex: 3, - assetOutIndex: 4, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.bbausd1.id, - assetInIndex: 0, - assetOutIndex: 5, - amount: usdcBptAmt, - userData: '0x', - }, - { - poolId: this.constants.linearUsdc1.id, - assetInIndex: 5, - assetOutIndex: 6, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.linearUsdc2.id, - assetInIndex: 6, - assetOutIndex: 7, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.bbausd2.id, - assetInIndex: 7, - assetOutIndex: 4, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.bbausd1.id, - assetInIndex: 0, - assetOutIndex: 8, - amount: usdtBptAmt, - userData: '0x', - }, - { - poolId: this.constants.linearUsdt1.id, - assetInIndex: 8, - assetOutIndex: 9, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.linearUsdt2.id, - assetInIndex: 9, - assetOutIndex: 10, - amount: '0', - userData: '0x', - }, - { - poolId: this.constants.bbausd2.id, - assetInIndex: 10, - assetOutIndex: 4, - amount: '0', - userData: '0x', - }, - ]; - - const assets = [ - this.constants.bbausd1.address, - this.constants.linearDai1.address, - this.constants.DAI, - this.constants.linearDai2.address, - this.constants.bbausd2.address, - this.constants.linearUsdc1.address, - this.constants.USDC, - this.constants.linearUsdc2.address, - this.constants.linearUsdt1.address, - this.constants.USDT, - this.constants.linearUsdt2.address, - ]; - - // For now assuming ref amounts will be safe - should we add more accurate? - const limits = [ - bptAmount, - '0', - '0', - '0', - expectedBptReturn, // Can use expectedBpt amount and slippage to set this limit - '0', - '0', - '0', - '0', - '0', - '0', - '0', - ]; - - // Swap to/from Relayer - const funds: FundManagement = { - sender: this.constants.relayer, - recipient: this.constants.relayer, - fromInternalBalance: false, - toInternalBalance: false, - }; - - // Output of exit is used as input to swaps - // This should have a value for each delta returned by batchSwap - const swapOutputReferences: OutputReference[] = []; - assets.forEach((asset, i) => { - const key = Relayer.toChainedReference(i); - swapOutputReferences.push({ - index: i, - key: key, - }); - }); - - const encodedBatchSwap = Relayer.encodeBatchSwap({ - swapType: SwapType.SwapExactIn, - swaps: swaps, - assets: assets, - funds: funds, - limits, - deadline: MaxUint256, - value: '0', - outputReferences: swapOutputReferences, - }); - - // We only need the deltas/amounts of the new bbausd2 pools (matches assets index) - // Final order should match token order required for joinPool - const bbausd2AmountsReference = swapOutputReferences[4]; - - return { - call: encodedBatchSwap, - bbausd2AmountsReference: bbausd2AmountsReference, - }; - } - - buildMigration( - migrator: string, - amount: string, - slippage: string - ): MigrationAttributes { - /* - the flow is: - withdraw from gauge - swap bbausd1 > bbausd2 via proportional underlying. - deposit into gauge - */ - const gaugeWithdraw = this.buildWithdraw(migrator, amount); - - // Fernando - final bbausd2 amount should equal bbausd1 input amount - // Use this to set final swap limit - const swaps = this.buildSwap(amount, amount, slippage); - - const gaugeDeposit = this.buildDeposit( - migrator, - swaps.bbausd2AmountsReference - ); - - const calls: CallData = [gaugeWithdraw, swaps.call, gaugeDeposit]; - - return { - to: this.constants.relayer, - functionName: 'multicall', - calldata: calls, - }; - } - - /** - * Statically calls migration action to find final bbausd2 BPT amount returned. - * @param migrator Migrator address. - * @param amount Amount of bbausd1 BPT. - * @param provider Provider. - * @returns BPT amount from poolJoin call. - */ - async queryMigration( - migrator: string, - amount: string, - poolData: Pool, - provider: JsonRpcProvider - ): Promise { - const migrationData = this.buildMigration(migrator, amount, '0'); - const relayerContract = new Contract( - this.constants.relayer, - balancerRelayerAbi, - provider - ); - // Returns result of each call in an array - const tx = await relayerContract.callStatic[migrationData.functionName]( - migrationData.calldata - ); - // bbausd2 delta amount from batchSwap call - return defaultAbiCoder.decode(['int256[]'], tx[1])[4].toString(); - } -} diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index c518bdf3e..78f16aaa3 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -1,6 +1,8 @@ import { defaultAbiCoder } from '@ethersproject/abi'; import { MaxInt256 } from '@ethersproject/constants'; import { StaBal3Builder } from './bbausd2-migrations/stabal3'; +import { BbaUsd1Builder } from './bbausd2-migrations/bbausd1'; +import { PoolToken } from '@/types'; export class Migrations { constructor(private network: 1 | 5) {} @@ -28,4 +30,30 @@ export class Migrations { defaultAbiCoder.decode(['int256[]'], output[2])[3].toString(), }; } + + bbaUsd( + userAddress: string, + amount: string, + limit = MaxInt256.toString(), + authorisation: string, + staked: boolean, + tokens: PoolToken[] + ): { to: string; data: string; decode: (output: string) => string } { + const builder = new BbaUsd1Builder(this.network); + const request = builder.calldata( + amount, + limit, + userAddress, + staked, + authorisation, + tokens + ); + + return { + to: request.to, + data: request.data, + decode: (output) => + defaultAbiCoder.decode(['int256[]'], output[2])[3].toString(), + }; + } } From b0fc5725a760dd50266f5916206a3fac9e579829 Mon Sep 17 00:00:00 2001 From: bronco Date: Sat, 23 Jul 2022 20:26:20 +0200 Subject: [PATCH 033/104] fix: Zaps module init --- balancer-js/src/modules/sdk.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balancer-js/src/modules/sdk.module.ts b/balancer-js/src/modules/sdk.module.ts index 238f879d9..07c8e32ef 100644 --- a/balancer-js/src/modules/sdk.module.ts +++ b/balancer-js/src/modules/sdk.module.ts @@ -46,7 +46,7 @@ export class BalancerSDK implements BalancerSDKRoot { networkConfig.addresses.contracts, sor.provider ); - this.zaps = new Zaps(networkConfig.chainId, this.relayer); + this.zaps = new Zaps(networkConfig.chainId); } get networkConfig(): BalancerNetworkConfig { From 74f264204e2f23d8f34c4112bd9aa8188c60da3f Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 25 Jul 2022 16:52:25 -0300 Subject: [PATCH 034/104] Fix findBy address on SubgraphRepository --- balancer-js/src/modules/data/pool/subgraph.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/balancer-js/src/modules/data/pool/subgraph.ts b/balancer-js/src/modules/data/pool/subgraph.ts index 67c9a250f..3def4012e 100644 --- a/balancer-js/src/modules/data/pool/subgraph.ts +++ b/balancer-js/src/modules/data/pool/subgraph.ts @@ -22,7 +22,7 @@ export class SubgraphPoolRepository implements PoolRepository { const { pool0 } = await this.client.Pools({ where: { address: value }, }); - return this.mapPool(pool0); + return this.mapPool(pool0[0]); default: return undefined; } @@ -33,9 +33,9 @@ export class SubgraphPoolRepository implements PoolRepository { // eslint-disable-next-line @typescript-eslint/no-explicit-any private mapPool(pool: any): Pool | undefined { if (!pool) return undefined; - const poolType = pool?.poolType as PoolType; + const poolType = pool.poolType as PoolType; if (!poolType) throw new Error('Unknown pool type'); - const tokens = (pool?.tokens as PoolToken[]) || []; + const tokens = (pool.tokens as PoolToken[]) || []; if (tokens.length === 0) throw new Error('Pool without tokens'); return { ...pool, From abecc57552f1ef8d12e2da274163fe7be373f686 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 25 Jul 2022 16:53:47 -0300 Subject: [PATCH 035/104] Add bbusd1 migration integration test --- .../bbausd1.integration.spec.ts | 256 ++++++++++++++++++ .../zaps/bbausd2-migrations/bbausd1.ts | 23 +- 2 files changed, 269 insertions(+), 10 deletions(-) create mode 100644 balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts 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 new file mode 100644 index 000000000..f235a568d --- /dev/null +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -0,0 +1,256 @@ +import dotenv from 'dotenv'; +import { expect } from 'chai'; +import hardhat from 'hardhat'; +import { + BalancerError, + BalancerErrorCode, + Network, + RelayerAuthorization, + PoolModel, + Subgraph, + SubgraphPoolRepository, +} from '@/.'; +import { BigNumber } from '@ethersproject/bignumber'; +import { Contracts } from '@/modules/contracts/contracts.module'; +import { ADDRESSES } from './addresses'; +import { BbaUsd1Builder as MigrationBuilder } from './bbausd1'; +import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; +import { parseEther, formatEther } from '@ethersproject/units'; +import { JsonRpcSigner } from '@ethersproject/providers'; +import { MaxUint256 } from '@ethersproject/constants'; + +import { Interface } from '@ethersproject/abi'; +import { PoolsProvider } from '@/modules/pools/provider'; +const liquidityGaugeAbi = ['function deposit(uint value) payable']; +const liquidityGauge = new Interface(liquidityGaugeAbi); + +/* + * Testing on GOERLI + * - Update hardhat.config.js with chainId = 5 + * - Update ALCHEMY_URL on .env with a goerli api key + * - Run goerli node on terminal: yarn run node + * - Change `network` to Network.GOERLI + * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli + */ + +dotenv.config(); + +const { ALCHEMY_URL: jsonRpcUrl, FORK_BLOCK_NUMBER: blockNumber } = process.env; +const { ethers } = hardhat; +const MAX_GAS_LIMIT = 8e6; + +const network = Network.GOERLI; +const rpcUrl = 'http://127.0.0.1:8545'; +const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); +const addresses = ADDRESSES[network]; +const { contracts } = new Contracts(network as number, provider); +const migration = new MigrationBuilder(network); + +const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; +const poolAddress = addresses.bbausd1.address; +const gaugeAddress = addresses.bbausd1.gauge; +const relayer = addresses.relayer; + +const getErc20Balance = (token: string, holder: string): Promise => + contracts.ERC20(token, provider).balanceOf(holder); + +// https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#impersonating-accounts +// WARNING: don't use hardhat SignerWithAddress to sendTransactions!! +// It's not working and we didn't have time to figure out why. +// Use JsonRpcSigner instead +const impersonateAccount = async (account: string) => { + await provider.send('hardhat_impersonateAccount', [account]); + await setBalance(account, parseEther('10000')); + return provider.getSigner(account); +}; + +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: (blockNumber && parseInt(blockNumber)) || 7277540, + }, + }, + ]); + +const move = async ( + token: string, + from: string, + to: string +): Promise => { + const holder = await impersonateAccount(from); + const balance = await getErc20Balance(token, from); + await contracts.ERC20(token, provider).connect(holder).transfer(to, balance); + + return balance; +}; + +const stake = async ( + signer: JsonRpcSigner, + balance: BigNumber +): Promise => { + await ( + await contracts + .ERC20(poolAddress, provider) + .connect(signer) + .approve(gaugeAddress, MaxUint256) + ).wait(); + + await ( + await signer.sendTransaction({ + to: gaugeAddress, + data: liquidityGauge.encodeFunctionData('deposit', [balance]), + }) + ).wait(); +}; + +describe('execution', async () => { + let signer: JsonRpcSigner; + let signerAddress: string; + let authorisation: string; + let balance: BigNumber; + let pool: PoolModel; + + beforeEach(async function () { + this.timeout(20000); + + 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(poolAddress, holderAddress, signerAddress); + + const config = { + network, + rpcUrl, + }; + const subgraph = new Subgraph(config); + const pools = new PoolsProvider( + config, + new SubgraphPoolRepository(subgraph.client) + ); + const _pool = await pools.findBy('address', poolAddress); + if (!_pool) throw new BalancerError(BalancerErrorCode.POOL_DOESNT_EXIST); + pool = _pool; + }); + + context('staked', async () => { + beforeEach(async function () { + this.timeout(20000); + + // Stake them + await stake(signer, balance); + }); + + it('should transfer tokens from stable to boosted', async () => { + // Store balance before migration + const before = { + from: await getErc20Balance(gaugeAddress, signerAddress), + to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), + }; + + const query = migration.calldata( + before.from.toString(), + undefined, + signerAddress, + true, + authorisation, + pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') + ); + + const { to, data } = query; + const gasLimit = MAX_GAS_LIMIT; + const response = await signer.sendTransaction({ to, data, gasLimit }); + + const reciept = await response.wait(); + console.log('Gas used', reciept.gasUsed.toString()); + + const after = { + from: await getErc20Balance(gaugeAddress, signerAddress), + to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), + }; + + const diffs = { + from: after.from.sub(before.from), + to: after.to.sub(before.to), + }; + + console.log(diffs.from, diffs.to); + + expect(diffs.from).to.eql(before.from.mul(-1)); + expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + }).timeout(20000); + }); + + context('not staked', async () => { + it('should transfer tokens from stable to boosted', async () => { + // Store balance before migration + const before = { + from: await getErc20Balance(poolAddress, signerAddress), + to: await getErc20Balance(addresses.bbausd2.address, signerAddress), + }; + + const query = migration.calldata( + before.from.toString(), + undefined, + signerAddress, + false, + authorisation, + pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') + ); + + const { to, data } = query; + const gasLimit = MAX_GAS_LIMIT; + const response = await signer.sendTransaction({ to, data, gasLimit }); + + const reciept = await response.wait(); + console.log('Gas used', reciept.gasUsed.toString()); + + const after = { + from: await getErc20Balance(poolAddress, signerAddress), + to: await getErc20Balance(addresses.bbausd2.address, signerAddress), + }; + + const diffs = { + from: after.from.sub(before.from), + to: after.to.sub(before.to), + }; + + console.log(diffs.from, diffs.to); + + expect(diffs.from).to.eql(before.from.mul(-1)); + expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + }).timeout(20000); + }); +}).timeout(20000); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 49ba3b63d..2ea67df93 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -6,7 +6,7 @@ import { MaxUint256, MaxInt256, Zero } from '@ethersproject/constants'; // TODO - Ask Nico to update Typechain? import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; import { PoolToken } from '@/types'; -import { BigNumber } from '@ethersproject/bignumber'; +import { BigNumber, parseFixed } from '@ethersproject/bignumber'; const balancerRelayerInterface = new Interface(balancerRelayerAbi); const SWAP_RESULT_BBAUSD = Relayer.toChainedReference('24'); @@ -88,14 +88,14 @@ export class BbaUsd1Builder { // Assuming 1:1 exchange rates between tokens // TODO: Fetch current prices, or use price or priceRate from subgraph? const totalLiquidity = tokens.reduce( - (sum, token) => sum.add(BigNumber.from(token.balance)), + (sum, token) => sum.add(parseFixed(token.balance, 18)), Zero ); - const weights = Object.fromEntries( + const balances = Object.fromEntries( tokens.map((token) => [ token.symbol, - BigNumber.from(token.balance).div(totalLiquidity), + parseFixed(token.balance, 18).toString(), ]) ); @@ -103,14 +103,17 @@ export class BbaUsd1Builder { // TO DO - Will swap order matter here? John to ask Fernando. // Split BPT amount proportionally: - const daiBptAmt = BigNumber.from(bptAmount) - .mul(weights['bb-a-DAI']) - .toString(); const usdcBptAmt = BigNumber.from(bptAmount) - .mul(weights['bb-a-USDC']) + .mul(balances['bb-a-USDC']) + .div(totalLiquidity) .toString(); const usdtBptAmt = BigNumber.from(bptAmount) - .mul(weights['bb-a-USDT']) + .mul(balances['bb-a-USDT']) + .div(totalLiquidity) + .toString(); + const daiBptAmt = BigNumber.from(bptAmount) + .sub(BigNumber.from(usdcBptAmt)) + .sub(BigNumber.from(usdtBptAmt)) .toString(); const swaps: BatchSwapStep[] = [ @@ -222,7 +225,7 @@ export class BbaUsd1Builder { */ buildWithdraw(sender: string, amount: string): string { return Relayer.encodeGaugeWithdraw( - this.addresses.staBal3.gauge, + this.addresses.bbausd1.gauge, sender, this.addresses.relayer, amount From 06abc0747c5ba35bab14b2bcb1e165f285e80821 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 25 Jul 2022 17:25:51 -0300 Subject: [PATCH 036/104] Add missing swaps --- .../zaps/bbausd2-migrations/bbausd1.ts | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 2ea67df93..c49167363 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -79,6 +79,7 @@ export class BbaUsd1Builder { this.addresses.USDT, this.addresses.linearUsdt1.address, this.addresses.linearUsdt2.address, + this.addresses.bbausd1.address, ]; const outputReferences = [{ index: 0, key: SWAP_RESULT_BBAUSD }]; @@ -117,11 +118,18 @@ export class BbaUsd1Builder { .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: daiBptAmt, + amount: '0', userData: '0x', }, { @@ -138,11 +146,18 @@ export class BbaUsd1Builder { 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: usdcBptAmt, + amount: '0', userData: '0x', }, { @@ -159,11 +174,18 @@ export class BbaUsd1Builder { 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: usdtBptAmt, + amount: '0', userData: '0x', }, { @@ -194,6 +216,7 @@ export class BbaUsd1Builder { MaxInt256.toString(), MaxInt256.toString(), MaxInt256.toString(), + MaxInt256.toString(), ]; // Swap to/from Relayer From b79dad92494884b2a4718049b48b9df2eeb88d87 Mon Sep 17 00:00:00 2001 From: bronco Date: Tue, 26 Jul 2022 08:34:14 +0200 Subject: [PATCH 037/104] adding waDai address --- balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 43fb05074..ee6de65d6 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -44,6 +44,7 @@ export const ADDRESSES = { DAI: '0x6b175474e89094c44da98b954eedeac495271d0f', USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', }, 5: { relayer: '0x7b9B6f094DC2Bd1c12024b0D9CC63d6993Be1888', @@ -90,5 +91,6 @@ export const ADDRESSES = { USDT: '0x1f1f156e0317167c11aa412e3d1435ea29dc3cce', DAI: '0x8c9e6c40d3402480ace624730524facc5482798c', USDC: '0xe0c9275e44ea80ef17579d33c55136b7da269aeb', + waDAI: '0x89534a24450081aa267c79b07411e9617d984052', }, }; From d49a8a6aee2f33638c83941ddfbcc84a5f520697 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Tue, 26 Jul 2022 15:05:49 -0300 Subject: [PATCH 038/104] Replace stable by wrapped tokens on migration swaps --- .../src/modules/zaps/bbausd2-migrations/addresses.ts | 4 ++++ balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index ee6de65d6..93f146180 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -45,6 +45,8 @@ export const ADDRESSES = { USDC: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7', waDAI: '0x02d60b84491589974263d922d9cc7a3152618ef6', + waUSDC: '0xd093fa4fb80d09bb30817fdcd442d4d02ed3e5de', + waUSDT: '0xf8fd466f12e236f4c96f7cce6c79eadb819abf58', }, 5: { relayer: '0x7b9B6f094DC2Bd1c12024b0D9CC63d6993Be1888', @@ -92,5 +94,7 @@ export const ADDRESSES = { DAI: '0x8c9e6c40d3402480ace624730524facc5482798c', USDC: '0xe0c9275e44ea80ef17579d33c55136b7da269aeb', waDAI: '0x89534a24450081aa267c79b07411e9617d984052', + waUSDC: '0x811151066392fd641fe74a9b55a712670572d161', + waUSDT: '0x4cb1892fddf14f772b2e39e299f44b2e5da90d04', }, }; diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index c49167363..7009b0489 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -70,13 +70,13 @@ export class BbaUsd1Builder { ): string { const assets = [ this.addresses.bbausd2.address, - this.addresses.DAI, + this.addresses.waDAI, this.addresses.linearDai1.address, this.addresses.linearDai2.address, - this.addresses.USDC, + this.addresses.waUSDC, this.addresses.linearUsdc1.address, this.addresses.linearUsdc2.address, - this.addresses.USDT, + this.addresses.waUSDT, this.addresses.linearUsdt1.address, this.addresses.linearUsdt2.address, this.addresses.bbausd1.address, From db9d4d49955cee28fccbf2a05472742aa9454bc0 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Tue, 26 Jul 2022 15:06:38 -0300 Subject: [PATCH 039/104] Fix swaps starting from relayer on non-staked migration scenario --- .../src/modules/zaps/bbausd2-migrations/bbausd1.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 7009b0489..3b32700a8 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -36,13 +36,19 @@ export class BbaUsd1Builder { calls = [ this.buildSetRelayerApproval(authorisation), this.buildWithdraw(userAddress, amount), - this.buildSwap(amount, expectedAmount, relayer, tokens), + this.buildSwap(amount, expectedAmount, relayer, relayer, tokens), this.buildDeposit(userAddress), ]; } else { calls = [ this.buildSetRelayerApproval(authorisation), - this.buildSwap(amount, expectedAmount, userAddress, tokens), + this.buildSwap( + amount, + expectedAmount, + userAddress, + userAddress, + tokens + ), ]; } @@ -65,6 +71,7 @@ export class BbaUsd1Builder { buildSwap( bptAmount: string, expectedBptReturn: string, + sender: string, recipient: string, tokens: PoolToken[] ): string { @@ -221,7 +228,7 @@ export class BbaUsd1Builder { // Swap to/from Relayer const funds: FundManagement = { - sender: this.addresses.relayer, + sender, recipient, fromInternalBalance: true, toInternalBalance: false, From a9e8d08e12fa254e13210a3ac2136d7c12849646 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Tue, 26 Jul 2022 15:08:03 -0300 Subject: [PATCH 040/104] Temporarily replace impersonated account to make integration test pass --- .../modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index f235a568d..6421829e1 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -46,7 +46,7 @@ const addresses = ADDRESSES[network]; const { contracts } = new Contracts(network as number, provider); const migration = new MigrationBuilder(network); -const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; +const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; const poolAddress = addresses.bbausd1.address; const gaugeAddress = addresses.bbausd1.gauge; const relayer = addresses.relayer; From cf75e4676141826ba7a49afc7b6a50e629dc2208 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 27 Jul 2022 09:41:03 -0300 Subject: [PATCH 041/104] Fix lint warnings --- balancer-js/src/modules/zaps/zaps.module.integration.spec.ts | 3 +-- balancer-js/src/test/lib/utils.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts b/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts index edbc60f14..a1ca40a7c 100644 --- a/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts +++ b/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts @@ -1,13 +1,12 @@ import dotenv from 'dotenv'; import { expect } from 'chai'; import { Contracts } from '@/modules/contracts/contracts.module'; -import { Network, Relayer } from '@/.'; +import { Network } from '@/.'; import hardhat from 'hardhat'; import { BigNumber, parseFixed } from '@ethersproject/bignumber'; import { forkSetup } from '@/test/lib/utils'; -import { Zaps } from './zaps.module'; /* * Testing on GOERLI diff --git a/balancer-js/src/test/lib/utils.ts b/balancer-js/src/test/lib/utils.ts index 3ecbd5f76..a8ccb9c2b 100644 --- a/balancer-js/src/test/lib/utils.ts +++ b/balancer-js/src/test/lib/utils.ts @@ -1,4 +1,4 @@ -import { Provider, JsonRpcSigner } from '@ethersproject/providers'; +import { JsonRpcSigner } from '@ethersproject/providers'; import { BigNumber } from '@ethersproject/bignumber'; import { balancerVault } from '@/lib/constants/config'; import { hexlify, zeroPad } from '@ethersproject/bytes'; From 1b4f423623718a7b3797c73eba3f1c8ea28e3fb8 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 27 Jul 2022 14:01:19 -0300 Subject: [PATCH 042/104] Fix stabal3 integration test timeout being too short --- .../zaps/bbausd2-migrations/stabal3.integration.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index 3fc623b4b..00547cbce 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -136,7 +136,8 @@ describe('execution', async () => { let authorisation: string; let balance: BigNumber; - beforeEach(async () => { + beforeEach(async function () { + this.timeout(20000); await reset(); signer = provider.getSigner(); From af7d3c504516d90af4ccd3463b6301bb2b15e65e Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 27 Jul 2022 14:02:07 -0300 Subject: [PATCH 043/104] Add generic stables migration flow --- .../zaps/bbausd2-migrations/addresses.ts | 6 + .../stables.integration.spec.ts | 251 ++++++++++++++++++ .../zaps/bbausd2-migrations/stables.ts | 207 +++++++++++++++ balancer-js/src/modules/zaps/migrations.ts | 31 +++ 4 files changed, 495 insertions(+) create mode 100644 balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts create mode 100644 balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 93f146180..eb986df66 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -56,6 +56,12 @@ export const ADDRESSES = { gauge: '0xfd364cda96bb7db06b65706182c448a73f0a5f9a', assetOrder: ['USDT', 'DAI', 'USDC'], }, + staBal3_2: { + id: '0xff9d677474d4344379924e10b68c8fea67e03294000000000000000000000072', + address: '0xff9d677474d4344379924e10b68c8fea67e03294', + gauge: '0x4e4ebf2aa90e41174d716a5168895357762d68af', + assetOrder: ['USDT', 'DAI', 'USDC'], + }, bbausd1: { id: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd00000000000000000000005f', address: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd', 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 new file mode 100644 index 000000000..1bad8af1c --- /dev/null +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -0,0 +1,251 @@ +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 { StablesBuilder as MigrationBuilder } from './stables'; +import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; +import { parseEther, formatEther } from '@ethersproject/units'; +import { JsonRpcSigner } from '@ethersproject/providers'; +import { MaxUint256 } from '@ethersproject/constants'; + +import { Interface } from '@ethersproject/abi'; +import { Migrations } from '../migrations'; +const liquidityGaugeAbi = ['function deposit(uint value) payable']; +const liquidityGauge = new Interface(liquidityGaugeAbi); + +/* + * Testing on GOERLI + * - Update hardhat.config.js with chainId = 5 + * - Update ALCHEMY_URL on .env with a goerli api key + * - Run goerli node on terminal: yarn run node + * - Change `network` to Network.GOERLI + * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli + */ + +dotenv.config(); + +const { ALCHEMY_URL: jsonRpcUrl, FORK_BLOCK_NUMBER: blockNumber } = process.env; +const { ethers } = hardhat; +const MAX_GAS_LIMIT = 8e6; + +const network = Network.GOERLI; +const rpcUrl = 'http://127.0.0.1:8545'; +const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); +const addresses = ADDRESSES[network]; +const { contracts } = new Contracts(network as number, provider); +const migration = new MigrationBuilder(network); + +const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; +const fromPool = { + id: addresses.staBal3.id, + address: addresses.staBal3.address, + gauge: addresses.staBal3.gauge, +}; +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 +const fromGauge = addresses.staBal3.gauge; +const toGauge = addresses.staBal3_2.gauge; +const relayer = addresses.relayer; + +const getErc20Balance = (token: string, holder: string): Promise => + contracts.ERC20(token, provider).balanceOf(holder); + +// https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#impersonating-accounts +// WARNING: don't use hardhat SignerWithAddress to sendTransactions!! +// It's not working and we didn't have time to figure out why. +// Use JsonRpcSigner instead +const impersonateAccount = async (account: string) => { + await provider.send('hardhat_impersonateAccount', [account]); + await setBalance(account, parseEther('10000')); + return provider.getSigner(account); +}; + +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: blockNumber && parseInt(blockNumber), + }, + }, + ]); + +const move = async ( + token: string, + from: string, + to: string +): Promise => { + const holder = await impersonateAccount(from); + const balance = await getErc20Balance(token, from); + await contracts.ERC20(token, provider).connect(holder).transfer(to, balance); + + return balance; +}; + +const stake = async ( + signer: JsonRpcSigner, + balance: BigNumber +): Promise => { + await ( + await contracts + .ERC20(fromPool.address, provider) + .connect(signer) + .approve(fromGauge, MaxUint256) + ).wait(); + + await ( + await signer.sendTransaction({ + to: fromGauge, + data: liquidityGauge.encodeFunctionData('deposit', [balance]), + }) + ).wait(); +}; + +describe('execution', async () => { + let signer: JsonRpcSigner; + let signerAddress: string; + let authorisation: string; + let balance: BigNumber; + + beforeEach(async function () { + this.timeout(20000); + 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); + }); + + context('staked', async () => { + beforeEach(async function () { + this.timeout(20000); + + // Stake them + await stake(signer, balance); + }); + + it('should transfer tokens from stable to boosted', async () => { + // Store balance before migration + const before = { + from: await getErc20Balance(fromGauge, signerAddress), + to: await getErc20Balance(toGauge, signerAddress), + }; + + const migrations = new Migrations(network); + const query = migrations.stables( + fromPool, + toPool, + signerAddress, + before.from.toString(), + undefined, + authorisation, + true, + tokens + ); + + const { to, data } = query; + const gasLimit = MAX_GAS_LIMIT; + const response = await signer.sendTransaction({ to, data, gasLimit }); + + const reciept = await response.wait(); + console.log('Gas used', reciept.gasUsed.toString()); + + const after = { + from: await getErc20Balance(fromGauge, signerAddress), + to: await getErc20Balance(toGauge, signerAddress), + }; + + const diffs = { + from: after.from.sub(before.from), + to: after.to.sub(before.to), + }; + + console.log(diffs.from, diffs.to); + + expect(diffs.from).to.eql(before.from.mul(-1)); + expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + }).timeout(20000); + }); + + context('not staked', async () => { + it('should transfer tokens from stable to boosted', async () => { + // Store balance before migration + const before = { + from: await getErc20Balance(fromPool.address, signerAddress), + to: await getErc20Balance(toPool.address, signerAddress), + }; + + const migrations = new Migrations(network); + const query = migrations.stables( + fromPool, + toPool, + signerAddress, + before.from.toString(), + undefined, + authorisation, + false, + tokens + ); + + const { to, data } = query; + const gasLimit = MAX_GAS_LIMIT; + const response = await signer.sendTransaction({ to, data, gasLimit }); + + const reciept = await response.wait(); + console.log('Gas used', reciept.gasUsed.toString()); + + const after = { + from: await getErc20Balance(fromPool.address, signerAddress), + to: await getErc20Balance(toPool.address, signerAddress), + }; + + const diffs = { + from: after.from.sub(before.from), + to: after.to.sub(before.to), + }; + + console.log(diffs.from, diffs.to); + + expect(diffs.from).to.eql(before.from.mul(-1)); + expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + }).timeout(20000); + }); +}).timeout(20000); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts new file mode 100644 index 000000000..c97911099 --- /dev/null +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -0,0 +1,207 @@ +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 { MaxUint256, MaxInt256 } from '@ethersproject/constants'; +// TODO - Ask Nico to update Typechain? +import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; +import { BigNumber } from 'ethers'; +const balancerRelayerInterface = new Interface(balancerRelayerAbi); + +const SWAP_RESULT = Relayer.toChainedReference('0'); +const EXIT_RESULTS: BigNumber[] = []; + +export class StablesBuilder { + private addresses; + + constructor(networkId: 1 | 5) { + this.addresses = ADDRESSES[networkId]; + } + + calldata( + from: { id: string; address: string; gauge?: string }, + to: { id: string; address: string; gauge?: string }, + userAddress: string, + amount: string, + expectedAmount = MaxInt256.toString(), + authorisation: string, + staked: boolean, + tokens: string[] + ): { + to: string; + data: string; + } { + const relayer = this.addresses.relayer; + let calls: string[] = []; + if (staked && (from.gauge == undefined || to.gauge == undefined)) + throw new Error( + 'Staked flow migration requires gauge addresses to be provided' + ); + + if (staked) { + calls = [ + this.buildSetRelayerApproval(authorisation), + this.buildWithdraw(userAddress, amount, from.gauge as string), + this.buildExit(from.id, relayer, relayer, amount, tokens), + this.buildSwap(expectedAmount, relayer, to.id, to.address, tokens), + this.buildDeposit(userAddress, to.gauge as string), + ]; + } else { + calls = [ + this.buildSetRelayerApproval(authorisation), + this.buildExit(from.id, userAddress, relayer, amount, tokens), + this.buildSwap(expectedAmount, userAddress, to.id, to.address, tokens), + ]; + } + + const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ + calls, + ]); + + return { + to: this.addresses.relayer, + data: callData, + }; + } + + /** + * Encodes exitPool callData. + * Exit staBal3 pool proportionally to underlying Linear BPTs. Exits to relayer. + * Outputreferences are used to store exit amounts for next transaction. + * + * @param migrator Migrator address. + * @param amount Amount of staBal3 BPT to exit with. + * @returns Encoded exitPool call. Output references. + */ + buildExit( + poolId: string, + sender: string, + recipient: string, + amount: string, + tokens: string[] + ): string { + // Assume gaugeWithdraw returns same amount value + const userData = StablePoolEncoder.exitExactBPTInForTokensOut(amount); + + // Ask to store exit outputs for batchSwap of exit is used as input to swaps + // TODO: check how does tokens order matter between exits and swaps + const outputReferences = []; + for (let i = 0; i < tokens.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 callData = Relayer.constructExitCall({ + assets: tokens, + minAmountsOut: ['0', '0', '0'], + userData, + toInternalBalance: true, + poolId, + poolKind: 0, // This will always be 0 to match supported Relayer types + sender, + recipient, + outputReferences, + exitPoolRequest: {} as ExitPoolRequest, + }); + + return callData; + } + + /** + * Creates encoded batchSwap function to swap Linear BPTs to underlying stables. + * outputreferences should contain the amounts of each new Linear BPT. + * + * @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 now assuming ref amounts will be safe - should we add more accurate? + const limits = [expectedBptReturn.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: MaxUint256, + value: '0', + outputReferences, + }); + + return encodedBatchSwap; + } + + /** + * Is using gauge relayer to withdraw staked BPT from user to itself + * + * @returns withdraw call + */ + buildWithdraw(sender: string, amount: string, address: string): string { + return Relayer.encodeGaugeWithdraw( + address, + sender, + this.addresses.relayer, + amount + ); + } + + /** + * Is using gauge relayer to deposit user's BPT to itself + * + * @returns deposit call + */ + buildDeposit(recipient: string, address: string): string { + return Relayer.encodeGaugeDeposit( + address, + this.addresses.relayer, + recipient, + SWAP_RESULT.toString() + ); + } + + 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 index 78f16aaa3..aac39288a 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -2,6 +2,7 @@ import { defaultAbiCoder } from '@ethersproject/abi'; import { MaxInt256 } from '@ethersproject/constants'; import { StaBal3Builder } from './bbausd2-migrations/stabal3'; import { BbaUsd1Builder } from './bbausd2-migrations/bbausd1'; +import { StablesBuilder } from './bbausd2-migrations/stables'; import { PoolToken } from '@/types'; export class Migrations { @@ -56,4 +57,34 @@ export class Migrations { defaultAbiCoder.decode(['int256[]'], output[2])[3].toString(), }; } + + stables( + from: { id: string; address: string; gauge?: string }, + to: { id: string; address: string; gauge?: string }, + userAddress: string, + amount: string, + limit = MaxInt256.toString(), + authorisation: string, + staked: boolean, + tokens: string[] + ): { to: string; data: string; decode: (output: string) => string } { + const builder = new StablesBuilder(this.network); + const request = builder.calldata( + from, + to, + userAddress, + amount, + limit, + authorisation, + staked, + tokens + ); + + return { + to: request.to, + data: request.data, + decode: (output) => + defaultAbiCoder.decode(['int256[]'], output[2])[3].toString(), + }; + } } From a5aa2d0da6b00675ef4941006fbe5598b5ae585d Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 27 Jul 2022 14:32:35 -0300 Subject: [PATCH 044/104] Fix remaining merge issue --- balancer-js/src/modules/swaps/swaps.module.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/balancer-js/src/modules/swaps/swaps.module.spec.ts b/balancer-js/src/modules/swaps/swaps.module.spec.ts index 798f990c0..c25257ac9 100644 --- a/balancer-js/src/modules/swaps/swaps.module.spec.ts +++ b/balancer-js/src/modules/swaps/swaps.module.spec.ts @@ -12,7 +12,7 @@ import { getNetworkConfig } from '@/modules/sdk.helpers'; import { mockPool, mockPoolDataService } from '@/test/lib/mockPool'; import { SwapTransactionRequest, SwapType } from './types'; import { Vault__factory } from '@balancer-labs/typechain'; -import vaultActionsAbi from '@/lib/abi/VaultActions.json'; +import BatchRelayerLibraryAbi from '@/lib/abi/BatchRelayerLibrary.json'; import { Interface } from '@ethersproject/abi'; import { BigNumber } from '@ethersproject/bignumber'; import { AddressZero, MaxUint256 } from '@ethersproject/constants'; @@ -34,7 +34,7 @@ const sdkConfig: BalancerSdkConfig = { }; const vaultInterface = Vault__factory.createInterface(); -const vaultActions = new Interface(vaultActionsAbi); +const vaultActions = new Interface(BatchRelayerLibraryAbi); const funds = { fromInternalBalance: false, From beb3112c83a992b572df009a1986f2abc6c066fa Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 27 Jul 2022 14:40:38 -0300 Subject: [PATCH 045/104] Update migration tests description --- .../zaps/bbausd2-migrations/bbausd1.integration.spec.ts | 2 +- .../zaps/bbausd2-migrations/stabal3.integration.spec.ts | 2 +- .../zaps/bbausd2-migrations/stables.integration.spec.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) 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 index 6421829e1..1b33de4e0 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -132,7 +132,7 @@ const stake = async ( ).wait(); }; -describe('execution', async () => { +describe('bbausd migration execution', async () => { let signer: JsonRpcSigner; let signerAddress: string; let authorisation: string; 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 index 00547cbce..c24e30679 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -130,7 +130,7 @@ const stake = async ( ).wait(); }; -describe('execution', async () => { +describe('stabal3 migration execution', async () => { let signer: JsonRpcSigner; let signerAddress: string; let authorisation: string; 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 index 1bad8af1c..53a76c208 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -99,7 +99,7 @@ const reset = () => { forking: { jsonRpcUrl, - blockNumber: blockNumber && parseInt(blockNumber), + blockNumber: (blockNumber && parseInt(blockNumber)) || 7300090, }, }, ]); @@ -135,7 +135,7 @@ const stake = async ( ).wait(); }; -describe('execution', async () => { +describe('stables migration execution', async () => { let signer: JsonRpcSigner; let signerAddress: string; let authorisation: string; From 1effa3ccf9bec88fd633b7c61136426f21fabd55 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 27 Jul 2022 15:04:13 -0300 Subject: [PATCH 046/104] Add env vars description to readme --- balancer-js/README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/balancer-js/README.md b/balancer-js/README.md index 2563518cc..0b1fb875b 100644 --- a/balancer-js/README.md +++ b/balancer-js/README.md @@ -22,7 +22,15 @@ Installation instructions for: * [Hardhat](https://hardhat.org/getting-started/#installation) - To start a forked node: + To start a forked node, set env vars: + + ``` + ALCHEMY_URL (required) - remote node url to be forked locally + FORK_BLOCK_NUMBER (optional) - block number at which fork will happen + ``` + + and run following command on terminal: + ``` npm run node ``` From 1b594614ac66a58cca8a58917ca993e6073839c1 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 27 Jul 2022 16:31:18 -0300 Subject: [PATCH 047/104] Remove FORK_BLOCK_NUMBER from node script. --- balancer-js/package.json | 208 +++++++++++++++++++-------------------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/balancer-js/package.json b/balancer-js/package.json index 504aa055b..85353faa0 100644 --- a/balancer-js/package.json +++ b/balancer-js/package.json @@ -1,106 +1,106 @@ { - "name": "@balancer-labs/sdk", - "version": "0.1.19", - "description": "JavaScript SDK for interacting with the Balancer Protocol V2", - "license": "GPL-3.0-only", - "homepage": "https://github.com/balancer-labs/balancer-sdk/balancer-js#readme", - "repository": { - "type": "git", - "url": "https://github.com/balancer-labs/balancer-sdk", - "directory": "balancer-js" - }, - "bugs": { - "url": "https://github.com/balancer-labs/balancer-sdk/issues" - }, - "main": "dist/index.js", - "module": "dist/index.esm.js", - "browser": "dist/index.umd.js", - "typings": "dist/index.d.ts", - "files": [ - "dist/" - ], - "scripts": { - "build": "rimraf dist && rollup -c", - "dev": "rollup -c -w", - "test": "ts-mocha --paths --recursive -p tsconfig.testing.json 'src/**/*.spec.ts'", - "test:only": "ts-mocha --paths --recursive -p tsconfig.testing.json", - "lint": "eslint ./src --ext .ts --max-warnings 0", - "lint:fix": "eslint ./src --ext .ts --max-warnings 0 --fix", - "subgraph:generate": "graphql-codegen --config src/modules/subgraph/codegen.yml -r dotenv/config", - "examples:run": "TS_NODE_PROJECT='tsconfig.testing.json' ts-node -r tsconfig-paths/register", - "node": "npx hardhat node --fork $(grep ALCHEMY_URL .env | tail -1 | cut -d '=' -f2) --fork-block-number $(grep FORK_BLOCK_NUMBER .env | tail -1 | cut -d '=' -f2)" - }, - "devDependencies": { - "@ethersproject/abi": "^5.4.0", - "@ethersproject/abstract-signer": "^5.4.0", - "@ethersproject/address": "^5.4.0", - "@ethersproject/bignumber": "^5.4.0", - "@ethersproject/bytes": "^5.4.0", - "@ethersproject/constants": "^5.4.0", - "@ethersproject/contracts": "^5.4.0", - "@ethersproject/providers": "^5.4.5", - "@ethersproject/solidity": "^5.6.1", - "@ethersproject/wallet": "^5.5.0", - "@georgeroman/balancer-v2-pools": "^0.0.5", - "@graphql-codegen/add": "^3.1.0", - "@graphql-codegen/cli": "^2.3.0", - "@graphql-codegen/introspection": "^2.1.0", - "@graphql-codegen/schema-ast": "^2.4.0", - "@graphql-codegen/typescript": "2.4.0", - "@graphql-codegen/typescript-document-nodes": "^2.2.0", - "@graphql-codegen/typescript-graphql-request": "^4.3.0", - "@graphql-codegen/typescript-operations": "^2.2.0", - "@graphql-codegen/typescript-resolvers": "2.4.1", - "@nomicfoundation/hardhat-network-helpers": "^1.0.3", - "@nomiclabs/hardhat-ethers": "^2.0.5", - "@rollup/plugin-commonjs": "^21.0.1", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.0.0", - "@rollup/plugin-typescript": "^8.2.1", - "@typechain/ethers-v5": "^7.0.1", - "@types/chai": "^4.2.12", - "@types/lodash": "^4.14.177", - "@types/mocha": "^8.0.3", - "@types/node": "^15.12.4", - "@typescript-eslint/eslint-plugin": "^4.1.1", - "@typescript-eslint/parser": "^4.1.1", - "chai": "^4.2.0", - "dotenv": "^10.0.0", - "eslint": "^7.9.0", - "eslint-plugin-mocha-no-only": "^1.1.1", - "eslint-plugin-prettier": "^3.1.4", - "ethers": "^5.0.0", - "fishery": "^2.2.2", - "hardhat": "^2.9.3", - "mocha": "^8.2.1", - "prettier": "^2.1.2", - "rimraf": "^3.0.2", - "rollup": "^2.52.8", - "rollup-plugin-dts": "^3.0.2", - "tiny-invariant": "^1.1.0", - "ts-mocha": "^9.0.2", - "ts-node": "^10.4.0", - "tsconfig-paths": "^3.12.0", - "typechain": "^5.1.1", - "typescript": "^4.0.2" - }, - "dependencies": { - "@balancer-labs/sor": "^4.0.1-beta.1", - "@balancer-labs/typechain": "^1.0.0", - "axios": "^0.24.0", - "bignumber.js": "^9.0.2", - "graphql": "^15.6.1", - "graphql-request": "^3.5.0", - "lodash": "^4.17.21" - }, - "peerDependencies": { - "@ethersproject/abi": "^5.4.0", - "@ethersproject/abstract-signer": "^5.4.0", - "@ethersproject/address": "^5.4.0", - "@ethersproject/bignumber": "^5.4.0", - "@ethersproject/bytes": "^5.4.0", - "@ethersproject/constants": "^5.4.0", - "@ethersproject/contracts": "^5.4.0", - "@ethersproject/providers": "^5.4.5" - } + "name": "@balancer-labs/sdk", + "version": "0.1.19", + "description": "JavaScript SDK for interacting with the Balancer Protocol V2", + "license": "GPL-3.0-only", + "homepage": "https://github.com/balancer-labs/balancer-sdk/balancer-js#readme", + "repository": { + "type": "git", + "url": "https://github.com/balancer-labs/balancer-sdk", + "directory": "balancer-js" + }, + "bugs": { + "url": "https://github.com/balancer-labs/balancer-sdk/issues" + }, + "main": "dist/index.js", + "module": "dist/index.esm.js", + "browser": "dist/index.umd.js", + "typings": "dist/index.d.ts", + "files": [ + "dist/" + ], + "scripts": { + "build": "rimraf dist && rollup -c", + "dev": "rollup -c -w", + "test": "ts-mocha --paths --recursive -p tsconfig.testing.json 'src/**/*.spec.ts'", + "test:only": "ts-mocha --paths --recursive -p tsconfig.testing.json", + "lint": "eslint ./src --ext .ts --max-warnings 0", + "lint:fix": "eslint ./src --ext .ts --max-warnings 0 --fix", + "subgraph:generate": "graphql-codegen --config src/modules/subgraph/codegen.yml -r dotenv/config", + "examples:run": "TS_NODE_PROJECT='tsconfig.testing.json' ts-node -r tsconfig-paths/register", + "node": "npx hardhat node --fork $(grep ALCHEMY_URL .env | tail -1 | cut -d '=' -f2)" + }, + "devDependencies": { + "@ethersproject/abi": "^5.4.0", + "@ethersproject/abstract-signer": "^5.4.0", + "@ethersproject/address": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/constants": "^5.4.0", + "@ethersproject/contracts": "^5.4.0", + "@ethersproject/providers": "^5.4.5", + "@ethersproject/solidity": "^5.6.1", + "@ethersproject/wallet": "^5.5.0", + "@georgeroman/balancer-v2-pools": "^0.0.5", + "@graphql-codegen/add": "^3.1.0", + "@graphql-codegen/cli": "^2.3.0", + "@graphql-codegen/introspection": "^2.1.0", + "@graphql-codegen/schema-ast": "^2.4.0", + "@graphql-codegen/typescript": "2.4.0", + "@graphql-codegen/typescript-document-nodes": "^2.2.0", + "@graphql-codegen/typescript-graphql-request": "^4.3.0", + "@graphql-codegen/typescript-operations": "^2.2.0", + "@graphql-codegen/typescript-resolvers": "2.4.1", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@nomiclabs/hardhat-ethers": "^2.0.5", + "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.0.0", + "@rollup/plugin-typescript": "^8.2.1", + "@typechain/ethers-v5": "^7.0.1", + "@types/chai": "^4.2.12", + "@types/lodash": "^4.14.177", + "@types/mocha": "^8.0.3", + "@types/node": "^15.12.4", + "@typescript-eslint/eslint-plugin": "^4.1.1", + "@typescript-eslint/parser": "^4.1.1", + "chai": "^4.2.0", + "dotenv": "^10.0.0", + "eslint": "^7.9.0", + "eslint-plugin-mocha-no-only": "^1.1.1", + "eslint-plugin-prettier": "^3.1.4", + "ethers": "^5.0.0", + "fishery": "^2.2.2", + "hardhat": "^2.9.3", + "mocha": "^8.2.1", + "prettier": "^2.1.2", + "rimraf": "^3.0.2", + "rollup": "^2.52.8", + "rollup-plugin-dts": "^3.0.2", + "tiny-invariant": "^1.1.0", + "ts-mocha": "^9.0.2", + "ts-node": "^10.4.0", + "tsconfig-paths": "^3.12.0", + "typechain": "^5.1.1", + "typescript": "^4.0.2" + }, + "dependencies": { + "@balancer-labs/sor": "^4.0.1-beta.1", + "@balancer-labs/typechain": "^1.0.0", + "axios": "^0.24.0", + "bignumber.js": "^9.0.2", + "graphql": "^15.6.1", + "graphql-request": "^3.5.0", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "@ethersproject/abi": "^5.4.0", + "@ethersproject/abstract-signer": "^5.4.0", + "@ethersproject/address": "^5.4.0", + "@ethersproject/bignumber": "^5.4.0", + "@ethersproject/bytes": "^5.4.0", + "@ethersproject/constants": "^5.4.0", + "@ethersproject/contracts": "^5.4.0", + "@ethersproject/providers": "^5.4.5" + } } From 58f7c4377d306eacceaec883cbd8424340881f08 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 27 Jul 2022 16:33:36 -0300 Subject: [PATCH 048/104] Refactor utils getBalances to a cleaner interface --- .../join.concern.integration.spec.ts | 32 ++-- .../stable/join.concern.integration.spec.ts | 32 ++-- .../weighted/join.concern.integration.spec.ts | 155 +++++------------- .../stables.integration.spec.ts | 2 - .../zaps/zaps.module.integration.spec.ts | 26 +-- balancer-js/src/test/lib/utils.ts | 38 ++--- 6 files changed, 90 insertions(+), 195 deletions(-) diff --git a/balancer-js/src/modules/pools/pool-types/concerns/metaStable/join.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/metaStable/join.concern.integration.spec.ts index 6793e5a81..48b5a7581 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/metaStable/join.concern.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/metaStable/join.concern.integration.spec.ts @@ -17,7 +17,7 @@ import { TransactionReceipt } from '@ethersproject/providers'; import { parseFixed, BigNumber } from '@ethersproject/bignumber'; import { ADDRESSES } from '@/test/lib/constants'; -import { forkSetup, setupPool, updateBalances } from '@/test/lib/utils'; +import { forkSetup, setupPool, getBalances } from '@/test/lib/utils'; import pools_14717479 from '@/test/lib/pools_14717479.json'; import { PoolsProvider } from '@/modules/pools/provider'; @@ -83,12 +83,12 @@ describe('join execution', async () => { parseFixed(initialBalance, token.decimals).toString() ); await forkSetup( - balancer, signer, tokensIn.map((t) => t.address), slots, balances, jsonRpcUrl as string, + false, 14717479 // holds the same state as the static repository ); signerAddress = await signer.getAddress(); @@ -101,11 +101,10 @@ describe('join execution', async () => { parseFixed(t.balance, t.decimals).div(amountsInDiv).toString() ); - [bptBalanceBefore, ...tokensBalanceBefore] = await updateBalances( - pool, + [bptBalanceBefore, ...tokensBalanceBefore] = await getBalances( + [pool.address, ...pool.tokensList], signer, - signerAddress, - balancer + signerAddress ); const slippage = '1'; @@ -120,11 +119,10 @@ describe('join execution', async () => { bptMinBalanceIncrease = BigNumber.from(minBPTOut); transactionReceipt = await (await signer.sendTransaction(tx)).wait(); - [bptBalanceAfter, ...tokensBalanceAfter] = await updateBalances( - pool, + [bptBalanceAfter, ...tokensBalanceAfter] = await getBalances( + [pool.address, ...pool.tokensList], signer, - signerAddress, - balancer + signerAddress ); }); @@ -154,11 +152,10 @@ describe('join execution', async () => { parseFixed(t.balance, t.decimals).div(amountsInDiv).toString() ); - [bptBalanceBefore, ...tokensBalanceBefore] = await updateBalances( - pool, + [bptBalanceBefore, ...tokensBalanceBefore] = await getBalances( + [pool.address, ...pool.tokensList], signer, - signerAddress, - balancer + signerAddress ); const slippage = '100'; @@ -174,11 +171,10 @@ describe('join execution', async () => { transactionReceipt = await transactionResponse.wait(); bptMinBalanceIncrease = BigNumber.from(minBPTOut); - [bptBalanceAfter, ...tokensBalanceAfter] = await updateBalances( - pool, + [bptBalanceAfter, ...tokensBalanceAfter] = await getBalances( + [pool.address, ...pool.tokensList], signer, - signerAddress, - balancer + signerAddress ); }); diff --git a/balancer-js/src/modules/pools/pool-types/concerns/stable/join.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/stable/join.concern.integration.spec.ts index 67573169e..ad1a9b50f 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/stable/join.concern.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/stable/join.concern.integration.spec.ts @@ -17,7 +17,7 @@ import { TransactionReceipt } from '@ethersproject/providers'; import { parseFixed, BigNumber } from '@ethersproject/bignumber'; import { ADDRESSES } from '@/test/lib/constants'; -import { forkSetup, setupPool, updateBalances } from '@/test/lib/utils'; +import { forkSetup, setupPool, getBalances } from '@/test/lib/utils'; import pools_14717479 from '@/test/lib/pools_14717479.json'; import { PoolsProvider } from '@/modules/pools/provider'; @@ -88,12 +88,12 @@ describe('join execution', async () => { parseFixed(initialBalance, token.decimals).toString() ); await forkSetup( - balancer, signer, tokensIn.map((t) => t.address), slots, balances, jsonRpcUrl as string, + false, 14717479 // holds the same state as the static repository ); signerAddress = await signer.getAddress(); @@ -106,11 +106,10 @@ describe('join execution', async () => { parseFixed(t.balance, t.decimals).div(amountsInDiv).toString() ); - [bptBalanceBefore, ...tokensBalanceBefore] = await updateBalances( - pool, + [bptBalanceBefore, ...tokensBalanceBefore] = await getBalances( + [pool.address, ...pool.tokensList], signer, - signerAddress, - balancer + signerAddress ); const { to, data, minBPTOut } = pool.buildJoin( @@ -124,11 +123,10 @@ describe('join execution', async () => { bptMinBalanceIncrease = BigNumber.from(minBPTOut); const transactionResponse = await signer.sendTransaction(tx); transactionReceipt = await transactionResponse.wait(); - [bptBalanceAfter, ...tokensBalanceAfter] = await updateBalances( - pool, + [bptBalanceAfter, ...tokensBalanceAfter] = await getBalances( + [pool.address, ...pool.tokensList], signer, - signerAddress, - balancer + signerAddress ); }); @@ -158,11 +156,10 @@ describe('join execution', async () => { parseFixed(t.balance, t.decimals).div(amountsInDiv).toString() ); - [bptBalanceBefore, ...tokensBalanceBefore] = await updateBalances( - pool, + [bptBalanceBefore, ...tokensBalanceBefore] = await getBalances( + [pool.address, ...pool.tokensList], signer, - signerAddress, - balancer + signerAddress ); const { functionName, attributes, value, minBPTOut } = pool.buildJoin( @@ -177,11 +174,10 @@ describe('join execution', async () => { transactionReceipt = await transactionResponse.wait(); bptMinBalanceIncrease = BigNumber.from(minBPTOut); - [bptBalanceAfter, ...tokensBalanceAfter] = await updateBalances( - pool, + [bptBalanceAfter, ...tokensBalanceAfter] = await getBalances( + [pool.address, ...pool.tokensList], signer, - signerAddress, - balancer + signerAddress ); }); diff --git a/balancer-js/src/modules/pools/pool-types/concerns/weighted/join.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/weighted/join.concern.integration.spec.ts index 8a1a77c06..de770c5ef 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/weighted/join.concern.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/weighted/join.concern.integration.spec.ts @@ -17,7 +17,7 @@ import { TransactionReceipt } from '@ethersproject/providers'; import { parseFixed, BigNumber } from '@ethersproject/bignumber'; import { AddressZero } from '@ethersproject/constants'; -import { forkSetup, setupPool, tokenBalance } from '@/test/lib/utils'; +import { forkSetup, setupPool, getBalances } from '@/test/lib/utils'; import pools_14717479 from '@/test/lib/pools_14717479.json'; import { PoolsProvider } from '@/modules/pools/provider'; @@ -85,12 +85,12 @@ describe('join execution', async () => { parseFixed(initialBalance, tokensIn[1].decimals).toString(), ]; await forkSetup( - balancer, signer, tokensIn.map((t) => t.address), slots, balances, jsonRpcUrl as string, + false, 14717479 // holds the same state as the static repository ); signerAddress = await signer.getAddress(); @@ -103,26 +103,11 @@ describe('join execution', async () => { parseFixed(t.balance, t.decimals).div(amountsInDiv).toString() ); - bptBalanceBefore = await tokenBalance( - pool.address, + [bptBalanceBefore, ...tokensBalanceBefore] = await getBalances( + [pool.address, ...tokensIn.map((t) => t.address)], signer, - signerAddress, - balancer + signerAddress ); - tokensBalanceBefore = [ - await tokenBalance( - tokensIn[0].address, - signer, - signerAddress, - balancer - ), - await tokenBalance( - tokensIn[1].address, - signer, - signerAddress, - balancer - ), - ]; const slippage = '100'; @@ -136,6 +121,11 @@ describe('join execution', async () => { bptMinBalanceIncrease = BigNumber.from(minBPTOut); transactionReceipt = await (await signer.sendTransaction(tx)).wait(); + [bptBalanceAfter, ...tokensBalanceAfter] = await getBalances( + [pool.address, ...tokensIn.map((t) => t.address)], + signer, + signerAddress + ); }); it('should work', async () => { @@ -143,34 +133,12 @@ describe('join execution', async () => { }); it('should increase BPT balance', async () => { - bptBalanceAfter = await tokenBalance( - pool.address, - signer, - signerAddress, - balancer - ); - expect( bptBalanceAfter.sub(bptBalanceBefore).toNumber() ).to.greaterThanOrEqual(bptMinBalanceIncrease.toNumber()); }); it('should decrease tokens balance', async () => { - tokensBalanceAfter = [ - await tokenBalance( - tokensIn[0].address, - signer, - signerAddress, - balancer - ), - await tokenBalance( - tokensIn[1].address, - signer, - signerAddress, - balancer - ), - ]; - for (let i = 0; i < tokensIn.length; i++) { expect( tokensBalanceBefore[i].sub(tokensBalanceAfter[i]).toString() @@ -187,26 +155,11 @@ describe('join execution', async () => { parseFixed(t.balance, t.decimals).div(amountsInDiv).toString() ); - bptBalanceBefore = await tokenBalance( - pool.address, + [bptBalanceBefore, ...tokensBalanceBefore] = await getBalances( + [pool.address, ...tokensIn.map((t) => t.address)], signer, - signerAddress, - balancer + signerAddress ); - tokensBalanceBefore = [ - await tokenBalance( - tokensIn[0].address, - signer, - signerAddress, - balancer - ), - await tokenBalance( - tokensIn[1].address, - signer, - signerAddress, - balancer - ), - ]; const slippage = '100'; const { functionName, attributes, value, minBPTOut } = @@ -222,6 +175,11 @@ describe('join execution', async () => { transactionReceipt = await transactionResponse.wait(); bptMinBalanceIncrease = BigNumber.from(minBPTOut); + [bptBalanceAfter, ...tokensBalanceAfter] = await getBalances( + [pool.address, ...tokensIn.map((t) => t.address)], + signer, + signerAddress + ); }); it('should work', async () => { @@ -229,34 +187,12 @@ describe('join execution', async () => { }); it('should increase BPT balance', async () => { - bptBalanceAfter = await tokenBalance( - pool.address, - signer, - signerAddress, - balancer - ); - expect( bptBalanceAfter.sub(bptBalanceBefore).toNumber() ).to.greaterThanOrEqual(bptMinBalanceIncrease.toNumber()); }); it('should decrease tokens balance', async () => { - tokensBalanceAfter = [ - await tokenBalance( - tokensIn[0].address, - signer, - signerAddress, - balancer - ), - await tokenBalance( - tokensIn[1].address, - signer, - signerAddress, - balancer - ), - ]; - for (let i = 0; i < tokensIn.length; i++) { expect( tokensBalanceBefore[i].sub(tokensBalanceAfter[i]).toString() @@ -274,26 +210,25 @@ describe('join execution', async () => { parseFixed(t.balance, t.decimals).div(amountsInDiv).toString() ); - bptBalanceBefore = await tokenBalance( - pool.address, + const tokensWithETH = tokensIn.map((t) => { + if ( + t.address === + balancer.networkConfig.addresses.tokens.wrappedNativeAsset + ) + return AddressZero; + return t.address; + }); + + [bptBalanceBefore, ...tokensBalanceBefore] = await getBalances( + [pool.address, ...tokensWithETH], signer, - signerAddress, - balancer + signerAddress ); - tokensBalanceBefore = [ - await tokenBalance( - tokensIn[0].address, - signer, - signerAddress, - balancer - ), - await signer.getBalance(), - ]; const slippage = '100'; const { to, data, value, minBPTOut } = await pool.buildJoin( signerAddress, - [tokensIn[0].address, AddressZero], + tokensWithETH, amountsIn, slippage ); @@ -304,6 +239,17 @@ describe('join execution', async () => { transactionCost = transactionReceipt.gasUsed.mul( transactionReceipt.effectiveGasPrice ); + + [bptBalanceAfter, ...tokensBalanceAfter] = await getBalances( + [pool.address, ...tokensWithETH], + signer, + signerAddress + ); + tokensWithETH.map((t, i) => { + if (t === AddressZero) { + tokensBalanceAfter[i] = tokensBalanceAfter[i].add(transactionCost); + } + }); }); it('should work', async () => { @@ -311,29 +257,12 @@ describe('join execution', async () => { }); it('should increase BPT balance', async () => { - bptBalanceAfter = await tokenBalance( - pool.address, - signer, - signerAddress, - balancer - ); - expect( bptBalanceAfter.sub(bptBalanceBefore).toNumber() ).to.greaterThanOrEqual(bptMinBalanceIncrease.toNumber()); }); it('should decrease tokens balance', async () => { - tokensBalanceAfter = [ - await tokenBalance( - tokensIn[0].address, - signer, - signerAddress, - balancer - ), - await (await signer.getBalance()).add(transactionCost), - ]; - for (let i = 0; i < tokensIn.length; i++) { expect( tokensBalanceBefore[i].sub(tokensBalanceAfter[i]).toString() 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 index 53a76c208..f75dea481 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -5,7 +5,6 @@ import { Network, RelayerAuthorization } from '@/.'; import { BigNumber } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; import { ADDRESSES } from './addresses'; -import { StablesBuilder as MigrationBuilder } from './stables'; import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; import { parseEther, formatEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; @@ -36,7 +35,6 @@ const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const addresses = ADDRESSES[network]; const { contracts } = new Contracts(network as number, provider); -const migration = new MigrationBuilder(network); const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; const fromPool = { diff --git a/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts b/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts index a1ca40a7c..000ade0e8 100644 --- a/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts +++ b/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts @@ -1,12 +1,11 @@ import dotenv from 'dotenv'; import { expect } from 'chai'; -import { Contracts } from '@/modules/contracts/contracts.module'; import { Network } from '@/.'; import hardhat from 'hardhat'; -import { BigNumber, parseFixed } from '@ethersproject/bignumber'; +import { parseFixed } from '@ethersproject/bignumber'; -import { forkSetup } from '@/test/lib/utils'; +import { forkSetup, getBalances } from '@/test/lib/utils'; /* * Testing on GOERLI @@ -37,25 +36,6 @@ const gaugeAddresses = ['0xf0f572ad66baacDd07d8c7ea3e0E5EFA56a76081']; // Balanc const initialBalance = '1000'; let signerAddress: string; -const { contracts } = new Contracts(5, provider); - -// Setup - -const tokenBalance = async (tokenAddress: string) => { - const balance: Promise = contracts - .ERC20(tokenAddress, signer.provider) - .balanceOf(signerAddress); - return balance; -}; - -const updateBalances = async (addresses: string[]) => { - const balances = []; - for (let i = 0; i < addresses.length; i++) { - balances[i] = tokenBalance(addresses[i]); - } - return Promise.all(balances); -}; - // Test Scenarios describe('zaps execution', async () => { @@ -75,7 +55,7 @@ describe('zaps execution', async () => { }); it('should update balances', async () => { - const balances = await updateBalances(gaugeAddresses); + const balances = await getBalances(gaugeAddresses, signer, signerAddress); for (let i = 0; i < balances.length; i++) { expect(balances[i].eq(parseFixed(initialBalance, 18))).to.be.true; } diff --git a/balancer-js/src/test/lib/utils.ts b/balancer-js/src/test/lib/utils.ts index d70bc6f6d..ddf5fb195 100644 --- a/balancer-js/src/test/lib/utils.ts +++ b/balancer-js/src/test/lib/utils.ts @@ -1,4 +1,4 @@ -import { JsonRpcSigner } from '@ethersproject/providers'; +import { JsonRpcProvider, JsonRpcSigner } from '@ethersproject/providers'; import { BigNumber } from '@ethersproject/bignumber'; import { AddressZero } from '@ethersproject/constants'; import { balancerVault } from '@/lib/constants/config'; @@ -6,7 +6,7 @@ import { hexlify, zeroPad } from '@ethersproject/bytes'; import { keccak256 } from '@ethersproject/solidity'; import { ERC20 } from '@/modules/contracts/ERC20'; import { PoolsProvider } from '@/modules/pools/provider'; -import { PoolModel, BalancerError, BalancerErrorCode, Pool } from '@/.'; +import { PoolModel, BalancerError, BalancerErrorCode } from '@/.'; export const forkSetup = async ( signer: JsonRpcSigner, @@ -115,28 +115,24 @@ export const setupPool = async ( return pool; }; -export const tokenBalance = async ( - tokenAddress: string, - signer: JsonRpcSigner, - signerAddress: string -): Promise => { - if (tokenAddress === AddressZero) return await signer.getBalance(); - const balance: Promise = ERC20( - tokenAddress, - signer.provider - ).balanceOf(signerAddress); - return balance; -}; +export const getErc20Balance = ( + token: string, + provider: JsonRpcProvider, + holder: string +): Promise => ERC20(token, provider).balanceOf(holder); -export const updateBalances = async ( - pool: Pool, +export const getBalances = async ( + tokens: string[], signer: JsonRpcSigner, signerAddress: string ): Promise> => { - const bptBalance = tokenBalance(pool.address, signer, signerAddress); - const balances = []; - for (let i = 0; i < pool.tokensList.length; i++) { - balances[i] = tokenBalance(pool.tokensList[i], signer, signerAddress); + const balances: Promise[] = []; + for (let i = 0; i < tokens.length; i++) { + if (tokens[i] === AddressZero) { + balances[i] = signer.getBalance(); + } else { + balances[i] = getErc20Balance(tokens[i], signer.provider, signerAddress); + } } - return Promise.all([bptBalance, ...balances]); + return Promise.all(balances); }; From 7b59ce4cba6ef35984300fbfec0fbee6f6b860dc Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 27 Jul 2022 17:16:21 -0300 Subject: [PATCH 049/104] Broaden integration tests scope by including migrations file --- .../bbausd1.integration.spec.ts | 16 +++++++-------- .../stabal3.integration.spec.ts | 20 +++++++++---------- .../stables.integration.spec.ts | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) 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 index 1b33de4e0..741383c78 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -13,11 +13,11 @@ import { import { BigNumber } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; import { ADDRESSES } from './addresses'; -import { BbaUsd1Builder as MigrationBuilder } from './bbausd1'; import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; import { parseEther, formatEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256 } from '@ethersproject/constants'; +import { Migrations } from '../migrations'; import { Interface } from '@ethersproject/abi'; import { PoolsProvider } from '@/modules/pools/provider'; @@ -44,7 +44,7 @@ const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const addresses = ADDRESSES[network]; const { contracts } = new Contracts(network as number, provider); -const migration = new MigrationBuilder(network); +const migrations = new Migrations(network); const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; const poolAddress = addresses.bbausd1.address; @@ -180,12 +180,12 @@ describe('bbausd migration execution', async () => { to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), }; - const query = migration.calldata( + const query = migrations.bbaUsd( + signerAddress, before.from.toString(), undefined, - signerAddress, - true, authorisation, + true, pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') ); @@ -221,12 +221,12 @@ describe('bbausd migration execution', async () => { to: await getErc20Balance(addresses.bbausd2.address, signerAddress), }; - const query = migration.calldata( + const query = migrations.bbaUsd( + signerAddress, before.from.toString(), undefined, - signerAddress, - false, authorisation, + false, pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') ); 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 index c24e30679..a5ff3d5d9 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -5,11 +5,11 @@ import { Network, RelayerAuthorization } from '@/.'; import { BigNumber } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; import { ADDRESSES } from './addresses'; -import { StaBal3Builder as MigrationBuilder } from './stabal3'; import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; import { parseEther, formatEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256 } from '@ethersproject/constants'; +import { Migrations } from '../migrations'; import { Interface } from '@ethersproject/abi'; const liquidityGaugeAbi = ['function deposit(uint value) payable']; @@ -35,7 +35,7 @@ const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const addresses = ADDRESSES[network]; const { contracts } = new Contracts(network as number, provider); -const migration = new MigrationBuilder(network); +const migrations = new Migrations(network); const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; const poolAddress = addresses.staBal3.address; @@ -164,12 +164,12 @@ describe('stabal3 migration execution', async () => { to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), }; - const query = migration.calldata( + const query = migrations.stabal3( + signerAddress, before.from.toString(), undefined, - signerAddress, - true, - authorisation + authorisation, + true ); const { to, data } = query; @@ -204,12 +204,12 @@ describe('stabal3 migration execution', async () => { to: await getErc20Balance(addresses.bbausd2.address, signerAddress), }; - const query = migration.calldata( + const query = migrations.stabal3( + signerAddress, before.from.toString(), undefined, - signerAddress, - false, - authorisation + authorisation, + false ); const { to, data } = query; 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 index f75dea481..d12806c96 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -9,9 +9,9 @@ import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; import { parseEther, formatEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256 } from '@ethersproject/constants'; +import { Migrations } from '../migrations'; import { Interface } from '@ethersproject/abi'; -import { Migrations } from '../migrations'; const liquidityGaugeAbi = ['function deposit(uint value) payable']; const liquidityGauge = new Interface(liquidityGaugeAbi); From 388c56944457f9804f2f8449ed245854e17ffdfe Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 27 Jul 2022 17:19:03 -0300 Subject: [PATCH 050/104] Fix typo on receipt --- .../zaps/bbausd2-migrations/bbausd1.integration.spec.ts | 8 ++++---- .../zaps/bbausd2-migrations/stabal3.integration.spec.ts | 8 ++++---- .../zaps/bbausd2-migrations/stables.integration.spec.ts | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) 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 index 741383c78..e33a81d92 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -193,8 +193,8 @@ describe('bbausd migration execution', async () => { const gasLimit = MAX_GAS_LIMIT; const response = await signer.sendTransaction({ to, data, gasLimit }); - const reciept = await response.wait(); - console.log('Gas used', reciept.gasUsed.toString()); + const receipt = await response.wait(); + console.log('Gas used', receipt.gasUsed.toString()); const after = { from: await getErc20Balance(gaugeAddress, signerAddress), @@ -234,8 +234,8 @@ describe('bbausd migration execution', async () => { const gasLimit = MAX_GAS_LIMIT; const response = await signer.sendTransaction({ to, data, gasLimit }); - const reciept = await response.wait(); - console.log('Gas used', reciept.gasUsed.toString()); + const receipt = await response.wait(); + console.log('Gas used', receipt.gasUsed.toString()); const after = { from: await getErc20Balance(poolAddress, signerAddress), 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 index a5ff3d5d9..2b60c7778 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -176,8 +176,8 @@ describe('stabal3 migration execution', async () => { const gasLimit = MAX_GAS_LIMIT; const response = await signer.sendTransaction({ to, data, gasLimit }); - const reciept = await response.wait(); - console.log('Gas used', reciept.gasUsed.toString()); + const receipt = await response.wait(); + console.log('Gas used', receipt.gasUsed.toString()); const after = { from: await getErc20Balance(gaugeAddress, signerAddress), @@ -216,8 +216,8 @@ describe('stabal3 migration execution', async () => { const gasLimit = MAX_GAS_LIMIT; const response = await signer.sendTransaction({ to, data, gasLimit }); - const reciept = await response.wait(); - console.log('Gas used', reciept.gasUsed.toString()); + const receipt = await response.wait(); + console.log('Gas used', receipt.gasUsed.toString()); const after = { from: await getErc20Balance(poolAddress, signerAddress), 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 index d12806c96..b79ae7fd3 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -183,8 +183,8 @@ describe('stables migration execution', async () => { const gasLimit = MAX_GAS_LIMIT; const response = await signer.sendTransaction({ to, data, gasLimit }); - const reciept = await response.wait(); - console.log('Gas used', reciept.gasUsed.toString()); + const receipt = await response.wait(); + console.log('Gas used', receipt.gasUsed.toString()); const after = { from: await getErc20Balance(fromGauge, signerAddress), @@ -227,8 +227,8 @@ describe('stables migration execution', async () => { const gasLimit = MAX_GAS_LIMIT; const response = await signer.sendTransaction({ to, data, gasLimit }); - const reciept = await response.wait(); - console.log('Gas used', reciept.gasUsed.toString()); + const receipt = await response.wait(); + console.log('Gas used', receipt.gasUsed.toString()); const after = { from: await getErc20Balance(fromPool.address, signerAddress), From 4002f93ae4007d9e0dc0fa8ac08ee37ebc1506f9 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 27 Jul 2022 17:48:39 -0300 Subject: [PATCH 051/104] Remove unnecessary toString conversions --- balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts | 2 +- balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts | 2 +- balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 3b32700a8..c6f7d4c72 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -213,7 +213,7 @@ export class BbaUsd1Builder { // For now assuming ref amounts will be safe - should we add more accurate? const limits = [ - expectedBptReturn.toString(), + expectedBptReturn, MaxInt256.toString(), MaxInt256.toString(), MaxInt256.toString(), diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 33b8d6cc8..48a1832f9 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -184,7 +184,7 @@ export class StaBal3Builder { // For now assuming ref amounts will be safe - should we add more accurate? const limits = [ - expectedBptReturn.toString(), + expectedBptReturn, MaxInt256.toString(), MaxInt256.toString(), MaxInt256.toString(), diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index c97911099..18d7cd18d 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -142,7 +142,7 @@ export class StablesBuilder { } // For now assuming ref amounts will be safe - should we add more accurate? - const limits = [expectedBptReturn.toString()]; + const limits = [expectedBptReturn]; for (let i = 0; i < tokens.length; i++) { limits.push(MaxInt256.toString()); } From 8d67397a15b4241a9f24a910934b6bb408a87ae1 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 28 Jul 2022 11:54:48 +0100 Subject: [PATCH 052/104] Fix bbausd migration decode. Update tests. --- .../bbausd1.integration.spec.ts | 126 ++++++++---------- balancer-js/src/modules/zaps/migrations.ts | 26 +++- 2 files changed, 76 insertions(+), 76 deletions(-) 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 index e33a81d92..1f2982d99 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -165,92 +165,72 @@ describe('bbausd migration execution', async () => { pool = _pool; }); + async function testFlow( + limit: string | undefined, + staked: boolean + ): Promise { + const addressIn = staked + ? addresses.bbausd1.gauge + : addresses.bbausd1.address; + const addressOut = staked + ? addresses.bbausd2.gauge + : addresses.bbausd2.address; + // Store balance before migration + const before = { + from: await getErc20Balance(addressIn, signerAddress), + to: await getErc20Balance(addressOut, signerAddress), + }; + + const amount = before.from; + + const query = migrations.bbaUsd( + signerAddress, + amount.toString(), + limit, + authorisation, + staked, + pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed + ); + + const { to, data } = query; + 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, data, gasLimit }); + const expectedBpts = query.decode(staticResult, staked); + + const response = await signer.sendTransaction({ to, data, gasLimit }); + + const receipt = await response.wait(); + console.log('Gas used', receipt.gasUsed.toString()); + + const after = { + from: await getErc20Balance(addressIn, signerAddress), + to: await getErc20Balance(addressOut, signerAddress), + }; + + console.log(expectedBpts); + + expect(BigNumber.from(expectedBpts.expectedBptOut).gt(0)).to.be.true; + expect(amount.toString()).to.eq(expectedBpts.expectedBptIn.toString()); + expect(after.to.toString()).to.eq(expectedBpts.expectedBptOut.toString()); + } + context('staked', async () => { beforeEach(async function () { this.timeout(20000); - // Stake them await stake(signer, balance); }); it('should transfer tokens from stable to boosted', async () => { - // Store balance before migration - const before = { - from: await getErc20Balance(gaugeAddress, signerAddress), - to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), - }; - - const query = migrations.bbaUsd( - signerAddress, - before.from.toString(), - undefined, - authorisation, - true, - pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') - ); - - const { to, data } = query; - const gasLimit = MAX_GAS_LIMIT; - const response = await signer.sendTransaction({ to, data, gasLimit }); - - const receipt = await response.wait(); - console.log('Gas used', receipt.gasUsed.toString()); - - const after = { - from: await getErc20Balance(gaugeAddress, signerAddress), - to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), - }; - - const diffs = { - from: after.from.sub(before.from), - to: after.to.sub(before.to), - }; - - console.log(diffs.from, diffs.to); - - expect(diffs.from).to.eql(before.from.mul(-1)); - expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + await testFlow(undefined, true); }).timeout(20000); }); context('not staked', async () => { it('should transfer tokens from stable to boosted', async () => { - // Store balance before migration - const before = { - from: await getErc20Balance(poolAddress, signerAddress), - to: await getErc20Balance(addresses.bbausd2.address, signerAddress), - }; - - const query = migrations.bbaUsd( - signerAddress, - before.from.toString(), - undefined, - authorisation, - false, - pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') - ); - - const { to, data } = query; - const gasLimit = MAX_GAS_LIMIT; - const response = await signer.sendTransaction({ to, data, gasLimit }); - - const receipt = await response.wait(); - console.log('Gas used', receipt.gasUsed.toString()); - - const after = { - from: await getErc20Balance(poolAddress, signerAddress), - to: await getErc20Balance(addresses.bbausd2.address, signerAddress), - }; - - const diffs = { - from: after.from.sub(before.from), - to: after.to.sub(before.to), - }; - - console.log(diffs.from, diffs.to); - - expect(diffs.from).to.eql(before.from.mul(-1)); - expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + await testFlow(undefined, false); }).timeout(20000); }); }).timeout(20000); diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index aac39288a..ff1aed6a8 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -39,7 +39,17 @@ export class Migrations { authorisation: string, staked: boolean, tokens: PoolToken[] - ): { to: string; data: string; decode: (output: string) => string } { + ): { + to: string; + data: string; + decode: ( + output: string, + staked: boolean + ) => { + expectedBptIn: string; + expectedBptOut: string; + }; + } { const builder = new BbaUsd1Builder(this.network); const request = builder.calldata( amount, @@ -53,8 +63,18 @@ export class Migrations { return { to: request.to, data: request.data, - decode: (output) => - defaultAbiCoder.decode(['int256[]'], output[2])[3].toString(), + decode: (output, staked) => { + const swapIndex = staked ? 2 : 1; + const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); + const swapDeltas = defaultAbiCoder.decode( + ['int256[]'], + multicallResult[0][swapIndex] + ); + return { + expectedBptIn: swapDeltas[0][10].toString(), + expectedBptOut: swapDeltas[0][0].abs().toString(), + }; + }, }; } From ae53ae7e9f6cde833e10b5484a459a88ec80148d Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 28 Jul 2022 14:12:39 +0100 Subject: [PATCH 053/104] Update limits for bbausd. --- .../bbausd1.integration.spec.ts | 46 +++++++++++----- .../zaps/bbausd2-migrations/bbausd1.ts | 52 +++++++++---------- balancer-js/src/modules/zaps/migrations.ts | 16 +++--- 3 files changed, 67 insertions(+), 47 deletions(-) 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 index 1f2982d99..c81ab3007 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -14,7 +14,7 @@ import { BigNumber } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; import { ADDRESSES } from './addresses'; import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; -import { parseEther, formatEther } from '@ethersproject/units'; +import { parseEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256 } from '@ethersproject/constants'; import { Migrations } from '../migrations'; @@ -166,9 +166,9 @@ describe('bbausd migration execution', async () => { }); async function testFlow( - limit: string | undefined, - staked: boolean - ): Promise { + staked: boolean, + minBbausd2Out: undefined | string = undefined + ): Promise { const addressIn = staked ? addresses.bbausd1.gauge : addresses.bbausd1.address; @@ -183,10 +183,10 @@ describe('bbausd migration execution', async () => { const amount = before.from; - const query = migrations.bbaUsd( + let query = migrations.bbaUsd( signerAddress, amount.toString(), - limit, + '0', authorisation, staked, pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed @@ -199,6 +199,15 @@ describe('bbausd migration execution', async () => { const staticResult = await signer.call({ to, data, gasLimit }); const expectedBpts = query.decode(staticResult, staked); + query = migrations.bbaUsd( + signerAddress, + amount.toString(), + minBbausd2Out ? minBbausd2Out : expectedBpts.bbausd2AmountOut, + authorisation, + staked, + pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed + ); + const response = await signer.sendTransaction({ to, data, gasLimit }); const receipt = await response.wait(); @@ -211,11 +220,14 @@ describe('bbausd migration execution', async () => { console.log(expectedBpts); - expect(BigNumber.from(expectedBpts.expectedBptOut).gt(0)).to.be.true; - expect(amount.toString()).to.eq(expectedBpts.expectedBptIn.toString()); - expect(after.to.toString()).to.eq(expectedBpts.expectedBptOut.toString()); + expect(BigNumber.from(expectedBpts.bbausd2AmountOut).gt(0)).to.be.true; + expect(amount.toString()).to.eq(expectedBpts.bbausd1AmountIn); + expect(after.to.toString()).to.eq(expectedBpts.bbausd2AmountOut); + return expectedBpts.bbausd2AmountOut; } + let bbausd2AmountOut: string; + context('staked', async () => { beforeEach(async function () { this.timeout(20000); @@ -223,14 +235,24 @@ describe('bbausd migration execution', async () => { await stake(signer, balance); }); - it('should transfer tokens from stable to boosted', async () => { - await testFlow(undefined, true); + it('should transfer tokens from stable to boosted - using exact bbausd2AmountOut from static call', async () => { + bbausd2AmountOut = await testFlow(true); + }).timeout(20000); + + it('should transfer tokens from stable to boosted - limit should fail', async () => { + await testFlow(true, bbausd2AmountOut); + expect(false).to.be.true; // Reminder - the above test should throw }).timeout(20000); }); context('not staked', async () => { it('should transfer tokens from stable to boosted', async () => { - await testFlow(undefined, false); + await testFlow(false); + }).timeout(20000); + + it('should transfer tokens from stable to boosted - limit should fail', async () => { + await testFlow(false, bbausd2AmountOut); + expect(false).to.be.true; // Reminder - the above test should throw }).timeout(20000); }); }).timeout(20000); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index c6f7d4c72..2e00e8faf 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -2,7 +2,7 @@ import { ADDRESSES } from './addresses'; import { Relayer } from '@/modules/relayer/relayer.module'; import { BatchSwapStep, FundManagement, SwapType } from '@/modules/swaps/types'; import { Interface } from '@ethersproject/abi'; -import { MaxUint256, MaxInt256, Zero } from '@ethersproject/constants'; +import { MaxUint256, Zero } from '@ethersproject/constants'; // TODO - Ask Nico to update Typechain? import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; import { PoolToken } from '@/types'; @@ -19,8 +19,8 @@ export class BbaUsd1Builder { } calldata( - amount: string, - expectedAmount = MaxInt256.toString(), + bbausd1Amount: string, + minBbausd2Out: string, userAddress: string, staked: boolean, authorisation: string, @@ -35,16 +35,16 @@ export class BbaUsd1Builder { if (staked) { calls = [ this.buildSetRelayerApproval(authorisation), - this.buildWithdraw(userAddress, amount), - this.buildSwap(amount, expectedAmount, relayer, relayer, tokens), + this.buildWithdraw(userAddress, bbausd1Amount), + this.buildSwap(bbausd1Amount, minBbausd2Out, relayer, relayer, tokens), this.buildDeposit(userAddress), ]; } else { calls = [ this.buildSetRelayerApproval(authorisation), this.buildSwap( - amount, - expectedAmount, + bbausd1Amount, + minBbausd2Out, userAddress, userAddress, tokens @@ -69,8 +69,8 @@ export class BbaUsd1Builder { * @returns BatchSwap call. */ buildSwap( - bptAmount: string, - expectedBptReturn: string, + bbausd1Amount: string, + minBbausd2Out: string, sender: string, recipient: string, tokens: PoolToken[] @@ -108,18 +108,16 @@ export class BbaUsd1Builder { ); // bbausd1[bbausd1]blinear1[linear1]stable[linear2]blinear2[bbausd2]bbausd2 and then do that proportionally for each underlying stable. - // TO DO - Will swap order matter here? John to ask Fernando. - // Split BPT amount proportionally: - const usdcBptAmt = BigNumber.from(bptAmount) + const usdcBptAmt = BigNumber.from(bbausd1Amount) .mul(balances['bb-a-USDC']) .div(totalLiquidity) .toString(); - const usdtBptAmt = BigNumber.from(bptAmount) + const usdtBptAmt = BigNumber.from(bbausd1Amount) .mul(balances['bb-a-USDT']) .div(totalLiquidity) .toString(); - const daiBptAmt = BigNumber.from(bptAmount) + const daiBptAmt = BigNumber.from(bbausd1Amount) .sub(BigNumber.from(usdcBptAmt)) .sub(BigNumber.from(usdtBptAmt)) .toString(); @@ -211,26 +209,26 @@ export class BbaUsd1Builder { }, ]; - // For now assuming ref amounts will be safe - should we add more accurate? + // 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 = [ - expectedBptReturn, - MaxInt256.toString(), - MaxInt256.toString(), - MaxInt256.toString(), - MaxInt256.toString(), - MaxInt256.toString(), - MaxInt256.toString(), - MaxInt256.toString(), - MaxInt256.toString(), - MaxInt256.toString(), - MaxInt256.toString(), + 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: true, + fromInternalBalance: false, toInternalBalance: false, }; diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index ff1aed6a8..b9d6dc8ac 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -34,8 +34,8 @@ export class Migrations { bbaUsd( userAddress: string, - amount: string, - limit = MaxInt256.toString(), + bbausd1Amount: string, + minBbausd2Out: string, authorisation: string, staked: boolean, tokens: PoolToken[] @@ -46,14 +46,14 @@ export class Migrations { output: string, staked: boolean ) => { - expectedBptIn: string; - expectedBptOut: string; + bbausd1AmountIn: string; + bbausd2AmountOut: string; }; } { const builder = new BbaUsd1Builder(this.network); const request = builder.calldata( - amount, - limit, + bbausd1Amount, + minBbausd2Out, userAddress, staked, authorisation, @@ -71,8 +71,8 @@ export class Migrations { multicallResult[0][swapIndex] ); return { - expectedBptIn: swapDeltas[0][10].toString(), - expectedBptOut: swapDeltas[0][0].abs().toString(), + bbausd1AmountIn: swapDeltas[0][10].toString(), + bbausd2AmountOut: swapDeltas[0][0].abs().toString(), }; }, }; From 5d93dd6e74389b492a264741c3a33800f1a75458 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 28 Jul 2022 14:14:46 +0100 Subject: [PATCH 054/104] Change to use address instead of symbol. --- balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 2e00e8faf..30c913b94 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -102,7 +102,7 @@ export class BbaUsd1Builder { const balances = Object.fromEntries( tokens.map((token) => [ - token.symbol, + token.address.toLowerCase(), parseFixed(token.balance, 18).toString(), ]) ); @@ -110,11 +110,11 @@ export class BbaUsd1Builder { // bbausd1[bbausd1]blinear1[linear1]stable[linear2]blinear2[bbausd2]bbausd2 and then do that proportionally for each underlying stable. // Split BPT amount proportionally: const usdcBptAmt = BigNumber.from(bbausd1Amount) - .mul(balances['bb-a-USDC']) + .mul(balances[this.addresses.linearUsdc1.address.toLowerCase()]) .div(totalLiquidity) .toString(); const usdtBptAmt = BigNumber.from(bbausd1Amount) - .mul(balances['bb-a-USDT']) + .mul(balances[this.addresses.linearUsdt1.address.toLowerCase()]) .div(totalLiquidity) .toString(); const daiBptAmt = BigNumber.from(bbausd1Amount) From 56ad65dd3d1655a02b196960f8cb28bc0bc2bdff Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 28 Jul 2022 10:49:07 -0300 Subject: [PATCH 055/104] Replace tokens by tokenBalances as input for bbausd migration flow --- .../zaps/bbausd2-migrations/addresses.ts | 2 + .../bbausd1.integration.spec.ts | 10 +++-- .../zaps/bbausd2-migrations/bbausd1.ts | 41 +++++++++---------- balancer-js/src/modules/zaps/migrations.ts | 4 +- 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index eb986df66..3d0631afa 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -11,6 +11,7 @@ export const ADDRESSES = { id: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb20000000000000000000000fe', address: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb2', gauge: '0x68d019f64a7aa97e2d4e7363aee42251d08124fb', + assetOrder: ['bb-a-USDT', 'bb-a-DAI', 'bb-a-USDC'], }, bbausd2: { id: '', @@ -66,6 +67,7 @@ export const ADDRESSES = { id: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd00000000000000000000005f', address: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd', gauge: '0xa2d0ea81a47d68598922cd54c59249ff58c2a3ff', + assetOrder: ['bb-a-USDC', 'bb-a-DAI', 'bb-a-USDT'], }, bbausd2: { id: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd00000000000000000000005f', 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 index c81ab3007..6b7627af7 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -10,7 +10,7 @@ import { Subgraph, SubgraphPoolRepository, } from '@/.'; -import { BigNumber } from '@ethersproject/bignumber'; +import { BigNumber, parseFixed } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; import { ADDRESSES } from './addresses'; import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; @@ -189,7 +189,9 @@ describe('bbausd migration execution', async () => { '0', authorisation, staked, - pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed + pool.tokens + .filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed + .map((token) => parseFixed(token.balance, token.decimals).toString()) ); const { to, data } = query; @@ -205,7 +207,9 @@ describe('bbausd migration execution', async () => { minBbausd2Out ? minBbausd2Out : expectedBpts.bbausd2AmountOut, authorisation, staked, - pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed + pool.tokens + .filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed + .map((token) => parseFixed(token.balance, token.decimals).toString()) ); const response = await signer.sendTransaction({ to, data, gasLimit }); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 30c913b94..136f0b645 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -5,8 +5,7 @@ import { Interface } from '@ethersproject/abi'; import { MaxUint256, Zero } from '@ethersproject/constants'; // TODO - Ask Nico to update Typechain? import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; -import { PoolToken } from '@/types'; -import { BigNumber, parseFixed } from '@ethersproject/bignumber'; +import { BigNumber } from '@ethersproject/bignumber'; const balancerRelayerInterface = new Interface(balancerRelayerAbi); const SWAP_RESULT_BBAUSD = Relayer.toChainedReference('24'); @@ -24,7 +23,7 @@ export class BbaUsd1Builder { userAddress: string, staked: boolean, authorisation: string, - tokens: PoolToken[] + tokenBalances: string[] ): { to: string; data: string; @@ -36,7 +35,13 @@ export class BbaUsd1Builder { calls = [ this.buildSetRelayerApproval(authorisation), this.buildWithdraw(userAddress, bbausd1Amount), - this.buildSwap(bbausd1Amount, minBbausd2Out, relayer, relayer, tokens), + this.buildSwap( + bbausd1Amount, + minBbausd2Out, + relayer, + relayer, + tokenBalances + ), this.buildDeposit(userAddress), ]; } else { @@ -47,7 +52,7 @@ export class BbaUsd1Builder { minBbausd2Out, userAddress, userAddress, - tokens + tokenBalances ), ]; } @@ -73,7 +78,7 @@ export class BbaUsd1Builder { minBbausd2Out: string, sender: string, recipient: string, - tokens: PoolToken[] + tokenBalances: string[] ): string { const assets = [ this.addresses.bbausd2.address, @@ -95,31 +100,25 @@ export class BbaUsd1Builder { // Assuming 1:1 exchange rates between tokens // TODO: Fetch current prices, or use price or priceRate from subgraph? - const totalLiquidity = tokens.reduce( - (sum, token) => sum.add(parseFixed(token.balance, 18)), + const totalLiquidity = tokenBalances.reduce( + (sum, tokenBalance) => sum.add(BigNumber.from(tokenBalance)), Zero ); - const balances = Object.fromEntries( - tokens.map((token) => [ - token.address.toLowerCase(), - parseFixed(token.balance, 18).toString(), - ]) - ); - // 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(balances[this.addresses.linearUsdc1.address.toLowerCase()]) + .mul(tokenBalances[assetOrder.indexOf('bb-a-USDC')]) .div(totalLiquidity) .toString(); - const usdtBptAmt = BigNumber.from(bbausd1Amount) - .mul(balances[this.addresses.linearUsdt1.address.toLowerCase()]) + const daiBptAmt = BigNumber.from(bbausd1Amount) + .mul(tokenBalances[assetOrder.indexOf('bb-a-DAI')]) .div(totalLiquidity) .toString(); - const daiBptAmt = BigNumber.from(bbausd1Amount) - .sub(BigNumber.from(usdcBptAmt)) - .sub(BigNumber.from(usdtBptAmt)) + const usdtBptAmt = BigNumber.from(bbausd1Amount) + .sub(usdcBptAmt) + .sub(daiBptAmt) .toString(); const swaps: BatchSwapStep[] = [ diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index b9d6dc8ac..f7cad68b7 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -38,7 +38,7 @@ export class Migrations { minBbausd2Out: string, authorisation: string, staked: boolean, - tokens: PoolToken[] + tokenBalances: string[] ): { to: string; data: string; @@ -57,7 +57,7 @@ export class Migrations { userAddress, staked, authorisation, - tokens + tokenBalances ); return { From 61ed0e66a5ad3ddbd1cc77216c554afa3cb2f7a8 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 28 Jul 2022 15:23:35 +0100 Subject: [PATCH 056/104] staBal migration decode fix and tidy. Updated tests. --- .../bbausd1.integration.spec.ts | 19 ++- .../stabal3.integration.spec.ts | 154 +++++++++--------- .../zaps/bbausd2-migrations/stabal3.ts | 26 +-- balancer-js/src/modules/zaps/migrations.ts | 27 ++- 4 files changed, 128 insertions(+), 98 deletions(-) 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 index c81ab3007..1216863ae 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -192,11 +192,14 @@ describe('bbausd migration execution', async () => { pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed ); - const { to, data } = query; 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, data, gasLimit }); + const staticResult = await signer.call({ + to: query.to, + data: query.data, + gasLimit, + }); const expectedBpts = query.decode(staticResult, staked); query = migrations.bbaUsd( @@ -208,7 +211,11 @@ describe('bbausd migration execution', async () => { pool.tokens.filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed ); - const response = await signer.sendTransaction({ to, data, gasLimit }); + const response = await signer.sendTransaction({ + to: query.to, + data: query.data, + gasLimit, + }); const receipt = await response.wait(); console.log('Gas used', receipt.gasUsed.toString()); @@ -240,18 +247,18 @@ describe('bbausd migration execution', async () => { }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { - await testFlow(true, bbausd2AmountOut); + await testFlow(true, BigNumber.from(bbausd2AmountOut).add(1).toString()); expect(false).to.be.true; // Reminder - the above test should throw }).timeout(20000); }); context('not staked', async () => { - it('should transfer tokens from stable to boosted', async () => { + it('should transfer tokens from stable to boosted - using exact bbausd2AmountOut from static call', async () => { await testFlow(false); }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { - await testFlow(false, bbausd2AmountOut); + await testFlow(false, BigNumber.from(bbausd2AmountOut).add(1).toString()); expect(false).to.be.true; // Reminder - the above test should throw }).timeout(20000); }); 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 index 2b60c7778..d1a36dbcc 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -39,7 +39,6 @@ const migrations = new Migrations(network); const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; const poolAddress = addresses.staBal3.address; -const gaugeAddress = addresses.staBal3.gauge; const relayer = addresses.relayer; const getErc20Balance = (token: string, holder: string): Promise => @@ -112,7 +111,7 @@ const stake = async ( await contracts .ERC20(poolAddress, provider) .connect(signer) - .approve(gaugeAddress, MaxUint256) + .approve(addresses.staBal3.gauge, MaxUint256) ).wait(); await ( @@ -124,7 +123,7 @@ const stake = async ( await ( await signer.sendTransaction({ - to: gaugeAddress, + to: addresses.staBal3.gauge, data: liquidityGauge.encodeFunctionData('deposit', [balance]), }) ).wait(); @@ -149,6 +148,73 @@ describe('stabal3 migration execution', async () => { balance = await move(poolAddress, holderAddress, signerAddress); }); + async function testFlow( + staked: boolean, + minBbausd2Out: undefined | string = undefined + ): Promise { + const addressIn = staked + ? addresses.staBal3.gauge + : addresses.staBal3.address; + const addressOut = staked + ? addresses.bbausd2.gauge + : addresses.bbausd2.address; + // Store balance before migration + const before = { + from: await getErc20Balance(addressIn, signerAddress), + to: await getErc20Balance(addressOut, signerAddress), + }; + + const amount = before.from; + + let query = migrations.stabal3( + signerAddress, + amount.toString(), + '0', + authorisation, + staked + ); + 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 bbausd2AmountOut = query.decode(staticResult, staked); + + query = migrations.stabal3( + signerAddress, + amount.toString(), + minBbausd2Out ? minBbausd2Out : bbausd2AmountOut, + authorisation, + staked + ); + + 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, signerAddress), + to: await getErc20Balance(addressOut, signerAddress), + }; + + console.log(bbausd2AmountOut); + + expect(BigNumber.from(bbausd2AmountOut).gt(0)).to.be.true; + expect(after.from.toString()).to.eq('0'); + expect(after.to.toString()).to.eq(bbausd2AmountOut); + return bbausd2AmountOut; + } + + let bbausd2AmountOut: string; + context('staked', async () => { beforeEach(async function () { this.timeout(20000); @@ -158,81 +224,23 @@ describe('stabal3 migration execution', async () => { }); it('should transfer tokens from stable to boosted', async () => { - // Store balance before migration - const before = { - from: await getErc20Balance(gaugeAddress, signerAddress), - to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), - }; - - const query = migrations.stabal3( - signerAddress, - before.from.toString(), - undefined, - authorisation, - true - ); - - const { to, data } = query; - const gasLimit = MAX_GAS_LIMIT; - const response = await signer.sendTransaction({ to, data, gasLimit }); - - const receipt = await response.wait(); - console.log('Gas used', receipt.gasUsed.toString()); - - const after = { - from: await getErc20Balance(gaugeAddress, signerAddress), - to: await getErc20Balance(addresses.bbausd2.gauge, signerAddress), - }; - - const diffs = { - from: after.from.sub(before.from), - to: after.to.sub(before.to), - }; - - console.log(diffs.from, diffs.to); - - expect(diffs.from).to.eql(before.from.mul(-1)); - expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + bbausd2AmountOut = await testFlow(true); + }); + + it('should transfer tokens from stable to boosted - limit should fail', async () => { + await testFlow(true, BigNumber.from(bbausd2AmountOut).add(1).toString()); + expect(false).to.be.true; // Reminder - the above test should throw }).timeout(20000); }); context('not staked', async () => { it('should transfer tokens from stable to boosted', async () => { - // Store balance before migration - const before = { - from: await getErc20Balance(poolAddress, signerAddress), - to: await getErc20Balance(addresses.bbausd2.address, signerAddress), - }; - - const query = migrations.stabal3( - signerAddress, - before.from.toString(), - undefined, - authorisation, - false - ); - - const { to, data } = query; - const gasLimit = MAX_GAS_LIMIT; - const response = await signer.sendTransaction({ to, data, gasLimit }); - - const receipt = await response.wait(); - console.log('Gas used', receipt.gasUsed.toString()); - - const after = { - from: await getErc20Balance(poolAddress, signerAddress), - to: await getErc20Balance(addresses.bbausd2.address, signerAddress), - }; - - const diffs = { - from: after.from.sub(before.from), - to: after.to.sub(before.to), - }; - - console.log(diffs.from, diffs.to); - - expect(diffs.from).to.eql(before.from.mul(-1)); - expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + bbausd2AmountOut = await testFlow(false); + }); + + it('should transfer tokens from stable to boosted - limit should fail', async () => { + await testFlow(false, BigNumber.from(bbausd2AmountOut).add(1).toString()); + expect(false).to.be.true; // Reminder - the above test should throw }).timeout(20000); }); }).timeout(20000); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 48a1832f9..4e7382fca 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -4,6 +4,7 @@ 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 { MaxUint256, MaxInt256 } from '@ethersproject/constants'; // TODO - Ask Nico to update Typechain? import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; @@ -22,8 +23,8 @@ export class StaBal3Builder { } calldata( - amount: string, - expectedAmount = MaxInt256.toString(), + staBal3Amount: string, + minBbausd2Out: string, userAddress: string, staked: boolean, authorisation: string @@ -37,16 +38,16 @@ export class StaBal3Builder { if (staked) { calls = [ this.buildSetRelayerApproval(authorisation), - this.buildWithdraw(userAddress, amount), - this.buildExit(relayer, relayer, amount), - this.buildSwap(expectedAmount, relayer), + this.buildWithdraw(userAddress, staBal3Amount), + this.buildExit(relayer, relayer, staBal3Amount), + this.buildSwap(minBbausd2Out, relayer), this.buildDeposit(userAddress), ]; } else { calls = [ this.buildSetRelayerApproval(authorisation), - this.buildExit(userAddress, relayer, amount), - this.buildSwap(expectedAmount, userAddress), + this.buildExit(userAddress, relayer, staBal3Amount), + this.buildSwap(minBbausd2Out, userAddress), ]; } @@ -182,15 +183,16 @@ export class StaBal3Builder { }, ]; - // For now assuming ref amounts will be safe - should we add more accurate? + // 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. + console.log(`Min: `, BigNumber.from(expectedBptReturn).mul(-1).toString()); const limits = [ - expectedBptReturn, - MaxInt256.toString(), - MaxInt256.toString(), - MaxInt256.toString(), + BigNumber.from(expectedBptReturn).mul(-1).toString(), MaxInt256.toString(), + '0', MaxInt256.toString(), + '0', MaxInt256.toString(), + '0', ]; // Swap to/from Relayer diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index b9d6dc8ac..4d9ffa826 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -10,15 +10,19 @@ export class Migrations { stabal3( userAddress: string, - amount: string, - limit = MaxInt256.toString(), + staBal3Amount: string, + minBbausd2Out: string, authorisation: string, staked: boolean - ): { to: string; data: string; decode: (output: string) => string } { + ): { + to: string; + data: string; + decode: (output: string, staked: boolean) => string; + } { const builder = new StaBal3Builder(this.network); const request = builder.calldata( - amount, - limit, + staBal3Amount, + minBbausd2Out, userAddress, staked, authorisation @@ -27,8 +31,17 @@ export class Migrations { return { to: request.to, data: request.data, - decode: (output) => - defaultAbiCoder.decode(['int256[]'], output[2])[3].toString(), + decode: (output, staked) => { + const swapIndex = staked ? 3 : 2; + const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); + const swapDeltas = defaultAbiCoder.decode( + ['int256[]'], + multicallResult[0][swapIndex] + ); + console.log(swapDeltas.toString()); + // bbausd2AmountOut + return swapDeltas[0][0].abs().toString(); + }, }; } From be62774c479f566c4ab049ea1388ad231616f0f7 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 28 Jul 2022 15:14:45 -0300 Subject: [PATCH 057/104] Asserts error messages to expected value --- .../bbausd1.integration.spec.ts | 26 +++++++++++++++---- .../stabal3.integration.spec.ts | 24 ++++++++++++++--- balancer-js/src/modules/zaps/migrations.ts | 1 - 3 files changed, 41 insertions(+), 10 deletions(-) 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 index 438c2bdb3..fb3ff6072 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -251,19 +251,35 @@ describe('bbausd migration execution', async () => { }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { - await testFlow(true, BigNumber.from(bbausd2AmountOut).add(1).toString()); - expect(false).to.be.true; // Reminder - the above test should throw + let errorMessage = ''; + try { + await testFlow( + true, + BigNumber.from(bbausd2AmountOut).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) }).timeout(20000); }); context('not staked', async () => { it('should transfer tokens from stable to boosted - using exact bbausd2AmountOut from static call', async () => { - await testFlow(false); + bbausd2AmountOut = await testFlow(false); }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { - await testFlow(false, BigNumber.from(bbausd2AmountOut).add(1).toString()); - expect(false).to.be.true; // Reminder - the above test should throw + let errorMessage = ''; + try { + await testFlow( + false, + BigNumber.from(bbausd2AmountOut).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) }).timeout(20000); }); }).timeout(20000); 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 index d1a36dbcc..4db0f421f 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -228,8 +228,16 @@ describe('stabal3 migration execution', async () => { }); it('should transfer tokens from stable to boosted - limit should fail', async () => { - await testFlow(true, BigNumber.from(bbausd2AmountOut).add(1).toString()); - expect(false).to.be.true; // Reminder - the above test should throw + let errorMessage = ''; + try { + await testFlow( + true, + BigNumber.from(bbausd2AmountOut).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) }).timeout(20000); }); @@ -239,8 +247,16 @@ describe('stabal3 migration execution', async () => { }); it('should transfer tokens from stable to boosted - limit should fail', async () => { - await testFlow(false, BigNumber.from(bbausd2AmountOut).add(1).toString()); - expect(false).to.be.true; // Reminder - the above test should throw + let errorMessage = ''; + try { + await testFlow( + false, + BigNumber.from(bbausd2AmountOut).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) }).timeout(20000); }); }).timeout(20000); diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index f498a0e23..4dc5faa24 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -3,7 +3,6 @@ import { MaxInt256 } from '@ethersproject/constants'; import { StaBal3Builder } from './bbausd2-migrations/stabal3'; import { BbaUsd1Builder } from './bbausd2-migrations/bbausd1'; import { StablesBuilder } from './bbausd2-migrations/stables'; -import { PoolToken } from '@/types'; export class Migrations { constructor(private network: 1 | 5) {} From f58f0ce4835d8a65ba72630de3a8018c6ec7e4b7 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 28 Jul 2022 17:25:01 -0300 Subject: [PATCH 058/104] Make authorisation optional input on migrations --- .../bbausd1.integration.spec.ts | 37 +++++++++++++++-- .../zaps/bbausd2-migrations/bbausd1.ts | 14 ++++--- .../stabal3.integration.spec.ts | 41 ++++++++++++++++--- .../zaps/bbausd2-migrations/stabal3.ts | 21 ++++------ balancer-js/src/modules/zaps/migrations.ts | 22 +++++----- 5 files changed, 95 insertions(+), 40 deletions(-) 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 index fb3ff6072..542fddde0 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -167,6 +167,7 @@ describe('bbausd migration execution', async () => { async function testFlow( staked: boolean, + authorized = true, minBbausd2Out: undefined | string = undefined ): Promise { const addressIn = staked @@ -187,11 +188,11 @@ describe('bbausd migration execution', async () => { signerAddress, amount.toString(), '0', - authorisation, staked, pool.tokens .filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed - .map((token) => parseFixed(token.balance, token.decimals).toString()) + .map((token) => parseFixed(token.balance, token.decimals).toString()), + authorisation ); const gasLimit = MAX_GAS_LIMIT; @@ -208,11 +209,11 @@ describe('bbausd migration execution', async () => { signerAddress, amount.toString(), minBbausd2Out ? minBbausd2Out : expectedBpts.bbausd2AmountOut, - authorisation, staked, pool.tokens .filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed - .map((token) => parseFixed(token.balance, token.decimals).toString()) + .map((token) => parseFixed(token.balance, token.decimals).toString()), + authorized ? authorisation : undefined ); const response = await signer.sendTransaction({ @@ -254,6 +255,7 @@ describe('bbausd migration execution', async () => { let errorMessage = ''; try { await testFlow( + true, true, BigNumber.from(bbausd2AmountOut).add(1).toString() ); @@ -274,6 +276,7 @@ describe('bbausd migration execution', async () => { try { await testFlow( false, + true, BigNumber.from(bbausd2AmountOut).add(1).toString() ); } catch (error) { @@ -282,4 +285,30 @@ describe('bbausd migration execution', async () => { expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) }).timeout(20000); }); + + context('authorization', async () => { + // authorisation wihtin relayer is the default case and is already tested on previous scenarios + + it('should transfer tokens from stable to boosted - pre authorized', async () => { + const approval = contracts.vault.interface.encodeFunctionData( + 'setRelayerApproval', + [signerAddress, relayer, true] + ); + await signer.sendTransaction({ + to: contracts.vault.address, + data: approval, + }); + await testFlow(false, false); + }).timeout(20000); + + 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 + }).timeout(20000); + }).timeout(20000); }).timeout(20000); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 136f0b645..068eedefd 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -18,22 +18,24 @@ export class BbaUsd1Builder { } calldata( + userAddress: string, bbausd1Amount: string, minBbausd2Out: string, - userAddress: string, staked: boolean, - authorisation: string, - tokenBalances: string[] + tokenBalances: string[], + authorisation?: string ): { to: string; data: string; } { const relayer = this.addresses.relayer; - let calls: string[] = []; + let calls: string[] = authorisation + ? [this.buildSetRelayerApproval(authorisation)] + : []; if (staked) { calls = [ - this.buildSetRelayerApproval(authorisation), + ...calls, this.buildWithdraw(userAddress, bbausd1Amount), this.buildSwap( bbausd1Amount, @@ -46,7 +48,7 @@ export class BbaUsd1Builder { ]; } else { calls = [ - this.buildSetRelayerApproval(authorisation), + ...calls, this.buildSwap( bbausd1Amount, minBbausd2Out, 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 index 4db0f421f..f047ccec7 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -150,6 +150,7 @@ describe('stabal3 migration execution', async () => { async function testFlow( staked: boolean, + authorised = true, minBbausd2Out: undefined | string = undefined ): Promise { const addressIn = staked @@ -170,8 +171,8 @@ describe('stabal3 migration execution', async () => { signerAddress, amount.toString(), '0', - authorisation, - staked + staked, + authorisation ); const gasLimit = MAX_GAS_LIMIT; @@ -187,8 +188,8 @@ describe('stabal3 migration execution', async () => { signerAddress, amount.toString(), minBbausd2Out ? minBbausd2Out : bbausd2AmountOut, - authorisation, - staked + staked, + authorised ? authorisation : undefined ); const response = await signer.sendTransaction({ @@ -225,12 +226,13 @@ describe('stabal3 migration execution', async () => { it('should transfer tokens from stable to boosted', async () => { bbausd2AmountOut = await testFlow(true); - }); + }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; try { await testFlow( + true, true, BigNumber.from(bbausd2AmountOut).add(1).toString() ); @@ -244,13 +246,14 @@ describe('stabal3 migration execution', async () => { context('not staked', async () => { it('should transfer tokens from stable to boosted', async () => { bbausd2AmountOut = await testFlow(false); - }); + }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; try { await testFlow( false, + true, BigNumber.from(bbausd2AmountOut).add(1).toString() ); } catch (error) { @@ -259,4 +262,30 @@ describe('stabal3 migration execution', async () => { expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) }).timeout(20000); }); + + context('authorization', async () => { + // authorisation wihtin relayer is the default case and is already tested on previous scenarios + + it('should transfer tokens from stable to boosted - pre authorized', async () => { + const approval = contracts.vault.interface.encodeFunctionData( + 'setRelayerApproval', + [signerAddress, relayer, true] + ); + await signer.sendTransaction({ + to: contracts.vault.address, + data: approval, + }); + await testFlow(false, false); + }).timeout(20000); + + 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 + }).timeout(20000); + }).timeout(20000); }).timeout(20000); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 4e7382fca..5ddb4d1b5 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -23,21 +23,23 @@ export class StaBal3Builder { } calldata( + userAddress: string, staBal3Amount: string, minBbausd2Out: string, - userAddress: string, staked: boolean, - authorisation: string + authorisation?: string ): { to: string; data: string; } { const relayer = this.addresses.relayer; - let calls: string[] = []; + let calls: string[] = authorisation + ? [this.buildSetRelayerApproval(authorisation)] + : []; if (staked) { calls = [ - this.buildSetRelayerApproval(authorisation), + ...calls, this.buildWithdraw(userAddress, staBal3Amount), this.buildExit(relayer, relayer, staBal3Amount), this.buildSwap(minBbausd2Out, relayer), @@ -45,21 +47,12 @@ export class StaBal3Builder { ]; } else { calls = [ - this.buildSetRelayerApproval(authorisation), + ...calls, this.buildExit(userAddress, relayer, staBal3Amount), this.buildSwap(minBbausd2Out, userAddress), ]; } - // TODO: Let's double check with setting approveVault to 0 if we need that or not, or ask Nico ;) - // const { assetOrder } = this.addresses.staBal3; - // ...assetOrder.map((name) => { - // const tokenAddress = this.addresses[ - // name as keyof typeof this.addresses - // ] as string; - // return this.buildApproveVault(tokenAddress); - // }), - const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ calls, ]); diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index 4dc5faa24..79125f389 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -11,8 +11,8 @@ export class Migrations { userAddress: string, staBal3Amount: string, minBbausd2Out: string, - authorisation: string, - staked: boolean + staked: boolean, + authorisation?: string ): { to: string; data: string; @@ -20,9 +20,9 @@ export class Migrations { } { const builder = new StaBal3Builder(this.network); const request = builder.calldata( + userAddress, staBal3Amount, minBbausd2Out, - userAddress, staked, authorisation ); @@ -31,7 +31,8 @@ export class Migrations { to: request.to, data: request.data, decode: (output, staked) => { - const swapIndex = staked ? 3 : 2; + let swapIndex = staked ? 3 : 2; + if (authorisation == undefined) swapIndex -= 1; const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); const swapDeltas = defaultAbiCoder.decode( ['int256[]'], @@ -48,9 +49,9 @@ export class Migrations { userAddress: string, bbausd1Amount: string, minBbausd2Out: string, - authorisation: string, staked: boolean, - tokenBalances: string[] + tokenBalances: string[], + authorisation?: string ): { to: string; data: string; @@ -64,19 +65,20 @@ export class Migrations { } { const builder = new BbaUsd1Builder(this.network); const request = builder.calldata( + userAddress, bbausd1Amount, minBbausd2Out, - userAddress, staked, - authorisation, - tokenBalances + tokenBalances, + authorisation ); return { to: request.to, data: request.data, decode: (output, staked) => { - const swapIndex = staked ? 2 : 1; + let swapIndex = staked ? 2 : 1; + if (authorisation == undefined) swapIndex -= 1; const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); const swapDeltas = defaultAbiCoder.decode( ['int256[]'], From 9a96f6c0eb074ea30cf8f98f2368e3a701689a3d Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 28 Jul 2022 19:27:37 -0300 Subject: [PATCH 059/104] Refactor generalised stables flow (WIP) --- .../stables.integration.spec.ts | 198 +++++++++++------- .../zaps/bbausd2-migrations/stables.ts | 15 +- balancer-js/src/modules/zaps/migrations.ts | 32 ++- 3 files changed, 157 insertions(+), 88 deletions(-) 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 index b79ae7fd3..8df1f4a57 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -152,6 +152,79 @@ describe('stables migration execution', async () => { balance = await move(fromPool.address, holderAddress, signerAddress); }); + const testFlow = async ( + staked: boolean, + authorised = true, + minBbausd2Out: undefined | string = undefined + ) => { + // Store balance before migration + const before = { + from: await getErc20Balance(fromGauge, signerAddress), + to: await getErc20Balance(toGauge, signerAddress), + }; + + const migrations = new Migrations(network); + 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 bbausd2AmountOut = query.decode(staticResult, staked); + + query = migrations.stables( + signerAddress, + fromPool, + toPool, + before.from.toString(), + minBbausd2Out ? minBbausd2Out : bbausd2AmountOut, + 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(fromGauge, signerAddress), + to: await getErc20Balance(toGauge, signerAddress), + }; + + const diffs = { + from: after.from.sub(before.from), + to: after.to.sub(before.to), + }; + + console.log(diffs.from, diffs.to); + + expect(BigNumber.from(bbausd2AmountOut).gt(0)).to.be.true; + expect(after.from.toString()).to.eq('0'); + expect(after.to.toString()).to.eq(bbausd2AmountOut); + return bbausd2AmountOut; + }; + + let bbausd2AmountOut: string; + context('staked', async () => { beforeEach(async function () { this.timeout(20000); @@ -161,89 +234,68 @@ describe('stables migration execution', async () => { }); it('should transfer tokens from stable to boosted', async () => { - // Store balance before migration - const before = { - from: await getErc20Balance(fromGauge, signerAddress), - to: await getErc20Balance(toGauge, signerAddress), - }; - - const migrations = new Migrations(network); - const query = migrations.stables( - fromPool, - toPool, - signerAddress, - before.from.toString(), - undefined, - authorisation, - true, - tokens - ); - - const { to, data } = query; - const gasLimit = MAX_GAS_LIMIT; - const response = await signer.sendTransaction({ to, data, gasLimit }); - - const receipt = await response.wait(); - console.log('Gas used', receipt.gasUsed.toString()); - - const after = { - from: await getErc20Balance(fromGauge, signerAddress), - to: await getErc20Balance(toGauge, signerAddress), - }; - - const diffs = { - from: after.from.sub(before.from), - to: after.to.sub(before.to), - }; - - console.log(diffs.from, diffs.to); + bbausd2AmountOut = await testFlow(true); + }).timeout(20000); - expect(diffs.from).to.eql(before.from.mul(-1)); - expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + it('should transfer tokens from stable to boosted - limit should fail', async () => { + let errorMessage = ''; + try { + await testFlow( + true, + true, + BigNumber.from(bbausd2AmountOut).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) }).timeout(20000); }); context('not staked', async () => { it('should transfer tokens from stable to boosted', async () => { // Store balance before migration - const before = { - from: await getErc20Balance(fromPool.address, signerAddress), - to: await getErc20Balance(toPool.address, signerAddress), - }; - - const migrations = new Migrations(network); - const query = migrations.stables( - fromPool, - toPool, - signerAddress, - before.from.toString(), - undefined, - authorisation, - false, - tokens - ); - - const { to, data } = query; - const gasLimit = MAX_GAS_LIMIT; - const response = await signer.sendTransaction({ to, data, gasLimit }); - - const receipt = await response.wait(); - console.log('Gas used', receipt.gasUsed.toString()); + bbausd2AmountOut = await testFlow(false); + }).timeout(20000); - const after = { - from: await getErc20Balance(fromPool.address, signerAddress), - to: await getErc20Balance(toPool.address, signerAddress), - }; + it('should transfer tokens from stable to boosted - limit should fail', async () => { + let errorMessage = ''; + try { + await testFlow( + false, + true, + BigNumber.from(bbausd2AmountOut).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) + }).timeout(20000); + }); - const diffs = { - from: after.from.sub(before.from), - to: after.to.sub(before.to), - }; + context('authorization', async () => { + // authorisation wihtin relayer is the default case and is already tested on previous scenarios - console.log(diffs.from, diffs.to); + it('should transfer tokens from stable to boosted - pre authorized', async () => { + const approval = contracts.vault.interface.encodeFunctionData( + 'setRelayerApproval', + [signerAddress, relayer, true] + ); + await signer.sendTransaction({ + to: contracts.vault.address, + data: approval, + }); + await testFlow(false, false); + }).timeout(20000); - expect(diffs.from).to.eql(before.from.mul(-1)); - expect(parseFloat(formatEther(diffs.to))).to.be.gt(0); + 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 }).timeout(20000); - }); + }).timeout(20000); }).timeout(20000); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index 18d7cd18d..72a981e9c 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -21,20 +21,23 @@ export class StablesBuilder { } calldata( + userAddress: string, from: { id: string; address: string; gauge?: string }, to: { id: string; address: string; gauge?: string }, - userAddress: string, amount: string, expectedAmount = MaxInt256.toString(), - authorisation: string, staked: boolean, - tokens: string[] + tokens: string[], + authorisation?: string ): { to: string; data: string; } { const relayer = this.addresses.relayer; - let calls: string[] = []; + let calls: string[] = authorisation + ? [this.buildSetRelayerApproval(authorisation)] + : []; + if (staked && (from.gauge == undefined || to.gauge == undefined)) throw new Error( 'Staked flow migration requires gauge addresses to be provided' @@ -42,7 +45,7 @@ export class StablesBuilder { if (staked) { calls = [ - this.buildSetRelayerApproval(authorisation), + ...calls, this.buildWithdraw(userAddress, amount, from.gauge as string), this.buildExit(from.id, relayer, relayer, amount, tokens), this.buildSwap(expectedAmount, relayer, to.id, to.address, tokens), @@ -50,7 +53,7 @@ export class StablesBuilder { ]; } else { calls = [ - this.buildSetRelayerApproval(authorisation), + ...calls, this.buildExit(from.id, userAddress, relayer, amount, tokens), this.buildSwap(expectedAmount, userAddress, to.id, to.address, tokens), ]; diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index 79125f389..8b7cfee02 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -93,32 +93,46 @@ export class Migrations { } stables( + userAddress: string, from: { id: string; address: string; gauge?: string }, to: { id: string; address: string; gauge?: string }, - userAddress: string, amount: string, limit = MaxInt256.toString(), - authorisation: string, staked: boolean, - tokens: string[] - ): { to: string; data: string; decode: (output: string) => string } { + tokens: 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, - userAddress, amount, limit, - authorisation, staked, - tokens + tokens, + authorisation ); return { to: request.to, data: request.data, - decode: (output) => - defaultAbiCoder.decode(['int256[]'], output[2])[3].toString(), + decode: (output, staked) => { + let swapIndex = staked ? 3 : 2; + if (authorisation == undefined) swapIndex -= 1; + const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); + const swapDeltas = defaultAbiCoder.decode( + ['int256[]'], + multicallResult[0][swapIndex] + ); + console.log(swapDeltas.toString()); + // bbausd2AmountOut + return swapDeltas[0][0].abs().toString(); + }, }; } } From 0068f524bfe650c39de725a5c8ef7336941eb6c1 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 29 Jul 2022 11:03:19 +0100 Subject: [PATCH 060/104] Expose Signature functions. --- balancer-js/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/balancer-js/src/index.ts b/balancer-js/src/index.ts index 8f0a1b489..22882e6db 100644 --- a/balancer-js/src/index.ts +++ b/balancer-js/src/index.ts @@ -15,6 +15,7 @@ export * from './modules/sor/sor.module'; export * from './modules/pools/pools.module'; export * from './modules/data'; export * from './balancerErrors'; +export * from './lib/utils/signatures'; export { SwapInfo, SubgraphPoolBase, From 25549734a0902565ee85650b83b0747cc76a5255 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Fri, 29 Jul 2022 10:39:23 -0300 Subject: [PATCH 061/104] Fix generalised stables migration flow pending issues --- .../stabal3.integration.spec.ts | 2 +- .../stables.integration.spec.ts | 50 ++++++++----------- .../zaps/bbausd2-migrations/stables.ts | 18 +++---- balancer-js/src/modules/zaps/migrations.ts | 20 ++++---- 4 files changed, 41 insertions(+), 49 deletions(-) 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 index f047ccec7..89c1b315e 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -6,7 +6,7 @@ import { BigNumber } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; import { ADDRESSES } from './addresses'; import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; -import { parseEther, formatEther } from '@ethersproject/units'; +import { parseEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256 } from '@ethersproject/constants'; import { Migrations } from '../migrations'; 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 index 8df1f4a57..80e9ece50 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -6,7 +6,7 @@ import { BigNumber } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; import { ADDRESSES } from './addresses'; import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; -import { parseEther, formatEther } from '@ethersproject/units'; +import { parseEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256 } from '@ethersproject/constants'; import { Migrations } from '../migrations'; @@ -35,6 +35,7 @@ const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const addresses = ADDRESSES[network]; const { contracts } = new Contracts(network as number, provider); +const migrations = new Migrations(network); const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; const fromPool = { @@ -48,8 +49,6 @@ const toPool = { 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 -const fromGauge = addresses.staBal3.gauge; -const toGauge = addresses.staBal3_2.gauge; const relayer = addresses.relayer; const getErc20Balance = (token: string, holder: string): Promise => @@ -122,12 +121,12 @@ const stake = async ( await contracts .ERC20(fromPool.address, provider) .connect(signer) - .approve(fromGauge, MaxUint256) + .approve(fromPool.gauge, MaxUint256) ).wait(); await ( await signer.sendTransaction({ - to: fromGauge, + to: fromPool.gauge, data: liquidityGauge.encodeFunctionData('deposit', [balance]), }) ).wait(); @@ -155,15 +154,16 @@ describe('stables migration execution', async () => { const testFlow = async ( staked: boolean, authorised = true, - minBbausd2Out: undefined | string = undefined + 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(fromGauge, signerAddress), - to: await getErc20Balance(toGauge, signerAddress), + from: await getErc20Balance(addressIn, signerAddress), + to: await getErc20Balance(addressOut, signerAddress), }; - const migrations = new Migrations(network); let query = migrations.stables( signerAddress, fromPool, @@ -183,14 +183,14 @@ describe('stables migration execution', async () => { data: query.data, gasLimit, }); - const bbausd2AmountOut = query.decode(staticResult, staked); + const bptOut = query.decode(staticResult, staked); query = migrations.stables( signerAddress, fromPool, toPool, before.from.toString(), - minBbausd2Out ? minBbausd2Out : bbausd2AmountOut, + minBptOut ? minBptOut : bptOut, staked, tokens, authorised ? authorisation : undefined @@ -206,8 +206,8 @@ describe('stables migration execution', async () => { console.log('Gas used', receipt.gasUsed.toString()); const after = { - from: await getErc20Balance(fromGauge, signerAddress), - to: await getErc20Balance(toGauge, signerAddress), + from: await getErc20Balance(addressIn, signerAddress), + to: await getErc20Balance(addressOut, signerAddress), }; const diffs = { @@ -217,13 +217,13 @@ describe('stables migration execution', async () => { console.log(diffs.from, diffs.to); - expect(BigNumber.from(bbausd2AmountOut).gt(0)).to.be.true; + expect(BigNumber.from(bptOut).gt(0)).to.be.true; expect(after.from.toString()).to.eq('0'); - expect(after.to.toString()).to.eq(bbausd2AmountOut); - return bbausd2AmountOut; + expect(after.to.toString()).to.eq(bptOut); + return bptOut; }; - let bbausd2AmountOut: string; + let bptOut: string; context('staked', async () => { beforeEach(async function () { @@ -234,17 +234,13 @@ describe('stables migration execution', async () => { }); it('should transfer tokens from stable to boosted', async () => { - bbausd2AmountOut = await testFlow(true); + bptOut = await testFlow(true); }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; try { - await testFlow( - true, - true, - BigNumber.from(bbausd2AmountOut).add(1).toString() - ); + await testFlow(true, true, BigNumber.from(bptOut).add(1).toString()); } catch (error) { errorMessage = (error as Error).message; } @@ -255,17 +251,13 @@ describe('stables migration execution', async () => { context('not staked', async () => { it('should transfer tokens from stable to boosted', async () => { // Store balance before migration - bbausd2AmountOut = await testFlow(false); + bptOut = await testFlow(false); }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; try { - await testFlow( - false, - true, - BigNumber.from(bbausd2AmountOut).add(1).toString() - ); + await testFlow(false, true, BigNumber.from(bptOut).add(1).toString()); } catch (error) { errorMessage = (error as Error).message; } diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index 72a981e9c..8604802d1 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -24,8 +24,8 @@ export class StablesBuilder { userAddress: string, from: { id: string; address: string; gauge?: string }, to: { id: string; address: string; gauge?: string }, - amount: string, - expectedAmount = MaxInt256.toString(), + bptIn: string, + minBptOut = MaxInt256.toString(), staked: boolean, tokens: string[], authorisation?: string @@ -46,16 +46,16 @@ export class StablesBuilder { if (staked) { calls = [ ...calls, - this.buildWithdraw(userAddress, amount, from.gauge as string), - this.buildExit(from.id, relayer, relayer, amount, tokens), - this.buildSwap(expectedAmount, relayer, to.id, to.address, tokens), + this.buildWithdraw(userAddress, bptIn, from.gauge as string), + this.buildExit(from.id, relayer, relayer, bptIn, tokens), + this.buildSwap(minBptOut, relayer, to.id, to.address, tokens), this.buildDeposit(userAddress, to.gauge as string), ]; } else { calls = [ ...calls, - this.buildExit(from.id, userAddress, relayer, amount, tokens), - this.buildSwap(expectedAmount, userAddress, to.id, to.address, tokens), + this.buildExit(from.id, userAddress, relayer, bptIn, tokens), + this.buildSwap(minBptOut, userAddress, to.id, to.address, tokens), ]; } @@ -144,8 +144,8 @@ export class StablesBuilder { }); } - // For now assuming ref amounts will be safe - should we add more accurate? - const limits = [expectedBptReturn]; + // 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()); } diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index 8b7cfee02..2cb8be035 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -31,8 +31,8 @@ export class Migrations { to: request.to, data: request.data, decode: (output, staked) => { - let swapIndex = staked ? 3 : 2; - if (authorisation == undefined) swapIndex -= 1; + let swapIndex = staked ? 2 : 1; + if (authorisation) swapIndex += 1; const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); const swapDeltas = defaultAbiCoder.decode( ['int256[]'], @@ -77,8 +77,8 @@ export class Migrations { to: request.to, data: request.data, decode: (output, staked) => { - let swapIndex = staked ? 2 : 1; - if (authorisation == undefined) swapIndex -= 1; + let swapIndex = staked ? 1 : 0; + if (authorisation) swapIndex += 1; const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); const swapDeltas = defaultAbiCoder.decode( ['int256[]'], @@ -96,8 +96,8 @@ export class Migrations { userAddress: string, from: { id: string; address: string; gauge?: string }, to: { id: string; address: string; gauge?: string }, - amount: string, - limit = MaxInt256.toString(), + bptIn: string, + minBptOut = MaxInt256.toString(), staked: boolean, tokens: string[], authorisation?: string @@ -111,8 +111,8 @@ export class Migrations { userAddress, from, to, - amount, - limit, + bptIn, + minBptOut, staked, tokens, authorisation @@ -122,8 +122,8 @@ export class Migrations { to: request.to, data: request.data, decode: (output, staked) => { - let swapIndex = staked ? 3 : 2; - if (authorisation == undefined) swapIndex -= 1; + let swapIndex = staked ? 2 : 1; + if (authorisation) swapIndex += 1; const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); const swapDeltas = defaultAbiCoder.decode( ['int256[]'], From dab24893aa8cefe35f65b52244aa9e0863e9ad0c Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Fri, 29 Jul 2022 13:38:22 -0300 Subject: [PATCH 062/104] Fix issue where exit step was hardcoded to 3 tokens on stables migration flow --- balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index 8604802d1..18799d619 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -99,9 +99,11 @@ export class StablesBuilder { EXIT_RESULTS.push(outputReferences[i].key); } + const minAmountsOut = Array(tokens.length).fill('0'); + const callData = Relayer.constructExitCall({ assets: tokens, - minAmountsOut: ['0', '0', '0'], + minAmountsOut, userData, toInternalBalance: true, poolId, From 17497b5da12580e31fb2974fa2a3ab24da2463d8 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Fri, 29 Jul 2022 15:34:58 -0300 Subject: [PATCH 063/104] Remove unused buildApproveVault functions --- balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts | 4 ---- balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts | 4 ---- 2 files changed, 8 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 068eedefd..9461dbe68 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -275,10 +275,6 @@ export class BbaUsd1Builder { ); } - buildApproveVault(token: string): string { - return Relayer.encodeApproveVault(token, MaxUint256.toString()); - } - buildSetRelayerApproval(authorisation: string): string { return Relayer.encodeSetRelayerApproval( this.addresses.relayer, diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 5ddb4d1b5..d21b816fa 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -238,10 +238,6 @@ export class StaBal3Builder { ); } - buildApproveVault(token: string): string { - return Relayer.encodeApproveVault(token, MaxUint256.toString()); - } - buildSetRelayerApproval(authorisation: string): string { return Relayer.encodeSetRelayerApproval( this.addresses.relayer, From ab5db0db4d7d59ce0dadd14274868733cd61b435 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Fri, 29 Jul 2022 15:35:28 -0300 Subject: [PATCH 064/104] Add comments describing function inputs/outputs --- .../zaps/bbausd2-migrations/bbausd1.ts | 37 ++++++++++-- .../zaps/bbausd2-migrations/stabal3.ts | 39 +++++++++--- .../zaps/bbausd2-migrations/stables.ts | 60 +++++++++++++++---- balancer-js/src/modules/zaps/migrations.ts | 42 ++++++++++++- 4 files changed, 150 insertions(+), 28 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 9461dbe68..8ef6cc26e 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -17,6 +17,19 @@ export class BbaUsd1Builder { 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 {string} userAddress User address. + * @param {string} bbausd1Amount Amount of BPT tokens to migrate. + * @param {string} minBbausd2Out Minimum of expected BPT out ot the migration flow. + * @param {boolean} staked Indicates whether tokens are initially staked or not. + * @param {string[]} 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 {string} authorisation Encoded authorisation call. + * @returns Migration transaction request ready to send with signer.sendTransaction + */ calldata( userAddress: string, bbausd1Amount: string, @@ -70,10 +83,15 @@ export class BbaUsd1Builder { } /** - * Creates encoded batchSwap function to swap Linear BPTs to underlying stables. - * outputreferences should contain the amounts of each new Linear BPT. + * Creates encoded batchSwap function with following swaps: boosted -> linears -> stables -> linears -> boosted + * outputreferences should contain the amount of resulting BPT. * - * @returns BatchSwap call. + * @param {string} bbausd1Amount Amount of BPT tokens to migrate. + * @param {string} minBbausd2Out Minimum of expected BPT out ot the migration flow. + * @param {string} sender Sender address. + * @param {string} recipient Recipient address. + * @param {string[]} tokenBalances Token balances in EVM scale. + * @returns Encoded batchSwap call. Output references. */ buildSwap( bbausd1Amount: string, @@ -248,8 +266,10 @@ export class BbaUsd1Builder { } /** - * Is using gauge relayer to withdraw staked BPT from user to itself + * Uses relayer to withdraw staked BPT from gauge and send to relayer * + * @param {string} sender Sender address. + * @param {string} amount Amount of BPT to exit with. * @returns withdraw call */ buildWithdraw(sender: string, amount: string): string { @@ -262,8 +282,9 @@ export class BbaUsd1Builder { } /** - * Is using gauge relayer to deposit user's BPT to itself + * Uses relayer to deposit user's BPT to gauge and sends to recipient * + * @param {string} recipient Recipient address. * @returns deposit call */ buildDeposit(recipient: string): string { @@ -275,6 +296,12 @@ export class BbaUsd1Builder { ); } + /** + * Uses relayer to approve itself to act in behalf of the user + * + * @param {string} authorisation Encoded authorisation call. + * @returns relayer approval call + */ buildSetRelayerApproval(authorisation: string): string { return Relayer.encodeSetRelayerApproval( this.addresses.relayer, diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index d21b816fa..bf9a137d0 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -22,6 +22,18 @@ export class StaBal3Builder { 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 {string} userAddress User address. + * @param {string} staBal3Amount Amount of BPT tokens to migrate. + * @param {string} minBbausd2Out Minimum of expected BPT out ot the migration flow. + * @param {boolean} staked Indicates whether tokens are initially staked or not. + * @param {string} authorisation Encoded authorisation call. + * @returns Migration transaction request ready to send with signer.sendTransaction + */ calldata( userAddress: string, staBal3Amount: string, @@ -68,8 +80,9 @@ export class StaBal3Builder { * Exit staBal3 pool proportionally to underlying Linear BPTs. Exits to relayer. * Outputreferences are used to store exit amounts for next transaction. * - * @param migrator Migrator address. - * @param amount Amount of staBal3 BPT to exit with. + * @param {string} sender Sender address. + * @param {string} recipient Recipient address. + * @param {string} amount Amount of staBal3 BPT to exit with. * @returns Encoded exitPool call. Output references. */ buildExit(sender: string, recipient: string, amount: string): string { @@ -110,10 +123,12 @@ export class StaBal3Builder { } /** - * Creates encoded batchSwap function to swap Linear BPTs to underlying stables. - * outputreferences should contain the amounts of each new Linear BPT. + * Creates encoded batchSwap function with following swaps: stables -> linear pools -> boosted pool + * outputreferences should contain the amount of resulting BPT. * - * @returns BatchSwap call. + * @param {string} expectedBptReturn BPT amount expected out of the swap. + * @param {string} recipient Recipient address. + * @returns Encoded batchSwap call. Output references. */ buildSwap(expectedBptReturn: string, recipient: string): string { const assets = [ @@ -177,7 +192,6 @@ export class StaBal3Builder { ]; // 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. - console.log(`Min: `, BigNumber.from(expectedBptReturn).mul(-1).toString()); const limits = [ BigNumber.from(expectedBptReturn).mul(-1).toString(), MaxInt256.toString(), @@ -211,8 +225,10 @@ export class StaBal3Builder { } /** - * Is using gauge relayer to withdraw staked BPT from user to itself + * Uses relayer to withdraw staked BPT from gauge and send to relayer * + * @param {string} sender Sender address. + * @param {string} amount Amount of BPT to exit with. * @returns withdraw call */ buildWithdraw(sender: string, amount: string): string { @@ -225,8 +241,9 @@ export class StaBal3Builder { } /** - * Is using gauge relayer to deposit user's BPT to itself + * Uses relayer to deposit user's BPT to gauge and sends to recipient * + * @param {string} recipient Recipient address. * @returns deposit call */ buildDeposit(recipient: string): string { @@ -238,6 +255,12 @@ export class StaBal3Builder { ); } + /** + * Uses relayer to approve itself to act in behalf of the user + * + * @param {string} authorisation Encoded authorisation call. + * @returns relayer approval call + */ buildSetRelayerApproval(authorisation: string): string { return Relayer.encodeSetRelayerApproval( this.addresses.relayer, diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index 18799d619..397dbf644 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -20,12 +20,27 @@ export class StablesBuilder { 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 {string} userAddress User address. + * @param {{string, string, string}} from Pool info being migrated from + * @param {{string, string, string}} to Pool info being migrated to + * @param {string} bptIn Amount of BPT tokens to migrate. + * @param {string} minBptOut Minimum of expected BPT out ot the migration flow. + * @param {boolean} staked Indicates whether tokens are initially staked or not. + * @param {string[]} tokens 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 {string} 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 = MaxInt256.toString(), + minBptOut: string = MaxInt256.toString(), staked: boolean, tokens: string[], authorisation?: string @@ -70,12 +85,15 @@ export class StablesBuilder { } /** - * Encodes exitPool callData. - * Exit staBal3 pool proportionally to underlying Linear BPTs. Exits to relayer. + * 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 migrator Migrator address. - * @param amount Amount of staBal3 BPT to exit with. + * @param {string} poolId Pool id. + * @param {string} sender Sender address. + * @param {string} recipient Recipient address. + * @param {string} amount Amount of BPT to exit with. + * @param {string[]} tokens Token addresses to exit to. * @returns Encoded exitPool call. Output references. */ buildExit( @@ -118,9 +136,14 @@ export class StablesBuilder { } /** - * Creates encoded batchSwap function to swap Linear BPTs to underlying stables. - * outputreferences should contain the amounts of each new Linear BPT. + * Creates encoded batchSwap function to swap stables to new phantom stable pool BPT. + * outputreferences should contain the amount of resulting BPT. * + * @param {string} expectedBptReturn BPT amount expected out of the swap. + * @param {string} recipient Recipient address. + * @param {string} poolId Pool id + * @param {string} poolAddress Pool address + * @param {string[]} tokens Token addresses to swap from. * @returns BatchSwap call. */ buildSwap( @@ -175,13 +198,16 @@ export class StablesBuilder { } /** - * Is using gauge relayer to withdraw staked BPT from user to itself + * Uses relayer to withdraw staked BPT from gauge and send to relayer * + * @param {string} sender Sender address. + * @param {string} amount Amount of BPT to exit with. + * @param {string} gaugeAddress Gauge address. * @returns withdraw call */ - buildWithdraw(sender: string, amount: string, address: string): string { + buildWithdraw(sender: string, amount: string, gaugeAddress: string): string { return Relayer.encodeGaugeWithdraw( - address, + gaugeAddress, sender, this.addresses.relayer, amount @@ -189,19 +215,27 @@ export class StablesBuilder { } /** - * Is using gauge relayer to deposit user's BPT to itself + * Uses relayer to deposit user's BPT to gauge and sends to recipient * + * @param {string} recipient Recipient address. + * @param {string} gaugeAddress Gauge address. * @returns deposit call */ - buildDeposit(recipient: string, address: string): string { + buildDeposit(recipient: string, gaugeAddress: string): string { return Relayer.encodeGaugeDeposit( - address, + gaugeAddress, this.addresses.relayer, recipient, SWAP_RESULT.toString() ); } + /** + * Uses relayer to approve itself to act in behalf of the user + * + * @param {string} authorisation Encoded authorisation call. + * @returns relayer approval call + */ buildSetRelayerApproval(authorisation: string): string { return Relayer.encodeSetRelayerApproval( this.addresses.relayer, diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index 2cb8be035..b0a1e41bf 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -7,6 +7,18 @@ import { StablesBuilder } from './bbausd2-migrations/stables'; export class Migrations { constructor(private network: 1 | 5) {} + /** + * 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 {string} userAddress User address. + * @param {string} staBal3Amount Amount of BPT tokens to migrate. + * @param {string} minBbausd2Out Minimum of expected BPT out ot the migration flow. + * @param {boolean} staked Indicates whether tokens are initially staked or not. + * @param {string} authorisation Encoded authorisation call. + * @returns Migration transaction request ready to send with signer.sendTransaction + */ stabal3( userAddress: string, staBal3Amount: string, @@ -38,13 +50,25 @@ export class Migrations { ['int256[]'], multicallResult[0][swapIndex] ); - console.log(swapDeltas.toString()); // 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 {string} userAddress User address. + * @param {string} bbausd1Amount Amount of BPT tokens to migrate. + * @param {string} minBbausd2Out Minimum of expected BPT out ot the migration flow. + * @param {boolean} staked Indicates whether tokens are initially staked or not. + * @param {string[]} 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 {string} authorisation Encoded authorisation call. + * @returns Migration transaction request ready to send with signer.sendTransaction + */ bbaUsd( userAddress: string, bbausd1Amount: string, @@ -92,6 +116,21 @@ export class Migrations { }; } + /** + * 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 {string} userAddress User address. + * @param {{string, string, string}} from Pool info being migrated from + * @param {{string, string, string}} to Pool info being migrated to + * @param {string} bptIn Amount of BPT tokens to migrate. + * @param {string} minBptOut Minimum of expected BPT out ot the migration flow. + * @param {boolean} staked Indicates whether tokens are initially staked or not. + * @param {string[]} tokens 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 {string} authorisation Encoded authorisation call. + * @returns Migration transaction request ready to send with signer.sendTransaction + */ stables( userAddress: string, from: { id: string; address: string; gauge?: string }, @@ -129,7 +168,6 @@ export class Migrations { ['int256[]'], multicallResult[0][swapIndex] ); - console.log(swapDeltas.toString()); // bbausd2AmountOut return swapDeltas[0][0].abs().toString(); }, From 7f293c5397a4d5d40eb08e1dc0cabf34b60d3cc3 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 1 Aug 2022 09:40:09 -0300 Subject: [PATCH 065/104] Remove unused zaps integration test --- .../zaps/zaps.module.integration.spec.ts | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 balancer-js/src/modules/zaps/zaps.module.integration.spec.ts diff --git a/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts b/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts deleted file mode 100644 index 000ade0e8..000000000 --- a/balancer-js/src/modules/zaps/zaps.module.integration.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import dotenv from 'dotenv'; -import { expect } from 'chai'; -import { Network } from '@/.'; -import hardhat from 'hardhat'; - -import { parseFixed } from '@ethersproject/bignumber'; - -import { forkSetup, getBalances } from '@/test/lib/utils'; - -/* - * Testing on GOERLI - * - Update hardhat.config.js with chainId = 5 - * - Update ALCHEMY_URL on .env with a goerli api key - * - Run goerli node on terminal: npx hardhat node --fork [ALCHEMY_URL] - * - Change `network` to Network.GOERLI - * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli - */ - -dotenv.config(); - -const { ALCHEMY_URL: jsonRpcUrl } = process.env; -const { ethers } = hardhat; - -const network = Network.GOERLI; -const rpcUrl = 'http://127.0.0.1:8545'; -const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); -const signer = provider.getSigner(); - -const gaugeSlots = [1]; // Info fetched using npm package slot20 - -// Goerli -const gaugeAddresses = ['0xf0f572ad66baacDd07d8c7ea3e0E5EFA56a76081']; // Balancer B-50WBTC-50WETH Gauge Deposit -// Mainnet -// const gaugeAddresses = ['0x68d019f64a7aa97e2d4e7363aee42251d08124fb']; // Balancer bb-a-USD Gauge Deposit - -const initialBalance = '1000'; -let signerAddress: string; - -// Test Scenarios - -describe('zaps execution', async () => { - before(async function () { - this.timeout(20000); - - const isVyperMapping = true; // required for gauge tokens - await forkSetup( - signer, - gaugeAddresses, - gaugeSlots, - [parseFixed(initialBalance, 18).toString()], - jsonRpcUrl as string, - isVyperMapping - ); - signerAddress = await signer.getAddress(); - }); - - it('should update balances', async () => { - const balances = await getBalances(gaugeAddresses, signer, signerAddress); - for (let i = 0; i < balances.length; i++) { - expect(balances[i].eq(parseFixed(initialBalance, 18))).to.be.true; - } - }); -}).timeout(20000); From 46d219309d5ebdb3b25bcf1b4acde92dee80e55d Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 1 Aug 2022 09:40:27 -0300 Subject: [PATCH 066/104] Fix build issues by replacing BigNumber import --- balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index 397dbf644..1f95b9d92 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -4,10 +4,10 @@ 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 { MaxUint256, MaxInt256 } from '@ethersproject/constants'; // TODO - Ask Nico to update Typechain? import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; -import { BigNumber } from 'ethers'; const balancerRelayerInterface = new Interface(balancerRelayerAbi); const SWAP_RESULT = Relayer.toChainedReference('0'); From 08090f0b1981985b2744e80fb9db6ab8d48f016d Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 1 Aug 2022 09:55:17 -0300 Subject: [PATCH 067/104] Make minBptOut required instead of optional parameter --- balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts | 2 +- balancer-js/src/modules/zaps/migrations.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index 1f95b9d92..a7eddf016 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -40,7 +40,7 @@ export class StablesBuilder { from: { id: string; address: string; gauge?: string }, to: { id: string; address: string; gauge?: string }, bptIn: string, - minBptOut: string = MaxInt256.toString(), + minBptOut: string, staked: boolean, tokens: string[], authorisation?: string diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index b0a1e41bf..9004330df 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -136,7 +136,7 @@ export class Migrations { from: { id: string; address: string; gauge?: string }, to: { id: string; address: string; gauge?: string }, bptIn: string, - minBptOut = MaxInt256.toString(), + minBptOut: string, staked: boolean, tokens: string[], authorisation?: string From bfdc33d3b54abc04e025bc12d26fa4d18717466b Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 1 Aug 2022 09:57:06 -0300 Subject: [PATCH 068/104] Apply code review suggestions --- .../zaps/bbausd2-migrations/stabal3.ts | 9 +++--- .../zaps/bbausd2-migrations/stables.ts | 32 +++++++++++-------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index bf9a137d0..0ae528010 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -53,14 +53,14 @@ export class StaBal3Builder { calls = [ ...calls, this.buildWithdraw(userAddress, staBal3Amount), - this.buildExit(relayer, relayer, staBal3Amount), + this.buildExit(relayer, staBal3Amount), this.buildSwap(minBbausd2Out, relayer), this.buildDeposit(userAddress), ]; } else { calls = [ ...calls, - this.buildExit(userAddress, relayer, staBal3Amount), + this.buildExit(userAddress, staBal3Amount), this.buildSwap(minBbausd2Out, userAddress), ]; } @@ -81,11 +81,10 @@ export class StaBal3Builder { * Outputreferences are used to store exit amounts for next transaction. * * @param {string} sender Sender address. - * @param {string} recipient Recipient address. * @param {string} amount Amount of staBal3 BPT to exit with. * @returns Encoded exitPool call. Output references. */ - buildExit(sender: string, recipient: string, amount: string): string { + buildExit(sender: string, amount: string): string { // Goerli and Mainnet has different assets ordering const { assetOrder } = this.addresses.staBal3; const assets = assetOrder.map( @@ -114,7 +113,7 @@ export class StaBal3Builder { poolId: this.addresses.staBal3.id, poolKind: 0, // This will always be 0 to match supported Relayer types sender, - recipient, + recipient: this.addresses.relayer, outputReferences, exitPoolRequest: {} as ExitPoolRequest, }); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index a7eddf016..f9ee2272d 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -31,7 +31,7 @@ export class StablesBuilder { * @param {string} bptIn Amount of BPT tokens to migrate. * @param {string} minBptOut Minimum of expected BPT out ot the migration flow. * @param {boolean} staked Indicates whether tokens are initially staked or not. - * @param {string[]} tokens 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 {string[]} 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 {string} authorisation Encoded authorisation call. * @returns Migration transaction request ready to send with signer.sendTransaction */ @@ -42,7 +42,7 @@ export class StablesBuilder { bptIn: string, minBptOut: string, staked: boolean, - tokens: string[], + underlyingTokens: string[], authorisation?: string ): { to: string; @@ -62,15 +62,21 @@ export class StablesBuilder { calls = [ ...calls, this.buildWithdraw(userAddress, bptIn, from.gauge as string), - this.buildExit(from.id, relayer, relayer, bptIn, tokens), - this.buildSwap(minBptOut, relayer, to.id, to.address, tokens), + 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, relayer, bptIn, tokens), - this.buildSwap(minBptOut, userAddress, to.id, to.address, tokens), + this.buildExit(from.id, userAddress, bptIn, underlyingTokens), + this.buildSwap( + minBptOut, + userAddress, + to.id, + to.address, + underlyingTokens + ), ]; } @@ -91,17 +97,15 @@ export class StablesBuilder { * * @param {string} poolId Pool id. * @param {string} sender Sender address. - * @param {string} recipient Recipient address. * @param {string} amount Amount of BPT to exit with. - * @param {string[]} tokens Token addresses to exit to. + * @param {string[]} underlyingTokens Token addresses to exit to. * @returns Encoded exitPool call. Output references. */ buildExit( poolId: string, sender: string, - recipient: string, amount: string, - tokens: string[] + underlyingTokens: string[] ): string { // Assume gaugeWithdraw returns same amount value const userData = StablePoolEncoder.exitExactBPTInForTokensOut(amount); @@ -109,7 +113,7 @@ export class StablesBuilder { // Ask to store exit outputs for batchSwap of exit is used as input to swaps // TODO: check how does tokens order matter between exits and swaps const outputReferences = []; - for (let i = 0; i < tokens.length; i++) { + 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 @@ -117,17 +121,17 @@ export class StablesBuilder { EXIT_RESULTS.push(outputReferences[i].key); } - const minAmountsOut = Array(tokens.length).fill('0'); + const minAmountsOut = Array(underlyingTokens.length).fill('0'); const callData = Relayer.constructExitCall({ - assets: tokens, + assets: underlyingTokens, minAmountsOut, userData, toInternalBalance: true, poolId, poolKind: 0, // This will always be 0 to match supported Relayer types sender, - recipient, + recipient: this.addresses.relayer, outputReferences, exitPoolRequest: {} as ExitPoolRequest, }); From 02aca2bfc571eadd98366cfc5fce6dc83372402e Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 1 Aug 2022 10:02:15 -0300 Subject: [PATCH 069/104] Fix lint issue --- balancer-js/src/modules/zaps/migrations.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index 9004330df..07c5c31b6 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -1,5 +1,4 @@ import { defaultAbiCoder } from '@ethersproject/abi'; -import { MaxInt256 } from '@ethersproject/constants'; import { StaBal3Builder } from './bbausd2-migrations/stabal3'; import { BbaUsd1Builder } from './bbausd2-migrations/bbausd1'; import { StablesBuilder } from './bbausd2-migrations/stables'; From 61245f86e7fa8e3a8530b49f7084622e2b6d48ac Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 4 Aug 2022 10:03:08 -0300 Subject: [PATCH 070/104] Remove temp var --- .../zaps/bbausd2-migrations/bbausd1.integration.spec.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 index 542fddde0..63e71ab49 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -160,9 +160,10 @@ describe('bbausd migration execution', async () => { config, new SubgraphPoolRepository(subgraph.client) ); - const _pool = await pools.findBy('address', poolAddress); - if (!_pool) throw new BalancerError(BalancerErrorCode.POOL_DOESNT_EXIST); - pool = _pool; + await pools.findBy('address', poolAddress).then((res) => { + if (!res) throw new BalancerError(BalancerErrorCode.POOL_DOESNT_EXIST); + pool = res; + }); }); async function testFlow( From f9cedec66272cf55e69f682b3476ad8da550bd0c Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 4 Aug 2022 10:03:37 -0300 Subject: [PATCH 071/104] Remove outdated comment --- balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index f9ee2272d..66cf0df22 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -110,8 +110,7 @@ export class StablesBuilder { // Assume gaugeWithdraw returns same amount value const userData = StablePoolEncoder.exitExactBPTInForTokensOut(amount); - // Ask to store exit outputs for batchSwap of exit is used as input to swaps - // TODO: check how does tokens order matter between exits and swaps + // Store exit outputs to be used as swaps inputs const outputReferences = []; for (let i = 0; i < underlyingTokens.length; i++) { outputReferences[i] = { From 943d72989c512a0082a949e1c53d6a4cd54ae867 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 4 Aug 2022 10:04:03 -0300 Subject: [PATCH 072/104] Refactor ternary operator into if clauses for clarity --- .../src/modules/zaps/bbausd2-migrations/bbausd1.ts | 8 +++++--- .../src/modules/zaps/bbausd2-migrations/stabal3.ts | 8 +++++--- .../src/modules/zaps/bbausd2-migrations/stables.ts | 12 +++++++----- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 8ef6cc26e..0572a936d 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -42,9 +42,11 @@ export class BbaUsd1Builder { data: string; } { const relayer = this.addresses.relayer; - let calls: string[] = authorisation - ? [this.buildSetRelayerApproval(authorisation)] - : []; + let calls: string[] = []; + + if (authorisation) { + calls = [this.buildSetRelayerApproval(authorisation)]; + } if (staked) { calls = [ diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 0ae528010..0dc3a2663 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -45,9 +45,11 @@ export class StaBal3Builder { data: string; } { const relayer = this.addresses.relayer; - let calls: string[] = authorisation - ? [this.buildSetRelayerApproval(authorisation)] - : []; + let calls: string[] = []; + + if (authorisation) { + calls = [this.buildSetRelayerApproval(authorisation)]; + } if (staked) { calls = [ diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index 66cf0df22..cc4ad0431 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -48,16 +48,18 @@ export class StablesBuilder { to: string; data: string; } { - const relayer = this.addresses.relayer; - let calls: string[] = authorisation - ? [this.buildSetRelayerApproval(authorisation)] - : []; - 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, From bc2dc5012fce9b2c51a0cd0ba5d4ffa52c7dd6a2 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 4 Aug 2022 10:30:42 -0300 Subject: [PATCH 073/104] Refactor tests in order to facilitate extraction of testFlow as reusable function --- .../bbausd1.integration.spec.ts | 38 ++++++++++--------- .../stabal3.integration.spec.ts | 38 +++++++++---------- .../stables.integration.spec.ts | 4 +- 3 files changed, 41 insertions(+), 39 deletions(-) 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 index 63e71ab49..d56af1c9b 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -43,12 +43,20 @@ const network = Network.GOERLI; const rpcUrl = 'http://127.0.0.1:8545'; 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 holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; -const poolAddress = addresses.bbausd1.address; -const gaugeAddress = addresses.bbausd1.gauge; const relayer = addresses.relayer; const getErc20Balance = (token: string, holder: string): Promise => @@ -119,14 +127,14 @@ const stake = async ( ): Promise => { await ( await contracts - .ERC20(poolAddress, provider) + .ERC20(fromPool.address, provider) .connect(signer) - .approve(gaugeAddress, MaxUint256) + .approve(fromPool.gauge, MaxUint256) ).wait(); await ( await signer.sendTransaction({ - to: gaugeAddress, + to: fromPool.gauge, data: liquidityGauge.encodeFunctionData('deposit', [balance]), }) ).wait(); @@ -149,7 +157,7 @@ describe('bbausd migration execution', async () => { 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(poolAddress, holderAddress, signerAddress); + balance = await move(fromPool.address, holderAddress, signerAddress); const config = { network, @@ -160,7 +168,7 @@ describe('bbausd migration execution', async () => { config, new SubgraphPoolRepository(subgraph.client) ); - await pools.findBy('address', poolAddress).then((res) => { + await pools.findBy('address', fromPool.address).then((res) => { if (!res) throw new BalancerError(BalancerErrorCode.POOL_DOESNT_EXIST); pool = res; }); @@ -168,15 +176,11 @@ describe('bbausd migration execution', async () => { async function testFlow( staked: boolean, - authorized = true, + authorised = true, minBbausd2Out: undefined | string = undefined ): Promise { - const addressIn = staked - ? addresses.bbausd1.gauge - : addresses.bbausd1.address; - const addressOut = staked - ? addresses.bbausd2.gauge - : addresses.bbausd2.address; + const addressIn = staked ? fromPool.gauge : fromPool.address; + const addressOut = staked ? toPool.gauge : toPool.address; // Store balance before migration const before = { from: await getErc20Balance(addressIn, signerAddress), @@ -214,7 +218,7 @@ describe('bbausd migration execution', async () => { pool.tokens .filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed .map((token) => parseFixed(token.balance, token.decimals).toString()), - authorized ? authorisation : undefined + authorised ? authorisation : undefined ); const response = await signer.sendTransaction({ @@ -287,10 +291,10 @@ describe('bbausd migration execution', async () => { }).timeout(20000); }); - context('authorization', async () => { + 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 authorized', async () => { + it('should transfer tokens from stable to boosted - pre authorised', async () => { const approval = contracts.vault.interface.encodeFunctionData( 'setRelayerApproval', [signerAddress, relayer, true] 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 index 89c1b315e..905952562 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -34,11 +34,20 @@ const network = Network.GOERLI; 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 holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; -const poolAddress = addresses.staBal3.address; const relayer = addresses.relayer; const getErc20Balance = (token: string, holder: string): Promise => @@ -109,21 +118,14 @@ const stake = async ( ): Promise => { await ( await contracts - .ERC20(poolAddress, provider) - .connect(signer) - .approve(addresses.staBal3.gauge, MaxUint256) - ).wait(); - - await ( - await contracts - .ERC20(addresses.bbausd1.address, provider) + .ERC20(fromPool.address, provider) .connect(signer) - .approve(addresses.bbausd1.gauge, MaxUint256) + .approve(fromPool.gauge, MaxUint256) ).wait(); await ( await signer.sendTransaction({ - to: addresses.staBal3.gauge, + to: fromPool.gauge, data: liquidityGauge.encodeFunctionData('deposit', [balance]), }) ).wait(); @@ -145,7 +147,7 @@ describe('stabal3 migration execution', async () => { // 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(poolAddress, holderAddress, signerAddress); + balance = await move(fromPool.address, holderAddress, signerAddress); }); async function testFlow( @@ -153,12 +155,8 @@ describe('stabal3 migration execution', async () => { authorised = true, minBbausd2Out: undefined | string = undefined ): Promise { - const addressIn = staked - ? addresses.staBal3.gauge - : addresses.staBal3.address; - const addressOut = staked - ? addresses.bbausd2.gauge - : addresses.bbausd2.address; + const addressIn = staked ? fromPool.gauge : fromPool.address; + const addressOut = staked ? toPool.gauge : toPool.address; // Store balance before migration const before = { from: await getErc20Balance(addressIn, signerAddress), @@ -263,10 +261,10 @@ describe('stabal3 migration execution', async () => { }).timeout(20000); }); - context('authorization', async () => { + 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 authorized', async () => { + it('should transfer tokens from stable to boosted - pre authorised', async () => { const approval = contracts.vault.interface.encodeFunctionData( 'setRelayerApproval', [signerAddress, relayer, true] 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 index 80e9ece50..7947a59bd 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -265,10 +265,10 @@ describe('stables migration execution', async () => { }).timeout(20000); }); - context('authorization', async () => { + 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 authorized', async () => { + it('should transfer tokens from stable to boosted - pre authorised', async () => { const approval = contracts.vault.interface.encodeFunctionData( 'setRelayerApproval', [signerAddress, relayer, true] From c1c693cf1dfd4bb267d5050b33720c94b87c840d Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 4 Aug 2022 11:25:47 -0300 Subject: [PATCH 074/104] Set migration swaps deadline to 1h --- balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts | 3 +-- balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts | 4 ++-- balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 0572a936d..d1051f663 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -2,7 +2,6 @@ import { ADDRESSES } from './addresses'; import { Relayer } from '@/modules/relayer/relayer.module'; import { BatchSwapStep, FundManagement, SwapType } from '@/modules/swaps/types'; import { Interface } from '@ethersproject/abi'; -import { MaxUint256, Zero } from '@ethersproject/constants'; // TODO - Ask Nico to update Typechain? import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; import { BigNumber } from '@ethersproject/bignumber'; @@ -259,7 +258,7 @@ export class BbaUsd1Builder { assets, funds, limits, - deadline: MaxUint256, + deadline: BigNumber.from(Math.ceil(Date.now() / 1000) + 3600), // 1 hour from now value: '0', outputReferences, }); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 0dc3a2663..3c8418f20 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -5,7 +5,7 @@ import { ExitPoolRequest } from '@/types'; import { BatchSwapStep, FundManagement, SwapType } from '@/modules/swaps/types'; import { Interface } from '@ethersproject/abi'; import { BigNumber } from '@ethersproject/bignumber'; -import { MaxUint256, MaxInt256 } from '@ethersproject/constants'; +import { MaxInt256 } from '@ethersproject/constants'; // TODO - Ask Nico to update Typechain? import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; const balancerRelayerInterface = new Interface(balancerRelayerAbi); @@ -217,7 +217,7 @@ export class StaBal3Builder { assets, funds, limits, - deadline: MaxUint256, + deadline: BigNumber.from(Math.ceil(Date.now() / 1000) + 3600), // 1 hour from now value: '0', outputReferences, }); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index cc4ad0431..6a130d5ce 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -5,7 +5,7 @@ import { ExitPoolRequest } from '@/types'; import { BatchSwapStep, FundManagement, SwapType } from '@/modules/swaps/types'; import { Interface } from '@ethersproject/abi'; import { BigNumber } from '@ethersproject/bignumber'; -import { MaxUint256, MaxInt256 } from '@ethersproject/constants'; +import { MaxInt256 } from '@ethersproject/constants'; // TODO - Ask Nico to update Typechain? import balancerRelayerAbi from '@/lib/abi/BalancerRelayer.json'; const balancerRelayerInterface = new Interface(balancerRelayerAbi); @@ -194,7 +194,7 @@ export class StablesBuilder { assets, funds, limits, - deadline: MaxUint256, + deadline: BigNumber.from(Math.ceil(Date.now() / 1000) + 3600), // 1 hour from now value: '0', outputReferences, }); From 17f5f3721a21b289c1f54ff27f5125392947839c Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 4 Aug 2022 13:07:27 -0300 Subject: [PATCH 075/104] Rename tokens to underlyingTokens --- balancer-js/src/modules/zaps/migrations.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index 07c5c31b6..7b77043ca 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -126,7 +126,7 @@ export class Migrations { * @param {string} bptIn Amount of BPT tokens to migrate. * @param {string} minBptOut Minimum of expected BPT out ot the migration flow. * @param {boolean} staked Indicates whether tokens are initially staked or not. - * @param {string[]} tokens 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 {string[]} 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 {string} authorisation Encoded authorisation call. * @returns Migration transaction request ready to send with signer.sendTransaction */ @@ -137,7 +137,7 @@ export class Migrations { bptIn: string, minBptOut: string, staked: boolean, - tokens: string[], + underlyingTokens: string[], authorisation?: string ): { to: string; @@ -152,7 +152,7 @@ export class Migrations { bptIn, minBptOut, staked, - tokens, + underlyingTokens, authorisation ); From c35a08c567611155fe1312cdeeca4eb23bc2f5bd Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Thu, 4 Aug 2022 17:12:25 +0100 Subject: [PATCH 076/104] Add missing import. --- balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index d1051f663..a57c40d05 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -5,10 +5,10 @@ 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'; const balancerRelayerInterface = new Interface(balancerRelayerAbi); const SWAP_RESULT_BBAUSD = Relayer.toChainedReference('24'); - export class BbaUsd1Builder { private addresses; From e75d124265ee69686f8a75bb744eee96a8ecd177 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Fri, 5 Aug 2022 15:38:37 -0300 Subject: [PATCH 077/104] Extract reusable methods to test/lib/utils --- .../bbausd1.integration.spec.ts | 68 ++++--------------- .../stabal3.integration.spec.ts | 68 ++++--------------- .../stables.integration.spec.ts | 68 ++++--------------- balancer-js/src/test/lib/utils.ts | 54 ++++++++++++++- 4 files changed, 89 insertions(+), 169 deletions(-) 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 index d56af1c9b..8175471fd 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -13,16 +13,11 @@ import { import { BigNumber, parseFixed } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; import { ADDRESSES } from './addresses'; -import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; -import { parseEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256 } from '@ethersproject/constants'; import { Migrations } from '../migrations'; - -import { Interface } from '@ethersproject/abi'; import { PoolsProvider } from '@/modules/pools/provider'; -const liquidityGaugeAbi = ['function deposit(uint value) payable']; -const liquidityGauge = new Interface(liquidityGaugeAbi); +import { getErc20Balance, move, stake } from '@/test/lib/utils'; /* * Testing on GOERLI @@ -59,19 +54,6 @@ const migrations = new Migrations(network); const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; const relayer = addresses.relayer; -const getErc20Balance = (token: string, holder: string): Promise => - contracts.ERC20(token, provider).balanceOf(holder); - -// https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#impersonating-accounts -// WARNING: don't use hardhat SignerWithAddress to sendTransactions!! -// It's not working and we didn't have time to figure out why. -// Use JsonRpcSigner instead -const impersonateAccount = async (account: string) => { - await provider.send('hardhat_impersonateAccount', [account]); - await setBalance(account, parseEther('10000')); - return provider.getSigner(account); -}; - const signRelayerApproval = async ( relayerAddress: string, signerAddress: string, @@ -109,37 +91,6 @@ const reset = async () => }, ]); -const move = async ( - token: string, - from: string, - to: string -): Promise => { - const holder = await impersonateAccount(from); - const balance = await getErc20Balance(token, from); - await contracts.ERC20(token, provider).connect(holder).transfer(to, balance); - - return balance; -}; - -const stake = async ( - signer: JsonRpcSigner, - balance: BigNumber -): Promise => { - await ( - await contracts - .ERC20(fromPool.address, provider) - .connect(signer) - .approve(fromPool.gauge, MaxUint256) - ).wait(); - - await ( - await signer.sendTransaction({ - to: fromPool.gauge, - data: liquidityGauge.encodeFunctionData('deposit', [balance]), - }) - ).wait(); -}; - describe('bbausd migration execution', async () => { let signer: JsonRpcSigner; let signerAddress: string; @@ -157,7 +108,12 @@ describe('bbausd migration execution', async () => { 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); + balance = await move( + fromPool.address, + holderAddress, + signerAddress, + provider + ); const config = { network, @@ -183,8 +139,8 @@ describe('bbausd migration execution', async () => { const addressOut = staked ? toPool.gauge : toPool.address; // Store balance before migration const before = { - from: await getErc20Balance(addressIn, signerAddress), - to: await getErc20Balance(addressOut, signerAddress), + from: await getErc20Balance(addressIn, provider, signerAddress), + to: await getErc20Balance(addressOut, provider, signerAddress), }; const amount = before.from; @@ -231,8 +187,8 @@ describe('bbausd migration execution', async () => { console.log('Gas used', receipt.gasUsed.toString()); const after = { - from: await getErc20Balance(addressIn, signerAddress), - to: await getErc20Balance(addressOut, signerAddress), + from: await getErc20Balance(addressIn, provider, signerAddress), + to: await getErc20Balance(addressOut, provider, signerAddress), }; console.log(expectedBpts); @@ -249,7 +205,7 @@ describe('bbausd migration execution', async () => { beforeEach(async function () { this.timeout(20000); // Stake them - await stake(signer, balance); + await stake(signer, fromPool.address, fromPool.gauge, balance); }); it('should transfer tokens from stable to boosted - using exact bbausd2AmountOut from static call', async () => { 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 index 905952562..da42c7c8c 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -5,15 +5,10 @@ import { Network, RelayerAuthorization } from '@/.'; import { BigNumber } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; import { ADDRESSES } from './addresses'; -import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; -import { parseEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256 } from '@ethersproject/constants'; import { Migrations } from '../migrations'; - -import { Interface } from '@ethersproject/abi'; -const liquidityGaugeAbi = ['function deposit(uint value) payable']; -const liquidityGauge = new Interface(liquidityGaugeAbi); +import { getErc20Balance, move, stake } from '@/test/lib/utils'; /* * Testing on GOERLI @@ -50,19 +45,6 @@ const migrations = new Migrations(network); const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; const relayer = addresses.relayer; -const getErc20Balance = (token: string, holder: string): Promise => - contracts.ERC20(token, provider).balanceOf(holder); - -// https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#impersonating-accounts -// WARNING: don't use hardhat SignerWithAddress to sendTransactions!! -// It's not working and we didn't have time to figure out why. -// Use JsonRpcSigner instead -const impersonateAccount = async (account: string) => { - await provider.send('hardhat_impersonateAccount', [account]); - await setBalance(account, parseEther('10000')); - return provider.getSigner(account); -}; - const signRelayerApproval = async ( relayerAddress: string, signerAddress: string, @@ -100,37 +82,6 @@ const reset = () => }, ]); -const move = async ( - token: string, - from: string, - to: string -): Promise => { - const holder = await impersonateAccount(from); - const balance = await getErc20Balance(token, from); - await contracts.ERC20(token, provider).connect(holder).transfer(to, balance); - - return balance; -}; - -const stake = async ( - signer: JsonRpcSigner, - balance: BigNumber -): Promise => { - await ( - await contracts - .ERC20(fromPool.address, provider) - .connect(signer) - .approve(fromPool.gauge, MaxUint256) - ).wait(); - - await ( - await signer.sendTransaction({ - to: fromPool.gauge, - data: liquidityGauge.encodeFunctionData('deposit', [balance]), - }) - ).wait(); -}; - describe('stabal3 migration execution', async () => { let signer: JsonRpcSigner; let signerAddress: string; @@ -147,7 +98,12 @@ describe('stabal3 migration execution', async () => { // 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); + balance = await move( + fromPool.address, + holderAddress, + signerAddress, + provider + ); }); async function testFlow( @@ -159,8 +115,8 @@ describe('stabal3 migration execution', async () => { const addressOut = staked ? toPool.gauge : toPool.address; // Store balance before migration const before = { - from: await getErc20Balance(addressIn, signerAddress), - to: await getErc20Balance(addressOut, signerAddress), + from: await getErc20Balance(addressIn, provider, signerAddress), + to: await getErc20Balance(addressOut, provider, signerAddress), }; const amount = before.from; @@ -200,8 +156,8 @@ describe('stabal3 migration execution', async () => { console.log('Gas used', receipt.gasUsed.toString()); const after = { - from: await getErc20Balance(addressIn, signerAddress), - to: await getErc20Balance(addressOut, signerAddress), + from: await getErc20Balance(addressIn, provider, signerAddress), + to: await getErc20Balance(addressOut, provider, signerAddress), }; console.log(bbausd2AmountOut); @@ -219,7 +175,7 @@ describe('stabal3 migration execution', async () => { this.timeout(20000); // Stake them - await stake(signer, balance); + await stake(signer, fromPool.address, fromPool.gauge, balance); }); it('should transfer tokens from stable to boosted', async () => { 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 index 7947a59bd..34178d4d5 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -5,15 +5,10 @@ import { Network, RelayerAuthorization } from '@/.'; import { BigNumber } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; import { ADDRESSES } from './addresses'; -import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; -import { parseEther } from '@ethersproject/units'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256 } from '@ethersproject/constants'; import { Migrations } from '../migrations'; - -import { Interface } from '@ethersproject/abi'; -const liquidityGaugeAbi = ['function deposit(uint value) payable']; -const liquidityGauge = new Interface(liquidityGaugeAbi); +import { getErc20Balance, move, stake } from '@/test/lib/utils'; /* * Testing on GOERLI @@ -51,19 +46,6 @@ const toPool = { const tokens = [addresses.USDT, addresses.DAI, addresses.USDC]; // this order only works for testing with Goerli - change order to test on Mainnet const relayer = addresses.relayer; -const getErc20Balance = (token: string, holder: string): Promise => - contracts.ERC20(token, provider).balanceOf(holder); - -// https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#impersonating-accounts -// WARNING: don't use hardhat SignerWithAddress to sendTransactions!! -// It's not working and we didn't have time to figure out why. -// Use JsonRpcSigner instead -const impersonateAccount = async (account: string) => { - await provider.send('hardhat_impersonateAccount', [account]); - await setBalance(account, parseEther('10000')); - return provider.getSigner(account); -}; - const signRelayerApproval = async ( relayerAddress: string, signerAddress: string, @@ -101,37 +83,6 @@ const reset = () => }, ]); -const move = async ( - token: string, - from: string, - to: string -): Promise => { - const holder = await impersonateAccount(from); - const balance = await getErc20Balance(token, from); - await contracts.ERC20(token, provider).connect(holder).transfer(to, balance); - - return balance; -}; - -const stake = async ( - signer: JsonRpcSigner, - balance: BigNumber -): Promise => { - await ( - await contracts - .ERC20(fromPool.address, provider) - .connect(signer) - .approve(fromPool.gauge, MaxUint256) - ).wait(); - - await ( - await signer.sendTransaction({ - to: fromPool.gauge, - data: liquidityGauge.encodeFunctionData('deposit', [balance]), - }) - ).wait(); -}; - describe('stables migration execution', async () => { let signer: JsonRpcSigner; let signerAddress: string; @@ -148,7 +99,12 @@ describe('stables migration execution', async () => { // 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); + balance = await move( + fromPool.address, + holderAddress, + signerAddress, + provider + ); }); const testFlow = async ( @@ -160,8 +116,8 @@ describe('stables migration execution', async () => { const addressOut = staked ? toPool.gauge : toPool.address; // Store balance before migration const before = { - from: await getErc20Balance(addressIn, signerAddress), - to: await getErc20Balance(addressOut, signerAddress), + from: await getErc20Balance(addressIn, provider, signerAddress), + to: await getErc20Balance(addressOut, provider, signerAddress), }; let query = migrations.stables( @@ -206,8 +162,8 @@ describe('stables migration execution', async () => { console.log('Gas used', receipt.gasUsed.toString()); const after = { - from: await getErc20Balance(addressIn, signerAddress), - to: await getErc20Balance(addressOut, signerAddress), + from: await getErc20Balance(addressIn, provider, signerAddress), + to: await getErc20Balance(addressOut, provider, signerAddress), }; const diffs = { @@ -230,7 +186,7 @@ describe('stables migration execution', async () => { this.timeout(20000); // Stake them - await stake(signer, balance); + await stake(signer, fromPool.address, fromPool.gauge, balance); }); it('should transfer tokens from stable to boosted', async () => { diff --git a/balancer-js/src/test/lib/utils.ts b/balancer-js/src/test/lib/utils.ts index ddf5fb195..7d97921a3 100644 --- a/balancer-js/src/test/lib/utils.ts +++ b/balancer-js/src/test/lib/utils.ts @@ -1,12 +1,18 @@ import { JsonRpcProvider, JsonRpcSigner } from '@ethersproject/providers'; import { BigNumber } from '@ethersproject/bignumber'; -import { AddressZero } from '@ethersproject/constants'; +import { AddressZero, MaxUint256 } from '@ethersproject/constants'; import { balancerVault } from '@/lib/constants/config'; import { hexlify, zeroPad } from '@ethersproject/bytes'; import { keccak256 } from '@ethersproject/solidity'; +import { parseEther } from '@ethersproject/units'; import { ERC20 } from '@/modules/contracts/ERC20'; import { PoolsProvider } from '@/modules/pools/provider'; import { PoolModel, BalancerError, BalancerErrorCode } from '@/.'; +import { setBalance } from '@nomicfoundation/hardhat-network-helpers'; + +import { Interface } from '@ethersproject/abi'; +const liquidityGaugeAbi = ['function deposit(uint value) payable']; +const liquidityGauge = new Interface(liquidityGaugeAbi); export const forkSetup = async ( signer: JsonRpcSigner, @@ -136,3 +142,49 @@ export const getBalances = async ( } return Promise.all(balances); }; + +export const move = async ( + token: string, + from: string, + to: string, + provider: JsonRpcProvider +): Promise => { + const holder = await impersonateAccount(from, provider); + const balance = await getErc20Balance(token, provider, from); + await ERC20(token, provider).connect(holder).transfer(to, balance); + + return balance; +}; + +// https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#impersonating-accounts +// WARNING: don't use hardhat SignerWithAddress to sendTransactions!! +// It's not working and we didn't have time to figure out why. +// Use JsonRpcSigner instead +export const impersonateAccount = async ( + account: string, + provider: JsonRpcProvider +): Promise => { + await provider.send('hardhat_impersonateAccount', [account]); + await setBalance(account, parseEther('10000')); + return provider.getSigner(account); +}; + +export const stake = async ( + signer: JsonRpcSigner, + pool: string, + gauge: string, + balance: BigNumber +): Promise => { + await ( + await ERC20(pool, signer.provider) + .connect(signer) + .approve(gauge, MaxUint256) + ).wait(); + + await ( + await signer.sendTransaction({ + to: gauge, + data: liquidityGauge.encodeFunctionData('deposit', [balance]), + }) + ).wait(); +}; From 8963f719b6c511cded7af6b5c1b319b861a2efee Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 8 Aug 2022 15:44:29 -0300 Subject: [PATCH 078/104] Remove unnecessary types from param description as that's already handled by typescrypt --- .../zaps/bbausd2-migrations/bbausd1.ts | 30 ++++++------ .../zaps/bbausd2-migrations/stabal3.ts | 28 +++++------ .../zaps/bbausd2-migrations/stables.ts | 46 +++++++++---------- balancer-js/src/modules/zaps/migrations.ts | 38 +++++++-------- 4 files changed, 71 insertions(+), 71 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index a57c40d05..fb10b7ef3 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -21,12 +21,12 @@ export class BbaUsd1Builder { * 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 {string} userAddress User address. - * @param {string} bbausd1Amount Amount of BPT tokens to migrate. - * @param {string} minBbausd2Out Minimum of expected BPT out ot the migration flow. - * @param {boolean} staked Indicates whether tokens are initially staked or not. - * @param {string[]} 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 {string} authorisation Encoded authorisation call. + * @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( @@ -87,11 +87,11 @@ export class BbaUsd1Builder { * Creates encoded batchSwap function with following swaps: boosted -> linears -> stables -> linears -> boosted * outputreferences should contain the amount of resulting BPT. * - * @param {string} bbausd1Amount Amount of BPT tokens to migrate. - * @param {string} minBbausd2Out Minimum of expected BPT out ot the migration flow. - * @param {string} sender Sender address. - * @param {string} recipient Recipient address. - * @param {string[]} tokenBalances Token balances in EVM scale. + * @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( @@ -269,8 +269,8 @@ export class BbaUsd1Builder { /** * Uses relayer to withdraw staked BPT from gauge and send to relayer * - * @param {string} sender Sender address. - * @param {string} amount Amount of BPT to exit with. + * @param sender Sender address. + * @param amount Amount of BPT to exit with. * @returns withdraw call */ buildWithdraw(sender: string, amount: string): string { @@ -285,7 +285,7 @@ export class BbaUsd1Builder { /** * Uses relayer to deposit user's BPT to gauge and sends to recipient * - * @param {string} recipient Recipient address. + * @param recipient Recipient address. * @returns deposit call */ buildDeposit(recipient: string): string { @@ -300,7 +300,7 @@ export class BbaUsd1Builder { /** * Uses relayer to approve itself to act in behalf of the user * - * @param {string} authorisation Encoded authorisation call. + * @param authorisation Encoded authorisation call. * @returns relayer approval call */ buildSetRelayerApproval(authorisation: string): string { diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 3c8418f20..e3c92494b 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -27,11 +27,11 @@ export class StaBal3Builder { * 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 {string} userAddress User address. - * @param {string} staBal3Amount Amount of BPT tokens to migrate. - * @param {string} minBbausd2Out Minimum of expected BPT out ot the migration flow. - * @param {boolean} staked Indicates whether tokens are initially staked or not. - * @param {string} authorisation Encoded authorisation call. + * @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( @@ -79,11 +79,11 @@ export class StaBal3Builder { /** * Encodes exitPool callData. - * Exit staBal3 pool proportionally to underlying Linear BPTs. Exits to relayer. + * Exit staBal3 pool proportionally to underlying stables. Exits to relayer. * Outputreferences are used to store exit amounts for next transaction. * - * @param {string} sender Sender address. - * @param {string} amount Amount of staBal3 BPT to exit with. + * @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 { @@ -127,8 +127,8 @@ export class StaBal3Builder { * Creates encoded batchSwap function with following swaps: stables -> linear pools -> boosted pool * outputreferences should contain the amount of resulting BPT. * - * @param {string} expectedBptReturn BPT amount expected out of the swap. - * @param {string} recipient Recipient address. + * @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 { @@ -228,8 +228,8 @@ export class StaBal3Builder { /** * Uses relayer to withdraw staked BPT from gauge and send to relayer * - * @param {string} sender Sender address. - * @param {string} amount Amount of BPT to exit with. + * @param sender Sender address. + * @param amount Amount of BPT to exit with. * @returns withdraw call */ buildWithdraw(sender: string, amount: string): string { @@ -244,7 +244,7 @@ export class StaBal3Builder { /** * Uses relayer to deposit user's BPT to gauge and sends to recipient * - * @param {string} recipient Recipient address. + * @param recipient Recipient address. * @returns deposit call */ buildDeposit(recipient: string): string { @@ -259,7 +259,7 @@ export class StaBal3Builder { /** * Uses relayer to approve itself to act in behalf of the user * - * @param {string} authorisation Encoded authorisation call. + * @param authorisation Encoded authorisation call. * @returns relayer approval call */ buildSetRelayerApproval(authorisation: string): string { diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index 6a130d5ce..fca1b0ae2 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -25,14 +25,14 @@ export class StablesBuilder { * 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 {string} userAddress User address. - * @param {{string, string, string}} from Pool info being migrated from - * @param {{string, string, string}} to Pool info being migrated to - * @param {string} bptIn Amount of BPT tokens to migrate. - * @param {string} minBptOut Minimum of expected BPT out ot the migration flow. - * @param {boolean} staked Indicates whether tokens are initially staked or not. - * @param {string[]} 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 {string} authorisation Encoded authorisation call. + * @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( @@ -97,10 +97,10 @@ export class StablesBuilder { * Exit stable pool proportionally to underlying stables. Exits to relayer. * Outputreferences are used to store exit amounts for next transaction. * - * @param {string} poolId Pool id. - * @param {string} sender Sender address. - * @param {string} amount Amount of BPT to exit with. - * @param {string[]} underlyingTokens Token addresses to exit to. + * @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( @@ -144,11 +144,11 @@ export class StablesBuilder { * Creates encoded batchSwap function to swap stables to new phantom stable pool BPT. * outputreferences should contain the amount of resulting BPT. * - * @param {string} expectedBptReturn BPT amount expected out of the swap. - * @param {string} recipient Recipient address. - * @param {string} poolId Pool id - * @param {string} poolAddress Pool address - * @param {string[]} tokens Token addresses to swap from. + * @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( @@ -205,9 +205,9 @@ export class StablesBuilder { /** * Uses relayer to withdraw staked BPT from gauge and send to relayer * - * @param {string} sender Sender address. - * @param {string} amount Amount of BPT to exit with. - * @param {string} gaugeAddress Gauge address. + * @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 { @@ -222,8 +222,8 @@ export class StablesBuilder { /** * Uses relayer to deposit user's BPT to gauge and sends to recipient * - * @param {string} recipient Recipient address. - * @param {string} gaugeAddress Gauge address. + * @param recipient Recipient address. + * @param gaugeAddress Gauge address. * @returns deposit call */ buildDeposit(recipient: string, gaugeAddress: string): string { @@ -238,7 +238,7 @@ export class StablesBuilder { /** * Uses relayer to approve itself to act in behalf of the user * - * @param {string} authorisation Encoded authorisation call. + * @param authorisation Encoded authorisation call. * @returns relayer approval call */ buildSetRelayerApproval(authorisation: string): string { diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index 7b77043ca..adf6ac392 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -11,11 +11,11 @@ export class Migrations { * 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 {string} userAddress User address. - * @param {string} staBal3Amount Amount of BPT tokens to migrate. - * @param {string} minBbausd2Out Minimum of expected BPT out ot the migration flow. - * @param {boolean} staked Indicates whether tokens are initially staked or not. - * @param {string} authorisation Encoded authorisation call. + * @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( @@ -60,12 +60,12 @@ export class Migrations { * 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 {string} userAddress User address. - * @param {string} bbausd1Amount Amount of BPT tokens to migrate. - * @param {string} minBbausd2Out Minimum of expected BPT out ot the migration flow. - * @param {boolean} staked Indicates whether tokens are initially staked or not. - * @param {string[]} 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 {string} authorisation Encoded authorisation call. + * @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( @@ -120,14 +120,14 @@ export class Migrations { * 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 {string} userAddress User address. - * @param {{string, string, string}} from Pool info being migrated from - * @param {{string, string, string}} to Pool info being migrated to - * @param {string} bptIn Amount of BPT tokens to migrate. - * @param {string} minBptOut Minimum of expected BPT out ot the migration flow. - * @param {boolean} staked Indicates whether tokens are initially staked or not. - * @param {string[]} 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 {string} authorisation Encoded authorisation call. + * @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( From 4acbadab62365559dad9c8908ffcf5602b2bb719 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 8 Aug 2022 15:45:51 -0300 Subject: [PATCH 079/104] Add new stabal3 pool for alternative test scenarios --- .../src/modules/zaps/bbausd2-migrations/addresses.ts | 6 ++++++ .../zaps/bbausd2-migrations/stables.integration.spec.ts | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 3d0631afa..e3318b202 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -63,6 +63,12 @@ export const ADDRESSES = { gauge: '0x4e4ebf2aa90e41174d716a5168895357762d68af', assetOrder: ['USDT', 'DAI', 'USDC'], }, + staBal3_3: { + id: '0x3bfc8a0509f1a68aefd446f6c19bf37b3c75a8fc0000000000000000000000a5', + address: '0x3bfc8a0509f1a68aefd446f6c19bf37b3c75a8fc', + gauge: '0x7776e1008d7c20ab54aa57a7c44fc7de602de29a', + assetOrder: ['USDT', 'DAI', 'USDC'], + }, bbausd1: { id: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd00000000000000000000005f', address: '0x13acd41c585d7ebb4a9460f7c8f50be60dc080cd', 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 index 34178d4d5..9745057f7 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -38,6 +38,13 @@ const fromPool = { address: addresses.staBal3.address, gauge: addresses.staBal3.gauge, }; +// const holderAddress = '0xdc6bd6653ff82946bb94c1d243038c5abf14f2ea'; +// const fromPool = { +// id: addresses.staBal3_3.id, +// address: addresses.staBal3_3.address, +// gauge: addresses.staBal3_3.gauge, +// }; +// blocknumber = 7352236 const toPool = { id: addresses.staBal3_2.id, address: addresses.staBal3_2.address, From 1c00d5f8fc50e15c674bede772a1d69fb51cd06a Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 8 Aug 2022 15:46:30 -0300 Subject: [PATCH 080/104] Add maiusd migration flow (wip) --- .../src/modules/relayer/relayer.module.ts | 53 ++- balancer-js/src/modules/relayer/types.ts | 13 +- .../zaps/bbausd2-migrations/addresses.ts | 26 ++ .../maiusd.integration.spec.ts | 237 ++++++++++++++ .../modules/zaps/bbausd2-migrations/maiusd.ts | 309 ++++++++++++++++++ balancer-js/src/modules/zaps/migrations.ts | 49 +++ 6 files changed, 685 insertions(+), 2 deletions(-) create mode 100644 balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts create mode 100644 balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts diff --git a/balancer-js/src/modules/relayer/relayer.module.ts b/balancer-js/src/modules/relayer/relayer.module.ts index 43ea48dfb..3d8d7cd9e 100644 --- a/balancer-js/src/modules/relayer/relayer.module.ts +++ b/balancer-js/src/modules/relayer/relayer.module.ts @@ -9,10 +9,17 @@ import { EncodeUnwrapAaveStaticTokenInput, OutputReference, EncodeExitPoolInput, + EncodeJoinPoolInput, ExitAndBatchSwapInput, ExitPoolData, + JoinPoolData, } from './types'; -import { TransactionData, ExitPoolRequest, BalancerSdkConfig } from '@/types'; +import { + TransactionData, + ExitPoolRequest, + JoinPoolRequest, + BalancerSdkConfig, +} from '@/types'; import { SwapType, FundManagement, @@ -112,6 +119,17 @@ export class Relayer { ]); } + static encodeJoinPool(params: EncodeJoinPoolInput): string { + return relayerLibrary.encodeFunctionData('joinPool', [ + params.poolId, + params.poolKind, + params.sender, + params.recipient, + params.joinPoolRequest, + params.outputReferences, + ]); + } + static encodeUnwrapAaveStaticToken( params: EncodeUnwrapAaveStaticTokenInput ): string { @@ -168,6 +186,39 @@ export class Relayer { return exitEncoded; } + static constructJoinCall(params: JoinPoolData): string { + const { + assets, + maxAmountsIn, + userData, + fromInternalBalance, + poolId, + poolKind, + sender, + recipient, + outputReferences, + } = params; + + const joinPoolRequest: JoinPoolRequest = { + assets, + maxAmountsIn, + userData, + fromInternalBalance, + }; + + const joinPoolInput: EncodeJoinPoolInput = { + poolId, + poolKind, + sender, + recipient, + outputReferences, + joinPoolRequest, + }; + + const joinEncoded = Relayer.encodeJoinPool(joinPoolInput); + return joinEncoded; + } + /** * fetchPools saves updated pools data to SOR internal onChainBalanceCache. * @param {SubgraphPoolBase[]} [poolsData=[]] If poolsData passed uses this as pools source otherwise fetches from config.subgraphUrl. diff --git a/balancer-js/src/modules/relayer/types.ts b/balancer-js/src/modules/relayer/types.ts index 9bf072316..6c05ae9ea 100644 --- a/balancer-js/src/modules/relayer/types.ts +++ b/balancer-js/src/modules/relayer/types.ts @@ -1,6 +1,6 @@ import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; -import { ExitPoolRequest } from '@/types'; +import { ExitPoolRequest, JoinPoolRequest } from '@/types'; import { SwapType, BatchSwapStep, @@ -33,6 +33,15 @@ export interface EncodeExitPoolInput { exitPoolRequest: ExitPoolRequest; } +export interface EncodeJoinPoolInput { + poolId: string; + poolKind: number; + sender: string; + recipient: string; + outputReferences: OutputReference[]; + joinPoolRequest: JoinPoolRequest; +} + export interface EncodeUnwrapAaveStaticTokenInput { staticToken: string; sender: string; @@ -55,3 +64,5 @@ export interface ExitAndBatchSwapInput { } export type ExitPoolData = ExitPoolRequest & EncodeExitPoolInput; + +export type JoinPoolData = JoinPoolRequest & EncodeJoinPoolInput; diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index e3318b202..8a0515ddb 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -42,12 +42,25 @@ export const ADDRESSES = { id: '', address: 'N/A', }, + 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', @@ -104,11 +117,24 @@ export const ADDRESSES = { id: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f00000000000000000000005e', address: '0xefd681a82970ac5d980b9b2d40499735e7bf3f1f', }, + maiusd: { + id: '0x6a8f9ab364b85725973d2a33cb9aae2dac43b5e30000000000000000000000a6', + address: '0x6a8f9ab364b85725973d2a33cb9aae2dac43b5e3', + gauge: '0x58141bdcecb7fbae006964f4131cf6f65c948357', + assetOrder: ['USDT', 'miMATIC', 'DAI', 'USDC'], + }, + maibbausd: { + id: '0xcd04894ddd31a3ec6ec39fa53a4c163b8842bc1a0002000000000000000000a9', + address: '0xcd04894ddd31a3ec6ec39fa53a4c163b8842bc1a', + gauge: '0x84383120351358ef73e31897521abcb60609582d', + assetOrder: ['bb-a-USD', 'miMATIC'], + }, USDT: '0x1f1f156e0317167c11aa412e3d1435ea29dc3cce', DAI: '0x8c9e6c40d3402480ace624730524facc5482798c', USDC: '0xe0c9275e44ea80ef17579d33c55136b7da269aeb', waDAI: '0x89534a24450081aa267c79b07411e9617d984052', waUSDC: '0x811151066392fd641fe74a9b55a712670572d161', waUSDT: '0x4cb1892fddf14f772b2e39e299f44b2e5da90d04', + miMATIC: '0x398106564948feeb1fedea0709ae7d969d62a391', }, }; 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 new file mode 100644 index 000000000..a297118e9 --- /dev/null +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts @@ -0,0 +1,237 @@ +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'; + +/* + * Testing on GOERLI + * - Update hardhat.config.js with chainId = 5 + * - Update ALCHEMY_URL on .env with a goerli api key + * - Run goerli node on terminal: yarn run node + * - Change `network` to Network.GOERLI + * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli + */ + +dotenv.config(); + +const { ALCHEMY_URL: jsonRpcUrl, FORK_BLOCK_NUMBER: blockNumber } = process.env; +const { ethers } = hardhat; +const MAX_GAS_LIMIT = 8e6; + +const network = Network.GOERLI; +const rpcUrl = 'http://127.0.0.1:8545'; +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 holderAddress = '0x8fe3a2a5ae6baa201c26fc7830eb713f33d6b313'; +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: (blockNumber && parseInt(blockNumber)) || 7369439, + }, + }, + ]); + +describe('stabal3 migration execution', async () => { + let signer: JsonRpcSigner; + let signerAddress: string; + let authorisation: string; + let balance: BigNumber; + + beforeEach(async function () { + this.timeout(20000); + 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 () { + this.timeout(20000); + + // Stake them + await stake(signer, fromPool.address, fromPool.gauge, balance); + }); + + it('should transfer tokens from stable to boosted', async () => { + bptOut = await testFlow(true); + }).timeout(20000); + + 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) + }).timeout(20000); + }); + + context('not staked', async () => { + it('should transfer tokens from stable to boosted', async () => { + bptOut = await testFlow(false); + }).timeout(20000); + + 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) + }).timeout(20000); + }); + + 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); + }).timeout(20000); + + 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 + }).timeout(20000); + }).timeout(20000); +}).timeout(20000); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts new file mode 100644 index 000000000..4bcceb9ff --- /dev/null +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts @@ -0,0 +1,309 @@ +import { StablePoolEncoder } from '@/pool-stable/encoder'; +import { ADDRESSES } from './addresses'; +import { Relayer } from '@/modules/relayer/relayer.module'; +import { ExitPoolRequest, JoinPoolRequest } 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 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_BBAUSD = Relayer.toChainedReference('24'); +const JOIN_MAIBBAUSD = Relayer.toChainedReference('25'); + +export class MaiusdBuilder { + private addresses; + + constructor(networkId: 1 | 5) { + 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; + } { + 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(), + this.buildJoin(relayer, minBptOut), + this.buildDeposit(userAddress), + ]; + } else { + calls = [ + ...calls, + this.buildExit(userAddress, bptIn), + this.buildSwap(), + this.buildJoin(userAddress, minBptOut), + ]; + } + + const callData = balancerRelayerInterface.encodeFunctionData('multicall', [ + calls, + ]); + + return { + to: this.addresses.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 callData = Relayer.constructExitCall({ + 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, + }); + + return callData; + } + + /** + * Creates encoded batchSwap function with following swaps: stables -> linear pools -> boosted pool + * outputreferences should contain the amount of resulting BPT. + * + * @returns Encoded batchSwap call. Output references. + */ + buildSwap(): 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_BBAUSD }]; + + 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 = [ + MaxInt256.mul(-1).toString(), // limit will be handled by the next transaction, which is the joinPool + MaxInt256.toString(), + '0', + MaxInt256.toString(), + '0', + MaxInt256.toString(), + '0', + ]; + + // Swap to/from Relayer + const funds: FundManagement = { + sender: this.addresses.relayer, + recipient: this.addresses.relayer, + fromInternalBalance: true, + toInternalBalance: true, + }; + + 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; + } + + /** + * Encodes joinPool callData. + * Join maibbausd pool. + * Outputreferences are used to store exit amounts for next transaction. + * + * @param recipient Sender address. + * @param minBptOut Minimum BPT out expected from the join transaction. + * @returns Encoded joinPool call. Output references. + */ + buildJoin(recipient: string, minBptOut: string): string { + const { assetOrder } = this.addresses.maibbausd; + const assets = assetOrder.map( + (key) => this.addresses[key as keyof typeof this.addresses] as string + ); + + const maxAmountsIn = [SWAP_BBAUSD, EXIT_MIMATIC]; + + const userData = StablePoolEncoder.joinExactTokensInForBPTOut( + maxAmountsIn, + minBptOut + ); + + const outputReferences = [{ index: 0, key: JOIN_MAIBBAUSD }]; + + const callData = Relayer.constructJoinCall({ + poolId: this.addresses.maibbausd.id, + poolKind: 0, // TODO: assuming it should be the same value as exit call - check if that's true + sender: this.addresses.relayer, + recipient, + outputReferences, + joinPoolRequest: {} as JoinPoolRequest, + assets, + maxAmountsIn, + userData, + fromInternalBalance: true, + }); + + return callData; + } + + /** + * 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, + JOIN_MAIBBAUSD.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 index adf6ac392..557fb3193 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -2,6 +2,7 @@ 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) {} @@ -172,4 +173,52 @@ export class Migrations { }, }; } + + /** + * 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 joinIndex = staked ? 3 : 2; + if (authorisation) joinIndex += 1; + const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); + const joinResult = defaultAbiCoder.decode( + ['uint256'], + multicallResult[0][joinIndex] + ); + return joinResult[0][0].abs().toString(); // bptOut + }, + }; + } } From 7803e5633d5b5ee857539b03d46cb10fd6d1c3f2 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Tue, 9 Aug 2022 14:45:53 -0300 Subject: [PATCH 081/104] Remove join in favor of swap for maiusd migration flow --- .../src/modules/relayer/relayer.module.ts | 53 +----------- balancer-js/src/modules/relayer/types.ts | 2 - .../modules/zaps/bbausd2-migrations/maiusd.ts | 83 +++++++------------ balancer-js/src/modules/zaps/migrations.ts | 13 +-- 4 files changed, 38 insertions(+), 113 deletions(-) diff --git a/balancer-js/src/modules/relayer/relayer.module.ts b/balancer-js/src/modules/relayer/relayer.module.ts index 3d8d7cd9e..43ea48dfb 100644 --- a/balancer-js/src/modules/relayer/relayer.module.ts +++ b/balancer-js/src/modules/relayer/relayer.module.ts @@ -9,17 +9,10 @@ import { EncodeUnwrapAaveStaticTokenInput, OutputReference, EncodeExitPoolInput, - EncodeJoinPoolInput, ExitAndBatchSwapInput, ExitPoolData, - JoinPoolData, } from './types'; -import { - TransactionData, - ExitPoolRequest, - JoinPoolRequest, - BalancerSdkConfig, -} from '@/types'; +import { TransactionData, ExitPoolRequest, BalancerSdkConfig } from '@/types'; import { SwapType, FundManagement, @@ -119,17 +112,6 @@ export class Relayer { ]); } - static encodeJoinPool(params: EncodeJoinPoolInput): string { - return relayerLibrary.encodeFunctionData('joinPool', [ - params.poolId, - params.poolKind, - params.sender, - params.recipient, - params.joinPoolRequest, - params.outputReferences, - ]); - } - static encodeUnwrapAaveStaticToken( params: EncodeUnwrapAaveStaticTokenInput ): string { @@ -186,39 +168,6 @@ export class Relayer { return exitEncoded; } - static constructJoinCall(params: JoinPoolData): string { - const { - assets, - maxAmountsIn, - userData, - fromInternalBalance, - poolId, - poolKind, - sender, - recipient, - outputReferences, - } = params; - - const joinPoolRequest: JoinPoolRequest = { - assets, - maxAmountsIn, - userData, - fromInternalBalance, - }; - - const joinPoolInput: EncodeJoinPoolInput = { - poolId, - poolKind, - sender, - recipient, - outputReferences, - joinPoolRequest, - }; - - const joinEncoded = Relayer.encodeJoinPool(joinPoolInput); - return joinEncoded; - } - /** * fetchPools saves updated pools data to SOR internal onChainBalanceCache. * @param {SubgraphPoolBase[]} [poolsData=[]] If poolsData passed uses this as pools source otherwise fetches from config.subgraphUrl. diff --git a/balancer-js/src/modules/relayer/types.ts b/balancer-js/src/modules/relayer/types.ts index 6c05ae9ea..dae4ac4f7 100644 --- a/balancer-js/src/modules/relayer/types.ts +++ b/balancer-js/src/modules/relayer/types.ts @@ -64,5 +64,3 @@ export interface ExitAndBatchSwapInput { } export type ExitPoolData = ExitPoolRequest & EncodeExitPoolInput; - -export type JoinPoolData = JoinPoolRequest & EncodeJoinPoolInput; diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts index 4bcceb9ff..64140adab 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts @@ -1,7 +1,7 @@ import { StablePoolEncoder } from '@/pool-stable/encoder'; import { ADDRESSES } from './addresses'; import { Relayer } from '@/modules/relayer/relayer.module'; -import { ExitPoolRequest, JoinPoolRequest } from '@/types'; +import { ExitPoolRequest } from '@/types'; import { BatchSwapStep, FundManagement, SwapType } from '@/modules/swaps/types'; import { Interface } from '@ethersproject/abi'; import { BigNumber } from '@ethersproject/bignumber'; @@ -14,8 +14,7 @@ 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_BBAUSD = Relayer.toChainedReference('24'); -const JOIN_MAIBBAUSD = Relayer.toChainedReference('25'); +const SWAP_RESULT = Relayer.toChainedReference('24'); export class MaiusdBuilder { private addresses; @@ -58,16 +57,14 @@ export class MaiusdBuilder { ...calls, this.buildWithdraw(userAddress, bptIn), this.buildExit(relayer, bptIn), - this.buildSwap(), - this.buildJoin(relayer, minBptOut), + this.buildSwap(relayer, minBptOut), this.buildDeposit(userAddress), ]; } else { calls = [ ...calls, this.buildExit(userAddress, bptIn), - this.buildSwap(), - this.buildJoin(userAddress, minBptOut), + this.buildSwap(userAddress, minBptOut), ]; } @@ -129,9 +126,11 @@ export class MaiusdBuilder { * 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(): string { + buildSwap(recipient: string, minBptOut: string): string { const assets = [ this.addresses.bbausd2.address, this.addresses.DAI, @@ -140,9 +139,11 @@ export class MaiusdBuilder { this.addresses.linearUsdc2.address, this.addresses.USDT, this.addresses.linearUsdt2.address, + this.addresses.miMATIC, + this.addresses.maibbausd.address, ]; - const outputReferences = [{ index: 0, key: SWAP_BBAUSD }]; + const outputReferences = [{ index: 0, key: SWAP_RESULT }]; const swaps: BatchSwapStep[] = [ { @@ -187,25 +188,41 @@ export class MaiusdBuilder { 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 = [ - MaxInt256.mul(-1).toString(), // limit will be handled by the next transaction, which is the joinPool + '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: this.addresses.relayer, + recipient, fromInternalBalance: true, - toInternalBalance: true, + toInternalBalance: false, }; const encodedBatchSwap = Relayer.encodeBatchSwap({ @@ -222,46 +239,6 @@ export class MaiusdBuilder { return encodedBatchSwap; } - /** - * Encodes joinPool callData. - * Join maibbausd pool. - * Outputreferences are used to store exit amounts for next transaction. - * - * @param recipient Sender address. - * @param minBptOut Minimum BPT out expected from the join transaction. - * @returns Encoded joinPool call. Output references. - */ - buildJoin(recipient: string, minBptOut: string): string { - const { assetOrder } = this.addresses.maibbausd; - const assets = assetOrder.map( - (key) => this.addresses[key as keyof typeof this.addresses] as string - ); - - const maxAmountsIn = [SWAP_BBAUSD, EXIT_MIMATIC]; - - const userData = StablePoolEncoder.joinExactTokensInForBPTOut( - maxAmountsIn, - minBptOut - ); - - const outputReferences = [{ index: 0, key: JOIN_MAIBBAUSD }]; - - const callData = Relayer.constructJoinCall({ - poolId: this.addresses.maibbausd.id, - poolKind: 0, // TODO: assuming it should be the same value as exit call - check if that's true - sender: this.addresses.relayer, - recipient, - outputReferences, - joinPoolRequest: {} as JoinPoolRequest, - assets, - maxAmountsIn, - userData, - fromInternalBalance: true, - }); - - return callData; - } - /** * Uses relayer to withdraw staked BPT from gauge and send to relayer * @@ -289,7 +266,7 @@ export class MaiusdBuilder { this.addresses.maibbausd.gauge, this.addresses.relayer, recipient, - JOIN_MAIBBAUSD.toString() + SWAP_RESULT.toString() ); } diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index 557fb3193..68817d135 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -210,14 +210,15 @@ export class Migrations { to: request.to, data: request.data, decode: (output, staked) => { - let joinIndex = staked ? 3 : 2; - if (authorisation) joinIndex += 1; + let swapIndex = staked ? 2 : 1; + if (authorisation) swapIndex += 1; const multicallResult = defaultAbiCoder.decode(['bytes[]'], output); - const joinResult = defaultAbiCoder.decode( - ['uint256'], - multicallResult[0][joinIndex] + const swapDeltas = defaultAbiCoder.decode( + ['int256[]'], + multicallResult[0][swapIndex] ); - return joinResult[0][0].abs().toString(); // bptOut + const bptOut = swapDeltas[0][8].abs().toString(); + return bptOut; }, }; } From bf2cc228f0fae1426a7ed6bc066c65c64a138265 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Tue, 9 Aug 2022 14:46:04 -0300 Subject: [PATCH 082/104] Minor fixes --- .../modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts | 2 +- balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts | 2 +- balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 index a297118e9..f720c986f 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts @@ -82,7 +82,7 @@ const reset = () => }, ]); -describe('stabal3 migration execution', async () => { +describe('maiusd migration execution', async () => { let signer: JsonRpcSigner; let signerAddress: string; let authorisation: string; diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts index 64140adab..2995f260e 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts @@ -73,7 +73,7 @@ export class MaiusdBuilder { ]); return { - to: this.addresses.relayer, + to: relayer, data: callData, }; } diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index e3c92494b..5d615e795 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -72,7 +72,7 @@ export class StaBal3Builder { ]); return { - to: this.addresses.relayer, + to: relayer, data: callData, }; } From 3cd8a6a2f602751f21db32e2ee56eede0b2fb65a Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Tue, 9 Aug 2022 22:03:33 -0300 Subject: [PATCH 083/104] Replace maibbausd addresses by test pool that accepts swap to join --- .../src/modules/zaps/bbausd2-migrations/addresses.ts | 8 ++++---- .../zaps/bbausd2-migrations/maiusd.integration.spec.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 8a0515ddb..953452fa3 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -124,10 +124,10 @@ export const ADDRESSES = { assetOrder: ['USDT', 'miMATIC', 'DAI', 'USDC'], }, maibbausd: { - id: '0xcd04894ddd31a3ec6ec39fa53a4c163b8842bc1a0002000000000000000000a9', - address: '0xcd04894ddd31a3ec6ec39fa53a4c163b8842bc1a', - gauge: '0x84383120351358ef73e31897521abcb60609582d', - assetOrder: ['bb-a-USD', 'miMATIC'], + id: '0xb04b03b78cf79788a1931545bd2744161029648f0000000000000000000000a8', + address: '0xb04b03b78cf79788a1931545bd2744161029648f', + gauge: '0xdc3f6fc8898830e53c777543fe252b14f22680d4', + assetOrder: ['bb-a-USD', 'miMATIC', 'MAI BSP'], }, USDT: '0x1f1f156e0317167c11aa412e3d1435ea29dc3cce', DAI: '0x8c9e6c40d3402480ace624730524facc5482798c', 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 index f720c986f..eb5e9d5f2 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts @@ -77,7 +77,7 @@ const reset = () => { forking: { jsonRpcUrl, - blockNumber: (blockNumber && parseInt(blockNumber)) || 7369439, + blockNumber: (blockNumber && parseInt(blockNumber)) || 7376670, }, }, ]); From 4e011aaf8e32643e6c01d2a588934062656cf7e2 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Tue, 9 Aug 2022 22:04:23 -0300 Subject: [PATCH 084/104] Add missing swaps and fix output ref index not pointing to the proper asset --- .../modules/zaps/bbausd2-migrations/maiusd.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts index 2995f260e..b382e5a20 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts @@ -143,7 +143,7 @@ export class MaiusdBuilder { this.addresses.maibbausd.address, ]; - const outputReferences = [{ index: 0, key: SWAP_RESULT }]; + const outputReferences = [{ index: 8, key: SWAP_RESULT }]; const swaps: BatchSwapStep[] = [ { @@ -160,6 +160,13 @@ export class MaiusdBuilder { amount: '0', userData: '0x', }, + { + poolId: this.addresses.maibbausd.id, + assetInIndex: 0, + assetOutIndex: 8, + amount: '0', + userData: '0x', + }, { poolId: this.addresses.linearUsdc2.id, assetInIndex: 3, @@ -174,6 +181,13 @@ export class MaiusdBuilder { amount: '0', userData: '0x', }, + { + poolId: this.addresses.maibbausd.id, + assetInIndex: 0, + assetOutIndex: 8, + amount: '0', + userData: '0x', + }, { poolId: this.addresses.linearUsdt2.id, assetInIndex: 5, From 39a2516f7f92ddc3f9d4c1ea63a0f7675ce9788d Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 19 Aug 2022 11:22:30 +0100 Subject: [PATCH 085/104] Updated bbausd2 addresses. Needs Gauge. --- .../zaps/bbausd2-migrations/addresses.ts | 18 +++++++++--------- .../bbausd1.integration.spec.ts | 7 +++++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 953452fa3..5b27bd595 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -1,6 +1,6 @@ export const ADDRESSES = { 1: { - relayer: 'TODO', + relayer: '0x886A3Ec7bcC508B8795990B60Fa21f85F9dB7948', staBal3: { id: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063', address: '0x06df3b2bbb68adc8b0e302443692037ed9f91b42', @@ -14,8 +14,8 @@ export const ADDRESSES = { assetOrder: ['bb-a-USDT', 'bb-a-DAI', 'bb-a-USDC'], }, bbausd2: { - id: '', - address: '', + id: '0x9B532AB955417AFD0D012EB9F7389457CD0EA712000000000000000000000338', + address: '0x9B532AB955417AFD0D012EB9F7389457CD0EA712', gauge: '', }, linearUsdc1: { @@ -31,16 +31,16 @@ export const ADDRESSES = { address: '0x2BBf681cC4eb09218BEe85EA2a5d3D13Fa40fC0C', }, linearUsdc2: { - id: '', - address: 'N/A', + id: '0x82698AECC9E28E9BB27608BD52CF57F704BD1B83000000000000000000000336', + address: '0x82698aeCc9E28e9Bb27608Bd52cF57f704BD1B83', }, linearDai2: { - id: '', - address: 'N/A', + id: '0xAE37D54AE477268B9997D4161B96B8200755935C000000000000000000000337', + address: '0xae37D54Ae477268B9997d4161B96b8200755935c', }, linearUsdt2: { - id: '', - address: 'N/A', + id: '0x2F4EB100552EF93840D5ADC30560E5513DFFFACB000000000000000000000334', + address: '0x2F4eb100552ef93840d5aDC30560E5513DFfFACb', }, maiusd: { id: '', 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 index 8175471fd..442998288 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -34,7 +34,7 @@ const { ALCHEMY_URL: jsonRpcUrl, FORK_BLOCK_NUMBER: blockNumber } = process.env; const { ethers } = hardhat; const MAX_GAS_LIMIT = 8e6; -const network = Network.GOERLI; +const network = Network.MAINNET; const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const addresses = ADDRESSES[network]; @@ -51,7 +51,8 @@ const toPool = { const { contracts } = new Contracts(network as number, provider); const migrations = new Migrations(network); -const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; +// const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; // Goerli +const holderAddress = '0xec576a26335de1c360d2fc9a68cba6ba37af4a13'; const relayer = addresses.relayer; const signRelayerApproval = async ( @@ -108,12 +109,14 @@ describe('bbausd migration execution', async () => { 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 + console.log('HERE???') balance = await move( fromPool.address, holderAddress, signerAddress, provider ); + console.log('HERE 2???') const config = { network, From ec57210b2c60cb6d8a073841e1676452c6b35485 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Fri, 19 Aug 2022 16:33:15 -0300 Subject: [PATCH 086/104] Add bbusd2 gauge address to constants file --- balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 5b27bd595..56d8a9261 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -16,7 +16,7 @@ export const ADDRESSES = { bbausd2: { id: '0x9B532AB955417AFD0D012EB9F7389457CD0EA712000000000000000000000338', address: '0x9B532AB955417AFD0D012EB9F7389457CD0EA712', - gauge: '', + gauge: '0x66122c9030030155fb2bbe2e1e9a72588065c4f5', }, linearUsdc1: { id: '0x9210f1204b5a24742eba12f710636d76240df3d00000000000000000000000fc', From eb80bf9dc343df0f30290c567d7f08ff63cd85ed Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Fri, 19 Aug 2022 16:34:10 -0300 Subject: [PATCH 087/104] Update stabal3 integration test with mainnet values --- .../stabal3.integration.spec.ts | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) 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 index da42c7c8c..262f0174a 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -10,22 +10,34 @@ import { MaxUint256 } from '@ethersproject/constants'; import { Migrations } from '../migrations'; import { getErc20Balance, move, stake } from '@/test/lib/utils'; +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 GOERLI - * - Update hardhat.config.js with chainId = 5 - * - Update ALCHEMY_URL on .env with a goerli api key - * - Run goerli node on terminal: yarn run node - * - Change `network` to Network.GOERLI - * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli + * 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 = 15372650; -dotenv.config(); - -const { ALCHEMY_URL: jsonRpcUrl, FORK_BLOCK_NUMBER: blockNumber } = process.env; const { ethers } = hardhat; const MAX_GAS_LIMIT = 8e6; -const network = Network.GOERLI; const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const addresses = ADDRESSES[network]; @@ -42,7 +54,6 @@ const toPool = { const { contracts } = new Contracts(network as number, provider); const migrations = new Migrations(network); -const holderAddress = '0xe0a171587b1cae546e069a943eda96916f5ee977'; const relayer = addresses.relayer; const signRelayerApproval = async ( @@ -77,7 +88,7 @@ const reset = () => { forking: { jsonRpcUrl, - blockNumber: (blockNumber && parseInt(blockNumber)) || 7277540, + blockNumber, }, }, ]); @@ -160,8 +171,6 @@ describe('stabal3 migration execution', async () => { to: await getErc20Balance(addressOut, provider, signerAddress), }; - console.log(bbausd2AmountOut); - expect(BigNumber.from(bbausd2AmountOut).gt(0)).to.be.true; expect(after.from.toString()).to.eq('0'); expect(after.to.toString()).to.eq(bbausd2AmountOut); From 738aa8d47712ae7bed7da34358133a73141efdf3 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Fri, 19 Aug 2022 17:19:53 -0300 Subject: [PATCH 088/104] Update bbausd migration tests for mainnet --- .../bbausd1.integration.spec.ts | 79 ++++++++++--------- .../stabal3.integration.spec.ts | 30 +++---- balancer-js/src/modules/zaps/migrations.ts | 13 +-- 3 files changed, 55 insertions(+), 67 deletions(-) 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 index 442998288..67d6d8300 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -14,27 +14,38 @@ import { BigNumber, parseFixed } 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 { MaxUint256, WeiPerEther } from '@ethersproject/constants'; import { Migrations } from '../migrations'; import { PoolsProvider } from '@/modules/pools/provider'; import { getErc20Balance, move, stake } from '@/test/lib/utils'; +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 goerli node on terminal: yarn run node - * - Change `network` to Network.GOERLI - * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli + * - Run node on terminal: yarn run node + * - Uncomment section below */ +// const network = Network.GOERLI; +// const blockNumber = 7277540; +// const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; -dotenv.config(); +/* + * 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 section below + */ +const network = Network.MAINNET; +const blockNumber = 15372650; +const holderAddress = '0xec576a26335de1c360d2fc9a68cba6ba37af4a13'; -const { ALCHEMY_URL: jsonRpcUrl, FORK_BLOCK_NUMBER: blockNumber } = process.env; const { ethers } = hardhat; const MAX_GAS_LIMIT = 8e6; - -const network = Network.MAINNET; const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const addresses = ADDRESSES[network]; @@ -51,8 +62,6 @@ const toPool = { const { contracts } = new Contracts(network as number, provider); const migrations = new Migrations(network); -// const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; // Goerli -const holderAddress = '0xec576a26335de1c360d2fc9a68cba6ba37af4a13'; const relayer = addresses.relayer; const signRelayerApproval = async ( @@ -87,7 +96,7 @@ const reset = async () => { forking: { jsonRpcUrl, - blockNumber: (blockNumber && parseInt(blockNumber)) || 7277540, + blockNumber, }, }, ]); @@ -98,6 +107,7 @@ describe('bbausd migration execution', async () => { let authorisation: string; let balance: BigNumber; let pool: PoolModel; + let bptOut: string; beforeEach(async function () { this.timeout(20000); @@ -109,14 +119,12 @@ describe('bbausd migration execution', async () => { 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 - console.log('HERE???') balance = await move( fromPool.address, holderAddress, signerAddress, provider ); - console.log('HERE 2???') const config = { network, @@ -155,7 +163,11 @@ describe('bbausd migration execution', async () => { staked, pool.tokens .filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed - .map((token) => parseFixed(token.balance, token.decimals).toString()), + .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 ); @@ -167,16 +179,21 @@ describe('bbausd migration execution', async () => { data: query.data, gasLimit, }); - const expectedBpts = query.decode(staticResult, staked); + + const bptOut = query.decode(staticResult, staked); query = migrations.bbaUsd( signerAddress, amount.toString(), - minBbausd2Out ? minBbausd2Out : expectedBpts.bbausd2AmountOut, + minBbausd2Out ? minBbausd2Out : bptOut, staked, pool.tokens .filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed - .map((token) => parseFixed(token.balance, token.decimals).toString()), + .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 ); @@ -194,16 +211,12 @@ describe('bbausd migration execution', async () => { to: await getErc20Balance(addressOut, provider, signerAddress), }; - console.log(expectedBpts); - - expect(BigNumber.from(expectedBpts.bbausd2AmountOut).gt(0)).to.be.true; - expect(amount.toString()).to.eq(expectedBpts.bbausd1AmountIn); - expect(after.to.toString()).to.eq(expectedBpts.bbausd2AmountOut); - return expectedBpts.bbausd2AmountOut; + 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 bbausd2AmountOut: string; - context('staked', async () => { beforeEach(async function () { this.timeout(20000); @@ -212,17 +225,13 @@ describe('bbausd migration execution', async () => { }); it('should transfer tokens from stable to boosted - using exact bbausd2AmountOut from static call', async () => { - bbausd2AmountOut = await testFlow(true); + bptOut = await testFlow(true); }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; try { - await testFlow( - true, - true, - BigNumber.from(bbausd2AmountOut).add(1).toString() - ); + await testFlow(true, true, BigNumber.from(bptOut).add(1).toString()); } catch (error) { errorMessage = (error as Error).message; } @@ -232,17 +241,13 @@ describe('bbausd migration execution', async () => { context('not staked', async () => { it('should transfer tokens from stable to boosted - using exact bbausd2AmountOut from static call', async () => { - bbausd2AmountOut = await testFlow(false); + bptOut = await testFlow(false); }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; try { - await testFlow( - false, - true, - BigNumber.from(bbausd2AmountOut).add(1).toString() - ); + await testFlow(false, true, BigNumber.from(bptOut).add(1).toString()); } catch (error) { errorMessage = (error as Error).message; } 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 index 262f0174a..261980d6b 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -120,7 +120,7 @@ describe('stabal3 migration execution', async () => { async function testFlow( staked: boolean, authorised = true, - minBbausd2Out: undefined | string = undefined + minBptOut: undefined | string = undefined ): Promise { const addressIn = staked ? fromPool.gauge : fromPool.address; const addressOut = staked ? toPool.gauge : toPool.address; @@ -147,12 +147,12 @@ describe('stabal3 migration execution', async () => { data: query.data, gasLimit, }); - const bbausd2AmountOut = query.decode(staticResult, staked); + const bptOut = query.decode(staticResult, staked); query = migrations.stabal3( signerAddress, amount.toString(), - minBbausd2Out ? minBbausd2Out : bbausd2AmountOut, + minBptOut ? minBptOut : bptOut, staked, authorised ? authorisation : undefined ); @@ -171,13 +171,13 @@ describe('stabal3 migration execution', async () => { to: await getErc20Balance(addressOut, provider, signerAddress), }; - expect(BigNumber.from(bbausd2AmountOut).gt(0)).to.be.true; + expect(BigNumber.from(bptOut).gt(0)).to.be.true; expect(after.from.toString()).to.eq('0'); - expect(after.to.toString()).to.eq(bbausd2AmountOut); - return bbausd2AmountOut; + expect(after.to.toString()).to.eq(bptOut); + return bptOut; } - let bbausd2AmountOut: string; + let bptOut: string; context('staked', async () => { beforeEach(async function () { @@ -188,17 +188,13 @@ describe('stabal3 migration execution', async () => { }); it('should transfer tokens from stable to boosted', async () => { - bbausd2AmountOut = await testFlow(true); + bptOut = await testFlow(true); }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; try { - await testFlow( - true, - true, - BigNumber.from(bbausd2AmountOut).add(1).toString() - ); + await testFlow(true, true, BigNumber.from(bptOut).add(1).toString()); } catch (error) { errorMessage = (error as Error).message; } @@ -208,17 +204,13 @@ describe('stabal3 migration execution', async () => { context('not staked', async () => { it('should transfer tokens from stable to boosted', async () => { - bbausd2AmountOut = await testFlow(false); + bptOut = await testFlow(false); }).timeout(20000); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; try { - await testFlow( - false, - true, - BigNumber.from(bbausd2AmountOut).add(1).toString() - ); + await testFlow(false, true, BigNumber.from(bptOut).add(1).toString()); } catch (error) { errorMessage = (error as Error).message; } diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index 68817d135..fa9f10e7e 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -79,13 +79,7 @@ export class Migrations { ): { to: string; data: string; - decode: ( - output: string, - staked: boolean - ) => { - bbausd1AmountIn: string; - bbausd2AmountOut: string; - }; + decode: (output: string, staked: boolean) => string; } { const builder = new BbaUsd1Builder(this.network); const request = builder.calldata( @@ -108,10 +102,7 @@ export class Migrations { ['int256[]'], multicallResult[0][swapIndex] ); - return { - bbausd1AmountIn: swapDeltas[0][10].toString(), - bbausd2AmountOut: swapDeltas[0][0].abs().toString(), - }; + return swapDeltas[0][0].abs().toString(); // bptOut }, }; } From afc77db7c8ded203dec5a77a15152b07a6fea6b7 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Wed, 24 Aug 2022 14:31:54 +0100 Subject: [PATCH 089/104] Throw on 0 input amount. Update bbausd tests for mainnet. --- balancer-js/src/balancerErrors.ts | 3 +++ .../bbausd1.integration.spec.ts | 20 +++++++++---------- .../zaps/bbausd2-migrations/bbausd1.ts | 3 +++ .../modules/zaps/bbausd2-migrations/maiusd.ts | 4 ++++ .../zaps/bbausd2-migrations/stabal3.ts | 3 +++ 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/balancer-js/src/balancerErrors.ts b/balancer-js/src/balancerErrors.ts index d0cc194bc..94a59e489 100644 --- a/balancer-js/src/balancerErrors.ts +++ b/balancer-js/src/balancerErrors.ts @@ -9,6 +9,7 @@ export enum BalancerErrorCode { NO_POOL_DATA = 'NO_POOL_DATA', INPUT_OUT_OF_BOUNDS = 'INPUT_OUT_OF_BOUNDS', INPUT_LENGTH_MISMATCH = 'INPUT_LENGTH_MISMATCH', + INPUT_ZERO_NOT_ALLOWED = 'INPUT_ZERO_NOT_ALLOWED', TOKEN_MISMATCH = 'TOKEN_MISMATCH', MISSING_TOKENS = 'MISSING_TOKENS', MISSING_AMP = 'MISSING_AMP', @@ -57,6 +58,8 @@ export class BalancerError extends Error { return 'missing price rate'; case BalancerErrorCode.MISSING_WEIGHT: return 'missing weight'; + case BalancerErrorCode.INPUT_ZERO_NOT_ALLOWED: + return 'zero input not allowed'; default: return 'Unknown error'; } 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 index 67d6d8300..9ad622ff0 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -107,7 +107,6 @@ describe('bbausd migration execution', async () => { let authorisation: string; let balance: BigNumber; let pool: PoolModel; - let bptOut: string; beforeEach(async function () { this.timeout(20000); @@ -144,7 +143,7 @@ describe('bbausd migration execution', async () => { async function testFlow( staked: boolean, authorised = true, - minBbausd2Out: undefined | string = undefined + minOutBuffer: string ): Promise { const addressIn = staked ? fromPool.gauge : fromPool.address; const addressOut = staked ? toPool.gauge : toPool.address; @@ -185,7 +184,7 @@ describe('bbausd migration execution', async () => { query = migrations.bbaUsd( signerAddress, amount.toString(), - minBbausd2Out ? minBbausd2Out : bptOut, + BigNumber.from(bptOut).add(minOutBuffer).toString(), staked, pool.tokens .filter((token) => token.symbol !== 'bb-a-USD') // Note that bbausd is removed @@ -210,10 +209,9 @@ describe('bbausd migration execution', async () => { 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.toString()).to.eq(bptOut); + expect(after.to.gte(bptOut)).to.be.true; return bptOut; } @@ -225,13 +223,13 @@ describe('bbausd migration execution', async () => { }); it('should transfer tokens from stable to boosted - using exact bbausd2AmountOut from static call', async () => { - bptOut = await testFlow(true); + await testFlow(true, undefined, '0'); }).timeout(20000); 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()); + await testFlow(true, true, '1000000000000000000'); } catch (error) { errorMessage = (error as Error).message; } @@ -241,13 +239,13 @@ describe('bbausd migration execution', async () => { context('not staked', async () => { it('should transfer tokens from stable to boosted - using exact bbausd2AmountOut from static call', async () => { - bptOut = await testFlow(false); + await testFlow(false, undefined, '0'); }).timeout(20000); 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()); + await testFlow(false, true, '1000000000000000000'); } catch (error) { errorMessage = (error as Error).message; } @@ -267,13 +265,13 @@ describe('bbausd migration execution', async () => { to: contracts.vault.address, data: approval, }); - await testFlow(false, false); + await testFlow(false, false, '0'); }).timeout(20000); it('should transfer tokens from stable to boosted - auhtorisation should fail', async () => { let errorMessage = ''; try { - await testFlow(false, false); + await testFlow(false, false, '0'); } catch (error) { errorMessage = (error as Error).message; } diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index fb10b7ef3..94dfe7864 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -6,6 +6,7 @@ import { Interface } from '@ethersproject/abi'; 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'); @@ -40,6 +41,8 @@ export class BbaUsd1Builder { 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[] = []; diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts index b382e5a20..40b7281b1 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts @@ -6,6 +6,7 @@ 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); @@ -45,6 +46,9 @@ export class MaiusdBuilder { 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[] = []; diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index 5d615e795..d935ffed9 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -6,6 +6,7 @@ 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); @@ -44,6 +45,8 @@ export class StaBal3Builder { 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[] = []; From 962884ef8b3cdfea2eeacbd30ecd64eaa4d412df Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Tue, 30 Aug 2022 10:23:54 +0100 Subject: [PATCH 090/104] Bump SOR package. --- balancer-js/package.json | 2 +- balancer-js/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/balancer-js/package.json b/balancer-js/package.json index 890dde3a4..d506991de 100644 --- a/balancer-js/package.json +++ b/balancer-js/package.json @@ -84,7 +84,7 @@ "typescript": "^4.0.2" }, "dependencies": { - "@balancer-labs/sor": "^4.0.1-beta.3", + "@balancer-labs/sor": "^4.0.1-beta.4", "@balancer-labs/typechain": "^1.0.0", "axios": "^0.24.0", "graphql": "^15.6.1", diff --git a/balancer-js/yarn.lock b/balancer-js/yarn.lock index e8ff7f3a5..d1cc6713f 100644 --- a/balancer-js/yarn.lock +++ b/balancer-js/yarn.lock @@ -483,10 +483,10 @@ "@babel/helper-validator-identifier" "^7.18.6" to-fast-properties "^2.0.0" -"@balancer-labs/sor@^4.0.1-beta.3": - version "4.0.1-beta.3" - resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.0.1-beta.3.tgz#57a90783edb09510382b821e354d5d5b30860404" - integrity sha512-xyMXsK45thq9Rqf3Ou8aIPMrg9aOtTy20wXCV39cb6K9ewWXp54XQRb3qFa8N8s+Zy3hau+FpwRbO55/zi41jg== +"@balancer-labs/sor@^4.0.1-beta.4": + version "4.0.1-beta.4" + resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.0.1-beta.4.tgz#284b81123e90f2d29ae032cf5c03110de94eff39" + integrity sha512-5HPxdleLcQe2uVW8f1QJxyXo502CTW9BaR0oGTgbGicos34YrmxwlDIvplssiCXSPhVbWp24WGi8/pc54C84Cg== dependencies: isomorphic-fetch "^2.2.1" From 1a08d15df33c33ac1c69639bc9fb7dd60634cd4b Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 8 Sep 2022 09:58:18 -0300 Subject: [PATCH 091/104] Post merge fixes --- balancer-js/package.json | 1 + .../metaStable/exit.concern.integration.spec.ts | 2 +- .../metaStable/join.concern.integration.spec.ts | 1 - .../stable/exit.concern.integration.spec.ts | 2 +- .../stable/join.concern.integration.spec.ts | 1 - .../weighted/exit.concern.integration.spec.ts | 2 +- .../weighted/join.concern.integration.spec.ts | 1 - .../bbausd2-migrations/bbausd1.integration.spec.ts | 14 ++++---------- balancer-js/src/test/lib/utils.ts | 4 ++-- balancer-js/yarn.lock | 8 ++++---- 10 files changed, 14 insertions(+), 22 deletions(-) diff --git a/balancer-js/package.json b/balancer-js/package.json index 0a1fb1d78..773156621 100644 --- a/balancer-js/package.json +++ b/balancer-js/package.json @@ -51,6 +51,7 @@ "@graphql-codegen/typescript-graphql-request": "^4.3.0", "@graphql-codegen/typescript-operations": "^2.2.0", "@graphql-codegen/typescript-resolvers": "2.4.1", + "@nomicfoundation/hardhat-network-helpers": "^1.0.4", "@nomiclabs/hardhat-ethers": "^2.0.5", "@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-json": "^4.1.0", diff --git a/balancer-js/src/modules/pools/pool-types/concerns/metaStable/exit.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/metaStable/exit.concern.integration.spec.ts index ffd4beb9d..4cc9bdb27 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/metaStable/exit.concern.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/metaStable/exit.concern.integration.spec.ts @@ -41,7 +41,7 @@ const pool = pools_14717479.find( const tokensOut = pool.tokens; const controller = Pools.wrap(pool, networkConfig); -describe('exit execution', async () => { +describe('exit meta stable pools execution', async () => { let amountsOut: string[]; let transactionReceipt: TransactionReceipt; let bptBalanceBefore: BigNumber; diff --git a/balancer-js/src/modules/pools/pool-types/concerns/metaStable/join.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/metaStable/join.concern.integration.spec.ts index a22b360f4..d4a8ce8b6 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/metaStable/join.concern.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/metaStable/join.concern.integration.spec.ts @@ -71,7 +71,6 @@ describe('join execution', async () => { slots, balances, jsonRpcUrl as string, - false, 14717479 // holds the same state as the static repository ); signerAddress = await signer.getAddress(); diff --git a/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.integration.spec.ts index d202582ce..a13d3f2ff 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.integration.spec.ts @@ -40,7 +40,7 @@ const pool = pools_14717479.find( const tokensOut = pool.tokens; const controller = Pools.wrap(pool, networkConfig); -describe('exit execution', async () => { +describe('exit stable pools execution', async () => { let amountsOut: string[]; let transactionReceipt: TransactionReceipt; let bptBalanceBefore: BigNumber; diff --git a/balancer-js/src/modules/pools/pool-types/concerns/stable/join.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/stable/join.concern.integration.spec.ts index f841b504d..aeabe9c48 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/stable/join.concern.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/stable/join.concern.integration.spec.ts @@ -75,7 +75,6 @@ describe('join execution', async () => { slots, balances, jsonRpcUrl as string, - false, 14717479 // holds the same state as the static repository ); signerAddress = await signer.getAddress(); diff --git a/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.integration.spec.ts index 56ed1d6a5..111061ed1 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.integration.spec.ts @@ -53,7 +53,7 @@ let tokensMinBalanceIncrease: BigNumber[]; let transactionCost: BigNumber; let signerAddress: string; -describe('exit execution', async () => { +describe('exit weighted pools execution', async () => { // Setup chain before(async function () { this.timeout(20000); diff --git a/balancer-js/src/modules/pools/pool-types/concerns/weighted/join.concern.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/weighted/join.concern.integration.spec.ts index 06f5c1f2e..e54748587 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/weighted/join.concern.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/weighted/join.concern.integration.spec.ts @@ -73,7 +73,6 @@ describe('join execution', async () => { slots, balances, jsonRpcUrl as string, - false, 14717479 // holds the same state as the static repository ); signerAddress = await signer.getAddress(); 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 index 9ad622ff0..b1fd7f86d 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -4,11 +4,10 @@ import hardhat from 'hardhat'; import { BalancerError, BalancerErrorCode, + BalancerSDK, Network, RelayerAuthorization, PoolModel, - Subgraph, - SubgraphPoolRepository, } from '@/.'; import { BigNumber, parseFixed } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; @@ -16,7 +15,6 @@ import { ADDRESSES } from './addresses'; import { JsonRpcSigner } from '@ethersproject/providers'; import { MaxUint256, WeiPerEther } from '@ethersproject/constants'; import { Migrations } from '../migrations'; -import { PoolsProvider } from '@/modules/pools/provider'; import { getErc20Balance, move, stake } from '@/test/lib/utils'; dotenv.config(); @@ -125,15 +123,11 @@ describe('bbausd migration execution', async () => { provider ); - const config = { + const sdk = new BalancerSDK({ network, rpcUrl, - }; - const subgraph = new Subgraph(config); - const pools = new PoolsProvider( - config, - new SubgraphPoolRepository(subgraph.client) - ); + }); + const { pools } = sdk; await pools.findBy('address', fromPool.address).then((res) => { if (!res) throw new BalancerError(BalancerErrorCode.POOL_DOESNT_EXIST); pool = res; diff --git a/balancer-js/src/test/lib/utils.ts b/balancer-js/src/test/lib/utils.ts index f67849b17..69883d950 100644 --- a/balancer-js/src/test/lib/utils.ts +++ b/balancer-js/src/test/lib/utils.ts @@ -30,8 +30,8 @@ export const forkSetup = async ( slots: number[], balances: string[], jsonRpcUrl: string, - isVyperMapping = false, - blockNumber?: number + blockNumber?: number, + isVyperMapping = false ): Promise => { await signer.provider.send('hardhat_reset', [ { diff --git a/balancer-js/yarn.lock b/balancer-js/yarn.lock index a019d27d8..4c46f2dca 100644 --- a/balancer-js/yarn.lock +++ b/balancer-js/yarn.lock @@ -483,7 +483,7 @@ "@babel/helper-validator-identifier" "^7.18.6" to-fast-properties "^2.0.0" -"@balancer-labs/sor@^4.0.1-beta.4": +"@balancer-labs/sor@^4.0.1-beta.3": version "4.0.1-beta.4" resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.0.1-beta.4.tgz#284b81123e90f2d29ae032cf5c03110de94eff39" integrity sha512-5HPxdleLcQe2uVW8f1QJxyXo502CTW9BaR0oGTgbGicos34YrmxwlDIvplssiCXSPhVbWp24WGi8/pc54C84Cg== @@ -1451,9 +1451,9 @@ fastq "^1.6.0" "@nomicfoundation/hardhat-network-helpers@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.4.tgz#265e807818b727c50dc6f115ee951e5c25cfe67f" - integrity sha512-bgS1HtuPZxOzEsQsF6jxfoOMQXKRlddsoJPT8dBNH1Pgpv9Y8AUQ3ecQk4ujAw9EOdTE1xAL4u7S6Gu4p3DO+Q== + version "1.0.6" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.6.tgz#5e2026ddde5ca539f70a2bf498528afd08bd0827" + integrity sha512-a35iVD4ycF6AoTfllAnKm96IPIzzHpgKX/ep4oKc2bsUKFfMlacWdyntgC/7d5blyCTXfFssgNAvXDZfzNWVGQ== dependencies: ethereumjs-util "^7.1.4" From 86d9768561b4f25a5c555dc95eb99980698bed1f Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 8 Sep 2022 09:59:15 -0300 Subject: [PATCH 092/104] Remove 20s timeout from tests since it is now the default value --- .../bbausd1.integration.spec.ts | 19 ++++++++----------- .../maiusd.integration.spec.ts | 19 ++++++++----------- .../stabal3.integration.spec.ts | 19 ++++++++----------- .../stables.integration.spec.ts | 19 ++++++++----------- 4 files changed, 32 insertions(+), 44 deletions(-) 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 index b1fd7f86d..1e17e86a1 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -107,8 +107,6 @@ describe('bbausd migration execution', async () => { let pool: PoolModel; beforeEach(async function () { - this.timeout(20000); - await reset(); signer = provider.getSigner(); @@ -211,14 +209,13 @@ describe('bbausd migration execution', async () => { context('staked', async () => { beforeEach(async function () { - this.timeout(20000); // 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'); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; @@ -228,13 +225,13 @@ describe('bbausd migration execution', async () => { errorMessage = (error as Error).message; } expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }).timeout(20000); + }); }); context('not staked', async () => { it('should transfer tokens from stable to boosted - using exact bbausd2AmountOut from static call', async () => { await testFlow(false, undefined, '0'); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; @@ -244,7 +241,7 @@ describe('bbausd migration execution', async () => { errorMessage = (error as Error).message; } expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }).timeout(20000); + }); }); context('authorisation', async () => { @@ -260,7 +257,7 @@ describe('bbausd migration execution', async () => { data: approval, }); await testFlow(false, false, '0'); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - auhtorisation should fail', async () => { let errorMessage = ''; @@ -270,6 +267,6 @@ describe('bbausd migration execution', async () => { 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 - }).timeout(20000); - }).timeout(20000); -}).timeout(20000); + }); + }); +}); 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 index eb5e9d5f2..936ee658a 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts @@ -89,7 +89,6 @@ describe('maiusd migration execution', async () => { let balance: BigNumber; beforeEach(async function () { - this.timeout(20000); await reset(); signer = provider.getSigner(); @@ -172,15 +171,13 @@ describe('maiusd migration execution', async () => { context('staked', async () => { beforeEach(async function () { - this.timeout(20000); - // Stake them await stake(signer, fromPool.address, fromPool.gauge, balance); }); it('should transfer tokens from stable to boosted', async () => { bptOut = await testFlow(true); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; @@ -190,13 +187,13 @@ describe('maiusd migration execution', async () => { errorMessage = (error as Error).message; } expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }).timeout(20000); + }); }); context('not staked', async () => { it('should transfer tokens from stable to boosted', async () => { bptOut = await testFlow(false); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; @@ -206,7 +203,7 @@ describe('maiusd migration execution', async () => { errorMessage = (error as Error).message; } expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }).timeout(20000); + }); }); context('authorisation', async () => { @@ -222,7 +219,7 @@ describe('maiusd migration execution', async () => { data: approval, }); await testFlow(false, false); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - auhtorisation should fail', async () => { let errorMessage = ''; @@ -232,6 +229,6 @@ describe('maiusd migration execution', async () => { 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 - }).timeout(20000); - }).timeout(20000); -}).timeout(20000); + }); + }); +}); 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 index 261980d6b..3b1d5dcc5 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -100,7 +100,6 @@ describe('stabal3 migration execution', async () => { let balance: BigNumber; beforeEach(async function () { - this.timeout(20000); await reset(); signer = provider.getSigner(); @@ -181,15 +180,13 @@ describe('stabal3 migration execution', async () => { context('staked', async () => { beforeEach(async function () { - this.timeout(20000); - // Stake them await stake(signer, fromPool.address, fromPool.gauge, balance); }); it('should transfer tokens from stable to boosted', async () => { bptOut = await testFlow(true); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; @@ -199,13 +196,13 @@ describe('stabal3 migration execution', async () => { errorMessage = (error as Error).message; } expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }).timeout(20000); + }); }); context('not staked', async () => { it('should transfer tokens from stable to boosted', async () => { bptOut = await testFlow(false); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; @@ -215,7 +212,7 @@ describe('stabal3 migration execution', async () => { errorMessage = (error as Error).message; } expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }).timeout(20000); + }); }); context('authorisation', async () => { @@ -231,7 +228,7 @@ describe('stabal3 migration execution', async () => { data: approval, }); await testFlow(false, false); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - auhtorisation should fail', async () => { let errorMessage = ''; @@ -241,6 +238,6 @@ describe('stabal3 migration execution', async () => { 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 - }).timeout(20000); - }).timeout(20000); -}).timeout(20000); + }); + }); +}); 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 index 9745057f7..a0aad61da 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -97,7 +97,6 @@ describe('stables migration execution', async () => { let balance: BigNumber; beforeEach(async function () { - this.timeout(20000); await reset(); signer = provider.getSigner(); @@ -190,15 +189,13 @@ describe('stables migration execution', async () => { context('staked', async () => { beforeEach(async function () { - this.timeout(20000); - // Stake them await stake(signer, fromPool.address, fromPool.gauge, balance); }); it('should transfer tokens from stable to boosted', async () => { bptOut = await testFlow(true); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; @@ -208,14 +205,14 @@ describe('stables migration execution', async () => { errorMessage = (error as Error).message; } expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }).timeout(20000); + }); }); context('not staked', async () => { it('should transfer tokens from stable to boosted', async () => { // Store balance before migration bptOut = await testFlow(false); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - limit should fail', async () => { let errorMessage = ''; @@ -225,7 +222,7 @@ describe('stables migration execution', async () => { errorMessage = (error as Error).message; } expect(errorMessage).to.contain('BAL#507'); // SWAP_LIMIT - Swap violates user-supplied limits (min out or max in) - }).timeout(20000); + }); }); context('authorisation', async () => { @@ -241,7 +238,7 @@ describe('stables migration execution', async () => { data: approval, }); await testFlow(false, false); - }).timeout(20000); + }); it('should transfer tokens from stable to boosted - auhtorisation should fail', async () => { let errorMessage = ''; @@ -251,6 +248,6 @@ describe('stables migration execution', async () => { 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 - }).timeout(20000); - }).timeout(20000); -}).timeout(20000); + }); + }); +}); From 78f4ff16c31fed0894966cf4d2cc31b45f12b79c Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 8 Sep 2022 10:37:40 -0300 Subject: [PATCH 093/104] Update bbausd2 pool address for mainnet --- .../src/modules/zaps/bbausd2-migrations/addresses.ts | 6 +++--- .../zaps/bbausd2-migrations/bbausd1.integration.spec.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 56d8a9261..e6dab93de 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -14,9 +14,9 @@ export const ADDRESSES = { assetOrder: ['bb-a-USDT', 'bb-a-DAI', 'bb-a-USDC'], }, bbausd2: { - id: '0x9B532AB955417AFD0D012EB9F7389457CD0EA712000000000000000000000338', - address: '0x9B532AB955417AFD0D012EB9F7389457CD0EA712', - gauge: '0x66122c9030030155fb2bbe2e1e9a72588065c4f5', + id: '0xa13a9247ea42d743238089903570127dda72fe4400000000000000000000035d', + address: '0xa13a9247ea42d743238089903570127dda72fe44', + gauge: '0xa6325e799d266632d347e41265a69af111b05403', }, linearUsdc1: { id: '0x9210f1204b5a24742eba12f710636d76240df3d00000000000000000000000fc', 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 index 1e17e86a1..af9d1ea61 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -39,7 +39,7 @@ const { ALCHEMY_URL: jsonRpcUrl } = process.env; * - Uncomment section below */ const network = Network.MAINNET; -const blockNumber = 15372650; +const blockNumber = 15496800; const holderAddress = '0xec576a26335de1c360d2fc9a68cba6ba37af4a13'; const { ethers } = hardhat; From 394be2d4a8b3b77f4c75e94f54037342d0982d5b Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 8 Sep 2022 16:17:43 -0300 Subject: [PATCH 094/104] Fix bbausd migration integration tests post merge --- .../zaps/bbausd2-migrations/bbausd1.integration.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index af9d1ea61..c602b35da 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.integration.spec.ts @@ -7,7 +7,7 @@ import { BalancerSDK, Network, RelayerAuthorization, - PoolModel, + PoolWithMethods, } from '@/.'; import { BigNumber, parseFixed } from '@ethersproject/bignumber'; import { Contracts } from '@/modules/contracts/contracts.module'; @@ -104,7 +104,7 @@ describe('bbausd migration execution', async () => { let signerAddress: string; let authorisation: string; let balance: BigNumber; - let pool: PoolModel; + let pool: PoolWithMethods; beforeEach(async function () { await reset(); From 2b8534f74df4f336e8e39655fa379388ac0e24a9 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 8 Sep 2022 16:19:34 -0300 Subject: [PATCH 095/104] Add polygon addresses for maibbausd migration tests --- .../zaps/bbausd2-migrations/addresses.ts | 63 +++++++++++++++++++ .../zaps/bbausd2-migrations/bbausd1.ts | 2 +- .../maiusd.integration.spec.ts | 25 +++++--- .../modules/zaps/bbausd2-migrations/maiusd.ts | 2 +- .../zaps/bbausd2-migrations/stabal3.ts | 2 +- .../zaps/bbausd2-migrations/stables.ts | 2 +- balancer-js/src/modules/zaps/migrations.ts | 2 +- 7 files changed, 86 insertions(+), 12 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index e6dab93de..82a47fac0 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -137,4 +137,67 @@ export const ADDRESSES = { waUSDT: '0x4cb1892fddf14f772b2e39e299f44b2e5da90d04', miMATIC: '0x398106564948feeb1fedea0709ae7d969d62a391', }, + 137: { + relayer: '0x4574ccBcC09A00C9eE55fB92Fe353699A4fA800e', + staBal3: { + id: '', + address: '', + gauge: '', + assetOrder: [], + }, + bbausd1: { + id: '', + address: '', + gauge: '', + assetOrder: [], + }, + 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.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts index 94dfe7864..a198d53b9 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/bbausd1.ts @@ -13,7 +13,7 @@ const SWAP_RESULT_BBAUSD = Relayer.toChainedReference('24'); export class BbaUsd1Builder { private addresses; - constructor(networkId: 1 | 5) { + constructor(networkId: 1 | 5 | 137) { this.addresses = ADDRESSES[networkId]; } 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 index 936ee658a..2da7b3cd2 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.integration.spec.ts @@ -14,18 +14,30 @@ import { getErc20Balance, move, stake } from '@/test/lib/utils'; * Testing on GOERLI * - Update hardhat.config.js with chainId = 5 * - Update ALCHEMY_URL on .env with a goerli api key - * - Run goerli node on terminal: yarn run node - * - Change `network` to Network.GOERLI - * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli + * - Run node on terminal: yarn run node + * - Uncomment section below */ +const network = Network.GOERLI; +const blockNumber = 7376670; +const holderAddress = '0x8fe3a2a5ae6baa201c26fc7830eb713f33d6b313'; + +/* + * Testing on POLYGON + * - Update hardhat.config.js with chainId = 137 + * - Update ALCHEMY_URL on .env with a goerli api key + * - Run node on terminal: yarn run node + * - Uncomment section below + */ +// const network = Network.POLYGON; +// const blockNumber = 32856000; +// const holderAddress = '0xfb0272990728a967ecaf702a1291fcd64c38ed25'; dotenv.config(); -const { ALCHEMY_URL: jsonRpcUrl, FORK_BLOCK_NUMBER: blockNumber } = process.env; +const { ALCHEMY_URL: jsonRpcUrl } = process.env; const { ethers } = hardhat; const MAX_GAS_LIMIT = 8e6; -const network = Network.GOERLI; const rpcUrl = 'http://127.0.0.1:8545'; const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const addresses = ADDRESSES[network]; @@ -42,7 +54,6 @@ const toPool = { const { contracts } = new Contracts(network as number, provider); const migrations = new Migrations(network); -const holderAddress = '0x8fe3a2a5ae6baa201c26fc7830eb713f33d6b313'; const relayer = addresses.relayer; const signRelayerApproval = async ( @@ -77,7 +88,7 @@ const reset = () => { forking: { jsonRpcUrl, - blockNumber: (blockNumber && parseInt(blockNumber)) || 7376670, + blockNumber, }, }, ]); diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts index 40b7281b1..d6789ba39 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/maiusd.ts @@ -20,7 +20,7 @@ const SWAP_RESULT = Relayer.toChainedReference('24'); export class MaiusdBuilder { private addresses; - constructor(networkId: 1 | 5) { + constructor(networkId: 1 | 5 | 137) { this.addresses = ADDRESSES[networkId]; } diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts index d935ffed9..32074ce5f 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.ts @@ -19,7 +19,7 @@ const SWAP_RESULT_BBAUSD = Relayer.toChainedReference('24'); export class StaBal3Builder { private addresses; - constructor(networkId: 1 | 5) { + constructor(networkId: 1 | 5 | 137) { this.addresses = ADDRESSES[networkId]; } diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts index fca1b0ae2..641f677f6 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.ts @@ -16,7 +16,7 @@ const EXIT_RESULTS: BigNumber[] = []; export class StablesBuilder { private addresses; - constructor(networkId: 1 | 5) { + constructor(networkId: 1 | 5 | 137) { this.addresses = ADDRESSES[networkId]; } diff --git a/balancer-js/src/modules/zaps/migrations.ts b/balancer-js/src/modules/zaps/migrations.ts index fa9f10e7e..29dfb9816 100644 --- a/balancer-js/src/modules/zaps/migrations.ts +++ b/balancer-js/src/modules/zaps/migrations.ts @@ -5,7 +5,7 @@ import { StablesBuilder } from './bbausd2-migrations/stables'; import { MaiusdBuilder } from './bbausd2-migrations/maiusd'; export class Migrations { - constructor(private network: 1 | 5) {} + constructor(private network: 1 | 5 | 137) {} /** * Builds migration call data. From 08e6636ee00e82c7163b66e696bbc8b91afcc4fb Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Thu, 8 Sep 2022 21:45:45 -0300 Subject: [PATCH 096/104] Update polygon relayer address --- balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 82a47fac0..66f1946a3 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -138,7 +138,7 @@ export const ADDRESSES = { miMATIC: '0x398106564948feeb1fedea0709ae7d969d62a391', }, 137: { - relayer: '0x4574ccBcC09A00C9eE55fB92Fe353699A4fA800e', + relayer: '0xcf6a66E32dCa0e26AcC3426b851FD8aCbF12Dac7', staBal3: { id: '', address: '', From 96346e038d05d1d0e10b45eb8830c666eced5661 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Fri, 9 Sep 2022 15:12:11 -0300 Subject: [PATCH 097/104] Fix yarn build issues --- balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts index 66f1946a3..d911d7f50 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/addresses.ts @@ -143,13 +143,13 @@ export const ADDRESSES = { id: '', address: '', gauge: '', - assetOrder: [], + assetOrder: ['USDT', 'DAI', 'USDC'], }, bbausd1: { id: '', address: '', gauge: '', - assetOrder: [], + assetOrder: ['bb-a-USDC', 'bb-a-DAI', 'bb-a-USDT'], }, bbausd2: { id: '0x48e6b98ef6329f8f0a30ebb8c7c960330d64808500000000000000000000075b', From ab3228266c95f4b250dfe903d92649591e7bb7f1 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Fri, 9 Sep 2022 16:02:50 -0300 Subject: [PATCH 098/104] Post merge fixes --- balancer-js/yarn.lock | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/balancer-js/yarn.lock b/balancer-js/yarn.lock index 14ff320d6..de065ea0f 100644 --- a/balancer-js/yarn.lock +++ b/balancer-js/yarn.lock @@ -1450,6 +1450,13 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@nomicfoundation/hardhat-network-helpers@^1.0.4": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.6.tgz#5e2026ddde5ca539f70a2bf498528afd08bd0827" + integrity sha512-a35iVD4ycF6AoTfllAnKm96IPIzzHpgKX/ep4oKc2bsUKFfMlacWdyntgC/7d5blyCTXfFssgNAvXDZfzNWVGQ== + dependencies: + ethereumjs-util "^7.1.4" + "@nomiclabs/hardhat-ethers@^2.0.5": version "2.1.1" resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.1.1.tgz#3f1d1ab49813d1bae4c035cc1adec224711e528b" From 5789d42cba2db5d8640ec2ce81afe9ad14ce94cb Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Mon, 12 Sep 2022 16:52:44 -0300 Subject: [PATCH 099/104] Add stMATIC and MaticX test cases on Polygon --- .../stables.integration.spec.ts | 85 ++++++++++++++----- 1 file changed, 62 insertions(+), 23 deletions(-) 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 index a0aad61da..0468cb767 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stables.integration.spec.ts @@ -10,48 +10,87 @@ import { MaxUint256 } from '@ethersproject/constants'; import { Migrations } from '../migrations'; import { getErc20Balance, move, stake } from '@/test/lib/utils'; +dotenv.config(); + /* * Testing on GOERLI * - Update hardhat.config.js with chainId = 5 * - Update ALCHEMY_URL on .env with a goerli api key - * - Run goerli node on terminal: yarn run node - * - Change `network` to Network.GOERLI - * - Provide gaugeAddresses from goerli which can be found on subgraph: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-gauges-goerli + * - Run node on terminal: yarn run node + * - Uncomment section below */ - -dotenv.config(); - -const { ALCHEMY_URL: jsonRpcUrl, FORK_BLOCK_NUMBER: blockNumber } = process.env; -const { ethers } = hardhat; -const MAX_GAS_LIMIT = 8e6; - const network = Network.GOERLI; -const rpcUrl = 'http://127.0.0.1:8545'; -const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network); const addresses = ADDRESSES[network]; -const { contracts } = new Contracts(network as number, provider); -const migrations = new Migrations(network); - +const blockNumber = 7300090; const holderAddress = '0xd86a11b0c859c18bfc1b4acd072c5afe57e79438'; +// stabal3 const fromPool = { id: addresses.staBal3.id, address: addresses.staBal3.address, gauge: addresses.staBal3.gauge, }; -// const holderAddress = '0xdc6bd6653ff82946bb94c1d243038c5abf14f2ea'; -// const fromPool = { -// id: addresses.staBal3_3.id, -// address: addresses.staBal3_3.address, -// gauge: addresses.staBal3_3.gauge, -// }; -// blocknumber = 7352236 +// 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 + * - Update hardhat.config.js with chainId = 137 + * - Update ALCHEMY_URL on .env with a goerli api key + * - 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 { ethers } = hardhat; +const MAX_GAS_LIMIT = 8e6; + +const rpcUrl = 'http://127.0.0.1:8545'; +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, @@ -85,7 +124,7 @@ const reset = () => { forking: { jsonRpcUrl, - blockNumber: (blockNumber && parseInt(blockNumber)) || 7300090, + blockNumber, }, }, ]); From 308e7745ab06efaa8d4e85c09502c528694a865d Mon Sep 17 00:00:00 2001 From: bronco Date: Tue, 13 Sep 2022 12:04:33 +0200 Subject: [PATCH 100/104] feat: composable stable pools --- .../src/modules/pools/pool-type-concerns.ts | 13 +- .../pool-types/composableStable.module.ts | 23 ++ .../composableStable/exit.concern.spec.ts | 47 ++++ .../concerns/composableStable/exit.concern.ts | 221 ++++++++++++++++++ .../pools/pool-types/concerns/types.ts | 22 +- .../src/pool-composable-stable/encoder.ts | 118 ++++++++++ .../src/pool-composable-stable/index.ts | 1 + balancer-js/src/types.ts | 1 + 8 files changed, 444 insertions(+), 2 deletions(-) create mode 100644 balancer-js/src/modules/pools/pool-types/composableStable.module.ts create mode 100644 balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.spec.ts create mode 100644 balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.ts create mode 100644 balancer-js/src/pool-composable-stable/encoder.ts create mode 100644 balancer-js/src/pool-composable-stable/index.ts diff --git a/balancer-js/src/modules/pools/pool-type-concerns.ts b/balancer-js/src/modules/pools/pool-type-concerns.ts index 4406537ed..1a3ce13df 100644 --- a/balancer-js/src/modules/pools/pool-type-concerns.ts +++ b/balancer-js/src/modules/pools/pool-type-concerns.ts @@ -1,5 +1,6 @@ import { BalancerSdkConfig, PoolType } from '@/types'; import { Stable } from './pool-types/stable.module'; +import { ComposableStable } from './pool-types/composableStable.module'; import { Weighted } from './pool-types/weighted.module'; import { MetaStable } from './pool-types/metaStable.module'; import { StablePhantom } from './pool-types/stablePhantom.module'; @@ -16,6 +17,7 @@ export class PoolTypeConcerns { config: BalancerSdkConfig, public weighted = new Weighted(), public stable = new Stable(), + public composableStable = new ComposableStable(), public metaStable = new MetaStable(), public stablePhantom = new StablePhantom(), public linear = new Linear() @@ -23,7 +25,13 @@ export class PoolTypeConcerns { static from( poolType: PoolType - ): Weighted | Stable | MetaStable | StablePhantom | Linear { + ): + | Weighted + | Stable + | ComposableStable + | MetaStable + | StablePhantom + | Linear { // Calculate spot price using pool type switch (poolType) { case 'Weighted': @@ -34,6 +42,9 @@ export class PoolTypeConcerns { case 'Stable': { return new Stable(); } + case 'ComposableStable': { + return new ComposableStable(); + } case 'MetaStable': { return new MetaStable(); } diff --git a/balancer-js/src/modules/pools/pool-types/composableStable.module.ts b/balancer-js/src/modules/pools/pool-types/composableStable.module.ts new file mode 100644 index 000000000..e39949d83 --- /dev/null +++ b/balancer-js/src/modules/pools/pool-types/composableStable.module.ts @@ -0,0 +1,23 @@ +import { StablePoolJoin } from './concerns/stable/join.concern'; +import { StablePoolLiquidity } from './concerns/stable/liquidity.concern'; +import { StablePoolSpotPrice } from './concerns/stable/spotPrice.concern'; +import { StablePoolPriceImpact } from './concerns/stable/priceImpact.concern'; +import { ComposableStablePoolExit } from './concerns/composableStable/exit.concern'; +import { PoolType } from './pool-type.interface'; +import { + ExitConcern, + JoinConcern, + LiquidityConcern, + PriceImpactConcern, + SpotPriceConcern, +} from './concerns/types'; + +export class ComposableStable implements PoolType { + constructor( + public exit: ExitConcern = new ComposableStablePoolExit(), + public join: JoinConcern = new StablePoolJoin(), + public liquidity: LiquidityConcern = new StablePoolLiquidity(), + public spotPriceCalculator: SpotPriceConcern = new StablePoolSpotPrice(), + public priceImpactCalculator: PriceImpactConcern = new StablePoolPriceImpact() + ) {} +} 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 new file mode 100644 index 000000000..aff3b6ee5 --- /dev/null +++ b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.spec.ts @@ -0,0 +1,47 @@ +import { expect } from 'chai'; +import { parseFixed } from '@ethersproject/bignumber'; +import { AddressZero } from '@ethersproject/constants'; + +import { BalancerSDK, Network, Pool } from '@/.'; +import pools_14717479 from '@/test/lib/pools_14717479.json'; +import { ComposableStablePoolExit } from './exit.concern'; + +const concern = new ComposableStablePoolExit(); + +const rpcUrl = ''; +const network = Network.MAINNET; +const { networkConfig } = new BalancerSDK({ network, rpcUrl }); +const wrappedNativeAsset = + networkConfig.addresses.tokens.wrappedNativeAsset.toLowerCase(); + +const pool = pools_14717479.find( + (pool) => + pool.id == + '0x06df3b2bbb68adc8b0e302443692037ed9f91b42000000000000000000000063' // Balancer USD Stable Pool - staBAL3 +) as unknown as Pool; + +describe('exit module', () => { + describe('buildExitExactBPTIn', () => { + context('exit with ETH', () => { + it('should fail due to conflicting inputs', () => { + let errorMessage = ''; + try { + concern.buildExitSingleTokenOut({ + exiter: '0x35f5a330FD2F8e521ebd259FA272bA8069590741', + pool, + bptIn: parseFixed('10', 18).toString(), + slippage: '100', // 100 bps + shouldUnwrapNativeAsset: false, + wrappedNativeAsset, + singleTokenMaxOut: AddressZero, + }); + } catch (error) { + errorMessage = (error as Error).message; + } + expect(errorMessage).to.eql( + 'shouldUnwrapNativeAsset and singleTokenMaxOut should not have conflicting values' + ); + }); + }); + }); +}); 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 new file mode 100644 index 000000000..e9cf66737 --- /dev/null +++ b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/exit.concern.ts @@ -0,0 +1,221 @@ +import { BigNumber, parseFixed } from '@ethersproject/bignumber'; +import { AddressZero } from '@ethersproject/constants'; +import * as SOR from '@balancer-labs/sor'; +import { + ExitConcern, + ExitExactBPTInSingleTokenOutParameters, + ExitExactTokensOutParameters, + ExitPool, + ExitPoolAttributes, +} from '../types'; +import { AssetHelpers, parsePoolInfo } from '@/lib/utils'; +import { Vault__factory } from '@balancer-labs/typechain'; +import { addSlippage, subSlippage } from '@/lib/utils/slippageHelper'; +import { balancerVault } from '@/lib/constants/config'; +import { BalancerError, BalancerErrorCode } from '@/balancerErrors'; +import { ComposableStablePoolEncoder } from '@/pool-composable-stable'; + +export class ComposableStablePoolExit implements ExitConcern { + buildExitSingleTokenOut = ({ + exiter, + pool, + bptIn, + slippage, + shouldUnwrapNativeAsset, + wrappedNativeAsset, + singleTokenMaxOut, + }: ExitExactBPTInSingleTokenOutParameters): ExitPoolAttributes => { + if (!bptIn.length || parseFixed(bptIn, 18).isNegative()) { + throw new BalancerError(BalancerErrorCode.INPUT_OUT_OF_BOUNDS); + } + if ( + singleTokenMaxOut && + singleTokenMaxOut !== AddressZero && + !pool.tokens.map((t) => t.address).some((a) => a === singleTokenMaxOut) + ) { + throw new BalancerError(BalancerErrorCode.TOKEN_MISMATCH); + } + + if (!shouldUnwrapNativeAsset && singleTokenMaxOut === AddressZero) + throw new Error( + 'shouldUnwrapNativeAsset and singleTokenMaxOut should not have conflicting values' + ); + + // Check if there's any relevant stable pool info missing + if (pool.tokens.some((token) => !token.decimals)) + throw new BalancerError(BalancerErrorCode.MISSING_DECIMALS); + if (!pool.amp) throw new BalancerError(BalancerErrorCode.MISSING_AMP); + + // Parse pool info into EVM amounts in order to match amountsIn scalling + const { + parsedTokens, + parsedBalances, + parsedAmp, + parsedTotalShares, + parsedSwapFee, + } = parsePoolInfo(pool); + + // Replace WETH address with ETH - required for exiting with ETH + const unwrappedTokens = parsedTokens.map((token) => + token === wrappedNativeAsset ? AddressZero : token + ); + + // Sort pool info based on tokens addresses + const assetHelpers = new AssetHelpers(wrappedNativeAsset); + const [sortedTokens, sortedBalances] = assetHelpers.sortTokens( + shouldUnwrapNativeAsset ? unwrappedTokens : parsedTokens, + parsedBalances + ) as [string[], string[]]; + + const minAmountsOut = Array(parsedTokens.length).fill('0'); + + // Exit pool with single token using exact bptIn + const singleTokenMaxOutIndex = parsedTokens.indexOf(singleTokenMaxOut); + + // Calculate amount out given BPT in + const amountOut = SOR.StableMathBigInt._calcTokenOutGivenExactBptIn( + BigInt(parsedAmp as string), + sortedBalances.map((b) => BigInt(b)), + singleTokenMaxOutIndex, + BigInt(bptIn), + BigInt(parsedTotalShares), + BigInt(parsedSwapFee) + ).toString(); + + // Apply slippage tolerance + minAmountsOut[singleTokenMaxOutIndex] = subSlippage( + BigNumber.from(amountOut), + BigNumber.from(slippage) + ).toString(); + + const userData = ComposableStablePoolEncoder.exitExactBPTInForOneTokenOut( + bptIn, + singleTokenMaxOutIndex + ); + + const to = balancerVault; + const functionName = 'exitPool'; + const attributes: ExitPool = { + poolId: pool.id, + sender: exiter, + recipient: exiter, + exitPoolRequest: { + assets: sortedTokens, + minAmountsOut, + userData, + toInternalBalance: false, + }, + }; + + // Encode transaction data into an ABI byte string which can be sent to the network to be executed + const vaultInterface = Vault__factory.createInterface(); + const data = vaultInterface.encodeFunctionData(functionName, [ + attributes.poolId, + attributes.sender, + attributes.recipient, + attributes.exitPoolRequest, + ]); + + return { + to, + functionName, + attributes, + data, + minAmountsOut, + maxBPTIn: bptIn, + }; + }; + + buildExitExactTokensOut = ({ + exiter, + pool, + tokensOut, + amountsOut, + slippage, + wrappedNativeAsset, + }: ExitExactTokensOutParameters): ExitPoolAttributes => { + if ( + tokensOut.length != amountsOut.length || + tokensOut.length != pool.tokensList.length + ) { + throw new BalancerError(BalancerErrorCode.INPUT_LENGTH_MISMATCH); + } + + // Check if there's any relevant stable pool info missing + if (pool.tokens.some((token) => !token.decimals)) + throw new BalancerError(BalancerErrorCode.MISSING_DECIMALS); + if (!pool.amp) throw new BalancerError(BalancerErrorCode.MISSING_AMP); + + // Parse pool info into EVM amounts in order to match amountsOut scalling + const { + parsedTokens, + parsedBalances, + parsedAmp, + parsedTotalShares, + parsedSwapFee, + } = parsePoolInfo(pool); + + // Sort pool info based on tokens addresses + const assetHelpers = new AssetHelpers(wrappedNativeAsset); + const [, sortedBalances] = assetHelpers.sortTokens( + parsedTokens, + parsedBalances + ) as [string[], string[]]; + const [sortedTokens, sortedAmounts] = assetHelpers.sortTokens( + tokensOut, + amountsOut + ) as [string[], string[]]; + + // Calculate expected BPT in given tokens out + const bptIn = SOR.StableMathBigInt._calcBptInGivenExactTokensOut( + BigInt(parsedAmp as string), + sortedBalances.map((b) => BigInt(b)), + sortedAmounts.map((a) => BigInt(a)), + BigInt(parsedTotalShares), + BigInt(parsedSwapFee) + ).toString(); + + // Apply slippage tolerance + const maxBPTIn = addSlippage( + BigNumber.from(bptIn), + BigNumber.from(slippage) + ).toString(); + + const userData = ComposableStablePoolEncoder.exitBPTInForExactTokensOut( + sortedAmounts, + maxBPTIn + ); + + const to = balancerVault; + const functionName = 'exitPool'; + const attributes: ExitPool = { + poolId: pool.id, + sender: exiter, + recipient: exiter, + exitPoolRequest: { + assets: sortedTokens, + minAmountsOut: sortedAmounts, + userData, + toInternalBalance: false, + }, + }; + + // encode transaction data into an ABI byte string which can be sent to the network to be executed + const vaultInterface = Vault__factory.createInterface(); + const data = vaultInterface.encodeFunctionData(functionName, [ + attributes.poolId, + attributes.sender, + attributes.recipient, + attributes.exitPoolRequest, + ]); + + return { + to, + functionName, + attributes, + data, + minAmountsOut: sortedAmounts, + maxBPTIn, + }; + }; +} 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 1878c0eab..d7f02e6b3 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/types.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/types.ts @@ -42,7 +42,7 @@ export interface ExitConcern { * @param singleTokenMaxOut Optional: token address that if provided will exit to given token * @returns transaction request ready to send with signer.sendTransaction */ - buildExitExactBPTIn: ({ + buildExitExactBPTIn?: ({ exiter, pool, bptIn, @@ -70,6 +70,16 @@ export interface ExitConcern { slippage, wrappedNativeAsset, }: ExitExactTokensOutParameters) => ExitPoolAttributes; + + buildExitSingleTokenOut?: ({ + exiter, + pool, + bptIn, + slippage, + shouldUnwrapNativeAsset, + wrappedNativeAsset, + singleTokenMaxOut, + }: ExitExactBPTInSingleTokenOutParameters) => ExitPoolAttributes; } export interface JoinPool { @@ -123,6 +133,16 @@ export interface ExitExactBPTInParameters { singleTokenMaxOut?: string; } +export interface ExitExactBPTInSingleTokenOutParameters { + exiter: string; + pool: Pool; + bptIn: string; + slippage: string; + shouldUnwrapNativeAsset: boolean; + wrappedNativeAsset: string; + singleTokenMaxOut: string; +} + export interface ExitExactTokensOutParameters { exiter: string; pool: Pool; diff --git a/balancer-js/src/pool-composable-stable/encoder.ts b/balancer-js/src/pool-composable-stable/encoder.ts new file mode 100644 index 000000000..b7702016f --- /dev/null +++ b/balancer-js/src/pool-composable-stable/encoder.ts @@ -0,0 +1,118 @@ +import { defaultAbiCoder } from '@ethersproject/abi'; +import { BigNumberish } from '@ethersproject/bignumber'; + +export enum ComposableStablePoolJoinKind { + INIT = 0, + EXACT_TOKENS_IN_FOR_BPT_OUT, + TOKEN_IN_FOR_EXACT_BPT_OUT, +} + +export enum StablePhantomPoolJoinKind { + INIT = 0, + COLLECT_PROTOCOL_FEES, +} + +export enum ComposableStablePoolExitKind { + EXACT_BPT_IN_FOR_ONE_TOKEN_OUT = 0, + BPT_IN_FOR_EXACT_TOKENS_OUT, +} + +export class ComposableStablePoolEncoder { + /** + * Cannot be constructed. + */ + private constructor() { + // eslint-disable-next-line @typescript-eslint/no-empty-function + } + + /** + * Encodes the userData parameter for providing the initial liquidity to a ComposableStablePool + * @param initialBalances - the amounts of tokens to send to the pool to form the initial balances + */ + static joinInit = (amountsIn: BigNumberish[]): string => + defaultAbiCoder.encode( + ['uint256', 'uint256[]'], + [ComposableStablePoolJoinKind.INIT, amountsIn] + ); + + /** + * Encodes the userData parameter for collecting protocol fees for StablePhantomPool + */ + static joinCollectProtocolFees = (): string => + defaultAbiCoder.encode( + ['uint256'], + [StablePhantomPoolJoinKind.COLLECT_PROTOCOL_FEES] + ); + + /** + * Encodes the userData parameter for joining a ComposableStablePool with exact token inputs + * @param amountsIn - the amounts each of token to deposit in the pool as liquidity + * @param minimumBPT - the minimum acceptable BPT to receive in return for deposited tokens + */ + static joinExactTokensInForBPTOut = ( + amountsIn: BigNumberish[], + minimumBPT: BigNumberish + ): string => + defaultAbiCoder.encode( + ['uint256', 'uint256[]', 'uint256'], + [ + ComposableStablePoolJoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT, + amountsIn, + minimumBPT, + ] + ); + + /** + * Encodes the userData parameter for joining a ComposableStablePool with to receive an exact amount of BPT + * @param bptAmountOut - the amount of BPT to be minted + * @param enterTokenIndex - the index of the token to be provided as liquidity + */ + static joinTokenInForExactBPTOut = ( + bptAmountOut: BigNumberish, + enterTokenIndex: number + ): string => + defaultAbiCoder.encode( + ['uint256', 'uint256', 'uint256'], + [ + ComposableStablePoolJoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT, + bptAmountOut, + enterTokenIndex, + ] + ); + + /** + * Encodes the userData parameter for exiting a ComposableStablePool by removing a single token in return for an exact amount of BPT + * @param bptAmountIn - the amount of BPT to be burned + * @param enterTokenIndex - the index of the token to removed from the pool + */ + static exitExactBPTInForOneTokenOut = ( + bptAmountIn: BigNumberish, + exitTokenIndex: number + ): string => + defaultAbiCoder.encode( + ['uint256', 'uint256', 'uint256'], + [ + ComposableStablePoolExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT, + bptAmountIn, + exitTokenIndex, + ] + ); + + /** + * Encodes the userData parameter for exiting a ComposableStablePool by removing exact amounts of tokens + * @param amountsOut - the amounts of each token to be withdrawn from the pool + * @param maxBPTAmountIn - the minimum acceptable BPT to burn in return for withdrawn tokens + */ + static exitBPTInForExactTokensOut = ( + amountsOut: BigNumberish[], + maxBPTAmountIn: BigNumberish + ): string => + defaultAbiCoder.encode( + ['uint256', 'uint256[]', 'uint256'], + [ + ComposableStablePoolExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT, + amountsOut, + maxBPTAmountIn, + ] + ); +} diff --git a/balancer-js/src/pool-composable-stable/index.ts b/balancer-js/src/pool-composable-stable/index.ts new file mode 100644 index 000000000..ff34a8a27 --- /dev/null +++ b/balancer-js/src/pool-composable-stable/index.ts @@ -0,0 +1 @@ +export * from './encoder'; diff --git a/balancer-js/src/types.ts b/balancer-js/src/types.ts index 35281359b..0c7a3bea6 100644 --- a/balancer-js/src/types.ts +++ b/balancer-js/src/types.ts @@ -196,6 +196,7 @@ export enum PoolType { Weighted = 'Weighted', Investment = 'Investment', Stable = 'Stable', + ComposableStable = 'ComposableStable', MetaStable = 'MetaStable', StablePhantom = 'StablePhantom', LiquidityBootstrapping = 'LiquidityBootstrapping', From ea377657eadd1ee76167ac91b32bf62f939b8326 Mon Sep 17 00:00:00 2001 From: bronco Date: Tue, 13 Sep 2022 12:15:36 +0200 Subject: [PATCH 101/104] fix: handle unsupported ExitExactBPTIn --- balancer-js/src/modules/pools/index.ts | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/balancer-js/src/modules/pools/index.ts b/balancer-js/src/modules/pools/index.ts index 2826c7601..ec14c5197 100644 --- a/balancer-js/src/modules/pools/index.ts +++ b/balancer-js/src/modules/pools/index.ts @@ -101,16 +101,21 @@ export class Pools implements Findable { slippage, shouldUnwrapNativeAsset = false, singleTokenMaxOut - ) => - methods.exit.buildExitExactBPTIn({ - exiter, - pool, - bptIn, - slippage, - shouldUnwrapNativeAsset, - wrappedNativeAsset, - singleTokenMaxOut, - }), + ) => { + if (methods.exit.buildExitExactBPTIn) { + return methods.exit.buildExitExactBPTIn({ + exiter, + pool, + bptIn, + slippage, + shouldUnwrapNativeAsset, + wrappedNativeAsset, + singleTokenMaxOut, + }); + } else { + throw 'ExitExactBPTIn not supported'; + } + }, buildExitExactTokensOut: (exiter, tokensOut, amountsOut, slippage) => methods.exit.buildExitExactTokensOut({ exiter, From 2d997d6a93dff16b5fd8067e4aae4f347c216e48 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Tue, 13 Sep 2022 11:56:44 +0100 Subject: [PATCH 102/104] Update blockno and add slippage. --- .../stabal3.integration.spec.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) 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 index 3b1d5dcc5..6b73b1e92 100644 --- a/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts +++ b/balancer-js/src/modules/zaps/bbausd2-migrations/stabal3.integration.spec.ts @@ -9,6 +9,7 @@ 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; @@ -33,7 +34,7 @@ const { ALCHEMY_URL: jsonRpcUrl } = process.env; */ const network = Network.MAINNET; const holderAddress = '0xf346592803eb47cb8d8fa9f90b0ef17a82f877e0'; -const blockNumber = 15372650; +const blockNumber = 15526452; const { ethers } = hardhat; const MAX_GAS_LIMIT = 8e6; @@ -146,12 +147,17 @@ describe('stabal3 migration execution', async () => { data: query.data, gasLimit, }); - const bptOut = query.decode(staticResult, staked); + 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 : bptOut, + minBptOut ? minBptOut : expectedWithSlippage.toString(), staked, authorised ? authorisation : undefined ); @@ -170,10 +176,10 @@ describe('stabal3 migration execution', async () => { to: await getErc20Balance(addressOut, provider, signerAddress), }; - expect(BigNumber.from(bptOut).gt(0)).to.be.true; + expect(BigNumber.from(expectedBptOut).gt(0)).to.be.true; expect(after.from.toString()).to.eq('0'); - expect(after.to.toString()).to.eq(bptOut); - return bptOut; + expect(after.to.gte(expectedWithSlippage)).to.be.true; + return expectedBptOut; } let bptOut: string; From bb2d3ad973b2087396d065e312623ff93c96c4db Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Tue, 13 Sep 2022 14:12:28 +0100 Subject: [PATCH 103/104] Expose ComposableStable encoder. --- balancer-js/src/index.ts | 1 + balancer-js/src/pool-composable-stable/encoder.ts | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/balancer-js/src/index.ts b/balancer-js/src/index.ts index 2ac3ad315..9e81badc1 100644 --- a/balancer-js/src/index.ts +++ b/balancer-js/src/index.ts @@ -1,5 +1,6 @@ export * from './pool-stable'; export * from './pool-weighted'; +export * from './pool-composable-stable'; export * from './pool-utils'; export * from './lib/utils'; export * from './types'; diff --git a/balancer-js/src/pool-composable-stable/encoder.ts b/balancer-js/src/pool-composable-stable/encoder.ts index b7702016f..f8c71f5d0 100644 --- a/balancer-js/src/pool-composable-stable/encoder.ts +++ b/balancer-js/src/pool-composable-stable/encoder.ts @@ -1,5 +1,6 @@ import { defaultAbiCoder } from '@ethersproject/abi'; import { BigNumberish } from '@ethersproject/bignumber'; +import { StablePhantomPoolJoinKind } from '../pool-stable/index'; export enum ComposableStablePoolJoinKind { INIT = 0, @@ -7,11 +8,6 @@ export enum ComposableStablePoolJoinKind { TOKEN_IN_FOR_EXACT_BPT_OUT, } -export enum StablePhantomPoolJoinKind { - INIT = 0, - COLLECT_PROTOCOL_FEES, -} - export enum ComposableStablePoolExitKind { EXACT_BPT_IN_FOR_ONE_TOKEN_OUT = 0, BPT_IN_FOR_EXACT_TOKENS_OUT, From 32feab270b7f87dafe37e885ff49cac778d458a9 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Tue, 20 Sep 2022 17:15:43 +0100 Subject: [PATCH 104/104] Update version to 0.1.24 --- balancer-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balancer-js/package.json b/balancer-js/package.json index 2a14023fd..48b10046f 100644 --- a/balancer-js/package.json +++ b/balancer-js/package.json @@ -1,6 +1,6 @@ { "name": "@balancer-labs/sdk", - "version": "0.1.23", + "version": "0.1.24", "description": "JavaScript SDK for interacting with the Balancer Protocol V2", "license": "GPL-3.0-only", "homepage": "https://github.com/balancer-labs/balancer-sdk/balancer-js#readme",