diff --git a/balancer-js/examples/swaps/historicalSwap.ts b/balancer-js/examples/swaps/historicalSwap.ts new file mode 100644 index 000000000..9d412ee88 --- /dev/null +++ b/balancer-js/examples/swaps/historicalSwap.ts @@ -0,0 +1,73 @@ +import { GraphQLArgs } from '@balancer-labs/sor'; +import { BalancerSDK, formatFixed, parseFixed } from '../../src'; +import { OrderDirection, Pool_OrderBy } from '@/modules/subgraph/subgraph'; +import { BigNumber } from '@ethersproject/bignumber'; + +const rpcUrl = `https://mainnet.infura.io/v3/${process.env.INFURA}`; + +async function historicalSwap() { + const balancer = new BalancerSDK({ + network: 1, + rpcUrl: rpcUrl, + }); + + const swapsService = balancer.swaps; + const queryArgWithBlock: GraphQLArgs = { + orderBy: Pool_OrderBy.TotalLiquidity, + block: { + number: 17_000_000, + }, + orderDirection: OrderDirection.Desc, + where: { + swapEnabled: { + eq: true, + }, + totalShares: { + gt: 0.000000000001, + }, + }, + }; + + const poolsFetchSuccess = await swapsService.fetchPools(queryArgWithBlock); + + const swapInfo = await swapsService.findRouteGivenIn({ + tokenIn: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + tokenOut: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + amount: parseFixed('1', 18), + gasPrice: BigNumber.from('0'), + maxPools: 4, + }); + + const balancerNow = new BalancerSDK({ + network: 1, + rpcUrl: rpcUrl, + }); + + const swapsServiceNow = balancerNow.swaps; + + const poolsFetchSuccessNow = await swapsServiceNow.fetchPools(); + + const swapInfoNow = await swapsServiceNow.findRouteGivenIn({ + tokenIn: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH + tokenOut: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDT + amount: parseFixed('1', 18), + gasPrice: BigNumber.from('0'), + maxPools: 4, + }); + + console.log( + `1 WETH is ${formatFixed( + swapInfoNow.returnAmount, + 6 + )} USDC using the most recent data` + ); + + console.log( + `1 WETH was ${formatFixed(swapInfo.returnAmount, 6)} USDC at block ${ + queryArgWithBlock.block?.number + }` + ); +} + +// start with "npm run example -- ./examples/swaps/historicalSwap.ts" +historicalSwap(); diff --git a/balancer-js/src/modules/sor/pool-data/onChainData.ts b/balancer-js/src/modules/sor/pool-data/onChainData.ts index 1f31ed957..c7c272f95 100644 --- a/balancer-js/src/modules/sor/pool-data/onChainData.ts +++ b/balancer-js/src/modules/sor/pool-data/onChainData.ts @@ -63,7 +63,8 @@ export async function getOnChainBalances< subgraphPoolsOriginal: GenericPool[], multiAddress: string, vaultAddress: string, - provider: Provider + provider: Provider, + blockNumber?: number ): Promise { if (subgraphPoolsOriginal.length === 0) return subgraphPoolsOriginal; @@ -87,7 +88,9 @@ export async function getOnChainBalances< const multicall = Multicall__factory.connect(multiAddress, provider); - const multiPool = new Multicaller(multicall, abis); + const multiPool = blockNumber + ? new Multicaller(multicall, abis, { blockTag: blockNumber }) + : new Multicaller(multicall, abis); const supportedPoolTypes: string[] = Object.values(PoolType); const subgraphPools: GenericPool[] = []; diff --git a/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts b/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts index 86dbcef33..7bf0b923a 100644 --- a/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts +++ b/balancer-js/src/modules/sor/pool-data/subgraphPoolDataService.ts @@ -95,7 +95,10 @@ export class SubgraphPoolDataService implements PoolDataService { mapped, this.network.addresses.contracts.multicall, this.network.addresses.contracts.vault, - this.provider + this.provider, + // if the queryArgs for TheGraph specify a blocknumber, + // we must also get the onChainData at this bocknumber + queryArgs?.block?.number ); logger.timeEnd(`fetching on-chain balances for ${mapped.length} pools`);