From 0b27b231cc0689513cacd3db6198509a0c815484 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 25 Aug 2023 12:32:53 +0200 Subject: [PATCH 01/12] fix: acknowledge query.args.first --- balancer-js/src/modules/data/pool/subgraph.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/balancer-js/src/modules/data/pool/subgraph.ts b/balancer-js/src/modules/data/pool/subgraph.ts index cfc963b7a..869c195a9 100644 --- a/balancer-js/src/modules/data/pool/subgraph.ts +++ b/balancer-js/src/modules/data/pool/subgraph.ts @@ -107,7 +107,9 @@ export class PoolsSubgraphRepository this.query.args.block = { number: await this.blockHeight() }; } - this.query.args.first = options?.first || 1000; + this.query.args.first = options?.first + ? options?.first + : this.query.args.first || 1000; const formattedQuery = new GraphQLArgsBuilder(this.query.args).format( new SubgraphArgsFormatter() From 81a7f8b53f332edcea29ba457b337a77041c2003 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 25 Aug 2023 17:58:50 +0200 Subject: [PATCH 02/12] fix: remove pool in recovery from specs --- .../pools/queries/queries.integration.spec.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/balancer-js/src/modules/pools/queries/queries.integration.spec.ts b/balancer-js/src/modules/pools/queries/queries.integration.spec.ts index c926f6252..efaf3be34 100644 --- a/balancer-js/src/modules/pools/queries/queries.integration.spec.ts +++ b/balancer-js/src/modules/pools/queries/queries.integration.spec.ts @@ -40,21 +40,21 @@ const composableStablePool = { ], }; -const composableStablePoolWithTokenAtZero = { - id: '0x02d928e68d8f10c0358566152677db51e1e2dc8c00000000000000000000051e', - poolType: PoolType.ComposableStable, - tokensList: [ - '0x02d928e68d8f10c0358566152677db51e1e2dc8c', - '0x60d604890feaa0b5460b28a424407c24fe89374a', - '0xf951e335afb289353dc249e82926178eac7ded78', - ], -}; +// const composableStablePoolWithTokenAtZero = { +// id: '0x02d928e68d8f10c0358566152677db51e1e2dc8c00000000000000000000051e', +// poolType: PoolType.ComposableStable, +// tokensList: [ +// '0x02d928e68d8f10c0358566152677db51e1e2dc8c', +// '0x60d604890feaa0b5460b28a424407c24fe89374a', +// '0xf951e335afb289353dc249e82926178eac7ded78', +// ], +// }; const pools = [ stETHPool, balPool, composableStablePool, - composableStablePoolWithTokenAtZero, + // composableStablePoolWithTokenAtZero, ]; let queryParams: ParamsBuilder; From 0998349f544b956a1122120096a74f4f3177d775 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 25 Aug 2023 17:59:26 +0200 Subject: [PATCH 03/12] new: onchain data via multicall3 with batching --- .../examples/data/onchain-multicall3.ts | 94 ++++ balancer-js/src/lib/abi/Multicall3.json | 440 ++++++++++++++++++ balancer-js/src/lib/utils/multiCaller3.ts | 103 ++++ .../src/modules/sor/pool-data/onChainData3.ts | 228 +++++++++ .../sor/pool-data/subgraphPoolDataService.ts | 2 +- 5 files changed, 866 insertions(+), 1 deletion(-) create mode 100644 balancer-js/examples/data/onchain-multicall3.ts create mode 100644 balancer-js/src/lib/abi/Multicall3.json create mode 100644 balancer-js/src/lib/utils/multiCaller3.ts create mode 100644 balancer-js/src/modules/sor/pool-data/onChainData3.ts diff --git a/balancer-js/examples/data/onchain-multicall3.ts b/balancer-js/examples/data/onchain-multicall3.ts new file mode 100644 index 000000000..48ad20e43 --- /dev/null +++ b/balancer-js/examples/data/onchain-multicall3.ts @@ -0,0 +1,94 @@ +import { PoolsSubgraphRepository } from '@/modules/data/pool/subgraph' +import { getOnChainBalances as getOnChainBalances3 } from '@/modules/sor/pool-data/onChainData3' +import { SubgraphPoolBase } from '@/.' +import { getOnChainBalances } from '@/modules/sor/pool-data/onChainData' +import { JsonRpcProvider } from '@ethersproject/providers' +import _ from 'lodash' + +const pools = new PoolsSubgraphRepository({ + // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2', + // chainId: 1, + // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-polygon-v2', + // chainId: 137, + // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-arbitrum-v2', + // chainId: 42161, + // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-optimism-v2', + // chainId: 10, + // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-gnosis-chain-v2', + // chainId: 100, + // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-avalanche-v2', + // chainId: 43114, + url: 'https://api.studio.thegraph.com/query/24660/balancer-base-v2/version/latest', + chainId: 8453, + // url: 'https://api.thegraph.com/subgraphs/name/beethovenxfi/beethovenx-v2-fantom', + // chainId: 250, + // url: 'https://api.studio.thegraph.com/query/24660/balancer-polygon-zk-v2/version/latest', + // chainId: 1101, + query: { + args: { + first: 1000, + skip: 0, + orderBy: 'totalLiquidity', + orderDirection: 'desc', + // where: { + // poolType: { + // eq: "MetaStable" + // }, + // }, + }, + attrs: {}, + }, +}) + +// const provider = new JsonRpcProvider('https://rpc.ankr.com/eth') +// const provider = new JsonRpcProvider('https://rpc.ankr.com/polygon') +// const provider = new JsonRpcProvider('https://rpc.ankr.com/arbitrum') +// const provider = new JsonRpcProvider('https://rpc.ankr.com/optimism') +const provider = new JsonRpcProvider('https://rpc.ankr.com/base') +// const provider = new JsonRpcProvider('https://rpc.ankr.com/fantom') +// const provider = new JsonRpcProvider('http://127.0.0.1:8545') +// const provider = new JsonRpcProvider('https://rpc.ankr.com/polygon_zkevm') + +function findNestedValueDifferences(object1: any, object2: any, path = ''): any { + const allKeys = _.union(Object.keys(object1), Object.keys(object2)) + + const differences = [] + + for (const key of allKeys) { + const newPath = path ? `${path}.${key}` : key + + if (_.isObject(object1[key]) && _.isObject(object2[key])) { + differences.push(...findNestedValueDifferences(object1[key], object2[key], newPath)) + } else if (!_.isEqual(object1[key], object2[key])) { + differences.push({ + path: newPath, + value1: object1[key], + value2: object2[key] + }) + } + } + + return differences +} + +async function main() { + const subgraph = await pools.fetch() as SubgraphPoolBase[]; + const onchain3 = await getOnChainBalances3(subgraph, '', '0xBA12222222228d8Ba445958a75a0704d566BF2C8', provider); + console.log(onchain3.length) + // const onchain = await getOnChainBalances(subgraph, '0xeefba1e63905ef1d7acba5a8513c70307c1ce441', '0xBA12222222228d8Ba445958a75a0704d566BF2C8', provider); + // console.log(onchain.length) + // for(const i in subgraph) { + // const one = onchain3.find((x) => x.id === subgraph[i].id) + // const two = onchain.find((x) => x.id === subgraph[i].id) + // console.log('Pool', subgraph[i].id) + // if (!two) { + // console.log('two missing') + // continue + // } + // console.log(JSON.stringify(findNestedValueDifferences(one, two), null, 2)); + // } +} + +main() + +// yarn example ./examples/data/onchain-multicall3.ts diff --git a/balancer-js/src/lib/abi/Multicall3.json b/balancer-js/src/lib/abi/Multicall3.json new file mode 100644 index 000000000..d9c5855e7 --- /dev/null +++ b/balancer-js/src/lib/abi/Multicall3.json @@ -0,0 +1,440 @@ +[ + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "aggregate", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "returnData", + "type": "bytes[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bool", + "name": "allowFailure", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call3[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "aggregate3", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bool", + "name": "allowFailure", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call3Value[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "aggregate3Value", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "blockAndAggregate", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "getBasefee", + "outputs": [ + { + "internalType": "uint256", + "name": "basefee", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "name": "getBlockHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBlockNumber", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getChainId", + "outputs": [ + { + "internalType": "uint256", + "name": "chainid", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentBlockCoinbase", + "outputs": [ + { + "internalType": "address", + "name": "coinbase", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentBlockDifficulty", + "outputs": [ + { + "internalType": "uint256", + "name": "difficulty", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentBlockGasLimit", + "outputs": [ + { + "internalType": "uint256", + "name": "gaslimit", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCurrentBlockTimestamp", + "outputs": [ + { + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "getEthBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLastBlockHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "requireSuccess", + "type": "bool" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "tryAggregate", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "requireSuccess", + "type": "bool" + }, + { + "components": [ + { + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Call[]", + "name": "calls", + "type": "tuple[]" + } + ], + "name": "tryBlockAndAggregate", + "outputs": [ + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "blockHash", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "bytes", + "name": "returnData", + "type": "bytes" + } + ], + "internalType": "struct Multicall3.Result[]", + "name": "returnData", + "type": "tuple[]" + } + ], + "stateMutability": "payable", + "type": "function" + } +] \ No newline at end of file diff --git a/balancer-js/src/lib/utils/multiCaller3.ts b/balancer-js/src/lib/utils/multiCaller3.ts new file mode 100644 index 000000000..9588b4467 --- /dev/null +++ b/balancer-js/src/lib/utils/multiCaller3.ts @@ -0,0 +1,103 @@ +import { set } from 'lodash'; +import { Fragment, JsonFragment, Interface, Result } from '@ethersproject/abi'; +import { CallOverrides } from '@ethersproject/contracts'; +import { Multicall3, Multicall3__factory } from '@/contracts'; +import { Provider } from '@ethersproject/providers'; + +export class Multicaller3 { + private interface: Interface; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private calls: [string, string, any][] = []; + private paths: string[] = []; + address = '0xcA11bde05977b3631167028862bE2a173976CA11'; + multicall: Multicall3; + + constructor( + abi: string | Array, + provider: Provider, + private options: CallOverrides = {} + ) { + this.interface = new Interface(abi); + this.multicall = Multicall3__factory.connect(this.address, provider); + } + + call( + path: string, + address: string, + functionName: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + params?: any[] + ): Multicaller3 { + this.calls.push([address, functionName, params]); + this.paths.push(path); + return this; + } + + async execute( + from: Record = {}, + batchSize = 1024 // Define the number of function calls in each batch + ): Promise> { + const obj = from; + const results = await this.executeMulticall(batchSize); + results.forEach((result, i) => + set(obj, this.paths[i], result.length > 1 ? result : result[0]) + ); + this.calls = []; + this.paths = []; + return obj; + } + + private async executeMulticall(batchSize: number): Promise { + const numBatches = Math.ceil(this.calls.length / batchSize); + const results: Result[] = []; + + const batchPromises = []; + + for (let batchIndex = 0; batchIndex < numBatches; batchIndex++) { + const batchCalls = this.calls.slice( + batchIndex * batchSize, + (batchIndex + 1) * batchSize + ); + + const batchRequests = batchCalls.map( + ([address, functionName, params]) => ({ + target: address, + allowFailure: true, + callData: this.interface.encodeFunctionData(functionName, params), + }) + ); + + batchPromises.push( + this.multicall.callStatic.aggregate3(batchRequests, this.options) + ); + } + + const batchResults = await Promise.all(batchPromises); + + batchResults.forEach((res, batchIndex) => { + const offset = batchIndex * batchSize; + + for (let i = 0; i < res.length; i++) { + const callIndex = offset + i; + const { success, returnData } = res[i]; + + if (success) { + try { + const result = this.interface.decodeFunctionResult( + this.calls[callIndex][1], + returnData + ); + results[callIndex] = result; + } catch (e) { + console.error('Multicall error', this.paths[callIndex]); + results[callIndex] = []; + } + } else { + results[callIndex] = []; + } + } + }); + + return results; + } +} diff --git a/balancer-js/src/modules/sor/pool-data/onChainData3.ts b/balancer-js/src/modules/sor/pool-data/onChainData3.ts new file mode 100644 index 000000000..1232273cf --- /dev/null +++ b/balancer-js/src/modules/sor/pool-data/onChainData3.ts @@ -0,0 +1,228 @@ +import { Multicaller3 } from '@/lib/utils/multiCaller3'; +import { Provider } from '@ethersproject/providers'; +import { SubgraphPoolBase } from '@/.'; +import { formatFixed } from '@ethersproject/bignumber'; +import { SubgraphToken } from '@balancer-labs/sor'; + +const abi = [ + 'function getSwapFeePercentage() view returns (uint256)', + 'function percentFee() view returns (uint256)', + 'function protocolPercentFee() view returns (uint256)', + 'function getNormalizedWeights() view returns (uint256[])', + 'function totalSupply() view returns (uint256)', + 'function getVirtualSupply() view returns (uint256)', + 'function getActualSupply() view returns (uint256)', + 'function getTargets() view returns (uint256 lowerTarget, uint256 upperTarget)', + 'function getTokenRates() view returns (uint256, uint256)', + 'function getWrappedTokenRate() view returns (uint256)', + 'function getAmplificationParameter() view returns (uint256 value, bool isUpdating, uint256 precision)', + 'function getPausedState() view returns (bool)', + 'function inRecoveryMode() view returns (bool)', + 'function getRate() view returns (uint256)', + 'function getScalingFactors() view returns (uint256[] memory)', // do we need this here? + 'function getPoolTokens(bytes32) view returns (address[], uint256[])', +]; + +const getTotalSupplyFn = (poolType: string) => { + if (poolType.includes('Linear') || ['StablePhantom'].includes(poolType)) { + return 'getVirtualSupply'; + } else if (poolType === 'ComposableStable') { + return 'getActualSupply'; + } else { + return 'totalSupply'; + } +}; + +const getSwapFeeFn = (poolType: string) => { + if (poolType === 'Element') { + return 'percentFee'; + } else if (poolType === 'FX') { + return 'protocolPercentFee'; + } else { + return 'getSwapFeePercentage'; + } +}; + +interface OnchainData { + poolTokens: [string[], string[]]; + totalShares: string; + swapFee: string; + isPaused?: boolean; + inRecoveryMode?: boolean; + rate?: string; + scalingFactors?: string[]; + weights?: string[]; + targets?: [string, string]; + wrappedTokenRate?: string; + amp?: [string, boolean, string]; + tokenRates?: [string, string]; +} + +type GenericPool = SubgraphPoolBase; +// Omit & { +// tokens: (SubgraphToken | PoolToken)[]; +// }; + +const defaultCalls = ( + id: string, + address: string, + vaultAddress: string, + poolType: string, + multicaller: Multicaller3 +) => { + multicaller.call(`${id}.poolTokens`, vaultAddress, 'getPoolTokens', [id]); + multicaller.call(`${id}.totalShares`, address, getTotalSupplyFn(poolType)); + multicaller.call(`${id}.swapFee`, address, getSwapFeeFn(poolType)); + // multicaller.call(`${id}.isPaused`, address, 'getPausedState'); + // multicaller.call(`${id}.inRecoveryMode`, address, 'inRecoveryMode'); + // multicaller.call(`${id}.rate`, address, 'getRate'); + // multicaller.call(`${id}.scalingFactors`, address, 'getScalingFactors'); +}; + +const weightedCalls = ( + id: string, + address: string, + multicaller: Multicaller3 +) => { + multicaller.call(`${id}.weights`, address, 'getNormalizedWeights'); +}; + +const linearCalls = ( + id: string, + address: string, + multicaller: Multicaller3 +) => { + multicaller.call(`${id}.targets`, address, 'getTargets'); + multicaller.call(`${id}.wrappedTokenRate`, address, 'getWrappedTokenRate'); +}; + +const stableCalls = ( + id: string, + address: string, + multicaller: Multicaller3 +) => { + multicaller.call(`${id}.amp`, address, 'getAmplificationParameter'); +}; + +const gyroECalls = (id: string, address: string, multicaller: Multicaller3) => { + multicaller.call(`${id}.tokenRates`, address, 'getTokenRates'); +}; + +const poolTypeCalls = (poolType: string) => { + switch (poolType) { + case 'Weighted': + case 'LiquidityBootstrapping': + case 'Investment': + return weightedCalls; + case 'Stable': + case 'StablePhantom': + case 'MetaStable': + case 'ComposableStable': + return stableCalls; + case 'GyroE': + return gyroECalls; + default: + if (poolType.includes('Linear')) { + return linearCalls; + } else { + return () => ({}); // do nothing + } + } +}; + +const merge = (pool: GenericPool, result: OnchainData) => ({ + ...pool, + tokens: pool.tokens.map((token) => { + const idx = result.poolTokens[0] + .map((t) => t.toLowerCase()) + .indexOf(token.address); + const wrappedToken = + pool.wrappedIndex && pool.tokensList[pool.wrappedIndex]; + return { + ...token, + balance: formatFixed(result.poolTokens[1][idx], token.decimals || 18), + weight: + (result.weights && formatFixed(result.weights[idx], 18)) || + token.weight, + priceRate: + (result.wrappedTokenRate && + wrappedToken && + wrappedToken.toLowerCase() === token.address.toLowerCase() && + formatFixed(result.wrappedTokenRate, 18)) || + token.priceRate, + } as SubgraphToken; + }), + totalShares: result.totalShares + ? formatFixed(result.totalShares, 18) + : pool.totalShares, + swapFee: formatFixed(result.swapFee, 18), + amp: + (result.amp && + result.amp[0] && + formatFixed(result.amp[0], String(result.amp[2]).length - 1)) || + undefined, + lowerTarget: + (result.targets && formatFixed(result.targets[0], 18)) || undefined, + upperTarget: + (result.targets && formatFixed(result.targets[1], 18)) || undefined, + tokenRates: + (result.tokenRates && + result.tokenRates.map((rate) => formatFixed(rate, 18))) || + undefined, + // rate: result.rate, + // isPaused: result.isPaused, + // inRecoveryMode: result.inRecoveryMode, + // scalingFactors: result.scalingFactors, +}); + +export const fetchOnChainPoolData = async ( + pools: { + id: string; + address: string; + poolType: string; + }[], + vaultAddress: string, + provider: Provider +): Promise<{ [id: string]: OnchainData }> => { + if (pools.length === 0) { + return {}; + } + + const multicaller = new Multicaller3(abi, provider); + + pools.forEach(({ id, address, poolType }) => { + defaultCalls(id, address, vaultAddress, poolType, multicaller); + poolTypeCalls(poolType)(id, address, multicaller); + }); + + // ZkEVM needs a smaller batch size + const results = (await multicaller.execute({}, 128)) as { + [id: string]: OnchainData; + }; + + return results; +}; + +export async function getOnChainBalances( + subgraphPoolsOriginal: GenericPool[], + _multiAddress: string, + vaultAddress: string, + provider: Provider +): Promise { + if (subgraphPoolsOriginal.length === 0) return subgraphPoolsOriginal; + + const poolsWithOnchainData: GenericPool[] = []; + + const onchainData = (await fetchOnChainPoolData( + subgraphPoolsOriginal, + vaultAddress, + provider + )) as { [id: string]: OnchainData }; + + subgraphPoolsOriginal.forEach((pool) => { + const data = onchainData[pool.id]; + poolsWithOnchainData.push(merge(pool, data)); + }); + + return poolsWithOnchainData; +} diff --git a/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts b/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts index 86dbcef33..94c0b1af7 100644 --- a/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts +++ b/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts @@ -6,7 +6,7 @@ import { SubgraphClient, } from '@/modules/subgraph/subgraph'; import { parseInt } from 'lodash'; -import { getOnChainBalances } from './onChainData'; +import { getOnChainBalances } from './onChainData3'; import { Provider } from '@ethersproject/providers'; import { BalancerNetworkConfig, From 8554edb950fa16c302fcd6f6bb769052e2276830 Mon Sep 17 00:00:00 2001 From: bronco Date: Fri, 25 Aug 2023 18:06:39 +0200 Subject: [PATCH 04/12] skipping recovery specs due to fixed block number --- .../concerns/composableStable/recovery.integration.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/recovery.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/recovery.integration.spec.ts index da92e61c4..207f80972 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/recovery.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/recovery.integration.spec.ts @@ -22,7 +22,7 @@ const signer = provider.getSigner(); const blockNumber = 46572274; let balancer: BalancerSDK; -describe('ComposableStable - recovery', () => { +describe.skip('ComposableStable - recovery', () => { context('V1', async () => { const poolId = '0x02d2e2d7a89d6c5cb3681cfcb6f7dac02a55eda400000000000000000000088f'; From 36fcf1a832f49ceb3647dfbd3890f4ee74a09d1a Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Fri, 25 Aug 2023 21:38:37 +0200 Subject: [PATCH 05/12] Update balancer-js/src/modules/data/pool/subgraph.ts Co-authored-by: Bruno Eidam Guerios --- balancer-js/src/modules/data/pool/subgraph.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/balancer-js/src/modules/data/pool/subgraph.ts b/balancer-js/src/modules/data/pool/subgraph.ts index 869c195a9..f0492ea8a 100644 --- a/balancer-js/src/modules/data/pool/subgraph.ts +++ b/balancer-js/src/modules/data/pool/subgraph.ts @@ -107,9 +107,7 @@ export class PoolsSubgraphRepository this.query.args.block = { number: await this.blockHeight() }; } - this.query.args.first = options?.first - ? options?.first - : this.query.args.first || 1000; + this.query.args.first = options?.first || this.query.args.first || 1000; const formattedQuery = new GraphQLArgsBuilder(this.query.args).format( new SubgraphArgsFormatter() From abc799700e7460751714b410a63460bbda7978de Mon Sep 17 00:00:00 2001 From: gmbronco <83549293+gmbronco@users.noreply.github.com> Date: Fri, 25 Aug 2023 21:39:16 +0200 Subject: [PATCH 06/12] Update balancer-js/examples/data/onchain-multicall3.ts Co-authored-by: Bruno Eidam Guerios --- .../examples/data/onchain-multicall3.ts | 66 +++++++++++-------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/balancer-js/examples/data/onchain-multicall3.ts b/balancer-js/examples/data/onchain-multicall3.ts index 48ad20e43..24ffabc0a 100644 --- a/balancer-js/examples/data/onchain-multicall3.ts +++ b/balancer-js/examples/data/onchain-multicall3.ts @@ -5,28 +5,35 @@ import { getOnChainBalances } from '@/modules/sor/pool-data/onChainData' import { JsonRpcProvider } from '@ethersproject/providers' import _ from 'lodash' +const network = Network.MAINNET; + +const urls: Record = { + [Network.MAINNET]: + 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2', + [Network.POLYGON]: + 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-polygon-v2', + [Network.ARBITRUM]: + 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-arbitrum-v2', + [Network.OPTIMISM]: + 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-optimism-v2', + [Network.GNOSIS]: + 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-gnosis-chain-v2', + [Network.AVALANCHE]: + 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-avalanche-v2', + [Network.BASE]: + 'https://api.studio.thegraph.com/query/24660/balancer-base-v2/version/latest', + [Network.FANTOM]: + 'https://api.thegraph.com/subgraphs/name/beethovenxfi/beethovenx-v2-fantom', + [Network.ZKEVM]: + 'https://api.studio.thegraph.com/query/24660/balancer-polygon-zk-v2/version/latest', +}; + const pools = new PoolsSubgraphRepository({ - // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2', - // chainId: 1, - // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-polygon-v2', - // chainId: 137, - // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-arbitrum-v2', - // chainId: 42161, - // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-optimism-v2', - // chainId: 10, - // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-gnosis-chain-v2', - // chainId: 100, - // url: 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-avalanche-v2', - // chainId: 43114, - url: 'https://api.studio.thegraph.com/query/24660/balancer-base-v2/version/latest', - chainId: 8453, - // url: 'https://api.thegraph.com/subgraphs/name/beethovenxfi/beethovenx-v2-fantom', - // chainId: 250, - // url: 'https://api.studio.thegraph.com/query/24660/balancer-polygon-zk-v2/version/latest', - // chainId: 1101, + url: urls[network], + chainId: network, query: { args: { - first: 1000, + first: 10, skip: 0, orderBy: 'totalLiquidity', orderDirection: 'desc', @@ -38,16 +45,19 @@ const pools = new PoolsSubgraphRepository({ }, attrs: {}, }, -}) +}); + +const providers: Record = { + [Network.MAINNET]: new JsonRpcProvider('https://rpc.ankr.com/eth'), + [Network.POLYGON]: new JsonRpcProvider('https://rpc.ankr.com/polygon'), + [Network.ARBITRUM]: new JsonRpcProvider('https://rpc.ankr.com/arbitrum'), + [Network.OPTIMISM]: new JsonRpcProvider('https://rpc.ankr.com/optimism'), + [Network.BASE]: new JsonRpcProvider('https://rpc.ankr.com/base'), + [Network.FANTOM]: new JsonRpcProvider('https://rpc.ankr.com/fantom'), + [Network.ZKEVM]: new JsonRpcProvider('https://rpc.ankr.com/polygon_zkevm'), +}; -// const provider = new JsonRpcProvider('https://rpc.ankr.com/eth') -// const provider = new JsonRpcProvider('https://rpc.ankr.com/polygon') -// const provider = new JsonRpcProvider('https://rpc.ankr.com/arbitrum') -// const provider = new JsonRpcProvider('https://rpc.ankr.com/optimism') -const provider = new JsonRpcProvider('https://rpc.ankr.com/base') -// const provider = new JsonRpcProvider('https://rpc.ankr.com/fantom') -// const provider = new JsonRpcProvider('http://127.0.0.1:8545') -// const provider = new JsonRpcProvider('https://rpc.ankr.com/polygon_zkevm') +const provider = providers[network]; function findNestedValueDifferences(object1: any, object2: any, path = ''): any { const allKeys = _.union(Object.keys(object1), Object.keys(object2)) From c2066ec83074455a3c32c772c58a16b4f670d4ff Mon Sep 17 00:00:00 2001 From: bronco Date: Tue, 29 Aug 2023 12:25:50 +0200 Subject: [PATCH 07/12] onchain data via multicall3 fixes --- .../examples/data/onchain-multicall3.ts | 15 +++++----- balancer-js/src/lib/utils/multiCaller3.ts | 1 + .../src/modules/sor/pool-data/onChainData3.ts | 30 ++++++++++--------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/balancer-js/examples/data/onchain-multicall3.ts b/balancer-js/examples/data/onchain-multicall3.ts index 24ffabc0a..32459fb4b 100644 --- a/balancer-js/examples/data/onchain-multicall3.ts +++ b/balancer-js/examples/data/onchain-multicall3.ts @@ -1,11 +1,11 @@ import { PoolsSubgraphRepository } from '@/modules/data/pool/subgraph' import { getOnChainBalances as getOnChainBalances3 } from '@/modules/sor/pool-data/onChainData3' -import { SubgraphPoolBase } from '@/.' +import { SubgraphPoolBase, Network } from '@/.' import { getOnChainBalances } from '@/modules/sor/pool-data/onChainData' import { JsonRpcProvider } from '@ethersproject/providers' import _ from 'lodash' -const network = Network.MAINNET; +const network = Network.POLYGON; const urls: Record = { [Network.MAINNET]: @@ -37,11 +37,11 @@ const pools = new PoolsSubgraphRepository({ skip: 0, orderBy: 'totalLiquidity', orderDirection: 'desc', - // where: { - // poolType: { - // eq: "MetaStable" - // }, - // }, + where: { + poolType: { + eq: "GyroE" + }, + }, }, attrs: {}, }, @@ -85,6 +85,7 @@ async function main() { const subgraph = await pools.fetch() as SubgraphPoolBase[]; const onchain3 = await getOnChainBalances3(subgraph, '', '0xBA12222222228d8Ba445958a75a0704d566BF2C8', provider); console.log(onchain3.length) + console.log(JSON.stringify(onchain3, null, 2)); // const onchain = await getOnChainBalances(subgraph, '0xeefba1e63905ef1d7acba5a8513c70307c1ce441', '0xBA12222222228d8Ba445958a75a0704d566BF2C8', provider); // console.log(onchain.length) // for(const i in subgraph) { diff --git a/balancer-js/src/lib/utils/multiCaller3.ts b/balancer-js/src/lib/utils/multiCaller3.ts index 9588b4467..db4c87f68 100644 --- a/balancer-js/src/lib/utils/multiCaller3.ts +++ b/balancer-js/src/lib/utils/multiCaller3.ts @@ -93,6 +93,7 @@ export class Multicaller3 { results[callIndex] = []; } } else { + console.error('Failed request in multicall', this.paths[callIndex]); results[callIndex] = []; } } diff --git a/balancer-js/src/modules/sor/pool-data/onChainData3.ts b/balancer-js/src/modules/sor/pool-data/onChainData3.ts index 1232273cf..83f8fc408 100644 --- a/balancer-js/src/modules/sor/pool-data/onChainData3.ts +++ b/balancer-js/src/modules/sor/pool-data/onChainData3.ts @@ -58,11 +58,6 @@ interface OnchainData { tokenRates?: [string, string]; } -type GenericPool = SubgraphPoolBase; -// Omit & { -// tokens: (SubgraphToken | PoolToken)[]; -// }; - const defaultCalls = ( id: string, address: string, @@ -73,6 +68,7 @@ const defaultCalls = ( multicaller.call(`${id}.poolTokens`, vaultAddress, 'getPoolTokens', [id]); multicaller.call(`${id}.totalShares`, address, getTotalSupplyFn(poolType)); multicaller.call(`${id}.swapFee`, address, getSwapFeeFn(poolType)); + // Following where added to the pools query contract, however legacy onchain data didn't have them. // multicaller.call(`${id}.isPaused`, address, 'getPausedState'); // multicaller.call(`${id}.inRecoveryMode`, address, 'inRecoveryMode'); // multicaller.call(`${id}.rate`, address, 'getRate'); @@ -108,7 +104,8 @@ const gyroECalls = (id: string, address: string, multicaller: Multicaller3) => { multicaller.call(`${id}.tokenRates`, address, 'getTokenRates'); }; -const poolTypeCalls = (poolType: string) => { +const poolTypeCalls = (poolType: string, poolTypeVersion = 1) => { + const do_nothing = () => ({}); switch (poolType) { case 'Weighted': case 'LiquidityBootstrapping': @@ -120,17 +117,21 @@ const poolTypeCalls = (poolType: string) => { case 'ComposableStable': return stableCalls; case 'GyroE': - return gyroECalls; + if (poolTypeVersion > 1) { + return gyroECalls; + } else { + return do_nothing; + } default: if (poolType.includes('Linear')) { return linearCalls; } else { - return () => ({}); // do nothing + return do_nothing; } } }; -const merge = (pool: GenericPool, result: OnchainData) => ({ +const merge = (pool: SubgraphPoolBase, result: OnchainData) => ({ ...pool, tokens: pool.tokens.map((token) => { const idx = result.poolTokens[0] @@ -180,6 +181,7 @@ export const fetchOnChainPoolData = async ( id: string; address: string; poolType: string; + poolTypeVersion?: number; }[], vaultAddress: string, provider: Provider @@ -190,9 +192,9 @@ export const fetchOnChainPoolData = async ( const multicaller = new Multicaller3(abi, provider); - pools.forEach(({ id, address, poolType }) => { + pools.forEach(({ id, address, poolType, poolTypeVersion }) => { defaultCalls(id, address, vaultAddress, poolType, multicaller); - poolTypeCalls(poolType)(id, address, multicaller); + poolTypeCalls(poolType, poolTypeVersion)(id, address, multicaller); }); // ZkEVM needs a smaller batch size @@ -204,14 +206,14 @@ export const fetchOnChainPoolData = async ( }; export async function getOnChainBalances( - subgraphPoolsOriginal: GenericPool[], + subgraphPoolsOriginal: SubgraphPoolBase[], _multiAddress: string, vaultAddress: string, provider: Provider -): Promise { +): Promise { if (subgraphPoolsOriginal.length === 0) return subgraphPoolsOriginal; - const poolsWithOnchainData: GenericPool[] = []; + const poolsWithOnchainData: SubgraphPoolBase[] = []; const onchainData = (await fetchOnChainPoolData( subgraphPoolsOriginal, From af598c8f8744355d343de1a36941bcb2c85355c0 Mon Sep 17 00:00:00 2001 From: bronco Date: Wed, 30 Aug 2023 13:08:00 +0200 Subject: [PATCH 08/12] onchain data via multicall3 fixes --- .../examples/data/onchain-multicall3.ts | 99 ++++---- balancer-js/src/modules/data/pool/index.ts | 1 + .../src/modules/data/pool/onchain-data.ts | 232 ++++++++++++++++++ .../src/modules/sor/pool-data/onChainData3.ts | 231 +---------------- 4 files changed, 282 insertions(+), 281 deletions(-) create mode 100644 balancer-js/src/modules/data/pool/onchain-data.ts diff --git a/balancer-js/examples/data/onchain-multicall3.ts b/balancer-js/examples/data/onchain-multicall3.ts index 32459fb4b..59aff46cd 100644 --- a/balancer-js/examples/data/onchain-multicall3.ts +++ b/balancer-js/examples/data/onchain-multicall3.ts @@ -1,35 +1,20 @@ -import { PoolsSubgraphRepository } from '@/modules/data/pool/subgraph' -import { getOnChainBalances as getOnChainBalances3 } from '@/modules/sor/pool-data/onChainData3' -import { SubgraphPoolBase, Network } from '@/.' -import { getOnChainBalances } from '@/modules/sor/pool-data/onChainData' -import { JsonRpcProvider } from '@ethersproject/providers' -import _ from 'lodash' +import { + PoolsSubgraphRepository, + SubgraphPoolBase, + Network, + BALANCER_NETWORK_CONFIG, + getOnChainBalances as getOnChainBalances3, +} from '@balancer-labs/sdk'; +import { JsonRpcProvider } from '@ethersproject/providers'; +// import _ from 'lodash'; -const network = Network.POLYGON; +// Importing legacy multicall fetcher for comparison +// import { getOnChainBalances } from '@/modules/sor/pool-data/onChainData'; -const urls: Record = { - [Network.MAINNET]: - 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2', - [Network.POLYGON]: - 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-polygon-v2', - [Network.ARBITRUM]: - 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-arbitrum-v2', - [Network.OPTIMISM]: - 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-optimism-v2', - [Network.GNOSIS]: - 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-gnosis-chain-v2', - [Network.AVALANCHE]: - 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-avalanche-v2', - [Network.BASE]: - 'https://api.studio.thegraph.com/query/24660/balancer-base-v2/version/latest', - [Network.FANTOM]: - 'https://api.thegraph.com/subgraphs/name/beethovenxfi/beethovenx-v2-fantom', - [Network.ZKEVM]: - 'https://api.studio.thegraph.com/query/24660/balancer-polygon-zk-v2/version/latest', -}; +const network = Network.POLYGON; const pools = new PoolsSubgraphRepository({ - url: urls[network], + url: BALANCER_NETWORK_CONFIG[network].urls.subgraph, chainId: network, query: { args: { @@ -39,7 +24,7 @@ const pools = new PoolsSubgraphRepository({ orderDirection: 'desc', where: { poolType: { - eq: "GyroE" + eq: 'GyroE', }, }, }, @@ -59,32 +44,44 @@ const providers: Record = { const provider = providers[network]; -function findNestedValueDifferences(object1: any, object2: any, path = ''): any { - const allKeys = _.union(Object.keys(object1), Object.keys(object2)) +/** + * Recursively finds differences between two objects. Use to compare onchain data from 2 different fetchers. + */ +// function diffObjects( +// object1: any, +// object2: any, +// path = '' +// ): any { +// const allKeys = _.union(Object.keys(object1), Object.keys(object2)); - const differences = [] +// const differences = []; - for (const key of allKeys) { - const newPath = path ? `${path}.${key}` : key +// for (const key of allKeys) { +// const newPath = path ? `${path}.${key}` : key; - if (_.isObject(object1[key]) && _.isObject(object2[key])) { - differences.push(...findNestedValueDifferences(object1[key], object2[key], newPath)) - } else if (!_.isEqual(object1[key], object2[key])) { - differences.push({ - path: newPath, - value1: object1[key], - value2: object2[key] - }) - } - } +// if (_.isObject(object1[key]) && _.isObject(object2[key])) { +// differences.push(...diffObjects(object1[key], object2[key], newPath)); +// } else if (!_.isEqual(object1[key], object2[key])) { +// differences.push({ +// path: newPath, +// value1: object1[key], +// value2: object2[key], +// }); +// } +// } - return differences -} +// return differences; +// } async function main() { - const subgraph = await pools.fetch() as SubgraphPoolBase[]; - const onchain3 = await getOnChainBalances3(subgraph, '', '0xBA12222222228d8Ba445958a75a0704d566BF2C8', provider); - console.log(onchain3.length) + const subgraph = (await pools.fetch()) as SubgraphPoolBase[]; + const onchain3 = await getOnChainBalances3( + subgraph, + '', + '0xBA12222222228d8Ba445958a75a0704d566BF2C8', + provider + ); + console.log(onchain3.length); console.log(JSON.stringify(onchain3, null, 2)); // const onchain = await getOnChainBalances(subgraph, '0xeefba1e63905ef1d7acba5a8513c70307c1ce441', '0xBA12222222228d8Ba445958a75a0704d566BF2C8', provider); // console.log(onchain.length) @@ -100,6 +97,6 @@ async function main() { // } } -main() +main(); -// yarn example ./examples/data/onchain-multicall3.ts +// yarn example ./debug/onchain-multicall3.ts diff --git a/balancer-js/src/modules/data/pool/index.ts b/balancer-js/src/modules/data/pool/index.ts index 89d24baf0..9fa9b327b 100644 --- a/balancer-js/src/modules/data/pool/index.ts +++ b/balancer-js/src/modules/data/pool/index.ts @@ -4,3 +4,4 @@ export * from './fallback'; export * from './static'; export * from './subgraph'; export * from './subgraphOnChain'; +export * from './onchain-data'; diff --git a/balancer-js/src/modules/data/pool/onchain-data.ts b/balancer-js/src/modules/data/pool/onchain-data.ts new file mode 100644 index 000000000..f1dd995d4 --- /dev/null +++ b/balancer-js/src/modules/data/pool/onchain-data.ts @@ -0,0 +1,232 @@ +import { Multicaller3 } from '@/lib/utils/multiCaller3'; +import { SubgraphPoolBase } from '@/.'; +import { Provider } from '@ethersproject/providers'; +import { formatFixed } from '@ethersproject/bignumber'; +import { SubgraphToken } from '@balancer-labs/sor'; + +const abi = [ + 'function getSwapFeePercentage() view returns (uint256)', + 'function percentFee() view returns (uint256)', + 'function protocolPercentFee() view returns (uint256)', + 'function getNormalizedWeights() view returns (uint256[])', + 'function totalSupply() view returns (uint256)', + 'function getVirtualSupply() view returns (uint256)', + 'function getActualSupply() view returns (uint256)', + 'function getTargets() view returns (uint256 lowerTarget, uint256 upperTarget)', + 'function getTokenRates() view returns (uint256, uint256)', + 'function getWrappedTokenRate() view returns (uint256)', + 'function getAmplificationParameter() view returns (uint256 value, bool isUpdating, uint256 precision)', + 'function getPausedState() view returns (bool)', + 'function inRecoveryMode() view returns (bool)', + 'function getRate() view returns (uint256)', + 'function getScalingFactors() view returns (uint256[] memory)', // do we need this here? + 'function getPoolTokens(bytes32) view returns (address[], uint256[])', +]; + +const getTotalSupplyFn = (poolType: string) => { + if (poolType.includes('Linear') || ['StablePhantom'].includes(poolType)) { + return 'getVirtualSupply'; + } else if (poolType === 'ComposableStable') { + return 'getActualSupply'; + } else { + return 'totalSupply'; + } +}; + +const getSwapFeeFn = (poolType: string) => { + if (poolType === 'Element') { + return 'percentFee'; + } else if (poolType === 'FX') { + return 'protocolPercentFee'; + } else { + return 'getSwapFeePercentage'; + } +}; + +interface OnchainData { + poolTokens: [string[], string[]]; + totalShares: string; + swapFee: string; + isPaused?: boolean; + inRecoveryMode?: boolean; + rate?: string; + scalingFactors?: string[]; + weights?: string[]; + targets?: [string, string]; + wrappedTokenRate?: string; + amp?: [string, boolean, string]; + tokenRates?: [string, string]; +} + +const defaultCalls = ( + id: string, + address: string, + vaultAddress: string, + poolType: string, + multicaller: Multicaller3 +) => { + multicaller.call(`${id}.poolTokens`, vaultAddress, 'getPoolTokens', [id]); + multicaller.call(`${id}.totalShares`, address, getTotalSupplyFn(poolType)); + multicaller.call(`${id}.swapFee`, address, getSwapFeeFn(poolType)); + // Following where added to the pools query contract, however legacy onchain data didn't have them. + // multicaller.call(`${id}.isPaused`, address, 'getPausedState'); + // multicaller.call(`${id}.inRecoveryMode`, address, 'inRecoveryMode'); + // multicaller.call(`${id}.rate`, address, 'getRate'); + // multicaller.call(`${id}.scalingFactors`, address, 'getScalingFactors'); +}; + +const weightedCalls = ( + id: string, + address: string, + multicaller: Multicaller3 +) => { + multicaller.call(`${id}.weights`, address, 'getNormalizedWeights'); +}; + +const linearCalls = ( + id: string, + address: string, + multicaller: Multicaller3 +) => { + multicaller.call(`${id}.targets`, address, 'getTargets'); + multicaller.call(`${id}.wrappedTokenRate`, address, 'getWrappedTokenRate'); +}; + +const stableCalls = ( + id: string, + address: string, + multicaller: Multicaller3 +) => { + multicaller.call(`${id}.amp`, address, 'getAmplificationParameter'); +}; + +const gyroECalls = (id: string, address: string, multicaller: Multicaller3) => { + multicaller.call(`${id}.tokenRates`, address, 'getTokenRates'); +}; + +const poolTypeCalls = (poolType: string, poolTypeVersion = 1) => { + const do_nothing = () => ({}); + switch (poolType) { + case 'Weighted': + case 'LiquidityBootstrapping': + case 'Investment': + return weightedCalls; + case 'Stable': + case 'StablePhantom': + case 'MetaStable': + case 'ComposableStable': + return stableCalls; + case 'GyroE': + if (poolTypeVersion === 2) { + return gyroECalls; + } else { + return do_nothing; + } + case 'AaveLinear': + if (poolTypeVersion === 1) { + return linearCalls; + } else { + return do_nothing; + } + default: + return do_nothing; + } +}; + +const merge = (pool: SubgraphPoolBase, result: OnchainData) => ({ + ...pool, + tokens: pool.tokens.map((token) => { + const idx = result.poolTokens[0] + .map((t) => t.toLowerCase()) + .indexOf(token.address); + const wrappedToken = + pool.wrappedIndex && pool.tokensList[pool.wrappedIndex]; + return { + ...token, + balance: formatFixed(result.poolTokens[1][idx], token.decimals || 18), + weight: + (result.weights && formatFixed(result.weights[idx], 18)) || + token.weight, + priceRate: + (result.wrappedTokenRate && + wrappedToken && + wrappedToken.toLowerCase() === token.address.toLowerCase() && + formatFixed(result.wrappedTokenRate, 18)) || + token.priceRate, + } as SubgraphToken; + }), + totalShares: result.totalShares + ? formatFixed(result.totalShares, 18) + : pool.totalShares, + swapFee: formatFixed(result.swapFee, 18), + amp: + (result.amp && + result.amp[0] && + formatFixed(result.amp[0], String(result.amp[2]).length - 1)) || + undefined, + lowerTarget: + (result.targets && formatFixed(result.targets[0], 18)) || undefined, + upperTarget: + (result.targets && formatFixed(result.targets[1], 18)) || undefined, + tokenRates: + (result.tokenRates && + result.tokenRates.map((rate) => formatFixed(rate, 18))) || + undefined, + // rate: result.rate, + // isPaused: result.isPaused, + // inRecoveryMode: result.inRecoveryMode, + // scalingFactors: result.scalingFactors, +}); + +export const fetchOnChainPoolData = async ( + pools: { + id: string; + address: string; + poolType: string; + poolTypeVersion?: number; + }[], + vaultAddress: string, + provider: Provider +): Promise<{ [id: string]: OnchainData }> => { + if (pools.length === 0) { + return {}; + } + + const multicaller = new Multicaller3(abi, provider); + + pools.forEach(({ id, address, poolType, poolTypeVersion }) => { + defaultCalls(id, address, vaultAddress, poolType, multicaller); + poolTypeCalls(poolType, poolTypeVersion)(id, address, multicaller); + }); + + // ZkEVM needs a smaller batch size + const results = (await multicaller.execute({}, 128)) as { + [id: string]: OnchainData; + }; + + return results; +}; + +export async function getOnChainBalances( + subgraphPoolsOriginal: SubgraphPoolBase[], + _multiAddress: string, + vaultAddress: string, + provider: Provider +): Promise { + if (subgraphPoolsOriginal.length === 0) return subgraphPoolsOriginal; + + const poolsWithOnchainData: SubgraphPoolBase[] = []; + + const onchainData = (await fetchOnChainPoolData( + subgraphPoolsOriginal, + vaultAddress, + provider + )) as { [id: string]: OnchainData }; + + subgraphPoolsOriginal.forEach((pool) => { + const data = onchainData[pool.id]; + poolsWithOnchainData.push(merge(pool, data)); + }); + + return poolsWithOnchainData; +} diff --git a/balancer-js/src/modules/sor/pool-data/onChainData3.ts b/balancer-js/src/modules/sor/pool-data/onChainData3.ts index 83f8fc408..15acacd2f 100644 --- a/balancer-js/src/modules/sor/pool-data/onChainData3.ts +++ b/balancer-js/src/modules/sor/pool-data/onChainData3.ts @@ -1,230 +1 @@ -import { Multicaller3 } from '@/lib/utils/multiCaller3'; -import { Provider } from '@ethersproject/providers'; -import { SubgraphPoolBase } from '@/.'; -import { formatFixed } from '@ethersproject/bignumber'; -import { SubgraphToken } from '@balancer-labs/sor'; - -const abi = [ - 'function getSwapFeePercentage() view returns (uint256)', - 'function percentFee() view returns (uint256)', - 'function protocolPercentFee() view returns (uint256)', - 'function getNormalizedWeights() view returns (uint256[])', - 'function totalSupply() view returns (uint256)', - 'function getVirtualSupply() view returns (uint256)', - 'function getActualSupply() view returns (uint256)', - 'function getTargets() view returns (uint256 lowerTarget, uint256 upperTarget)', - 'function getTokenRates() view returns (uint256, uint256)', - 'function getWrappedTokenRate() view returns (uint256)', - 'function getAmplificationParameter() view returns (uint256 value, bool isUpdating, uint256 precision)', - 'function getPausedState() view returns (bool)', - 'function inRecoveryMode() view returns (bool)', - 'function getRate() view returns (uint256)', - 'function getScalingFactors() view returns (uint256[] memory)', // do we need this here? - 'function getPoolTokens(bytes32) view returns (address[], uint256[])', -]; - -const getTotalSupplyFn = (poolType: string) => { - if (poolType.includes('Linear') || ['StablePhantom'].includes(poolType)) { - return 'getVirtualSupply'; - } else if (poolType === 'ComposableStable') { - return 'getActualSupply'; - } else { - return 'totalSupply'; - } -}; - -const getSwapFeeFn = (poolType: string) => { - if (poolType === 'Element') { - return 'percentFee'; - } else if (poolType === 'FX') { - return 'protocolPercentFee'; - } else { - return 'getSwapFeePercentage'; - } -}; - -interface OnchainData { - poolTokens: [string[], string[]]; - totalShares: string; - swapFee: string; - isPaused?: boolean; - inRecoveryMode?: boolean; - rate?: string; - scalingFactors?: string[]; - weights?: string[]; - targets?: [string, string]; - wrappedTokenRate?: string; - amp?: [string, boolean, string]; - tokenRates?: [string, string]; -} - -const defaultCalls = ( - id: string, - address: string, - vaultAddress: string, - poolType: string, - multicaller: Multicaller3 -) => { - multicaller.call(`${id}.poolTokens`, vaultAddress, 'getPoolTokens', [id]); - multicaller.call(`${id}.totalShares`, address, getTotalSupplyFn(poolType)); - multicaller.call(`${id}.swapFee`, address, getSwapFeeFn(poolType)); - // Following where added to the pools query contract, however legacy onchain data didn't have them. - // multicaller.call(`${id}.isPaused`, address, 'getPausedState'); - // multicaller.call(`${id}.inRecoveryMode`, address, 'inRecoveryMode'); - // multicaller.call(`${id}.rate`, address, 'getRate'); - // multicaller.call(`${id}.scalingFactors`, address, 'getScalingFactors'); -}; - -const weightedCalls = ( - id: string, - address: string, - multicaller: Multicaller3 -) => { - multicaller.call(`${id}.weights`, address, 'getNormalizedWeights'); -}; - -const linearCalls = ( - id: string, - address: string, - multicaller: Multicaller3 -) => { - multicaller.call(`${id}.targets`, address, 'getTargets'); - multicaller.call(`${id}.wrappedTokenRate`, address, 'getWrappedTokenRate'); -}; - -const stableCalls = ( - id: string, - address: string, - multicaller: Multicaller3 -) => { - multicaller.call(`${id}.amp`, address, 'getAmplificationParameter'); -}; - -const gyroECalls = (id: string, address: string, multicaller: Multicaller3) => { - multicaller.call(`${id}.tokenRates`, address, 'getTokenRates'); -}; - -const poolTypeCalls = (poolType: string, poolTypeVersion = 1) => { - const do_nothing = () => ({}); - switch (poolType) { - case 'Weighted': - case 'LiquidityBootstrapping': - case 'Investment': - return weightedCalls; - case 'Stable': - case 'StablePhantom': - case 'MetaStable': - case 'ComposableStable': - return stableCalls; - case 'GyroE': - if (poolTypeVersion > 1) { - return gyroECalls; - } else { - return do_nothing; - } - default: - if (poolType.includes('Linear')) { - return linearCalls; - } else { - return do_nothing; - } - } -}; - -const merge = (pool: SubgraphPoolBase, result: OnchainData) => ({ - ...pool, - tokens: pool.tokens.map((token) => { - const idx = result.poolTokens[0] - .map((t) => t.toLowerCase()) - .indexOf(token.address); - const wrappedToken = - pool.wrappedIndex && pool.tokensList[pool.wrappedIndex]; - return { - ...token, - balance: formatFixed(result.poolTokens[1][idx], token.decimals || 18), - weight: - (result.weights && formatFixed(result.weights[idx], 18)) || - token.weight, - priceRate: - (result.wrappedTokenRate && - wrappedToken && - wrappedToken.toLowerCase() === token.address.toLowerCase() && - formatFixed(result.wrappedTokenRate, 18)) || - token.priceRate, - } as SubgraphToken; - }), - totalShares: result.totalShares - ? formatFixed(result.totalShares, 18) - : pool.totalShares, - swapFee: formatFixed(result.swapFee, 18), - amp: - (result.amp && - result.amp[0] && - formatFixed(result.amp[0], String(result.amp[2]).length - 1)) || - undefined, - lowerTarget: - (result.targets && formatFixed(result.targets[0], 18)) || undefined, - upperTarget: - (result.targets && formatFixed(result.targets[1], 18)) || undefined, - tokenRates: - (result.tokenRates && - result.tokenRates.map((rate) => formatFixed(rate, 18))) || - undefined, - // rate: result.rate, - // isPaused: result.isPaused, - // inRecoveryMode: result.inRecoveryMode, - // scalingFactors: result.scalingFactors, -}); - -export const fetchOnChainPoolData = async ( - pools: { - id: string; - address: string; - poolType: string; - poolTypeVersion?: number; - }[], - vaultAddress: string, - provider: Provider -): Promise<{ [id: string]: OnchainData }> => { - if (pools.length === 0) { - return {}; - } - - const multicaller = new Multicaller3(abi, provider); - - pools.forEach(({ id, address, poolType, poolTypeVersion }) => { - defaultCalls(id, address, vaultAddress, poolType, multicaller); - poolTypeCalls(poolType, poolTypeVersion)(id, address, multicaller); - }); - - // ZkEVM needs a smaller batch size - const results = (await multicaller.execute({}, 128)) as { - [id: string]: OnchainData; - }; - - return results; -}; - -export async function getOnChainBalances( - subgraphPoolsOriginal: SubgraphPoolBase[], - _multiAddress: string, - vaultAddress: string, - provider: Provider -): Promise { - if (subgraphPoolsOriginal.length === 0) return subgraphPoolsOriginal; - - const poolsWithOnchainData: SubgraphPoolBase[] = []; - - const onchainData = (await fetchOnChainPoolData( - subgraphPoolsOriginal, - vaultAddress, - provider - )) as { [id: string]: OnchainData }; - - subgraphPoolsOriginal.forEach((pool) => { - const data = onchainData[pool.id]; - poolsWithOnchainData.push(merge(pool, data)); - }); - - return poolsWithOnchainData; -} +export * from '@/modules/data/pool/onchain-data'; From 725988b2ae4be9436caddfe97ea1371e1919b3cd Mon Sep 17 00:00:00 2001 From: bronco Date: Thu, 31 Aug 2023 11:47:52 +0200 Subject: [PATCH 09/12] fix: skipping specs with disabled pools --- .../exits.module.integration-mainnet.spec.ts | 6 +- .../exits/exits.module.integration.spec.ts | 4 +- ...itsProportional.module.integration.spec.ts | 4 +- .../joins/joins.module.integration.spec.ts | 95 ++++++++++--------- 4 files changed, 56 insertions(+), 53 deletions(-) diff --git a/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts b/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts index 18e96277d..d278254d5 100644 --- a/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts +++ b/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts @@ -45,7 +45,7 @@ describe('generalised exit execution', async function () { }); }); - context('ERC4626 - bbausd3', async () => { + context.skip('ERC4626 - bbausd3', async () => { if (!TEST_BBAUSD3) return true; const network = Network.MAINNET; const pool = ADDRESSES[network].bbausd3; @@ -113,7 +113,7 @@ describe('generalised exit execution', async function () { }); }); - context('GearboxLinear - bbgusd', async () => { + context.skip('GearboxLinear - bbgusd', async () => { const network = Network.MAINNET; const pool = ADDRESSES[network].bbgusd; const slippage = '10'; // 10 bps = 0.1% @@ -180,7 +180,7 @@ describe('generalised exit execution', async function () { }); }); - context('AaveLinear - bbausd2', async () => { + context.skip('AaveLinear - bbausd2', async () => { const network = Network.MAINNET; const pool = ADDRESSES[network].bbausd2; const slippage = '10'; // 10 bps = 0.1% diff --git a/balancer-js/src/modules/exits/exits.module.integration.spec.ts b/balancer-js/src/modules/exits/exits.module.integration.spec.ts index bd35a25c9..00f374afa 100644 --- a/balancer-js/src/modules/exits/exits.module.integration.spec.ts +++ b/balancer-js/src/modules/exits/exits.module.integration.spec.ts @@ -25,7 +25,7 @@ const poolAddresses = Object.values(ADDRESSES[network]).map( ); const addresses = ADDRESSES[network]; -describe('generalised exit execution', async function () { +describe.skip('generalised exit execution', async function () { this.timeout(120000); // Sets timeout for all tests within this scope to 2 minutes /* @@ -224,7 +224,7 @@ describe('generalised exit execution', async function () { b-a-weth: Linear, aWeth/Weth b-a-usd2: ComposableStable, b-a-usdt/b-a-usdc/b-a-dai */ - context('boostedWeightedMetaGeneral', async () => { + context.skip('boostedWeightedMetaGeneral', async () => { if (!TEST_BOOSTED_WEIGHTED_META_GENERAL) return true; const pool = addresses.boostedWeightedMetaGeneral1; const amount = parseFixed('0.05', pool.decimals).toString(); diff --git a/balancer-js/src/modules/exits/exitsProportional.module.integration.spec.ts b/balancer-js/src/modules/exits/exitsProportional.module.integration.spec.ts index e37bf72d8..501616476 100644 --- a/balancer-js/src/modules/exits/exitsProportional.module.integration.spec.ts +++ b/balancer-js/src/modules/exits/exitsProportional.module.integration.spec.ts @@ -53,7 +53,7 @@ describe('generalised exit execution', async () => { }, ]); }); - context('composable stable pool - boosted', async () => { + context.skip('composable stable pool - boosted', async () => { const testPool = addresses.bbgusd; await runTests([ { @@ -67,7 +67,7 @@ describe('generalised exit execution', async () => { }, ]); }); - context('weighted with boosted', async () => { + context.skip('weighted with boosted', async () => { const testPool = addresses.STG_BBAUSD; await runTests([ { diff --git a/balancer-js/src/modules/joins/joins.module.integration.spec.ts b/balancer-js/src/modules/joins/joins.module.integration.spec.ts index c30ba558f..cc3223c8b 100644 --- a/balancer-js/src/modules/joins/joins.module.integration.spec.ts +++ b/balancer-js/src/modules/joins/joins.module.integration.spec.ts @@ -105,52 +105,55 @@ describe('generalised join execution', async function () { }); }); - context('join with wETH vs ETH - where first step is a swap', async () => { - if (!TEST_JOIN_WITH_ETH_SWAP_FIRST) return true; - - before(async () => { - testPool = addresses.swEth_bbaweth; - tokens = [addresses.WETH, addresses.swETH]; - balances = [ - parseFixed('10', addresses.WETH.decimals).toString(), - parseFixed('10', addresses.swETH.decimals).toString(), - ]; - }); - - it('should join with wETH', async () => { - const tokensIn = [addresses.WETH.address, addresses.swETH.address]; - const amountsIn = [ - parseFixed('1', addresses.WETH.decimals).toString(), - parseFixed('1', addresses.swETH.decimals).toString(), - ]; - await testGeneralisedJoin( - sdk, - signer, - userAddress, - testPool, - tokensIn, - amountsIn, - simulationType - ); - }); - - it('should join with ETH', async () => { - const tokensIn = [AddressZero, addresses.swETH.address]; - const amountsIn = [ - parseFixed('1', 18).toString(), - parseFixed('1', addresses.swETH.decimals).toString(), - ]; - await testGeneralisedJoin( - sdk, - signer, - userAddress, - testPool, - tokensIn, - amountsIn, - simulationType - ); - }); - }); + context.skip( + 'join with wETH vs ETH - where first step is a swap', + async () => { + if (!TEST_JOIN_WITH_ETH_SWAP_FIRST) return true; + + before(async () => { + testPool = addresses.swEth_bbaweth; + tokens = [addresses.WETH, addresses.swETH]; + balances = [ + parseFixed('10', addresses.WETH.decimals).toString(), + parseFixed('10', addresses.swETH.decimals).toString(), + ]; + }); + + it('should join with wETH', async () => { + const tokensIn = [addresses.WETH.address, addresses.swETH.address]; + const amountsIn = [ + parseFixed('1', addresses.WETH.decimals).toString(), + parseFixed('1', addresses.swETH.decimals).toString(), + ]; + await testGeneralisedJoin( + sdk, + signer, + userAddress, + testPool, + tokensIn, + amountsIn, + simulationType + ); + }); + + it('should join with ETH', async () => { + const tokensIn = [AddressZero, addresses.swETH.address]; + const amountsIn = [ + parseFixed('1', 18).toString(), + parseFixed('1', addresses.swETH.decimals).toString(), + ]; + await testGeneralisedJoin( + sdk, + signer, + userAddress, + testPool, + tokensIn, + amountsIn, + simulationType + ); + }); + } + ); context('join with wETH vs ETH - where first step is a join', async () => { if (!TEST_JOIN_WITH_ETH_JOIN_FIRST) return true; From 71aed4ab83fd2f090c14f4f23d650a8f1cceceec Mon Sep 17 00:00:00 2001 From: bronco Date: Thu, 31 Aug 2023 16:27:45 +0200 Subject: [PATCH 10/12] fix: should fetch data for all linear pools --- .../src/modules/data/pool/onchain-data.ts | 7 +- .../exits.module.integration-mainnet.spec.ts | 6 +- .../exits/exits.module.integration.spec.ts | 4 +- ...itsProportional.module.integration.spec.ts | 4 +- .../joins/joins.module.integration.spec.ts | 95 +++++++++---------- 5 files changed, 55 insertions(+), 61 deletions(-) diff --git a/balancer-js/src/modules/data/pool/onchain-data.ts b/balancer-js/src/modules/data/pool/onchain-data.ts index f1dd995d4..628db0598 100644 --- a/balancer-js/src/modules/data/pool/onchain-data.ts +++ b/balancer-js/src/modules/data/pool/onchain-data.ts @@ -122,13 +122,10 @@ const poolTypeCalls = (poolType: string, poolTypeVersion = 1) => { } else { return do_nothing; } - case 'AaveLinear': - if (poolTypeVersion === 1) { + default: + if (poolType.includes('Linear')) { return linearCalls; - } else { - return do_nothing; } - default: return do_nothing; } }; diff --git a/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts b/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts index d278254d5..18e96277d 100644 --- a/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts +++ b/balancer-js/src/modules/exits/exits.module.integration-mainnet.spec.ts @@ -45,7 +45,7 @@ describe('generalised exit execution', async function () { }); }); - context.skip('ERC4626 - bbausd3', async () => { + context('ERC4626 - bbausd3', async () => { if (!TEST_BBAUSD3) return true; const network = Network.MAINNET; const pool = ADDRESSES[network].bbausd3; @@ -113,7 +113,7 @@ describe('generalised exit execution', async function () { }); }); - context.skip('GearboxLinear - bbgusd', async () => { + context('GearboxLinear - bbgusd', async () => { const network = Network.MAINNET; const pool = ADDRESSES[network].bbgusd; const slippage = '10'; // 10 bps = 0.1% @@ -180,7 +180,7 @@ describe('generalised exit execution', async function () { }); }); - context.skip('AaveLinear - bbausd2', async () => { + context('AaveLinear - bbausd2', async () => { const network = Network.MAINNET; const pool = ADDRESSES[network].bbausd2; const slippage = '10'; // 10 bps = 0.1% diff --git a/balancer-js/src/modules/exits/exits.module.integration.spec.ts b/balancer-js/src/modules/exits/exits.module.integration.spec.ts index 00f374afa..bd35a25c9 100644 --- a/balancer-js/src/modules/exits/exits.module.integration.spec.ts +++ b/balancer-js/src/modules/exits/exits.module.integration.spec.ts @@ -25,7 +25,7 @@ const poolAddresses = Object.values(ADDRESSES[network]).map( ); const addresses = ADDRESSES[network]; -describe.skip('generalised exit execution', async function () { +describe('generalised exit execution', async function () { this.timeout(120000); // Sets timeout for all tests within this scope to 2 minutes /* @@ -224,7 +224,7 @@ describe.skip('generalised exit execution', async function () { b-a-weth: Linear, aWeth/Weth b-a-usd2: ComposableStable, b-a-usdt/b-a-usdc/b-a-dai */ - context.skip('boostedWeightedMetaGeneral', async () => { + context('boostedWeightedMetaGeneral', async () => { if (!TEST_BOOSTED_WEIGHTED_META_GENERAL) return true; const pool = addresses.boostedWeightedMetaGeneral1; const amount = parseFixed('0.05', pool.decimals).toString(); diff --git a/balancer-js/src/modules/exits/exitsProportional.module.integration.spec.ts b/balancer-js/src/modules/exits/exitsProportional.module.integration.spec.ts index 501616476..e37bf72d8 100644 --- a/balancer-js/src/modules/exits/exitsProportional.module.integration.spec.ts +++ b/balancer-js/src/modules/exits/exitsProportional.module.integration.spec.ts @@ -53,7 +53,7 @@ describe('generalised exit execution', async () => { }, ]); }); - context.skip('composable stable pool - boosted', async () => { + context('composable stable pool - boosted', async () => { const testPool = addresses.bbgusd; await runTests([ { @@ -67,7 +67,7 @@ describe('generalised exit execution', async () => { }, ]); }); - context.skip('weighted with boosted', async () => { + context('weighted with boosted', async () => { const testPool = addresses.STG_BBAUSD; await runTests([ { diff --git a/balancer-js/src/modules/joins/joins.module.integration.spec.ts b/balancer-js/src/modules/joins/joins.module.integration.spec.ts index cc3223c8b..c30ba558f 100644 --- a/balancer-js/src/modules/joins/joins.module.integration.spec.ts +++ b/balancer-js/src/modules/joins/joins.module.integration.spec.ts @@ -105,55 +105,52 @@ describe('generalised join execution', async function () { }); }); - context.skip( - 'join with wETH vs ETH - where first step is a swap', - async () => { - if (!TEST_JOIN_WITH_ETH_SWAP_FIRST) return true; - - before(async () => { - testPool = addresses.swEth_bbaweth; - tokens = [addresses.WETH, addresses.swETH]; - balances = [ - parseFixed('10', addresses.WETH.decimals).toString(), - parseFixed('10', addresses.swETH.decimals).toString(), - ]; - }); - - it('should join with wETH', async () => { - const tokensIn = [addresses.WETH.address, addresses.swETH.address]; - const amountsIn = [ - parseFixed('1', addresses.WETH.decimals).toString(), - parseFixed('1', addresses.swETH.decimals).toString(), - ]; - await testGeneralisedJoin( - sdk, - signer, - userAddress, - testPool, - tokensIn, - amountsIn, - simulationType - ); - }); - - it('should join with ETH', async () => { - const tokensIn = [AddressZero, addresses.swETH.address]; - const amountsIn = [ - parseFixed('1', 18).toString(), - parseFixed('1', addresses.swETH.decimals).toString(), - ]; - await testGeneralisedJoin( - sdk, - signer, - userAddress, - testPool, - tokensIn, - amountsIn, - simulationType - ); - }); - } - ); + context('join with wETH vs ETH - where first step is a swap', async () => { + if (!TEST_JOIN_WITH_ETH_SWAP_FIRST) return true; + + before(async () => { + testPool = addresses.swEth_bbaweth; + tokens = [addresses.WETH, addresses.swETH]; + balances = [ + parseFixed('10', addresses.WETH.decimals).toString(), + parseFixed('10', addresses.swETH.decimals).toString(), + ]; + }); + + it('should join with wETH', async () => { + const tokensIn = [addresses.WETH.address, addresses.swETH.address]; + const amountsIn = [ + parseFixed('1', addresses.WETH.decimals).toString(), + parseFixed('1', addresses.swETH.decimals).toString(), + ]; + await testGeneralisedJoin( + sdk, + signer, + userAddress, + testPool, + tokensIn, + amountsIn, + simulationType + ); + }); + + it('should join with ETH', async () => { + const tokensIn = [AddressZero, addresses.swETH.address]; + const amountsIn = [ + parseFixed('1', 18).toString(), + parseFixed('1', addresses.swETH.decimals).toString(), + ]; + await testGeneralisedJoin( + sdk, + signer, + userAddress, + testPool, + tokensIn, + amountsIn, + simulationType + ); + }); + }); context('join with wETH vs ETH - where first step is a join', async () => { if (!TEST_JOIN_WITH_ETH_JOIN_FIRST) return true; From b1d74809d2f1ff62fe2469c94bc96baef37abcf9 Mon Sep 17 00:00:00 2001 From: bronco Date: Thu, 31 Aug 2023 16:31:02 +0200 Subject: [PATCH 11/12] fix: should return pool's default data --- balancer-js/src/modules/data/pool/onchain-data.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/balancer-js/src/modules/data/pool/onchain-data.ts b/balancer-js/src/modules/data/pool/onchain-data.ts index 628db0598..cd168be7c 100644 --- a/balancer-js/src/modules/data/pool/onchain-data.ts +++ b/balancer-js/src/modules/data/pool/onchain-data.ts @@ -122,10 +122,13 @@ const poolTypeCalls = (poolType: string, poolTypeVersion = 1) => { } else { return do_nothing; } - default: - if (poolType.includes('Linear')) { + case 'AaveLinear': + if (poolTypeVersion === 1) { return linearCalls; + } else { + return do_nothing; } + default: return do_nothing; } }; @@ -160,15 +163,15 @@ const merge = (pool: SubgraphPoolBase, result: OnchainData) => ({ (result.amp && result.amp[0] && formatFixed(result.amp[0], String(result.amp[2]).length - 1)) || - undefined, + pool.amp, lowerTarget: - (result.targets && formatFixed(result.targets[0], 18)) || undefined, + (result.targets && formatFixed(result.targets[0], 18)) || pool.lowerTarget, upperTarget: - (result.targets && formatFixed(result.targets[1], 18)) || undefined, + (result.targets && formatFixed(result.targets[1], 18)) || pool.upperTarget, tokenRates: (result.tokenRates && result.tokenRates.map((rate) => formatFixed(rate, 18))) || - undefined, + pool.tokenRates, // rate: result.rate, // isPaused: result.isPaused, // inRecoveryMode: result.inRecoveryMode, From 54a5228a0b1865006b4872638ac2bf9592c13e8e Mon Sep 17 00:00:00 2001 From: bronco Date: Thu, 31 Aug 2023 17:42:13 +0200 Subject: [PATCH 12/12] fix: bringing back commented out tests --- .../concerns/composableStable/recovery.integration.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/recovery.integration.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/recovery.integration.spec.ts index 413b33eb6..ce2daa630 100644 --- a/balancer-js/src/modules/pools/pool-types/concerns/composableStable/recovery.integration.spec.ts +++ b/balancer-js/src/modules/pools/pool-types/concerns/composableStable/recovery.integration.spec.ts @@ -22,7 +22,7 @@ const signer = provider.getSigner(); const blockNumber = 46939238; let balancer: BalancerSDK; -describe.skip('ComposableStable - recovery', () => { +describe('ComposableStable - recovery', () => { context('V1', async () => { const poolId = '0x02d2e2d7a89d6c5cb3681cfcb6f7dac02a55eda400000000000000000000088f';