From a45a075fd3a28f6d0ee529bed3eb1f5012e8d672 Mon Sep 17 00:00:00 2001 From: David Hamme Date: Wed, 10 Mar 2021 14:50:20 -0800 Subject: [PATCH] Make pages generic w/ accept poolName prop (#372) remove the concept of "DepositBTC", instead just have --- src/constants/index.ts | 37 ++++++++-- src/hooks/useApproveAndDeposit.ts | 17 ++--- src/hooks/useApproveAndWithdraw.ts | 12 +-- src/hooks/useContract.ts | 11 ++- src/hooks/usePoolData.ts | 25 +++---- src/hooks/useWithdrawFormState.ts | 28 +++---- src/pages/App.tsx | 30 ++++++-- src/pages/{DepositBTC.tsx => Deposit.tsx} | 81 +++++++++++---------- src/pages/{SwapBTC.tsx => Swap.tsx} | 28 ++++--- src/pages/{WithdrawBTC.tsx => Withdraw.tsx} | 49 ++++++++----- src/state/wallet/hooks.ts | 26 ++++++- 11 files changed, 214 insertions(+), 130 deletions(-) rename src/pages/{DepositBTC.tsx => Deposit.tsx} (78%) rename src/pages/{SwapBTC.tsx => Swap.tsx} (91%) rename src/pages/{WithdrawBTC.tsx => Withdraw.tsx} (80%) diff --git a/src/constants/index.ts b/src/constants/index.ts index fe74883..b41a61f 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -64,6 +64,13 @@ export const MERKLETREE_DATA: { [chainId in ChainId]: string } = { [ChainId.HARDHAT]: "hardhat.json", } +export const STABLECOIN_SWAP_TOKEN_CONTRACT_ADDRESSES: { + [chainId in ChainId]: string +} = { + [ChainId.MAINNET]: "", + [ChainId.HARDHAT]: "0x6A358FD7B7700887b0cd974202CdF93208F793E2", +} + export const BTC_SWAP_TOKEN_CONTRACT_ADDRESSES: { [chainId in ChainId]: string } = { @@ -74,9 +81,18 @@ export const BTC_SWAP_TOKEN_CONTRACT_ADDRESSES: { export const BTC_SWAP_TOKEN = new Token( BTC_SWAP_TOKEN_CONTRACT_ADDRESSES, 18, - "BLPT", - "blpt", - "Saddle BTC Pool LP Token", + "saddleBTC", + "saddlebtc", + "Saddle TBTC/WBTC/RENBTC/SBTC", + saddleLogo, +) + +export const STABLECOIN_SWAP_TOKEN = new Token( + STABLECOIN_SWAP_TOKEN_CONTRACT_ADDRESSES, + 18, + "saddleUSD", + "saddleusd", + "Saddle DAI/USDC/USDT", saddleLogo, ) @@ -199,10 +215,19 @@ export const TOKENS_MAP: { ) export const POOLS_MAP: { - [poolName: string]: Token[] + [poolName in PoolName]: { + lpToken: Token + poolTokens: Token[] + } } = { - [BTC_POOL_NAME]: BTC_POOL_TOKENS, - [STABLECOIN_POOL_NAME]: STABLECOIN_POOL_TOKENS, + [BTC_POOL_NAME]: { + lpToken: BTC_SWAP_TOKEN, + poolTokens: BTC_POOL_TOKENS, + }, + [STABLECOIN_POOL_NAME]: { + lpToken: STABLECOIN_SWAP_TOKEN, + poolTokens: STABLECOIN_POOL_TOKENS, + }, } export const TRANSACTION_TYPES = { diff --git a/src/hooks/useApproveAndDeposit.ts b/src/hooks/useApproveAndDeposit.ts index 8b23115..1d9ffbe 100644 --- a/src/hooks/useApproveAndDeposit.ts +++ b/src/hooks/useApproveAndDeposit.ts @@ -41,9 +41,7 @@ export function useApproveAndDeposit( transactionDeadlineSelected, infiniteApproval, } = useSelector((state: AppState) => state.user) - const POOL_TOKENS = POOLS_MAP[poolName] - if (!POOL_TOKENS) - throw new Error("useApproveAndDeposit requires a valid pool name") + const POOL = POOLS_MAP[poolName] return async function approveAndDeposit( state: ApproveAndDepositStateArgument, @@ -92,14 +90,13 @@ export function useApproveAndDeposit( } try { // For each token being deposited, check the allowance and approve it if necessary - // await Promise.all(POOL_TOKENS.map((token) => approveSingleToken(token))) - for (const token of POOL_TOKENS) { - await approveSingleToken(token) - } + await Promise.all( + POOL.poolTokens.map((token) => approveSingleToken(token)), + ) // "isFirstTransaction" check can be removed after launch const poolTokenBalances: BigNumber[] = await Promise.all( - POOL_TOKENS.map(async (token, i) => { + POOL.poolTokens.map(async (token, i) => { return await swapContract.getTokenBalance(i) }), ) @@ -110,7 +107,7 @@ export function useApproveAndDeposit( } else { minToMint = await swapContract.calculateTokenAmount( account, - POOL_TOKENS.map(({ symbol }) => state[symbol].valueSafe), + POOL.poolTokens.map(({ symbol }) => state[symbol].valueSafe), true, // deposit boolean ) } @@ -137,7 +134,7 @@ export function useApproveAndDeposit( ) const spendTransaction = await swapContract.addLiquidity( - POOL_TOKENS.map(({ symbol }) => state[symbol].valueSafe), + POOL.poolTokens.map(({ symbol }) => state[symbol].valueSafe), minToMint, Math.round(new Date().getTime() / 1000 + 60 * deadline), [], diff --git a/src/hooks/useApproveAndWithdraw.ts b/src/hooks/useApproveAndWithdraw.ts index e739337..a22cecc 100644 --- a/src/hooks/useApproveAndWithdraw.ts +++ b/src/hooks/useApproveAndWithdraw.ts @@ -42,9 +42,7 @@ export function useApproveAndWithdraw( infiniteApproval, } = useSelector((state: AppState) => state.user) const lpTokenContract = useLPTokenContract(poolName) - const POOL_TOKENS = POOLS_MAP[poolName] - if (!POOL_TOKENS) - throw new Error("useApproveAndWithdraw requires a valid pool name") + const POOL = POOLS_MAP[poolName] return async function approveAndWithdraw( state: ApproveAndWithdrawStateArgument, @@ -122,7 +120,7 @@ export function useApproveAndWithdraw( if (state.withdrawType === "ALL") { spendTransaction = await swapContract.removeLiquidity( state.lpTokenAmountToSpend, - POOL_TOKENS.map(({ symbol }) => + POOL.poolTokens.map(({ symbol }) => subtractSlippage( BigNumber.from(state.tokenFormState[symbol].valueSafe), slippageSelected, @@ -136,7 +134,7 @@ export function useApproveAndWithdraw( ) } else if (state.withdrawType === "IMBALANCE") { spendTransaction = await swapContract.removeLiquidityImbalance( - POOL_TOKENS.map( + POOL.poolTokens.map( ({ symbol }) => state.tokenFormState[symbol].valueSafe, ), addSlippage( @@ -153,7 +151,9 @@ export function useApproveAndWithdraw( // state.withdrawType === [TokenSymbol] spendTransaction = await swapContract.removeLiquidityOneToken( state.lpTokenAmountToSpend, - POOL_TOKENS.findIndex(({ symbol }) => symbol === state.withdrawType), + POOL.poolTokens.findIndex( + ({ symbol }) => symbol === state.withdrawType, + ), subtractSlippage( BigNumber.from( state.tokenFormState[state.withdrawType || ""].valueSafe, diff --git a/src/hooks/useContract.ts b/src/hooks/useContract.ts index 09be771..a25c4b3 100644 --- a/src/hooks/useContract.ts +++ b/src/hooks/useContract.ts @@ -6,7 +6,9 @@ import { PoolName, RENBTC, SBTC, + STABLECOIN_POOL_NAME, STABLECOIN_SWAP_ADDRESSES, + STABLECOIN_SWAP_TOKEN, SUSD, TBTC, Token, @@ -75,9 +77,10 @@ export function useSwapContract(poolName: PoolName): Swap | null { return useMemo(() => { if (poolName === BTC_POOL_NAME) { return btcSwapContract as Swap - } else { + } else if (poolName === STABLECOIN_POOL_NAME) { return stablecoinSwapContract as Swap } + return null }, [stablecoinSwapContract, btcSwapContract, poolName]) } @@ -103,6 +106,9 @@ export function useAllContracts(): AllContractsObject | null { const usdtContract = useTokenContract(USDT) as Erc20 const susdContract = useTokenContract(SUSD) as Erc20 const btcSwapTokenContract = useTokenContract(BTC_SWAP_TOKEN) as Swap + const stablecoinSwapTokenContract = useTokenContract( + STABLECOIN_SWAP_TOKEN, + ) as Swap return useMemo(() => { if ( @@ -116,6 +122,7 @@ export function useAllContracts(): AllContractsObject | null { usdtContract, susdContract, btcSwapTokenContract, + // stablecoinSwapTokenContract, // TODO: add back when contract deployed ].some(Boolean) ) return null @@ -129,6 +136,7 @@ export function useAllContracts(): AllContractsObject | null { [USDT.symbol]: usdtContract, [SUSD.symbol]: susdContract, [BTC_SWAP_TOKEN.symbol]: btcSwapTokenContract, + [STABLECOIN_SWAP_TOKEN.symbol]: stablecoinSwapTokenContract, } }, [ tbtcContract, @@ -140,5 +148,6 @@ export function useAllContracts(): AllContractsObject | null { usdtContract, susdContract, btcSwapTokenContract, + stablecoinSwapTokenContract, ]) } diff --git a/src/hooks/usePoolData.ts b/src/hooks/usePoolData.ts index 717ce94..9de38a9 100644 --- a/src/hooks/usePoolData.ts +++ b/src/hooks/usePoolData.ts @@ -1,6 +1,5 @@ import { POOLS_MAP, PoolName, TRANSACTION_TYPES } from "../constants" import { formatBNToPercentString, getContract } from "../utils" -import { useAllContracts, useSwapContract } from "./useContract" import { useEffect, useState } from "react" import { AddressZero } from "@ethersproject/constants" @@ -12,6 +11,7 @@ import { Zero } from "@ethersproject/constants" import { parseUnits } from "@ethersproject/units" import { useActiveWeb3React } from "." import { useSelector } from "react-redux" +import { useSwapContract } from "./useContract" interface TokenShareType { percent: string @@ -53,7 +53,6 @@ export default function usePoolData( ): PoolDataHookReturnType { const { account, library } = useActiveWeb3React() const swapContract = useSwapContract(poolName) - const tokenContracts = useAllContracts() const [poolData, setPoolData] = useState([null, null]) const { tokenPricesUSD, lastTransactionTimes } = useSelector( (state: AppState) => state.application, @@ -67,14 +66,13 @@ export default function usePoolData( if ( poolName == null || swapContract == null || - tokenContracts == null || tokenPricesUSD == null || library == null || account == null ) return - const POOL_TOKENS = POOLS_MAP[poolName] + const POOL = POOLS_MAP[poolName] // Swap fees, price, and LP Token data const [userCurrentWithdrawFee, swapStorage] = await Promise.all([ @@ -82,7 +80,7 @@ export default function usePoolData( swapContract.swapStorage(), ]) const { adminFee, lpToken: lpTokenAddress, swapFee } = swapStorage - const lpToken = getContract( + const lpTokenContract = getContract( lpTokenAddress, LPTOKEN_ABI, library, @@ -93,9 +91,9 @@ export default function usePoolData( userLpTokenMinted, totalLpTokenBalance, ] = await Promise.all([ - lpToken.balanceOf(account || AddressZero), - lpToken.mintedAmounts(account || AddressZero), - lpToken.totalSupply(), + lpTokenContract.balanceOf(account || AddressZero), + lpTokenContract.mintedAmounts(account || AddressZero), + lpTokenContract.totalSupply(), ]) const virtualPrice = totalLpTokenBalance.isZero() @@ -104,7 +102,7 @@ export default function usePoolData( // Pool token data const tokenBalances: BigNumber[] = await Promise.all( - POOL_TOKENS.map(async (token, i) => { + POOL.poolTokens.map(async (token, i) => { const balance = await swapContract.getTokenBalance(i) return BigNumber.from(10) .pow(18 - token.decimals) // cast all to 18 decimals @@ -114,7 +112,7 @@ export default function usePoolData( const tokenBalancesSum: BigNumber = tokenBalances.reduce((sum, b) => sum.add(b), ) - const tokenBalancesUSD = POOL_TOKENS.map((token, i) => { + const tokenBalancesUSD = POOL.poolTokens.map((token, i) => { const balance = tokenBalances[i] return balance .mul(parseUnits(String(tokenPricesUSD[token.symbol]), 18)) @@ -130,7 +128,7 @@ export default function usePoolData( .div(tokenBalancesSum) // (weeksPerYear * KEEPPerWeek * KEEPPrice) / (BTCPrice * BTCInPool) - const comparisonPoolToken = POOL_TOKENS[0] + const comparisonPoolToken = POOL.poolTokens[0] const keepAPRNumerator = BigNumber.from(52 * 250000) .mul(BigNumber.from(10).pow(18)) .mul(parseUnits(String(tokenPricesUSD.KEEP), 18)) @@ -163,7 +161,7 @@ export default function usePoolData( (sum, b) => sum.add(b), ) - const poolTokens = POOL_TOKENS.map((token, i) => ({ + const poolTokens = POOL.poolTokens.map((token, i) => ({ symbol: token.symbol, percent: formatBNToPercentString( tokenBalances[i] @@ -177,7 +175,7 @@ export default function usePoolData( ), value: tokenBalances[i], })) - const userPoolTokens = POOL_TOKENS.map((token, i) => ({ + const userPoolTokens = POOL.poolTokens.map((token, i) => ({ symbol: token.symbol, percent: formatBNToPercentString( tokenBalances[i] @@ -227,7 +225,6 @@ export default function usePoolData( lastSwapTime, poolName, swapContract, - tokenContracts, tokenPricesUSD, account, library, diff --git a/src/hooks/useWithdrawFormState.ts b/src/hooks/useWithdrawFormState.ts index a620c47..4bb7701 100644 --- a/src/hooks/useWithdrawFormState.ts +++ b/src/hooks/useWithdrawFormState.ts @@ -39,7 +39,7 @@ export type WithdrawFormAction = { export default function useWithdrawFormState( poolName: PoolName, ): [WithdrawFormState, (action: WithdrawFormAction) => void] { - const POOL_TOKENS = POOLS_MAP[poolName] + const POOL = POOLS_MAP[poolName] const swapContract = useSwapContract(poolName) const [, userShareData] = usePoolData(poolName) const { account } = useActiveWeb3React() @@ -47,25 +47,25 @@ export default function useWithdrawFormState( [tokenSymbol: string]: ReturnType } = useMemo( () => - POOL_TOKENS.reduce( + POOL.poolTokens.reduce( (acc, { symbol, decimals }) => ({ ...acc, [symbol]: numberInputStateCreator(decimals, BigNumber.from("0")), }), {}, ), - [POOL_TOKENS], + [POOL.poolTokens], ) const tokenInputsEmptyState = useMemo( () => - POOL_TOKENS.reduce( + POOL.poolTokens.reduce( (acc, { symbol }) => ({ ...acc, [symbol]: tokenInputStateCreators[symbol]("0"), }), {}, ), - [POOL_TOKENS, tokenInputStateCreators], + [POOL.poolTokens, tokenInputStateCreators], ) const formEmptyState = useMemo( () => ({ @@ -106,7 +106,7 @@ export default function useWithdrawFormState( try { const inputCalculatedLPTokenAmount = await swapContract.calculateTokenAmount( account, - POOL_TOKENS.map( + POOL.poolTokens.map( ({ symbol }) => state.tokenInputs[symbol].valueSafe, ), false, @@ -144,7 +144,7 @@ export default function useWithdrawFormState( ) nextState = { lpTokenAmountToSpend: effectiveUserLPTokenBalance, - tokenInputs: POOL_TOKENS.reduce( + tokenInputs: POOL.poolTokens.reduce( (acc, { symbol }, i) => ({ ...acc, [symbol]: tokenInputStateCreators[symbol](tokenAmounts[i]), @@ -164,7 +164,7 @@ export default function useWithdrawFormState( } else { try { if (state.percentage) { - const tokenIndex = POOL_TOKENS.findIndex( + const tokenIndex = POOL.poolTokens.findIndex( ({ symbol }) => symbol === state.withdrawType, ) const tokenAmount = await swapContract.calculateRemoveLiquidityOneToken( @@ -174,7 +174,7 @@ export default function useWithdrawFormState( ) // actual coin amount to be returned nextState = { lpTokenAmountToSpend: effectiveUserLPTokenBalance, - tokenInputs: POOL_TOKENS.reduce( + tokenInputs: POOL.poolTokens.reduce( (acc, { symbol }, i) => ({ ...acc, [symbol]: tokenInputStateCreators[symbol]( @@ -189,7 +189,7 @@ export default function useWithdrawFormState( // This branch addresses a user manually inputting a value for one token const inputCalculatedLPTokenAmount = await swapContract.calculateTokenAmount( account, - POOL_TOKENS.map( + POOL.poolTokens.map( ({ symbol }) => state.tokenInputs[symbol].valueSafe, ), false, @@ -223,7 +223,7 @@ export default function useWithdrawFormState( ...nextState, })) }, 250), - [userShareData, swapContract, POOL_TOKENS, tokenInputStateCreators], + [userShareData, swapContract, POOL.poolTokens, tokenInputStateCreators], ) const handleUpdateForm = useCallback( @@ -243,7 +243,7 @@ export default function useWithdrawFormState( valueInput, ), } - const activeInputTokens = POOL_TOKENS.filter( + const activeInputTokens = POOL.poolTokens.filter( ({ symbol }) => +newTokenInputs[symbol].valueRaw !== 0, ) let withdrawType @@ -295,7 +295,7 @@ export default function useWithdrawFormState( } const pendingTokenInput = action.fieldName === "tokenInputs" && - POOL_TOKENS.every(({ symbol }) => { + POOL.poolTokens.every(({ symbol }) => { const stateValue = finalState.tokenInputs[symbol].valueRaw return isNaN(+stateValue) || +stateValue === 0 }) @@ -306,7 +306,7 @@ export default function useWithdrawFormState( }) }, [ - POOL_TOKENS, + POOL.poolTokens, calculateAndUpdateDynamicFields, tokenInputStateCreators, tokenInputsEmptyState, diff --git a/src/pages/App.tsx b/src/pages/App.tsx index b5786f3..cd97123 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -1,16 +1,16 @@ import "../styles/global.scss" +import { BLOCK_TIME, BTC_POOL_NAME } from "../constants" import React, { ReactElement, Suspense, useCallback } from "react" import { Route, Switch } from "react-router-dom" import { AppDispatch } from "../state" -import { BLOCK_TIME } from "../constants" -import DepositBTC from "./DepositBTC" +import Deposit from "./Deposit" import Risk from "./Risk" -import SwapBTC from "./SwapBTC" +import Swap from "./Swap" import ToastsProvider from "../providers/ToastsProvider" import Web3ReactManager from "../components/Web3ReactManager" -import WithdrawBTC from "./WithdrawBTC" +import Withdraw from "./Withdraw" import fetchGasPrices from "../utils/updateGasPrices" import fetchTokenPricesUSD from "../utils/updateTokenPrices" import { useDispatch } from "react-redux" @@ -33,9 +33,25 @@ export default function App(): ReactElement { - - - + } + /> + ( + + )} + /> + ( + + )} + /> diff --git a/src/pages/DepositBTC.tsx b/src/pages/Deposit.tsx similarity index 78% rename from src/pages/DepositBTC.tsx rename to src/pages/Deposit.tsx index 22ff4c0..e67b6fc 100644 --- a/src/pages/DepositBTC.tsx +++ b/src/pages/Deposit.tsx @@ -1,13 +1,5 @@ -import { - BTC_POOL_NAME, - BTC_POOL_TOKENS, - BTC_SWAP_TOKEN, - RENBTC, - SBTC, - TBTC, - WBTC, -} from "../constants" import { DepositTransaction, TransactionItem } from "../interfaces/transactions" +import { POOLS_MAP, PoolName, Token } from "../constants" import React, { ReactElement, useEffect, useState } from "react" import { TokensStateType, useTokenFormState } from "../hooks/useTokenFormState" import { formatBNToString, shiftBNDecimals } from "../utils" @@ -22,18 +14,24 @@ import { calculatePriceImpact } from "../utils/priceImpact" import { parseUnits } from "@ethersproject/units" import { useActiveWeb3React } from "../hooks" import { useApproveAndDeposit } from "../hooks/useApproveAndDeposit" +import { usePoolTokenBalances } from "../state/wallet/hooks" import { useSelector } from "react-redux" import { useSwapContract } from "../hooks/useContract" -import { useTokenBalance } from "../state/wallet/hooks" -function DepositBTC(): ReactElement | null { +interface Props { + poolName: PoolName +} + +function Deposit({ poolName }: Props): ReactElement | null { + const POOL = POOLS_MAP[poolName] const { account } = useActiveWeb3React() - const approveAndDeposit = useApproveAndDeposit(BTC_POOL_NAME) - const [poolData, userShareData] = usePoolData(BTC_POOL_NAME) - const swapContract = useSwapContract(BTC_POOL_NAME) + const approveAndDeposit = useApproveAndDeposit(poolName) + const [poolData, userShareData] = usePoolData(poolName) + const swapContract = useSwapContract(poolName) const [tokenFormState, updateTokenFormState] = useTokenFormState( - BTC_POOL_TOKENS, + POOL.poolTokens, ) + const tokenBalances = usePoolTokenBalances(poolName) const { tokenPricesUSD } = useSelector((state: AppState) => state.application) const [estDepositLPTokenAmount, setEstDepositLPTokenAmount] = useState(Zero) const [priceImpact, setPriceImpact] = useState(Zero) @@ -51,17 +49,19 @@ function DepositBTC(): ReactElement | null { return } const tokenInputSum = parseUnits( - BTC_POOL_TOKENS.reduce( - (sum, { symbol }) => sum + (+tokenFormState[symbol].valueRaw || 0), - 0, - ).toFixed(18), + POOL.poolTokens + .reduce( + (sum, { symbol }) => sum + (+tokenFormState[symbol].valueRaw || 0), + 0, + ) + .toFixed(18), 18, ) let depositLPTokenAmount if (poolData.totalLocked.gt(0) && tokenInputSum.gt(0)) { depositLPTokenAmount = await swapContract.calculateTokenAmount( account, - BTC_POOL_TOKENS.map(({ symbol }) => tokenFormState[symbol].valueSafe), + POOL.poolTokens.map(({ symbol }) => tokenFormState[symbol].valueSafe), true, // deposit boolean ) } else { @@ -79,25 +79,26 @@ function DepositBTC(): ReactElement | null { ) } void calculateMaxDeposits() - }, [poolData, tokenFormState, swapContract, userShareData, account]) - // Account Token balances - const tokenBalances = { - [TBTC.symbol]: useTokenBalance(TBTC), - [WBTC.symbol]: useTokenBalance(WBTC), - [RENBTC.symbol]: useTokenBalance(RENBTC), - [SBTC.symbol]: useTokenBalance(SBTC), - } + }, [ + poolData, + tokenFormState, + swapContract, + userShareData, + account, + POOL.poolTokens, + ]) + // A represention of tokens used for UI - const tokens = BTC_POOL_TOKENS.map(({ symbol, name, icon, decimals }) => ({ + const tokens = POOL.poolTokens.map(({ symbol, name, icon, decimals }) => ({ symbol, name, icon, - max: formatBNToString(tokenBalances[symbol], decimals), + max: formatBNToString(tokenBalances?.[symbol] || Zero, decimals), inputValue: tokenFormState[symbol].valueRaw, })) - const exceedsWallet = BTC_POOL_TOKENS.some(({ symbol }) => { - const exceedsBoolean = tokenBalances[symbol].lt( + const exceedsWallet = POOL.poolTokens.some(({ symbol }) => { + const exceedsBoolean = (tokenBalances?.[symbol] || Zero).lt( BigNumber.from(tokenFormState[symbol].valueSafe), ) return exceedsBoolean @@ -107,7 +108,7 @@ function DepositBTC(): ReactElement | null { await approveAndDeposit(tokenFormState) // Clear input after deposit updateTokenFormState( - BTC_POOL_TOKENS.reduce( + POOL.poolTokens.reduce( (acc, t) => ({ ...acc, [t.symbol]: "", @@ -122,6 +123,8 @@ function DepositBTC(): ReactElement | null { const depositTransaction = buildTransactionData( tokenFormState, poolData, + POOL.poolTokens, + POOL.lpToken, priceImpact, estDepositLPTokenAmount, tokenPricesUSD, @@ -131,7 +134,7 @@ function DepositBTC(): ReactElement | null { { + poolTokens.forEach((token) => { const { symbol, decimals } = token const amount = BigNumber.from(tokenFormState[symbol].valueSafe) const usdPriceBN = parseUnits( @@ -179,10 +184,10 @@ function buildTransactionData( const lpTokenPriceUSD = poolData?.lpTokenPriceUSD || Zero const toTotalValueUSD = estDepositLPTokenAmount .mul(lpTokenPriceUSD) - ?.div(BigNumber.from(10).pow(BTC_SWAP_TOKEN.decimals)) + ?.div(BigNumber.from(10).pow(poolLpToken.decimals)) const to = { item: { - token: BTC_SWAP_TOKEN, + token: poolLpToken, amount: estDepositLPTokenAmount, singleTokenPriceUSD: lpTokenPriceUSD, valueUSD: toTotalValueUSD, @@ -203,4 +208,4 @@ function buildTransactionData( } } -export default DepositBTC +export default Deposit diff --git a/src/pages/SwapBTC.tsx b/src/pages/Swap.tsx similarity index 91% rename from src/pages/SwapBTC.tsx rename to src/pages/Swap.tsx index 6ba2111..5c9ad9f 100644 --- a/src/pages/SwapBTC.tsx +++ b/src/pages/Swap.tsx @@ -1,4 +1,4 @@ -import { BTC_POOL_NAME, BTC_POOL_TOKENS, TOKENS_MAP } from "../constants" +import { POOLS_MAP, PoolName, TOKENS_MAP } from "../constants" import React, { ReactElement, useCallback, useState } from "react" import { formatUnits, parseUnits } from "@ethersproject/units" @@ -26,27 +26,31 @@ interface FormState { priceImpact: BigNumber exchangeRate: BigNumber } -function SwapBTC(): ReactElement { +interface Props { + poolName: PoolName +} +function Swap({ poolName }: Props): ReactElement { const { t } = useTranslation() - const [poolData] = usePoolData(BTC_POOL_NAME) - const approveAndSwap = useApproveAndSwap(BTC_POOL_NAME) - const tokenBalances = usePoolTokenBalances(BTC_POOL_NAME) - const swapContract = useSwapContract(BTC_POOL_NAME) + const [poolData] = usePoolData(poolName) + const approveAndSwap = useApproveAndSwap(poolName) + const tokenBalances = usePoolTokenBalances(poolName) + const swapContract = useSwapContract(poolName) + const POOL = POOLS_MAP[poolName] const [formState, setFormState] = useState({ error: null, from: { - symbol: BTC_POOL_TOKENS[0].symbol, + symbol: POOL.poolTokens[0].symbol, value: "0.0", }, to: { - symbol: BTC_POOL_TOKENS[1].symbol, + symbol: POOL.poolTokens[1].symbol, value: BigNumber.from("0"), }, priceImpact: BigNumber.from("0"), exchangeRate: BigNumber.from("0"), }) // build a representation of pool tokens for the UI - const tokens = BTC_POOL_TOKENS.map(({ symbol, name, icon, decimals }) => ({ + const tokens = POOL.poolTokens.map(({ symbol, name, icon, decimals }) => ({ name, icon, symbol, @@ -71,10 +75,10 @@ function SwapBTC(): ReactElement { return } // TODO: improve the relationship between token / index - const tokenIndexFrom = BTC_POOL_TOKENS.findIndex( + const tokenIndexFrom = POOL.poolTokens.findIndex( ({ symbol }) => symbol === formStateArg.from.symbol, ) - const tokenIndexTo = BTC_POOL_TOKENS.findIndex( + const tokenIndexTo = POOL.poolTokens.findIndex( ({ symbol }) => symbol === formStateArg.to.symbol, ) const amountToGive = parseUnits( @@ -246,4 +250,4 @@ function SwapBTC(): ReactElement { ) } -export default SwapBTC +export default Swap diff --git a/src/pages/WithdrawBTC.tsx b/src/pages/Withdraw.tsx similarity index 80% rename from src/pages/WithdrawBTC.tsx rename to src/pages/Withdraw.tsx index 71ee804..051c83e 100644 --- a/src/pages/WithdrawBTC.tsx +++ b/src/pages/Withdraw.tsx @@ -1,4 +1,4 @@ -import { BTC_POOL_NAME, BTC_POOL_TOKENS } from "../constants" +import { POOLS_MAP, PoolName } from "../constants" import React, { ReactElement, useEffect, useState } from "react" import WithdrawPage, { ReviewWithdrawData } from "../components/WithdrawPage" import { commify, formatUnits, parseUnits } from "@ethersproject/units" @@ -15,18 +15,22 @@ import { useSelector } from "react-redux" import { useSwapContract } from "../hooks/useContract" import useWithdrawFormState from "../hooks/useWithdrawFormState" -function WithdrawBTC(): ReactElement { - const [poolData, userShareData] = usePoolData(BTC_POOL_NAME) +interface Props { + poolName: PoolName +} +function Withdraw({ poolName }: Props): ReactElement { + const [poolData, userShareData] = usePoolData(poolName) const [withdrawFormState, updateWithdrawFormState] = useWithdrawFormState( - BTC_POOL_NAME, + poolName, ) const { slippageCustom, slippageSelected } = useSelector( (state: AppState) => state.user, ) const { tokenPricesUSD } = useSelector((state: AppState) => state.application) - const approveAndWithdraw = useApproveAndWithdraw(BTC_POOL_NAME) - const swapContract = useSwapContract(BTC_POOL_NAME) + const approveAndWithdraw = useApproveAndWithdraw(poolName) + const swapContract = useSwapContract(poolName) const { account } = useActiveWeb3React() + const POOL = POOLS_MAP[poolName] const [estWithdrawBonus, setEstWithdrawBonus] = useState(Zero) useEffect(() => { @@ -41,18 +45,20 @@ function WithdrawBTC(): ReactElement { return } const tokenInputSum = parseUnits( - BTC_POOL_TOKENS.reduce( - (sum, { symbol }) => - sum + (+withdrawFormState.tokenInputs[symbol].valueRaw || 0), - 0, - ).toFixed(18), + POOL.poolTokens + .reduce( + (sum, { symbol }) => + sum + (+withdrawFormState.tokenInputs[symbol].valueRaw || 0), + 0, + ) + .toFixed(18), 18, ) let withdrawLPTokenAmount if (poolData.totalLocked.gt(0) && tokenInputSum.gt(0)) { withdrawLPTokenAmount = await swapContract.calculateTokenAmount( account, - BTC_POOL_TOKENS.map( + POOL.poolTokens.map( ({ symbol }) => withdrawFormState.tokenInputs[symbol].valueSafe, ), false, @@ -70,7 +76,14 @@ function WithdrawBTC(): ReactElement { ) } void calculateWithdrawBonus() - }, [poolData, withdrawFormState, swapContract, userShareData, account]) + }, [ + poolData, + withdrawFormState, + swapContract, + userShareData, + account, + POOL.poolTokens, + ]) async function onConfirmTransaction(): Promise { const { withdrawType, @@ -87,13 +100,13 @@ function WithdrawBTC(): ReactElement { const tokensData = React.useMemo( () => - BTC_POOL_TOKENS.map(({ name, symbol, icon }) => ({ + POOL.poolTokens.map(({ name, symbol, icon }) => ({ name, symbol, icon, inputValue: withdrawFormState.tokenInputs[symbol].valueRaw, })), - [withdrawFormState], + [withdrawFormState, POOL.poolTokens], ) const reviewWithdrawData: ReviewWithdrawData = { @@ -102,7 +115,7 @@ function WithdrawBTC(): ReactElement { slippage: formatSlippageToString(slippageSelected, slippageCustom), priceImpact: estWithdrawBonus, } - BTC_POOL_TOKENS.forEach(({ name, decimals, icon, symbol }) => { + POOL.poolTokens.forEach(({ name, decimals, icon, symbol }) => { if (BigNumber.from(withdrawFormState.tokenInputs[symbol].valueSafe).gt(0)) { reviewWithdrawData.withdraw.push({ name, @@ -129,7 +142,7 @@ function WithdrawBTC(): ReactElement { return ( ({ [TBTC.symbol]: tbtcTokenBalance, - [WBTC.symbol]: wtcTokenBalance, + [WBTC.symbol]: wbtcTokenBalance, [RENBTC.symbol]: renbtcTokenBalance, [SBTC.symbol]: sbtcTokenBalance, }), - [tbtcTokenBalance, wtcTokenBalance, renbtcTokenBalance, sbtcTokenBalance], + [tbtcTokenBalance, wbtcTokenBalance, renbtcTokenBalance, sbtcTokenBalance], + ) + const stablecoinPoolTokenBalances = useMemo( + () => ({ + [DAI.symbol]: daiTokenBalance, + [USDC.symbol]: usdcTokenBalance, + [USDT.symbol]: usdtTokenBalance, + [SUSD.symbol]: susdTokenBalance, + }), + [daiTokenBalance, usdcTokenBalance, usdtTokenBalance, susdTokenBalance], ) if (poolName === BTC_POOL_NAME) { return btcPoolTokenBalances + } else if (poolName === STABLECOIN_POOL_NAME) { + return stablecoinPoolTokenBalances } return null }