diff --git a/src/App.tsx b/src/App.tsx
index 47ebfbea6..cd8144326 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -17,7 +17,6 @@ import {
} from "react-router-dom"
import { BigNumberish } from "@ethersproject/bignumber"
import { Event } from "@ethersproject/contracts"
-import { TokenContextProvider } from "./contexts/TokenContext"
import theme from "./theme"
import reduxStore, { resetStoreAction } from "./store"
import ModalRoot from "./components/Modal"
@@ -204,11 +203,9 @@ const App: FC = () => {
-
-
-
-
-
+
+
+
diff --git a/src/components/TokenBalanceCard/index.tsx b/src/components/TokenBalanceCard/index.tsx
index 857b49deb..921bcb394 100644
--- a/src/components/TokenBalanceCard/index.tsx
+++ b/src/components/TokenBalanceCard/index.tsx
@@ -8,7 +8,7 @@ import { useToken } from "../../hooks/useToken"
import { tBTCFillBlack } from "../../static/icons/tBTCFillBlack"
export interface TokenBalanceCardProps {
- token: Exclude
+ token: Exclude
title?: string
tokenSymbol?: string
withSymbol?: boolean
@@ -18,7 +18,7 @@ const tokenToIconMap = {
[Token.Keep]: KeepCircleBrand,
[Token.Nu]: NuCircleBrand,
[Token.T]: T,
- [Token.TBTCV2]: tBTCFillBlack,
+ [Token.TBTC]: tBTCFillBlack,
}
const TokenBalanceCard: FC = ({
diff --git a/src/contexts/TokenContext.tsx b/src/contexts/TokenContext.tsx
deleted file mode 100644
index 68467c305..000000000
--- a/src/contexts/TokenContext.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-import React, { createContext } from "react"
-import { Contract } from "@ethersproject/contracts"
-import { AddressZero } from "@ethersproject/constants"
-import { useWeb3React } from "@web3-react/core"
-import { useKeep } from "../web3/hooks/useKeep"
-import { useNu } from "../web3/hooks/useNu"
-import { useT } from "../web3/hooks/useT"
-import { useTokenState } from "../hooks/useTokenState"
-import { useTokensBalanceCall } from "../hooks/useTokensBalanceCall"
-import { Token } from "../enums"
-import { TokenState } from "../types"
-import { useTBTCTokenContract } from "../web3/hooks"
-import { useVendingMachineRatio } from "../web3/hooks/useVendingMachineRatio"
-import { useFetchOwnerStakes } from "../hooks/useFetchOwnerStakes"
-import { useTBTCv2TokenContract } from "../web3/hooks/useTBTCv2TokenContract"
-import { featureFlags } from "../constants"
-
-interface TokenContextState extends TokenState {
- contract: Contract | null
-}
-
-export const TokenContext = createContext<{
- [key in Token]: TokenContextState
-}>({
- [Token.Keep]: {} as TokenContextState,
- [Token.Nu]: {} as TokenContextState,
- [Token.T]: {} as TokenContextState,
- [Token.TBTC]: {} as TokenContextState,
- [Token.TBTCV2]: {} as TokenContextState,
-})
-
-// Context that handles data fetching when a user connects their wallet or
-// switches their network
-export const TokenContextProvider: React.FC = ({ children }) => {
- const keep = useKeep()
- const nu = useNu()
- const t = useT()
- const tbtc = useTBTCTokenContract()
- const tbtcv2 = useTBTCv2TokenContract()
- const nuConversion = useVendingMachineRatio(Token.Nu)
- const keepConversion = useVendingMachineRatio(Token.Keep)
- const { active, chainId, account } = useWeb3React()
- const fetchOwnerStakes = useFetchOwnerStakes()
-
- const {
- fetchTokenPriceUSD,
- setTokenBalance,
- setTokenConversionRate,
- keep: keepData,
- nu: nuData,
- t: tData,
- tbtc: tbtcData,
- tbtcv2: tbtcv2Data,
- } = useTokenState()
-
- const tokenContracts = [keep.contract!, nu.contract!, t.contract!]
-
- if (!!tbtcv2) tokenContracts.push(tbtcv2.contract)
-
- const fetchBalances = useTokensBalanceCall(
- tokenContracts,
- active ? account! : AddressZero
- )
-
- //
- // SET T CONVERSION RATE FOR KEEP, NU
- //
- React.useEffect(() => {
- setTokenConversionRate(Token.Nu, nuConversion)
- setTokenConversionRate(Token.Keep, keepConversion)
- }, [nuConversion, keepConversion])
-
- //
- // SET USD PRICE
- //
- React.useEffect(() => {
- for (const token in Token) {
- if (token) {
- // @ts-ignore
- fetchTokenPriceUSD(Token[token])
- }
- }
- }, [])
-
- //
- // FETCH BALANCES ON WALLET LOAD OR NETWORK SWITCH
- //
- React.useEffect(() => {
- if (active) {
- fetchBalances().then(
- ([keepBalance, nuBalance, tBalance, tbtcv2Balance]) => {
- setTokenBalance(Token.Keep, keepBalance.toString())
- setTokenBalance(Token.Nu, nuBalance.toString())
- setTokenBalance(Token.T, tBalance.toString())
- if (featureFlags.TBTC_V2) {
- setTokenBalance(Token.TBTCV2, tbtcv2Balance.toString())
- }
- }
- )
- } else {
- // set all token balances to 0 if the user disconnects the wallet
- for (const token in Token) {
- if (token) {
- // @ts-ignore
- setTokenBalance(Token[token], 0)
- }
- }
- }
- }, [active, chainId, account])
-
- // fetch user stakes when they connect their wallet
- React.useEffect(() => {
- fetchOwnerStakes(account!)
- }, [fetchOwnerStakes, account])
-
- return (
-
- {children}
-
- )
-}
diff --git a/src/enums/token.ts b/src/enums/token.ts
index 024ccdac0..53527a97a 100644
--- a/src/enums/token.ts
+++ b/src/enums/token.ts
@@ -2,8 +2,8 @@ export enum Token {
Keep = "KEEP",
Nu = "NU",
T = "T",
+ TBTCV1 = "TBTCV1",
TBTC = "TBTC",
- TBTCV2 = "TBTCV2",
}
export enum CoingeckoID {
@@ -11,9 +11,9 @@ export enum CoingeckoID {
NU = "nucypher",
T = "threshold-network-token",
ETH = "ethereum",
- TBTC = "tbtc",
+ TBTCV1 = "tbtc",
// TODO: add prope tbtc-v2 id when it lands on coingecko
- TBTCV2 = "tbtc",
+ TBTC = "tbtc",
}
export enum TConversionRates {
diff --git a/src/hooks/__tests__/useFetchTvl.test.tsx b/src/hooks/__tests__/useFetchTvl.test.tsx
index 1eed3f3d7..674209be2 100644
--- a/src/hooks/__tests__/useFetchTvl.test.tsx
+++ b/src/hooks/__tests__/useFetchTvl.test.tsx
@@ -11,8 +11,7 @@ import {
} from "../../web3/hooks"
import { useETHData } from "../useETHData"
import { useFetchTvl } from "../useFetchTvl"
-import * as useTokenModule from "../useToken"
-import { TokenContext } from "../../contexts/TokenContext"
+import { useToken } from "../useToken"
import * as usdUtils from "../../utils/getUsdBalance"
jest.mock("../../web3/hooks", () => ({
@@ -30,6 +29,11 @@ jest.mock("../useETHData", () => ({
useETHData: jest.fn(),
}))
+jest.mock("../useToken", () => ({
+ ...(jest.requireActual("../useToken") as {}),
+ useToken: jest.fn(),
+}))
+
describe("Test `useFetchTvl` hook", () => {
const keepContext = {
contract: {} as any,
@@ -56,18 +60,7 @@ describe("Test `useFetchTvl` hook", () => {
const mockedMultiCallContract = { interface: {}, address: "0x3" }
const mockedKeepAssetPoolContract = { interface: {}, address: "0x4" }
- const wrapper = ({ children }) => (
-
- {children}
-
- )
+ const wrapper = ({ children }) => <>{children}>
const multicallRequest = jest.fn()
const mockedETHData = { usdPrice: 20 }
@@ -88,6 +81,16 @@ describe("Test `useFetchTvl` hook", () => {
;(useKeepTokenStakingContract as jest.Mock).mockReturnValue(
mockedKeepTokenStakingContract
)
+ ;(useToken as jest.Mock).mockImplementation((token: Token) => {
+ switch (token) {
+ case Token.Keep:
+ return keepContext
+ case Token.T:
+ return tContext
+ case Token.TBTCV1:
+ return tbtcContext
+ }
+ })
})
test("should fetch tvl data correctly.", async () => {
@@ -110,7 +113,6 @@ describe("Test `useFetchTvl` hook", () => {
const spyOnFormatUnits = jest.spyOn(ethersUnits, "formatUnits")
const spyOnToUsdBalance = jest.spyOn(usdUtils, "toUsdBalance")
- const spyOnUseToken = jest.spyOn(useTokenModule, "useToken")
const _expectedResult = {
ecdsa: ethInKeepBonding.format * mockedETHData.usdPrice,
@@ -144,9 +146,9 @@ describe("Test `useFetchTvl` hook", () => {
// then
expect(useETHData).toHaveBeenCalled()
- expect(spyOnUseToken).toHaveBeenCalledWith(Token.Keep)
- expect(spyOnUseToken).toHaveBeenCalledWith(Token.TBTC)
- expect(spyOnUseToken).toHaveBeenCalledWith(Token.T)
+ expect(useToken).toHaveBeenCalledWith(Token.Keep)
+ expect(useToken).toHaveBeenCalledWith(Token.TBTCV1)
+ expect(useToken).toHaveBeenCalledWith(Token.T)
expect(useKeepBondingContract).toHaveBeenCalled()
expect(useMulticallContract).toHaveBeenCalled()
expect(useKeepAssetPoolContract).toHaveBeenCalled()
diff --git a/src/hooks/useFetchTvl.ts b/src/hooks/useFetchTvl.ts
index 811977b02..5dbf4d2da 100644
--- a/src/hooks/useFetchTvl.ts
+++ b/src/hooks/useFetchTvl.ts
@@ -51,7 +51,7 @@ export const useFetchTvl = (): [TVLData, () => Promise] => {
const eth = useETHData()
const keep = useToken(Token.Keep)
- const tbtc = useToken(Token.TBTC)
+ const tbtc = useToken(Token.TBTCV1)
const t = useToken(Token.T)
const keepBonding = useKeepBondingContract()
const multicall = useMulticallContract()
diff --git a/src/hooks/useToken.ts b/src/hooks/useToken.ts
index be6a222ed..3a0204ee6 100644
--- a/src/hooks/useToken.ts
+++ b/src/hooks/useToken.ts
@@ -1,9 +1,38 @@
-import { useContext } from "react"
-import { TokenContext } from "../contexts/TokenContext"
import { Token } from "../enums"
+import { selectTokenByTokenName } from "../store/tokens/selectors"
+import {
+ useKeep,
+ useNu,
+ useT,
+ useTBTCTokenContract,
+ useTBTCv2TokenContract,
+} from "../web3/hooks"
+import { useAppSelector } from "./store"
+
+const useSupportedTokens = () => {
+ const keep = useKeep()
+ const nu = useNu()
+ const t = useT()
+ const tbtcv1 = useTBTCTokenContract()
+ const tbtc = useTBTCv2TokenContract()
+
+ return {
+ [Token.Keep]: keep,
+ [Token.Nu]: nu,
+ [Token.T]: t,
+ [Token.TBTCV1]: tbtcv1,
+ [Token.TBTC]: tbtc,
+ }
+}
export const useToken = (token: Token) => {
- const tokenContext = useContext(TokenContext)
+ const tokenState = useAppSelector((state) =>
+ selectTokenByTokenName(state, token)
+ )
+ const _token = useSupportedTokens()[token]
- return tokenContext[token]
+ return {
+ ...tokenState,
+ ..._token,
+ }
}
diff --git a/src/hooks/useTokenState.ts b/src/hooks/useTokenState.ts
index 7e1629d78..75964a769 100644
--- a/src/hooks/useTokenState.ts
+++ b/src/hooks/useTokenState.ts
@@ -1,46 +1,54 @@
-import { useSelector, useDispatch } from "react-redux"
import {
- setTokenBalance as setTokenBalanceAction,
- setTokenLoading as setTokenLoadingAction,
+ tokenBalanceFetched as setTokenBalanceAction,
+ tokenBalanceFetching as setTokenLoadingAction,
fetchTokenPriceUSD as fetchTokenPriceAction,
- setTokenConversionRate as setTokenConversionRateAction,
+ tokenBalanceFetchFailed as setTokenBalanceErrorAction,
} from "../store/tokens"
-import { RootState } from "../store"
+import { useAppDispatch, useAppSelector } from "./store"
import { Token } from "../enums"
import { UseTokenState } from "../types/token"
+import { useCallback } from "react"
export const useTokenState: UseTokenState = () => {
- const keep = useSelector((state: RootState) => state.token[Token.Keep])
- const nu = useSelector((state: RootState) => state.token[Token.Nu])
- const t = useSelector((state: RootState) => state.token[Token.T])
- const tbtc = useSelector((state: RootState) => state.token[Token.TBTC])
- const tbtcv2 = useSelector((state: RootState) => state.token[Token.TBTCV2])
+ const keep = useAppSelector((state) => state.token[Token.Keep])
+ const nu = useAppSelector((state) => state.token[Token.Nu])
+ const t = useAppSelector((state) => state.token[Token.T])
+ const tbtcv1 = useAppSelector((state) => state.token[Token.TBTCV1])
+ const tbtc = useAppSelector((state) => state.token[Token.TBTC])
- const dispatch = useDispatch()
+ const dispatch = useAppDispatch()
- const setTokenConversionRate = (
- token: Token,
- conversionRate: number | string
- ) => dispatch(setTokenConversionRateAction({ token, conversionRate }))
+ const setTokenBalance = useCallback(
+ (token: Token, balance: number | string) =>
+ dispatch(setTokenBalanceAction({ token, balance })),
+ [dispatch]
+ )
- const setTokenBalance = (token: Token, balance: number | string) =>
- dispatch(setTokenBalanceAction({ token, balance }))
+ const setTokenLoading = useCallback(
+ (token: Token) => dispatch(setTokenLoadingAction({ token })),
+ [dispatch]
+ )
- const setTokenLoading = (token: Token, loading: boolean) =>
- dispatch(setTokenLoadingAction({ token, loading }))
+ const fetchTokenPriceUSD = useCallback(
+ (token: Token) => dispatch(fetchTokenPriceAction({ token })),
+ [dispatch]
+ )
- const fetchTokenPriceUSD = (token: Token) =>
- dispatch(fetchTokenPriceAction({ token }))
+ const setTokenBalanceError = useCallback(
+ (token: Token, error: string) =>
+ dispatch(setTokenBalanceErrorAction({ token, error })),
+ [dispatch]
+ )
return {
keep,
nu,
t,
- tbtc,
- tbtcv2,
+ tbtc: tbtcv1,
+ tbtcv2: tbtc,
fetchTokenPriceUSD,
setTokenBalance,
setTokenLoading,
- setTokenConversionRate,
+ setTokenBalanceError,
}
}
diff --git a/src/hooks/useTransaction.ts b/src/hooks/useTransaction.ts
index c7a275d32..d23c85ec8 100644
--- a/src/hooks/useTransaction.ts
+++ b/src/hooks/useTransaction.ts
@@ -3,6 +3,7 @@ import { setTransactionStatus as setTransactionStatusAction } from "../store/tra
import { RootState } from "../store"
import { UseTransaction } from "../types/transaction"
import { TransactionStatus, TransactionType } from "../enums/transactionType"
+import { useCallback } from "react"
export const useTransaction: UseTransaction = () => {
const keepApproval = useSelector(
@@ -20,10 +21,11 @@ export const useTransaction: UseTransaction = () => {
const dispatch = useDispatch()
- const setTransactionStatus = (
- type: TransactionType,
- status: TransactionStatus
- ) => dispatch(setTransactionStatusAction({ type, status }))
+ const setTransactionStatus = useCallback(
+ (type: TransactionType, status: TransactionStatus) =>
+ dispatch(setTransactionStatusAction({ type, status })),
+ [dispatch]
+ )
return {
setTransactionStatus,
diff --git a/src/pages/Overview/Network/WalletBalances.tsx b/src/pages/Overview/Network/WalletBalances.tsx
index 0b72fdd4f..0a8a6abd1 100644
--- a/src/pages/Overview/Network/WalletBalances.tsx
+++ b/src/pages/Overview/Network/WalletBalances.tsx
@@ -19,6 +19,7 @@ import InfoBox from "../../../components/InfoBox"
import Link from "../../../components/Link"
import useUpgradeHref from "../../../hooks/useUpgradeHref"
import ButtonLink from "../../../components/ButtonLink"
+import { useTExchangeRate } from "../../../hooks/useTExchangeRate"
const BalanceStat: FC<{
balance: string | number
@@ -39,7 +40,7 @@ const BalanceStat: FC<{
/>
{conversionRate && (
- 1 {text} = {conversionRate} T
+ 1 {text} = {formatTokenAmount(conversionRate, "0.0000")} T
)}
@@ -86,6 +87,8 @@ const WalletBalances: FC = () => {
const { amount: keepToT } = useTConvertedAmount(Token.Keep, keep.balance)
const { amount: nuToT } = useTConvertedAmount(Token.Nu, nu.balance)
+ const { amount: keepToTConversionRate } = useTExchangeRate(Token.Keep)
+ const { amount: nuToTConversionRate } = useTExchangeRate(Token.Nu)
const conversionToTAmount = useMemo(() => {
return BigNumber.from(keepToT).add(nuToT).toString()
@@ -105,14 +108,14 @@ const WalletBalances: FC = () => {
)}
> = ({
}) => {
return (
{
registerStakingListeners()
registerStakingAppsListeners()
registerAccountListeners()
+ registerTokensListeners()
state = {
eth: { ...state.eth },
token: {
diff --git a/src/store/tokens/effects.ts b/src/store/tokens/effects.ts
new file mode 100644
index 000000000..5dc63bb6d
--- /dev/null
+++ b/src/store/tokens/effects.ts
@@ -0,0 +1,87 @@
+import { BigNumber } from "ethers"
+import { featureFlags } from "../../constants"
+import { Token } from "../../enums"
+import { isAddress } from "../../web3/utils"
+import { walletConnected } from "../account"
+import { AppListenerEffectAPI } from "../listener"
+import {
+ tokenBalanceFetched,
+ tokenBalanceFetching,
+ fetchTokenPriceUSD,
+ tokenBalanceFetchFailed,
+} from "./tokenSlice"
+
+export const fetchTokenBalances = async (
+ actionCreator: ReturnType,
+ listenerApi: AppListenerEffectAPI
+) => {
+ const address = actionCreator.payload
+ if (!isAddress(address)) return
+
+ const { keep, nu, t, tbtc, tbtcv1 } = listenerApi.extra.threshold.token
+
+ const tokens = [
+ { token: keep, name: Token.Keep },
+ { token: nu, name: Token.Nu },
+ { token: t, name: Token.T },
+ { token: tbtcv1, name: Token.TBTCV1 },
+ { token: tbtc, name: Token.TBTC },
+ ]
+
+ if (featureFlags.TBTC_V2) {
+ tokens.push({ token: tbtc, name: Token.TBTC })
+ }
+
+ listenerApi.unsubscribe()
+ try {
+ tokens.forEach((_) => {
+ listenerApi.dispatch(
+ tokenBalanceFetching({
+ token: _.name,
+ })
+ )
+ })
+
+ const balances: BigNumber[] =
+ await listenerApi.extra.threshold.multicall.aggregate(
+ tokens
+ .map((_) => _.token)
+ .map((_) => ({
+ interface: _.contract.interface,
+ address: _.contract.address,
+ method: "balanceOf",
+ args: [address],
+ }))
+ )
+
+ tokens.forEach((_, index) => {
+ listenerApi.dispatch(
+ tokenBalanceFetched({
+ token: _.name,
+ balance: balances[index].toString(),
+ })
+ )
+ })
+
+ tokens
+ .map((_) => _.name)
+ .forEach((tokenName) =>
+ listenerApi.dispatch(fetchTokenPriceUSD({ token: tokenName }))
+ )
+ } catch (error) {
+ console.error("Could not fetch token balances", error)
+ tokens
+ .map((_) => _.name)
+ .forEach((tokenName) =>
+ listenerApi.dispatch(
+ tokenBalanceFetchFailed({
+ token: tokenName,
+ error: `Could not fetch token balances. Error: ${(
+ error as Error
+ )?.toString()}`,
+ })
+ )
+ )
+ listenerApi.subscribe()
+ }
+}
diff --git a/src/store/tokens/selectors.ts b/src/store/tokens/selectors.ts
new file mode 100644
index 000000000..78792d38e
--- /dev/null
+++ b/src/store/tokens/selectors.ts
@@ -0,0 +1,13 @@
+import { createSelector } from "@reduxjs/toolkit"
+import { RootState } from ".."
+import { TokensState } from "./tokenSlice"
+import { Token } from "../../enums"
+
+export const selectTokensState = (state: RootState) => state.token
+
+export const selectTokenByTokenName = createSelector(
+ [selectTokensState, (_: RootState, tokenName: Token) => tokenName],
+ (tokensState: TokensState, tokenName: Token) => {
+ return tokensState[tokenName]
+ }
+)
diff --git a/src/store/tokens/tokenSlice.ts b/src/store/tokens/tokenSlice.ts
index daf7ebabe..3cd936dde 100644
--- a/src/store/tokens/tokenSlice.ts
+++ b/src/store/tokens/tokenSlice.ts
@@ -1,19 +1,18 @@
-import numeral from "numeral"
-import axios from "axios"
-import { FixedNumber } from "@ethersproject/bignumber"
-import { formatUnits } from "@ethersproject/units"
import { PayloadAction } from "@reduxjs/toolkit/dist/createAction"
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"
import { CoingeckoID, Token } from "../../enums/token"
import {
TokenState,
SetTokenBalanceActionPayload,
- SetTokenConversionRateActionPayload,
SetTokenLoadingActionPayload,
+ SetTokenBalanceErrorActionPayload,
} from "../../types/token"
import { exchangeAPI } from "../../utils/exchangeAPI"
import Icon from "../../enums/icon"
import getUsdBalance from "../../utils/getUsdBalance"
+import { startAppListening } from "../listener"
+import { walletConnected } from "../account"
+import { fetchTokenBalances } from "./effects"
export const fetchTokenPriceUSD = createAsyncThunk(
"tokens/fetchTokenPriceUSD",
@@ -24,78 +23,80 @@ export const fetchTokenPriceUSD = createAsyncThunk(
}
)
+export type TokensState = Record
+
export const tokenSlice = createSlice({
name: "tokens",
initialState: {
[Token.Keep]: {
loading: false,
balance: 0,
- conversionRate: 4.87,
text: Token.Keep,
icon: Icon.KeepCircleBrand,
usdConversion: 0,
usdBalance: "0",
+ error: "",
},
[Token.Nu]: {
loading: false,
balance: 0,
- conversionRate: 2.66,
text: Token.Nu,
icon: Icon.NuCircleBrand,
usdConversion: 0,
usdBalance: "0",
+ error: "",
},
[Token.T]: {
loading: false,
balance: 0,
- conversionRate: 1,
text: Token.T,
icon: Icon.TCircleBrand,
usdConversion: 0,
usdBalance: "0",
+ error: "",
},
- [Token.TBTC]: {
+ [Token.TBTCV1]: {
loading: false,
balance: 0,
usdConversion: 0,
usdBalance: "0",
+ error: "",
},
- [Token.TBTCV2]: {
+ [Token.TBTC]: {
loading: false,
balance: 0,
usdConversion: 0,
usdBalance: "0",
+ error: "",
},
- } as Record,
+ } as TokensState,
reducers: {
- setTokenLoading: (
+ tokenBalanceFetching: (
state,
action: PayloadAction
) => {
- state[action.payload.token].loading = action.payload.loading
+ state[action.payload.token].loading = true
},
- setTokenBalance: (
+ tokenBalanceFetched: (
state,
action: PayloadAction
) => {
const { token, balance } = action.payload
+ state[token].loading = false
state[token].balance = balance
state[token].usdBalance = getUsdBalance(
state[token].balance,
state[token].usdConversion
)
+ state[token].error = ""
},
- setTokenConversionRate: (
+ tokenBalanceFetchFailed: (
state,
- action: PayloadAction
+ action: PayloadAction
) => {
- const { token, conversionRate } = action.payload
-
- const formattedConversionRate = numeral(
- +conversionRate / 10 ** 15
- ).format("0.0000")
-
- state[token].conversionRate = formattedConversionRate
+ const { token, error } = action.payload
+ state[token].loading = false
+ state[token].error = error
},
},
extraReducers: (builder) => {
@@ -111,5 +112,16 @@ export const tokenSlice = createSlice({
},
})
-export const { setTokenBalance, setTokenLoading, setTokenConversionRate } =
- tokenSlice.actions
+export const {
+ tokenBalanceFetched,
+ tokenBalanceFetching,
+ tokenBalanceFetchFailed,
+} = tokenSlice.actions
+
+export const registerTokensListeners = () => {
+ startAppListening({
+ actionCreator: walletConnected,
+ effect: fetchTokenBalances,
+ })
+}
+registerTokensListeners()
diff --git a/src/threshold-ts/index.ts b/src/threshold-ts/index.ts
index 6fd493e8a..ec74edd9d 100644
--- a/src/threshold-ts/index.ts
+++ b/src/threshold-ts/index.ts
@@ -1,6 +1,7 @@
import { MultiAppStaking } from "./mas"
import { IMulticall, Multicall } from "./multicall"
import { IStaking, Staking } from "./staking"
+import { ITokens, Tokens } from "./tokens"
import { ThresholdConfig } from "./types"
import { IVendingMachines, VendingMachines } from "./vending-machine"
@@ -9,6 +10,7 @@ export class Threshold {
staking!: IStaking
multiAppStaking!: MultiAppStaking
vendingMachines!: IVendingMachines
+ token!: ITokens
constructor(config: ThresholdConfig) {
this._initialize(config)
@@ -16,6 +18,7 @@ export class Threshold {
private _initialize = (config: ThresholdConfig) => {
this.multicall = new Multicall(config.ethereum)
+ this.token = new Tokens(config.ethereum)
this.vendingMachines = new VendingMachines(config.ethereum)
this.staking = new Staking(
config.ethereum,
diff --git a/src/threshold-ts/tokens/__tests__/tokens.test.ts b/src/threshold-ts/tokens/__tests__/tokens.test.ts
new file mode 100644
index 000000000..e587a78ce
--- /dev/null
+++ b/src/threshold-ts/tokens/__tests__/tokens.test.ts
@@ -0,0 +1,73 @@
+import T from "@threshold-network/solidity-contracts/artifacts/T.json"
+import NuCypherToken from "@threshold-network/solidity-contracts/artifacts/NuCypherToken.json"
+import KeepToken from "@keep-network/keep-core/artifacts/KeepToken.json"
+import { ethers } from "ethers"
+import { ITokens, Tokens } from ".."
+import { ERC20TokenWithApproveAndCall } from "../erc20"
+import { EthereumConfig } from "../../types"
+import { getContractAddressFromTruffleArtifact } from "../../utils"
+
+jest.mock("../erc20", () => ({
+ ...(jest.requireActual("../erc20") as {}),
+ ERC20TokenWithApproveAndCall: jest.fn(),
+}))
+
+jest.mock("../../utils", () => ({
+ ...(jest.requireActual("../../utils") as {}),
+ getContractAddressFromTruffleArtifact: jest.fn(),
+}))
+
+jest.mock("@threshold-network/solidity-contracts/artifacts/T.json", () => ({
+ address: "0x6A55B762689Ba514569E565E439699aBC731f156",
+ abi: [],
+}))
+
+jest.mock(
+ "@threshold-network/solidity-contracts/artifacts/NuCypherToken.json",
+ () => ({
+ address: "0xd696d5a9b083959587F30e487038529a876b08C2",
+ abi: [],
+ })
+)
+
+jest.mock("@keep-network/keep-core/artifacts/KeepToken.json", () => ({
+ address: "0x73A63e2Be2D911dc7eFAc189Bfdf48FbB6532B5b",
+ abi: [],
+}))
+
+describe("ERC20 token test", () => {
+ let tokens: ITokens
+ let config: EthereumConfig
+ const account = "0xaC1933A3Ee78A26E16030801273fBa250631eD5f"
+ const keepTokenAddress = (KeepToken as unknown as { address: string }).address
+
+ beforeEach(() => {
+ config = {
+ providerOrSigner: {} as ethers.providers.Provider,
+ chainId: 1,
+ account,
+ }
+ ;(getContractAddressFromTruffleArtifact as jest.Mock).mockReturnValue(
+ keepTokenAddress
+ )
+ tokens = new Tokens(config)
+ })
+
+ test("should create the Tokens wrapper correctly", () => {
+ expect(ERC20TokenWithApproveAndCall).toHaveBeenNthCalledWith(1, config, {
+ address: T.address,
+ abi: T.abi,
+ })
+ expect(ERC20TokenWithApproveAndCall).toHaveBeenNthCalledWith(2, config, {
+ address: NuCypherToken.address,
+ abi: NuCypherToken.abi,
+ })
+ expect(ERC20TokenWithApproveAndCall).toHaveBeenNthCalledWith(3, config, {
+ address: keepTokenAddress,
+ abi: KeepToken.abi,
+ })
+ expect(tokens.t).toBeInstanceOf(ERC20TokenWithApproveAndCall)
+ expect(tokens.keep).toBeInstanceOf(ERC20TokenWithApproveAndCall)
+ expect(tokens.nu).toBeInstanceOf(ERC20TokenWithApproveAndCall)
+ })
+})
diff --git a/src/threshold-ts/tokens/erc20/__tests__/erc20.test.ts b/src/threshold-ts/tokens/erc20/__tests__/erc20.test.ts
new file mode 100644
index 000000000..8e2a0827c
--- /dev/null
+++ b/src/threshold-ts/tokens/erc20/__tests__/erc20.test.ts
@@ -0,0 +1,143 @@
+import { BigNumber, ContractTransaction, ethers } from "ethers"
+import {
+ BaseERC20Token,
+ ERC20TokenWithApproveAndCall,
+ IERC20,
+ IERC20WithApproveAndCall,
+} from ".."
+import { EthereumConfig } from "../../../types"
+import { getContract } from "../../../utils"
+
+jest.mock("../../../utils", () => ({
+ ...(jest.requireActual("../../../utils") as {}),
+ getContract: jest.fn(),
+}))
+
+describe("ERC20 token test", () => {
+ let config: EthereumConfig
+ let artifact: { abi: any; address: string }
+
+ const account = "0xaC1933A3Ee78A26E16030801273fBa250631eD5f"
+ const spender = "0x6c7960687253e43e98A0d3d602dD5085d2443e75"
+ const amount = BigNumber.from("100000000")
+
+ beforeEach(() => {
+ artifact = {
+ abi: [],
+ address: "0xC49C8567DE3Cd9aA28c36b88dFb2A0EfF3BE41cE",
+ }
+
+ config = {
+ providerOrSigner: {} as ethers.providers.Provider,
+ chainId: 1,
+ account,
+ }
+ })
+
+ describe("Base ERC20 token test", () => {
+ let erc20: IERC20
+ let mockErc20TokenContract: {
+ balanceOf: jest.MockedFn
+ allowance: jest.MockedFn
+ totalSupply: jest.MockedFn
+ }
+
+ beforeEach(() => {
+ mockErc20TokenContract = {
+ balanceOf: jest.fn(),
+ allowance: jest.fn(),
+ totalSupply: jest.fn(),
+ }
+ ;(getContract as jest.Mock).mockImplementation(
+ () => mockErc20TokenContract
+ )
+
+ erc20 = new BaseERC20Token(config, artifact)
+ })
+
+ test("should create the base erc20 token instance", () => {
+ expect(getContract).toHaveBeenCalledWith(
+ artifact.address,
+ artifact.abi,
+ config.providerOrSigner,
+ config.account
+ )
+ expect(erc20.contract).toEqual(mockErc20TokenContract)
+ })
+
+ test("should return balance of a given address", async () => {
+ mockErc20TokenContract.balanceOf.mockResolvedValue(amount)
+
+ const result = await erc20.balanceOf(account)
+
+ expect(mockErc20TokenContract.balanceOf).toHaveBeenCalledWith(account)
+ expect(result).toEqual(amount)
+ })
+ test("should return allowed amount of tokens that spender will be allowed to spend on behalf of owner", async () => {
+ mockErc20TokenContract.allowance.mockResolvedValue(amount)
+
+ const result = await erc20.allowance(account, spender)
+
+ expect(mockErc20TokenContract.allowance).toHaveBeenCalledWith(
+ account,
+ spender
+ )
+ expect(result).toEqual(amount)
+ })
+
+ test("should return the total supply of token", async () => {
+ mockErc20TokenContract.totalSupply.mockResolvedValue(amount)
+
+ const result = await erc20.totalSupply()
+
+ expect(mockErc20TokenContract.totalSupply).toHaveBeenCalled()
+ expect(result).toEqual(amount)
+ })
+ })
+
+ describe("ERC20 with approve and call pattern test", () => {
+ let erc20withApproveAndCall: IERC20WithApproveAndCall
+ let mockErc20TokenContract: {
+ balanceOf: jest.MockedFn
+ allowance: jest.MockedFn
+ totalSupply: jest.MockedFn
+ approveAndCall: jest.MockedFn
+ }
+
+ beforeEach(() => {
+ mockErc20TokenContract = {
+ balanceOf: jest.fn(),
+ allowance: jest.fn(),
+ totalSupply: jest.fn(),
+ approveAndCall: jest.fn(),
+ }
+ ;(getContract as jest.Mock).mockImplementation(
+ () => mockErc20TokenContract
+ )
+
+ erc20withApproveAndCall = new ERC20TokenWithApproveAndCall(
+ config,
+ artifact
+ )
+ })
+
+ test("should call the approve and call correctly", async () => {
+ const extraData = "0x123456789"
+ const mockTx = {} as ContractTransaction
+ mockErc20TokenContract.approveAndCall.mockResolvedValue(mockTx)
+
+ const result = await erc20withApproveAndCall.approveAndCall(
+ spender,
+ amount.toString(),
+ extraData
+ )
+
+ expect(mockErc20TokenContract.approveAndCall).toHaveBeenCalledWith(
+ spender,
+ amount.toString(),
+ extraData
+ )
+ expect(result).toEqual(mockTx)
+ })
+ })
+})
diff --git a/src/threshold-ts/tokens/erc20/index.ts b/src/threshold-ts/tokens/erc20/index.ts
new file mode 100644
index 000000000..995d0b2a1
--- /dev/null
+++ b/src/threshold-ts/tokens/erc20/index.ts
@@ -0,0 +1,68 @@
+import { BigNumber, Contract, ContractTransaction } from "ethers"
+import { EthereumConfig } from "../../types"
+import { getContract } from "../../utils"
+
+export interface IERC20 {
+ contract: Contract
+ balanceOf: (account: string) => Promise
+ allowance: (owner: string, spender: string) => Promise
+ approve: (spender: string, amount: string) => Promise
+ totalSupply: () => Promise
+}
+
+export interface IERC20WithApproveAndCall extends IERC20 {
+ approveAndCall: (
+ spender: string,
+ amount: string,
+ extraData: string
+ ) => Promise
+}
+
+export class BaseERC20Token implements IERC20 {
+ protected _contract: Contract
+
+ constructor(config: EthereumConfig, artifact: { abi: any; address: string }) {
+ this._contract = getContract(
+ artifact.address,
+ artifact.abi,
+ config.providerOrSigner,
+ config.account
+ )
+ }
+
+ balanceOf = async (account: string): Promise => {
+ return await this._contract.balanceOf(account)
+ }
+
+ allowance = async (owner: string, spender: string): Promise => {
+ return await this._contract.allowance(owner, spender)
+ }
+
+ totalSupply = async (): Promise => {
+ return await this._contract.totalSupply()
+ }
+
+ approve = async (
+ spender: string,
+ amount: string
+ ): Promise => {
+ return await this._contract.approve(spender, amount)
+ }
+
+ get contract() {
+ return this._contract
+ }
+}
+
+export class ERC20TokenWithApproveAndCall
+ extends BaseERC20Token
+ implements IERC20WithApproveAndCall
+{
+ approveAndCall = async (
+ spender: string,
+ amount: string,
+ extraData: string
+ ): Promise => {
+ return await this._contract.approveAndCall(spender, amount, extraData)
+ }
+}
diff --git a/src/threshold-ts/tokens/index.ts b/src/threshold-ts/tokens/index.ts
new file mode 100644
index 000000000..b05b454d3
--- /dev/null
+++ b/src/threshold-ts/tokens/index.ts
@@ -0,0 +1,47 @@
+import T from "@threshold-network/solidity-contracts/artifacts/T.json"
+import NuCypherToken from "@threshold-network/solidity-contracts/artifacts/NuCypherToken.json"
+import KeepToken from "@keep-network/keep-core/artifacts/KeepToken.json"
+import TBTCV1Token from "@keep-network/tbtc/artifacts/TBTCToken.json"
+import TBTC from "@keep-network/tbtc-v2/artifacts/TBTC.json"
+import { IERC20WithApproveAndCall, ERC20TokenWithApproveAndCall } from "./erc20"
+import { EthereumConfig } from "../types"
+import { getContractAddressFromTruffleArtifact } from "../utils"
+
+export interface ITokens {
+ t: IERC20WithApproveAndCall
+ keep: IERC20WithApproveAndCall
+ nu: IERC20WithApproveAndCall
+ tbtcv1: IERC20WithApproveAndCall
+ tbtc: IERC20WithApproveAndCall
+}
+
+export class Tokens implements ITokens {
+ public readonly t: IERC20WithApproveAndCall
+ public readonly nu: IERC20WithApproveAndCall
+ public readonly keep: IERC20WithApproveAndCall
+ public readonly tbtcv1: IERC20WithApproveAndCall
+ public readonly tbtc: IERC20WithApproveAndCall
+
+ constructor(config: EthereumConfig) {
+ this.t = new ERC20TokenWithApproveAndCall(config, {
+ address: T.address,
+ abi: T.abi,
+ })
+ this.nu = new ERC20TokenWithApproveAndCall(config, {
+ address: NuCypherToken.address,
+ abi: NuCypherToken.abi,
+ })
+ this.keep = new ERC20TokenWithApproveAndCall(config, {
+ address: getContractAddressFromTruffleArtifact(KeepToken),
+ abi: KeepToken.abi,
+ })
+ this.tbtcv1 = new ERC20TokenWithApproveAndCall(config, {
+ address: getContractAddressFromTruffleArtifact(TBTCV1Token),
+ abi: TBTCV1Token.abi,
+ })
+ this.tbtc = new ERC20TokenWithApproveAndCall(config, {
+ address: TBTC.address,
+ abi: TBTC.abi,
+ })
+ }
+}
diff --git a/src/types/token.ts b/src/types/token.ts
index 3dde6a7a1..b89d3b0e1 100644
--- a/src/types/token.ts
+++ b/src/types/token.ts
@@ -2,16 +2,17 @@ import { Contract } from "@ethersproject/contracts"
import { Token } from "../enums"
import { TransactionType } from "../enums/transactionType"
import Icon from "../enums/icon"
+import { IERC20, IERC20WithApproveAndCall } from "../threshold-ts/tokens/erc20"
export interface TokenState {
loading: boolean
- conversionRate: number | string
text: string
icon: Icon
balance: number | string
usdConversion: number
usdBalance: string
decimals?: number
+ error: string
}
export interface SetTokenBalanceActionPayload {
@@ -19,14 +20,13 @@ export interface SetTokenBalanceActionPayload {
balance: number | string
}
-export interface SetTokenConversionRateActionPayload {
+export interface SetTokenBalanceErrorActionPayload {
token: Token
- conversionRate: string | number
+ error: string
}
export interface SetTokenLoadingActionPayload {
token: Token
- loading: boolean
}
export interface SetTokenBalance {
@@ -37,14 +37,7 @@ export interface SetTokenLoading {
payload: SetTokenLoadingActionPayload
}
-export interface SetTokenConversionRate {
- payload: SetTokenConversionRateActionPayload
-}
-
-export type TokenActionTypes =
- | SetTokenBalance
- | SetTokenLoading
- | SetTokenConversionRate
+export type TokenActionTypes = SetTokenBalance | SetTokenLoading
export interface UseTokenState {
(): {
@@ -57,12 +50,9 @@ export interface UseTokenState {
token: Token,
balance: number | string
) => TokenActionTypes
- setTokenConversionRate: (
- token: Token,
- conversionRate: number | string
- ) => TokenActionTypes
setTokenLoading: (token: Token, loading: boolean) => TokenActionTypes
fetchTokenPriceUSD: (token: Token) => void
+ setTokenBalanceError: (token: Token, error: string) => TokenActionTypes
}
}
@@ -71,13 +61,13 @@ export interface BalanceOf {
}
export interface Approve {
- (transactionType: TransactionType): any
+ (spender: string, amount: string): any
}
export interface UseErc20Interface {
- (tokenAddress: string, withSignerIfPossible?: boolean, abi?: any): {
- approve: Approve
+ (token: IERC20WithApproveAndCall | IERC20, tokenName: Token): {
balanceOf: BalanceOf
+ wrapper: IERC20 | IERC20WithApproveAndCall
contract: Contract | null
}
}
diff --git a/src/web3/hooks/index.ts b/src/web3/hooks/index.ts
index c18ab75d6..b0387739b 100644
--- a/src/web3/hooks/index.ts
+++ b/src/web3/hooks/index.ts
@@ -18,3 +18,4 @@ export * from "./useTStakingContract"
export * from "./useKeepTokenStakingContract"
export * from "./usePREContract"
export * from "./useClaimMerkleRewardsTransaction"
+export * from "./useTBTCv2TokenContract"
diff --git a/src/web3/hooks/useERC20.ts b/src/web3/hooks/useERC20.ts
index 51febb27c..1d352d065 100644
--- a/src/web3/hooks/useERC20.ts
+++ b/src/web3/hooks/useERC20.ts
@@ -1,76 +1,36 @@
import { useCallback } from "react"
-import { MaxUint256 } from "@ethersproject/constants"
-import { useWeb3React } from "@web3-react/core"
-import { useContract } from "./useContract"
-import ERC20_ABI from "../abi/ERC20.json"
import { Token } from "../../enums"
import { useTokenState } from "../../hooks/useTokenState"
-import { Approve, UseErc20Interface } from "../../types/token"
-import { useTransaction } from "../../hooks/useTransaction"
-import { TransactionStatus } from "../../enums/transactionType"
-import { isWalletRejectionError } from "../../utils/isWalletRejectionError"
-import { once } from "@storybook/node-logger"
+import { UseErc20Interface } from "../../types/token"
+import {
+ IERC20,
+ IERC20WithApproveAndCall,
+} from "../../threshold-ts/tokens/erc20"
export const useErc20TokenContract: UseErc20Interface = (
- tokenAddress,
- withSignerIfPossible,
- abi = ERC20_ABI
+ token: IERC20WithApproveAndCall | IERC20,
+ tokenName: Token
) => {
- const { account } = useWeb3React()
- const { setTokenLoading, setTokenBalance } = useTokenState()
- const { setTransactionStatus } = useTransaction()
-
- // TODO: Figure out how to type the ERC20 contract
- // return useContract(tokenAddress, ERC20_ABI, withSignerIfPossible)
- const contract = useContract(tokenAddress, abi, withSignerIfPossible)
-
- const approve: Approve = useCallback(
- async (transactionType) => {
- if (account) {
- try {
- setTransactionStatus(transactionType, TransactionStatus.PendingWallet)
- const tx = await contract?.approve(
- tokenAddress,
- MaxUint256.toString()
- )
- setTransactionStatus(
- transactionType,
- TransactionStatus.PendingOnChain
- )
- await tx.wait(1)
- setTransactionStatus(transactionType, TransactionStatus.Succeeded)
- } catch (error: any) {
- setTransactionStatus(
- transactionType,
- isWalletRejectionError(error)
- ? TransactionStatus.Rejected
- : TransactionStatus.Failed
- )
- }
- }
- },
- [contract, account]
- )
+ const { setTokenLoading, setTokenBalance, setTokenBalanceError } =
+ useTokenState()
const balanceOf = useCallback(
- async (token: Token) => {
- if (account) {
- try {
- setTokenLoading(token, true)
- const balance = await contract?.balanceOf(account as string)
- setTokenBalance(token, balance.toString())
- setTokenLoading(token, false)
- } catch (error) {
- setTokenLoading(Token.Nu, false)
- console.log(
- `Error: Fetching ${token} balance failed for ${account}`,
- error
- )
- }
+ async (address) => {
+ try {
+ setTokenLoading(tokenName, true)
+ const balance = await token.balanceOf(address)
+ setTokenBalance(tokenName, balance.toString())
+ } catch (error) {
+ const errorMessage = `Error: Fetching ${token} balance failed for ${address}`
+ setTokenBalanceError(tokenName, errorMessage)
+ console.log(
+ `Error: Fetching ${token} balance failed for ${address}`,
+ error
+ )
}
},
- [account, contract]
+ [token, tokenName, setTokenLoading, setTokenBalanceError, setTokenBalance]
)
- return { approve, balanceOf, contract }
+ return { balanceOf, contract: token.contract, wrapper: token }
}
diff --git a/src/web3/hooks/useKeep.ts b/src/web3/hooks/useKeep.ts
index 91d093981..a3879cb6c 100644
--- a/src/web3/hooks/useKeep.ts
+++ b/src/web3/hooks/useKeep.ts
@@ -1,36 +1,9 @@
-import KeepToken from "@keep-network/keep-core/artifacts/KeepToken.json"
import { useErc20TokenContract } from "./useERC20"
import { Token } from "../../enums"
-import { TransactionType } from "../../enums/transactionType"
-import { Contract } from "@ethersproject/contracts"
-import { getContractAddressFromTruffleArtifact } from "../../utils/getContract"
+import { useThreshold } from "../../contexts/ThresholdContext"
-export interface UseKeep {
- (): {
- approveKeep: () => void
- fetchKeepBalance: () => void
- contract: Contract | null
- }
-}
-
-export const useKeep: UseKeep = () => {
- const { balanceOf, approve, contract } = useErc20TokenContract(
- getContractAddressFromTruffleArtifact(KeepToken),
- undefined,
- KeepToken.abi
- )
-
- const approveKeep = () => {
- approve(TransactionType.ApproveKeep)
- }
-
- const fetchKeepBalance = () => {
- balanceOf(Token.Keep)
- }
+export const useKeep = () => {
+ const threshold = useThreshold()
- return {
- approveKeep,
- fetchKeepBalance,
- contract,
- }
+ return useErc20TokenContract(threshold.token.keep, Token.Keep)
}
diff --git a/src/web3/hooks/useNu.ts b/src/web3/hooks/useNu.ts
index b902a337f..07d69ea9a 100644
--- a/src/web3/hooks/useNu.ts
+++ b/src/web3/hooks/useNu.ts
@@ -1,35 +1,8 @@
-import NuCypherToken from "@threshold-network/solidity-contracts/artifacts/NuCypherToken.json"
-import { Contract } from "@ethersproject/contracts"
import { useErc20TokenContract } from "./useERC20"
import { Token } from "../../enums"
-import { TransactionType } from "../../enums/transactionType"
+import { useThreshold } from "../../contexts/ThresholdContext"
-export interface UseNu {
- (): {
- approveNu: () => void
- fetchNuBalance: () => void
- contract: Contract | null
- }
-}
-
-export const useNu: UseNu = () => {
- const { balanceOf, approve, contract } = useErc20TokenContract(
- NuCypherToken.address,
- undefined,
- NuCypherToken.abi
- )
-
- const approveNu = () => {
- approve(TransactionType.ApproveNu)
- }
-
- const fetchNuBalance = () => {
- balanceOf(Token.Nu)
- }
-
- return {
- fetchNuBalance,
- approveNu,
- contract,
- }
+export const useNu = () => {
+ const threshold = useThreshold()
+ return useErc20TokenContract(threshold.token.nu, Token.Nu)
}
diff --git a/src/web3/hooks/useT.ts b/src/web3/hooks/useT.ts
index 68907448d..b22795688 100644
--- a/src/web3/hooks/useT.ts
+++ b/src/web3/hooks/useT.ts
@@ -1,34 +1,8 @@
-import T from "@threshold-network/solidity-contracts/artifacts/T.json"
-import { Contract } from "@ethersproject/contracts"
import { useErc20TokenContract } from "./useERC20"
-import { Token, TransactionType } from "../../enums"
+import { Token } from "../../enums"
+import { useThreshold } from "../../contexts/ThresholdContext"
-export interface UseT {
- (): {
- approveT: () => void
- fetchTBalance: () => void
- contract: Contract | null
- }
-}
-
-export const useT: UseT = () => {
- const { balanceOf, approve, contract } = useErc20TokenContract(
- T.address,
- undefined,
- T.abi
- )
-
- const approveT = () => {
- approve(TransactionType.ApproveT)
- }
-
- const fetchTBalance = () => {
- balanceOf(Token.T)
- }
-
- return {
- approveT,
- fetchTBalance,
- contract,
- }
+export const useT = () => {
+ const threshold = useThreshold()
+ return useErc20TokenContract(threshold.token.t, Token.T)
}
diff --git a/src/web3/hooks/useTBTCTokenContract.ts b/src/web3/hooks/useTBTCTokenContract.ts
index 1900fd6c7..7f5577138 100644
--- a/src/web3/hooks/useTBTCTokenContract.ts
+++ b/src/web3/hooks/useTBTCTokenContract.ts
@@ -1,7 +1,8 @@
-import TBTCToken from "@keep-network/tbtc/artifacts/TBTCToken.json"
import { useErc20TokenContract } from "./useERC20"
-import { getContractAddressFromTruffleArtifact } from "../../utils/getContract"
+import { useThreshold } from "../../contexts/ThresholdContext"
+import { Token } from "../../enums"
export const useTBTCTokenContract = () => {
- return useErc20TokenContract(getContractAddressFromTruffleArtifact(TBTCToken))
+ const threshold = useThreshold()
+ return useErc20TokenContract(threshold.token.tbtcv1, Token.TBTCV1)
}
diff --git a/src/web3/hooks/useTBTCv2TokenContract.ts b/src/web3/hooks/useTBTCv2TokenContract.ts
index 5235886ec..60b0b3b32 100644
--- a/src/web3/hooks/useTBTCv2TokenContract.ts
+++ b/src/web3/hooks/useTBTCv2TokenContract.ts
@@ -1,29 +1,8 @@
import { useErc20TokenContract } from "./useERC20"
-import { Token, TransactionType } from "../../enums"
-import TBTC from "@keep-network/tbtc-v2/artifacts/TBTC.json"
-import { featureFlags } from "../../constants"
+import { Token } from "../../enums"
+import { useThreshold } from "../../contexts/ThresholdContext"
-export const useTBTCv2TokenContract: any = () => {
- if (featureFlags.TBTC_V2) {
- const { balanceOf, approve, contract } = useErc20TokenContract(
- TBTC.address,
- undefined,
- TBTC.abi
- )
-
- // TODO:
- const approveTBTCV2 = () => {}
-
- const fetchTBTCV2Balance = () => {
- balanceOf(Token.TBTCV2)
- }
-
- return {
- fetchTBTCV2Balance,
- approveTBTCV2,
- contract,
- }
- }
-
- return undefined
+export const useTBTCv2TokenContract = () => {
+ const threshold = useThreshold()
+ return useErc20TokenContract(threshold.token.tbtc, Token.TBTC)
}