import { BigNumber } from '@ethersproject/bignumber' import { Zero } from '@ethersproject/constants' import { Pool, PoolInfo, PoolToken } from '../router' import { SynapseSDK } from '../sdk' /** * Gets pool tokens for a pool address. * * @param chainId The chain ID * @param poolAddress The pool address * @returns The pool tokens * @throws Will throw an error if SynapseRouter is not deployed on the given chain. */ export async function getPoolTokens( this: SynapseSDK, chainId: number, poolAddress: string ): Promise { return this.synapseRouterSet .getSynapseRouter(chainId) .getPoolTokens(poolAddress) } /** * Gets info for a pool (number of tokens and LP token). * * @param chainId The chain ID * @param poolAddress The pool address * @returns The pool info (number of tokens and LP token) * @throws Will throw an error if SynapseRouter is not deployed on the given chain. */ export async function getPoolInfo( this: SynapseSDK, chainId: number, poolAddress: string ): Promise { return this.synapseRouterSet .getSynapseRouter(chainId) .getPoolInfo(poolAddress) } /** * Gets all pools for a chain ID. * * @param chainId The chain ID * @returns An array of all pools (address, tokens, LP token) * @throws Will throw an error if SynapseRouter is not deployed on the given chain. */ export async function getAllPools( this: SynapseSDK, chainId: number ): Promise { return this.synapseRouterSet.getSynapseRouter(chainId).getAllPools() } /** * Calculates the amount required to add liquidity for amounts of each token. * * @param chainId The chain ID * @param poolAddress The pool address * @param amounts The amounts of each token to add * @returns The amount of LP tokens needed and router address * @throws Will throw an error if SynapseRouter is not deployed on the given chain. */ export async function calculateAddLiquidity( this: SynapseSDK, chainId: number, poolAddress: string, amounts: Record ): Promise<{ amount: BigNumber; routerAddress: string }> { // TODO (Chi): use amounts array as the input instead of map in the first place const router = this.synapseRouterSet.getSynapseRouter(chainId) const routerAddress = router.address const poolTokens = await router.getPoolTokens(poolAddress) // Create a map that uses lowercase token addresses as keys const lowerCaseAmounts: Record = {} Object.keys(amounts).forEach((key) => { lowerCaseAmounts[key.toLowerCase()] = amounts[key] }) // Populate amounts array by combining amounts map and pool tokens, preserving tokens order // and adding 0 for tokens not in the map const amountsArray: BigNumber[] = poolTokens.map( (poolToken) => lowerCaseAmounts[poolToken.token.toLowerCase()] ?? Zero ) // Don't do a contract call if all amounts are 0 const amount = amountsArray.every((value) => value.isZero()) ? Zero : await router.calculateAddLiquidity(poolAddress, amountsArray) return { amount, routerAddress } } /** * Calculates the amounts received when removing liquidity. * * @param chainId The chain ID * @param poolAddress The pool address * @param amount The amount of LP tokens to remove * @returns The amounts of each token received and router address * @throws Will throw an error if SynapseRouter is not deployed on the given chain. */ export async function calculateRemoveLiquidity( this: SynapseSDK, chainId: number, poolAddress: string, amount: BigNumber ): Promise<{ amounts: Array<{ value: BigNumber; index: number }> routerAddress: string }> { const router = this.synapseRouterSet.getSynapseRouter(chainId) const routerAddress = router.address const amountsOut = await router.calculateRemoveLiquidity(poolAddress, amount) // Zip amounts with token indexes const amounts = amountsOut.map((value, index) => ({ value, index })) return { amounts, routerAddress } } /** * Calculates the amount of one token received when removing liquidity. * * @param chainId The chain ID * @param poolAddress The pool address * @param amount The amount of LP tokens to remove * @param poolIndex The index of the token to receive * @returns The amount received and router address * @throws Will throw an error if SynapseRouter is not deployed on the given chain. */ export async function calculateRemoveLiquidityOne( this: SynapseSDK, chainId: number, poolAddress: string, amount: BigNumber, poolIndex: number ): Promise<{ amount: { value: BigNumber; index: number } routerAddress: string }> { const router = this.synapseRouterSet.getSynapseRouter(chainId) const routerAddress = router.address const amountOut = { value: await router.calculateWithdrawOneToken( poolAddress, amount, poolIndex ), index: poolIndex, } return { amount: amountOut, routerAddress } }