From 9673602bf98c8e4f58b26432f23d687224a04314 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Wed, 5 Jul 2023 10:25:03 +0100 Subject: [PATCH 1/4] Update SOR to 4.1.1-beta.12. --- 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 15fbbd7d4..daf0d6f5c 100644 --- a/balancer-js/package.json +++ b/balancer-js/package.json @@ -86,7 +86,7 @@ "typescript": "^4.0.2" }, "dependencies": { - "@balancer-labs/sor": "4.1.1-beta.9", + "@balancer-labs/sor": "4.1.1-beta.12", "@ethersproject/abi": "^5.4.0", "@ethersproject/abstract-signer": "^5.4.0", "@ethersproject/address": "^5.4.0", diff --git a/balancer-js/yarn.lock b/balancer-js/yarn.lock index 2d374bb08..70eab36cd 100644 --- a/balancer-js/yarn.lock +++ b/balancer-js/yarn.lock @@ -507,10 +507,10 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" -"@balancer-labs/sor@4.1.1-beta.9": - version "4.1.1-beta.9" - resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.1.1-beta.9.tgz#68ea312f57d43595a0156642b56e7713f87cf4bb" - integrity sha512-jwqEkjOgc9qTnuQGne/ZnG+ynx4ca4qEIgRClJVH2tCCf+pXL7jVPWv/v3I+7dJs2aCyet4uIsXwU/vi2jK+/Q== +"@balancer-labs/sor@4.1.1-beta.12": + version "4.1.1-beta.12" + resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.1.1-beta.12.tgz#35a77b14c4cbe99a9a4cd1b538c9615b002d2c30" + integrity sha512-H0k6Zv3KH79wncPXs0iamRwv2MmRJBazk0WIAmnXE1opZAPOSxTPgf1YJh4/hAZlFbHuI2LXOZAVY7ueSCRewQ== dependencies: isomorphic-fetch "^2.2.1" From fced123cdce0b77c1600f0f9f4c3538d4f5a8edf Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Wed, 5 Jul 2023 10:25:22 +0100 Subject: [PATCH 2/4] Add FX pool to onchainData. --- balancer-js/src/modules/sor/pool-data/onChainData.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/balancer-js/src/modules/sor/pool-data/onChainData.ts b/balancer-js/src/modules/sor/pool-data/onChainData.ts index a5846d984..a8e4823b7 100644 --- a/balancer-js/src/modules/sor/pool-data/onChainData.ts +++ b/balancer-js/src/modules/sor/pool-data/onChainData.ts @@ -144,6 +144,7 @@ export async function getOnChainBalances< ); break; case 'Element': + case 'FX': multiPool.call(`${pool.id}.swapFee`, pool.address, 'percentFee'); break; case 'Gyro2': From 5ca9a3da3f3015386203fd1b4f806cefdcd6058f Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Wed, 5 Jul 2023 11:12:25 +0100 Subject: [PATCH 3/4] Use correct onchain method for FX. --- balancer-js/src/modules/sor/pool-data/onChainData.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/balancer-js/src/modules/sor/pool-data/onChainData.ts b/balancer-js/src/modules/sor/pool-data/onChainData.ts index a8e4823b7..121cdcede 100644 --- a/balancer-js/src/modules/sor/pool-data/onChainData.ts +++ b/balancer-js/src/modules/sor/pool-data/onChainData.ts @@ -15,6 +15,7 @@ import { StaticATokenRateProvider__factory, WeightedPool__factory, GyroEV2__factory, + FXPool__factory, } from '@/contracts'; import { JsonFragment } from '@ethersproject/abi'; @@ -43,6 +44,7 @@ export async function getOnChainBalances< ...(LinearPool__factory.abi as readonly JsonFragment[]), ...(ComposableStablePool__factory.abi as readonly JsonFragment[]), ...(GyroEV2__factory.abi as readonly JsonFragment[]), + ...(FXPool__factory.abi as readonly JsonFragment[]), ].map((row) => [row.name, row]) ) ); @@ -144,9 +146,15 @@ export async function getOnChainBalances< ); break; case 'Element': - case 'FX': multiPool.call(`${pool.id}.swapFee`, pool.address, 'percentFee'); break; + case 'FX': + multiPool.call( + `${pool.id}.swapFee`, + pool.address, + 'protocolPercentFee' + ); + break; case 'Gyro2': case 'Gyro3': multiPool.call(`${pool.id}.poolTokens`, vaultAddress, 'getPoolTokens', [ From 7d8eabc394a38e755b4c55c5a344f0b38c5ac2c6 Mon Sep 17 00:00:00 2001 From: Bruno Eidam Guerios Date: Wed, 12 Jul 2023 17:26:01 -0300 Subject: [PATCH 4/4] Add protocolPercentFee as FX pool swapFee --- .../src/modules/sor/pool-data/multicall/fx.ts | 85 +++++++++++++++++++ .../sor/pool-data/multicall/gyroEv2.ts | 4 +- .../src/modules/sor/pool-data/onChainData.ts | 2 + 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 balancer-js/src/modules/sor/pool-data/multicall/fx.ts diff --git a/balancer-js/src/modules/sor/pool-data/multicall/fx.ts b/balancer-js/src/modules/sor/pool-data/multicall/fx.ts new file mode 100644 index 000000000..761bd12c0 --- /dev/null +++ b/balancer-js/src/modules/sor/pool-data/multicall/fx.ts @@ -0,0 +1,85 @@ +import { formatFixed } from '@ethersproject/bignumber'; +import { Provider } from '@ethersproject/providers'; +import { SubgraphPoolBase } from '@balancer-labs/sor'; +import { Multicaller } from '@/lib/utils/multiCaller'; +import { FXPool__factory, Multicall__factory } from '@/contracts'; +import { Pool, PoolType } from '@/types'; +import { JsonFragment } from '@ethersproject/abi'; +import { BalancerPool } from '../onChainData'; +import { Logger } from '@/lib/utils/logger'; + +type SwapFees = Record< + string, + { + swapFee: string; + } +>; + +/** + * Update pool swapFees using mulitcall + * @param pools + * @param multicallAddr + * @param provider + */ +export async function decorateFx( + pools: GenericPool[], + multicallAddr: string, + provider: Provider +): Promise { + const fxPools = pools.filter((p) => { + return p.poolType === 'FX'; + }); + // Use multicall to get swapFees for all FX pools + const fxSwapFees = await getFxSwapFee(fxPools, multicallAddr, provider); + fxPools.forEach((pool) => { + if (fxSwapFees[pool.id]) { + pool.swapFee = formatFixed(fxSwapFees[pool.id].swapFee, 18); + } else { + console.warn(`FX missing protocolPercentFee: `, pool.id); + } + }); +} + +async function getFxSwapFee< + GenericPool extends Pick< + SubgraphPoolBase | Pool, + 'poolType' | 'id' | 'address' + > +>( + fxPools: GenericPool[], + multiAddress: string, + provider: Provider +): Promise { + if (fxPools.length === 0) return {} as SwapFees; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const abis: any = Object.values( + // Remove duplicate entries using their names + Object.fromEntries( + [...(FXPool__factory.abi as readonly JsonFragment[])].map((row) => [ + row.name, + row, + ]) + ) + ); + const multicall = Multicall__factory.connect(multiAddress, provider); + const multiPool = new Multicaller(multicall, abis); + fxPools.forEach((pool) => { + if (pool.poolType !== PoolType.FX) { + const logger = Logger.getInstance(); + logger.warn( + `Incorrectly calling protocolPercentFee on pool: ${pool.poolType} ${pool.id}` + ); + return; + } + multiPool.call(`${pool.id}.swapFee`, pool.address, 'protocolPercentFee'); + }); + + let swapFees = {} as SwapFees; + try { + swapFees = (await multiPool.execute()) as SwapFees; + } catch (err) { + console.error(`Issue with FX multicall execution.`); + } + return swapFees; +} diff --git a/balancer-js/src/modules/sor/pool-data/multicall/gyroEv2.ts b/balancer-js/src/modules/sor/pool-data/multicall/gyroEv2.ts index 23673117c..3dc7bb76c 100644 --- a/balancer-js/src/modules/sor/pool-data/multicall/gyroEv2.ts +++ b/balancer-js/src/modules/sor/pool-data/multicall/gyroEv2.ts @@ -7,6 +7,7 @@ import { Pool, PoolType } from '@/types'; import { GyroEV2__factory } from '@/contracts'; import { JsonFragment } from '@ethersproject/abi'; import { BalancerPool } from '../onChainData'; +import { Logger } from '@/lib/utils/logger'; type TokenRates = Record< string, @@ -74,7 +75,8 @@ async function getGyroTokenRates< const multiPool = new Multicaller(multicall, abis); gyroPools.forEach((pool) => { if (!(pool.poolType === PoolType.GyroE && pool.poolTypeVersion === 2)) { - console.warn( + const logger = Logger.getInstance(); + logger.warn( `Incorrectly calling tokenRates on pool: ${pool.poolType} ${pool.id}` ); return; diff --git a/balancer-js/src/modules/sor/pool-data/onChainData.ts b/balancer-js/src/modules/sor/pool-data/onChainData.ts index 6f6dcf44d..2eb2b44c3 100644 --- a/balancer-js/src/modules/sor/pool-data/onChainData.ts +++ b/balancer-js/src/modules/sor/pool-data/onChainData.ts @@ -4,6 +4,7 @@ import { Pool, PoolToken, PoolType } from '@/types'; import { decorateGyroEv2 } from './multicall/gyroEv2'; import { getPoolsFromDataQuery } from './poolDataQueries'; import { Logger } from '@/lib/utils/logger'; +import { decorateFx } from './multicall/fx'; export type Tokens = (SubgraphToken | PoolToken)[]; @@ -34,5 +35,6 @@ export async function getOnChainPools( ); // GyroEV2 requires tokenRates onchain update that dataQueries does not provide await decorateGyroEv2(onChainPools, multicallAddr, provider); + await decorateFx(onChainPools, multicallAddr, provider); return onChainPools; }