diff --git a/apps/frontend-v2/src/__generated__/swaylend/gql.ts b/apps/frontend-v2/src/__generated__/swaylend/gql.ts index e4130a19..bf58c3ff 100644 --- a/apps/frontend-v2/src/__generated__/swaylend/gql.ts +++ b/apps/frontend-v2/src/__generated__/swaylend/gql.ts @@ -16,6 +16,7 @@ import * as types from './graphql'; const documents = { "query GetCollateralAssets($account: String) {\n User(where: {address: {_eq: $account}}) {\n collateralAssets {\n amount\n collateralAsset_id\n }\n }\n}": types.GetCollateralAssetsDocument, "query GetCollateralConfigurations {\n CollateralAsset {\n supplyCap\n priceFeedId\n id\n paused\n liquidationPenalty\n liquidateCollateralFactor\n decimals\n borrowCollateralFactor\n }\n}": types.GetCollateralConfigurationsDocument, + "query GetMarketConfiguration {\n MarketConfiguartion {\n baseToken\n baseTokenDecimals\n baseTokenPriceFeedId\n baseBorrowMin\n }\n}": types.GetMarketConfigurationDocument, "query GetMarketState {\n MarketState {\n totalBorrowBase\n totalSupplyBase\n }\n}": types.GetMarketStateDocument, }; @@ -27,6 +28,10 @@ export function graphql(source: "query GetCollateralAssets($account: String) {\n * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "query GetCollateralConfigurations {\n CollateralAsset {\n supplyCap\n priceFeedId\n id\n paused\n liquidationPenalty\n liquidateCollateralFactor\n decimals\n borrowCollateralFactor\n }\n}"): typeof import('./graphql').GetCollateralConfigurationsDocument; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "query GetMarketConfiguration {\n MarketConfiguartion {\n baseToken\n baseTokenDecimals\n baseTokenPriceFeedId\n baseBorrowMin\n }\n}"): typeof import('./graphql').GetMarketConfigurationDocument; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/apps/frontend-v2/src/__generated__/swaylend/graphql.ts b/apps/frontend-v2/src/__generated__/swaylend/graphql.ts index f207571b..9660d733 100644 --- a/apps/frontend-v2/src/__generated__/swaylend/graphql.ts +++ b/apps/frontend-v2/src/__generated__/swaylend/graphql.ts @@ -3648,6 +3648,11 @@ export type GetCollateralConfigurationsQueryVariables = Exact<{ [key: string]: n export type GetCollateralConfigurationsQuery = { __typename?: 'query_root', CollateralAsset: Array<{ __typename?: 'CollateralAsset', supplyCap: any, priceFeedId: string, id: string, paused: boolean, liquidationPenalty: any, liquidateCollateralFactor: any, decimals: number, borrowCollateralFactor: any }> }; +export type GetMarketConfigurationQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetMarketConfigurationQuery = { __typename?: 'query_root', MarketConfiguartion: Array<{ __typename?: 'MarketConfiguartion', baseToken: string, baseTokenDecimals: number, baseTokenPriceFeedId: string, baseBorrowMin: any }> }; + export type GetMarketStateQueryVariables = Exact<{ [key: string]: never; }>; @@ -3692,6 +3697,16 @@ export const GetCollateralConfigurationsDocument = new TypedDocumentString(` } } `) as unknown as TypedDocumentString; +export const GetMarketConfigurationDocument = new TypedDocumentString(` + query GetMarketConfiguration { + MarketConfiguartion { + baseToken + baseTokenDecimals + baseTokenPriceFeedId + baseBorrowMin + } +} + `) as unknown as TypedDocumentString; export const GetMarketStateDocument = new TypedDocumentString(` query GetMarketState { MarketState { diff --git a/apps/frontend-v2/src/components/DashboardView/Header.tsx b/apps/frontend-v2/src/components/DashboardView/Header.tsx index ba82027a..ac468685 100644 --- a/apps/frontend-v2/src/components/DashboardView/Header.tsx +++ b/apps/frontend-v2/src/components/DashboardView/Header.tsx @@ -1,14 +1,15 @@ -import { useBorrowRate, useSupplyRate, useUserSupplyBorrow } from '@/hooks'; -import { usePrice } from '@/hooks'; -import { useUserCollateralAssets } from '@/hooks'; import { - TOKENS_BY_SYMBOL, - TOKENS_LIST, - formatUnits, - getBorrowApr, - getSupplyApr, - getTotalSuppliedBalance, -} from '@/utils'; + useBorrowCapacity, + useBorrowRate, + useCollateralConfigurations, + useMarketConfiguration, + usePrice, + useSupplyRate, + useUserCollateralAssets, + useUserSupplyBorrow, +} from '@/hooks'; + +import { formatUnits, getBorrowApr, getSupplyApr } from '@/utils'; import BigNumber from 'bignumber.js'; import React, { useMemo } from 'react'; @@ -17,42 +18,70 @@ export const Header = () => { const { data: supplyRate } = useSupplyRate(); const { data: userSupplyBorrow } = useUserSupplyBorrow(); const { data: userCollateralAssets } = useUserCollateralAssets(); - const { data: priceData } = usePrice(TOKENS_LIST.map((i) => i.assetId)); - - // TODO[Martin]: Later implement this using loading and error states. - const borrowedBalance = useMemo(() => { - if (userSupplyBorrow == null) return new BigNumber(0); - return userSupplyBorrow[1]; - }, [userSupplyBorrow]); - const suppliedBalance = useMemo(() => { - if (userSupplyBorrow == null) return new BigNumber(0); - return userSupplyBorrow[0]; - }, [userSupplyBorrow]); + const { data: priceData } = usePrice(); + const { data: marketConfiguration } = useMarketConfiguration(); + const { data: colateralConfigurations } = useCollateralConfigurations(); + const { data: borrowCapacity } = useBorrowCapacity(); const totalSuppliedBalance = useMemo(() => { - return getTotalSuppliedBalance( - suppliedBalance, - userCollateralAssets ?? {}, - priceData?.prices ?? {} + if ( + !marketConfiguration || + !userSupplyBorrow || + !priceData || + !userCollateralAssets || + !colateralConfigurations + ) { + return BigNumber(0).toFormat(2); + } + + const baseTokenSupliedBalance = formatUnits( + userSupplyBorrow.supplied.times( + priceData.prices[marketConfiguration.baseToken] + ), + marketConfiguration.baseTokenDecimals ); - }, [userSupplyBorrow, userCollateralAssets, priceData]); - const borrowed = formatUnits( - borrowedBalance ?? new BigNumber(0), - TOKENS_BY_SYMBOL.USDC.decimals - ).toFormat(2); + const collateralSuppiedBalance = Object.entries( + userCollateralAssets + ).reduce((acc, [key, value]) => { + return acc.plus( + formatUnits( + value.times(priceData.prices[key]), + colateralConfigurations[key].decimals + ) + ); + }, new BigNumber(0)); + + return baseTokenSupliedBalance.plus(collateralSuppiedBalance).toFormat(2); + }, [ + userSupplyBorrow, + userCollateralAssets, + priceData, + marketConfiguration, + colateralConfigurations, + ]); const borrowApr = useMemo(() => getBorrowApr(borrowRate), [borrowRate]); const supplyApr = useMemo(() => getSupplyApr(supplyRate), [supplyRate]); + if (!marketConfiguration) return
Loading...
; + return (
Supplied Balance: {totalSuppliedBalance}$
Supply{supplyApr}/borrow APR{borrowApr}
-
Borrowed balance: {borrowed}$
+
+ Borrowed balance:{' '} + {formatUnits( + userSupplyBorrow?.borrowed ?? new BigNumber(0), + marketConfiguration.baseTokenDecimals + ).toFormat(2)} + $ +
+
Borrow capacity: {borrowCapacity?.toFormat(2)}
); }; diff --git a/apps/frontend-v2/src/components/DashboardView/Input.tsx b/apps/frontend-v2/src/components/DashboardView/Input.tsx index 9cad7fdf..4d928811 100644 --- a/apps/frontend-v2/src/components/DashboardView/Input.tsx +++ b/apps/frontend-v2/src/components/DashboardView/Input.tsx @@ -1,9 +1,12 @@ -import { usePrice, useSupplyCollateral } from '@/hooks'; -import { useSupplyBase } from '@/hooks/useSupplyBase'; -import { useWithdrawBase } from '@/hooks/useWithdrawBase'; -import { useWithdrawCollateral } from '@/hooks/useWithdrawCollateral'; +import { + useMarketConfiguration, + usePrice, + useSupplyBase, + useSupplyCollateral, + useWithdrawBase, + useWithdrawCollateral, +} from '@/hooks'; import { ACTION_TYPE, useMarketStore } from '@/stores'; -import { TOKENS_BY_SYMBOL, TOKENS_LIST } from '@/utils'; import BigNumber from 'bignumber.js'; import React from 'react'; import { Button } from '../ui/button'; @@ -20,13 +23,15 @@ export const Input = () => { changeActionTokenAssetId, } = useMarketStore(); + const { data: marketConfiguration } = useMarketConfiguration(); + const handleBaseTokenClick = (action: ACTION_TYPE) => { changeAction(action); changeTokenAmount(BigNumber(0)); - changeActionTokenAssetId(TOKENS_BY_SYMBOL.USDC.assetId); + changeActionTokenAssetId(marketConfiguration?.baseToken); }; - const { data: priceData } = usePrice(TOKENS_LIST.map((i) => i.assetId)); + const { data: priceData } = usePrice(); const { mutate: supplyCollateral } = useSupplyCollateral({ actionTokenAssetId, @@ -41,9 +46,11 @@ export const Input = () => { const { mutate: withdrawBase } = useWithdrawBase(); const handleSubmit = () => { + if (!marketConfiguration) return; + switch (action) { case ACTION_TYPE.SUPPLY: { - if (actionTokenAssetId === TOKENS_BY_SYMBOL.USDC.assetId) { + if (actionTokenAssetId === marketConfiguration.baseToken) { supplyBase(tokenAmount); } else { supplyCollateral(tokenAmount); @@ -53,7 +60,7 @@ export const Input = () => { case ACTION_TYPE.WITHDRAW: { if (!priceData) return; - if (actionTokenAssetId === TOKENS_BY_SYMBOL.USDC.assetId) { + if (actionTokenAssetId === marketConfiguration.baseToken) { withdrawBase({ tokenAmount, priceUpdateData: priceData.priceUpdateData, diff --git a/apps/frontend-v2/src/components/DashboardView/Table.tsx b/apps/frontend-v2/src/components/DashboardView/Table.tsx index 980c31cd..9af3b036 100644 --- a/apps/frontend-v2/src/components/DashboardView/Table.tsx +++ b/apps/frontend-v2/src/components/DashboardView/Table.tsx @@ -4,12 +4,77 @@ import { useUserCollateralAssets, } from '@/hooks'; import { ACTION_TYPE, useMarketStore } from '@/stores'; -import { TOKENS_BY_SYMBOL, collaterals, formatUnits } from '@/utils'; +import { ASSET_ID_TO_SYMBOL, type IToken, formatUnits } from '@/utils'; import { useAccount, useBalance } from '@fuels/react'; import BigNumber from 'bignumber.js'; -import React from 'react'; +import clsx from 'clsx'; +import React, { useMemo } from 'react'; import { Button } from '../ui/button'; +type TableRowProps = { + account: string | undefined; + assetId: string; + symbol: string; + decimals: number; + protocolBalance: BigNumber; + protocolBalancePending: boolean; + handleAssetClick: (action: ACTION_TYPE, assetId: string) => void; +}; + +const TableRow = ({ + account, + assetId, + symbol, + decimals, + protocolBalance, + protocolBalancePending, + handleAssetClick, +}: TableRowProps) => { + const { balance } = useBalance({ + address: account, + assetId: assetId, + }); + + const formattedBalance = formatUnits( + BigNumber(balance ? balance.toString() : '0'), + decimals + ).toFormat(6); + + const canSupply = balance?.gt(0); + const canWithdraw = protocolBalance.gt(0); + + return ( +
+ {symbol} +
+ Bal: + {formattedBalance} + {symbol} +
+
+ Deposited:{formatUnits(protocolBalance, decimals).toFormat(4)} + {symbol} +
+ + +
+ ); +}; + export const Table = () => { const { changeAction, @@ -17,25 +82,17 @@ export const Table = () => { changeTokenAmount, changeActionTokenAssetId, } = useMarketStore(); - const { data: userCollateralAssets } = useUserCollateralAssets(); - const { data: collateralConfigurations } = useCollateralConfigurations(); + const { data: userCollateralAssets, isLoading: userCollateralAssetsLoading } = + useUserCollateralAssets(); + const { + data: collateralConfigurations, + isPending: collateralConfigurationsPending, + error: collateralConfigurationsError, + } = useCollateralConfigurations(); const { data: totalCollateralInfo } = useTotalCollateral(); const { account } = useAccount(); - const { balance: etherBalance } = useBalance({ - address: account as string, - assetId: TOKENS_BY_SYMBOL.ETH.assetId, - }); - const { balance: btcBalance } = useBalance({ - address: account as string, - assetId: TOKENS_BY_SYMBOL.BTC.assetId, - }); - const { balance: uniBalance } = useBalance({ - address: account as string, - assetId: TOKENS_BY_SYMBOL.UNI.assetId, - }); - const handleAssetClick = (action: ACTION_TYPE, assetId: string) => { changeTokenAmount(new BigNumber(0)); changeAction(action); @@ -43,76 +100,36 @@ export const Table = () => { changeActionTokenAssetId(assetId); }; + const collaterals = useMemo(() => { + if (!collateralConfigurations) return []; + + return Object.values(collateralConfigurations); + }, [collateralConfigurations]); + + if (collateralConfigurationsPending) { + return
Loading...
; + } + + if (!collateralConfigurations || collateralConfigurationsError) { + return
Failed to load collateral configurations
; + } + return (
- {collaterals.map((token) => { - const supplyCap = - collateralConfigurations == null - ? BigNumber(0) - : new BigNumber( - collateralConfigurations[token.assetId].supply_cap.toString() - ); - const collateralReserve = - totalCollateralInfo == null - ? BigNumber(0) - : totalCollateralInfo[token.assetId]; - let userBalance = new BigNumber(0); - switch (token.symbol) { - case 'ETH': - userBalance = (etherBalance ?? new BigNumber(0)) as BigNumber; - break; - case 'BTC': - userBalance = (btcBalance ?? new BigNumber(0)) as BigNumber; - break; - case 'UNI': - userBalance = (uniBalance ?? new BigNumber(0)) as BigNumber; - break; - default: - break; - } - const protocolBalance = - userCollateralAssets != null - ? userCollateralAssets[token.assetId] ?? BigNumber(0) - : BigNumber(0); - const canWithdraw = protocolBalance.gt(0); - const protocolBalanceFormatted = formatUnits( - protocolBalance, - token.decimals - ).toFormat(4); - const collateralCapacityLeft = supplyCap.minus(collateralReserve); - const canSupply = userBalance?.gt(0); - - return ( -
- {token.symbol} -
- Bal:{formatUnits(userBalance, token.decimals).toFormat(6)} - {token.symbol} -
-
- Deposited:{protocolBalanceFormatted} - {token.symbol} -
- - -
- ); - })} + {collaterals.map((collateral) => ( + + ))}
); }; diff --git a/apps/frontend-v2/src/components/FaucetView/index.tsx b/apps/frontend-v2/src/components/FaucetView/index.tsx index d6d43929..64cc91dc 100644 --- a/apps/frontend-v2/src/components/FaucetView/index.tsx +++ b/apps/frontend-v2/src/components/FaucetView/index.tsx @@ -1,113 +1,136 @@ 'use client'; -import { useMintToken } from '@/hooks'; -import { FAUCET_URL, TOKENS_BY_SYMBOL } from '@/utils'; -import { useAccount, useBalance, useIsConnected } from '@fuels/react'; +import { + useCollateralConfigurations, + useMarketConfiguration, + useMintToken, +} from '@/hooks'; +import { + ASSET_ID_TO_SYMBOL, + FAUCET_URL, + FUEL_ETH_BASE_ASSET_ID, + formatUnits, +} from '@/utils'; +import { useAccount, useBalance } from '@fuels/react'; +import { useIsMutating } from '@tanstack/react-query'; +import BigNumber from 'bignumber.js'; import { BN, toFixed } from 'fuels'; import React, { useMemo } from 'react'; import { Button } from '../ui/button'; +type FaucetRowProps = { + account: string | undefined; + assetId: string; + symbol: string; + decimals: number; + mintPending: boolean; + ethBalance: BN; +}; + +const FaucetRow = ({ + account, + assetId, + symbol, + decimals, + mintPending, + ethBalance, +}: FaucetRowProps) => { + const { balance } = useBalance({ + address: account, + assetId: assetId, + }); + + const { mutate: mint } = useMintToken(symbol, decimals); + + return ( +
+
+ {toFixed( + formatUnits( + BigNumber(balance ? balance.toString() : '0'), + decimals + ).toString(), + { + precision: 4, + } + )} + {symbol} +
+ +
+ ); +}; + export const FaucetView = () => { - const { isConnected } = useIsConnected(); const { account } = useAccount(); - const { balance: etherBalance } = useBalance({ - address: account as string, - assetId: TOKENS_BY_SYMBOL.ETH.assetId, - }); - const { balance: usdcBalance } = useBalance({ - address: account as string, - assetId: TOKENS_BY_SYMBOL.USDC.assetId, - }); - const { balance: btcBalance } = useBalance({ - address: account as string, - assetId: TOKENS_BY_SYMBOL.BTC.assetId, - }); - const { balance: uniBalance } = useBalance({ - address: account as string, - assetId: TOKENS_BY_SYMBOL.UNI.assetId, + const { data: marketConfiguration, isPending: isPendingMarketConfiguration } = + useMarketConfiguration(); + + const { + data: collateralConfigurations, + isPending: isPendingCollateralConfigurations, + } = useCollateralConfigurations(); + + const { balance: ethBalance } = useBalance({ + address: account ?? undefined, + assetId: FUEL_ETH_BASE_ASSET_ID, }); - const { mutate: mintTokenBTC, isPending: isMintingBTC } = useMintToken( - 'BTC', - TOKENS_BY_SYMBOL.BTC.decimals - ); + const assets = useMemo(() => { + if (!marketConfiguration || !collateralConfigurations) return []; - const { mutate: mintTokenUSDC, isPending: isMintingUSDC } = useMintToken( - 'USDC', - TOKENS_BY_SYMBOL.USDC.decimals - ); + return [ + ...Object.values(collateralConfigurations).map( + (collateralConfiguration) => { + return { + assetId: collateralConfiguration.asset_id, + symbol: ASSET_ID_TO_SYMBOL[collateralConfiguration.asset_id], + decimals: + collateralConfigurations[collateralConfiguration.asset_id] + .decimals, + }; + } + ), + { + assetId: marketConfiguration.baseToken, + symbol: ASSET_ID_TO_SYMBOL[marketConfiguration.baseToken], + decimals: marketConfiguration.baseTokenDecimals, + }, + ]; + }, [marketConfiguration, collateralConfigurations]); - const { mutate: mintTokenUNI, isPending: isMintingUNI } = useMintToken( - 'UNI', - TOKENS_BY_SYMBOL.UNI.decimals - ); + const numberOfMintsPending = useIsMutating({ mutationKey: ['mintToken'] }); - const isMintingInProgress = useMemo( - () => isMintingBTC || isMintingUSDC || isMintingUNI, - [isMintingBTC, isMintingUSDC, isMintingUNI] - ); + if (isPendingMarketConfiguration || isPendingCollateralConfigurations) { + return
Loading...
; + } return (
- {Object.values(TOKENS_BY_SYMBOL).map((token) => { - let balance = new BN(0); - switch (token.symbol) { - case 'ETH': - balance = etherBalance ?? new BN(0); - break; - case 'BTC': - balance = btcBalance ?? new BN(0); - break; - case 'USDC': - balance = usdcBalance ?? new BN(0); - break; - case 'UNI': - balance = uniBalance ?? new BN(0); - break; - default: - break; - } - - return ( -
-
{token.name}
-
- {toFixed(balance.formatUnits(token.decimals).toString(), { - precision: 4, - })} - {token.symbol} -
- -
- ); - })} + {assets.map((asset) => ( + 0} + ethBalance={ethBalance ?? new BN(0)} + /> + ))}
); }; diff --git a/apps/frontend-v2/src/components/Navbar/ConnectButton.tsx b/apps/frontend-v2/src/components/Navbar/ConnectButton.tsx index 29992948..f2124332 100644 --- a/apps/frontend-v2/src/components/Navbar/ConnectButton.tsx +++ b/apps/frontend-v2/src/components/Navbar/ConnectButton.tsx @@ -24,7 +24,11 @@ export const ConnectButton = () => { disconnect(); }} > - {isConnected ? account : isConnecting ? 'Connecting' : 'Connect'} + {isConnected + ? `${account?.slice(0, 6)}...${account?.slice(-4)}` + : isConnecting + ? 'Connecting' + : 'Connect'} ); diff --git a/apps/frontend-v2/src/components/Navbar/MarketSwitcher.tsx b/apps/frontend-v2/src/components/Navbar/MarketSwitcher.tsx new file mode 100644 index 00000000..1240548b --- /dev/null +++ b/apps/frontend-v2/src/components/Navbar/MarketSwitcher.tsx @@ -0,0 +1,16 @@ +'use client'; +import { useMarketStore } from '@/stores'; +import { DeployedMarket } from '@/utils'; +import { Button } from '../ui/button'; + +export const MarketSwitcher = () => { + const { market, changeMarket } = useMarketStore(); + + const switchMarket = () => { + changeMarket( + market === DeployedMarket.USDC ? DeployedMarket.USDT : DeployedMarket.USDC + ); + }; + + return ; +}; diff --git a/apps/frontend-v2/src/components/Navbar/index.tsx b/apps/frontend-v2/src/components/Navbar/index.tsx index 6fa346e4..adb05b4c 100644 --- a/apps/frontend-v2/src/components/Navbar/index.tsx +++ b/apps/frontend-v2/src/components/Navbar/index.tsx @@ -3,6 +3,7 @@ import Link from 'next/link'; import React from 'react'; import Logo from '/public/icons/dark-logo.svg?url'; import { ConnectButton } from './ConnectButton'; +import { MarketSwitcher } from './MarketSwitcher'; export const Navbar = () => { return ( @@ -16,6 +17,7 @@ export const Navbar = () => { Market
+
diff --git a/apps/frontend-v2/src/components/Toasts/ErrorToast.tsx b/apps/frontend-v2/src/components/Toasts/ErrorToast.tsx new file mode 100644 index 00000000..becf5263 --- /dev/null +++ b/apps/frontend-v2/src/components/Toasts/ErrorToast.tsx @@ -0,0 +1,26 @@ +import { toast } from 'react-toastify'; + +type ErrorToastProps = { + error: string; +}; + +export const ErrorToast = ({ error }: ErrorToastProps) => { + console.error(error); + const extractErrorReason = (error: string) => { + if (error.includes('Out of gas')) { + return 'Transaction failed. Out of gas'; + } + + if (error === 'not enough coins to fit the target') { + return 'Insufficient balance.'; + } + + if (error.includes('transaction reverted')) { + return 'Transaction reverted.'; + } + + return ''; + }; + + return toast.error(extractErrorReason(error)); +}; diff --git a/apps/frontend-v2/src/components/Toasts/TransactionSuccessToast.tsx b/apps/frontend-v2/src/components/Toasts/TransactionSuccessToast.tsx new file mode 100644 index 00000000..a653145e --- /dev/null +++ b/apps/frontend-v2/src/components/Toasts/TransactionSuccessToast.tsx @@ -0,0 +1,25 @@ +import { EXPLORER_URL } from '@/utils'; +import { toast } from 'react-toastify'; + +type TransactionSuccessToastProps = { + transactionId: string; +}; + +export const TransactionSuccessToast = ({ + transactionId, +}: TransactionSuccessToastProps) => { + console.log(transactionId); + return toast( +
+ Transaction successful:{' '} + + {transactionId} + +
+ ); +}; diff --git a/apps/frontend-v2/src/components/Toasts/index.ts b/apps/frontend-v2/src/components/Toasts/index.ts new file mode 100644 index 00000000..8ed106f5 --- /dev/null +++ b/apps/frontend-v2/src/components/Toasts/index.ts @@ -0,0 +1,2 @@ +export * from './ErrorToast'; +export * from './TransactionSuccessToast'; diff --git a/apps/frontend-v2/src/hooks/index.ts b/apps/frontend-v2/src/hooks/index.ts index 7af36d71..f35446e5 100644 --- a/apps/frontend-v2/src/hooks/index.ts +++ b/apps/frontend-v2/src/hooks/index.ts @@ -9,3 +9,9 @@ export * from './useTotalCollateral'; export * from './useCollateralConfigurations'; export * from './useProvider'; export * from './useSupplyCollateral'; +export * from './useWithdrawCollateral'; +export * from './useWithdrawBase'; +export * from './useSupplyBase'; +export * from './useMarketConfiguration'; +export * from './useCollateralConfigurations'; +export * from './useBorrowCapacity'; diff --git a/apps/frontend-v2/src/hooks/useBorrowCapacity.ts b/apps/frontend-v2/src/hooks/useBorrowCapacity.ts new file mode 100644 index 00000000..f760978c --- /dev/null +++ b/apps/frontend-v2/src/hooks/useBorrowCapacity.ts @@ -0,0 +1,72 @@ +import { useMarketStore } from '@/stores'; +import { formatUnits } from '@/utils'; +import { useAccount } from '@fuels/react'; +import { useQuery } from '@tanstack/react-query'; +import BigNumber from 'bignumber.js'; +import { useCollateralConfigurations } from './useCollateralConfigurations'; +import { useMarketConfiguration } from './useMarketConfiguration'; +import { usePrice } from './usePrice'; +import { useUserCollateralAssets } from './useUserCollateralAssets'; +import { useUserSupplyBorrow } from './useUserSupplyBorrow'; + +export const useBorrowCapacity = () => { + const { market } = useMarketStore(); + const { account } = useAccount(); + const { data: supplyBorrow } = useUserSupplyBorrow(); + const { data: collateralConfigurations } = useCollateralConfigurations(); + const { data: userCollateralAssets } = useUserCollateralAssets(); + const { data: priceData } = usePrice(); + const { data: marketConfiguration } = useMarketConfiguration(); + + return useQuery({ + queryKey: [ + 'borrowCapacity', + account, + supplyBorrow, + collateralConfigurations, + market, + userCollateralAssets, + priceData?.prices, + marketConfiguration, + ], + queryFn: async () => { + if ( + !account || + !supplyBorrow || + !collateralConfigurations || + !userCollateralAssets || + !priceData || + !marketConfiguration + ) { + return BigNumber(0); + } + + const borrowCapacity = Object.entries(userCollateralAssets) + .reduce((acc, [key, value]) => { + return acc.plus( + formatUnits( + value.times(priceData.prices[key]), + collateralConfigurations[key].decimals + ) + ); + }, new BigNumber(0)) + .minus( + formatUnits( + supplyBorrow.borrowed.times( + priceData.prices[marketConfiguration.baseToken] + ), + marketConfiguration.baseTokenDecimals + ) + ); + + return borrowCapacity; + }, + enabled: + !!account && + !!supplyBorrow && + !!collateralConfigurations && + !!userCollateralAssets && + !!priceData && + !!marketConfiguration, + }); +}; diff --git a/apps/frontend-v2/src/hooks/useBorrowRate.ts b/apps/frontend-v2/src/hooks/useBorrowRate.ts index 35623cfa..ca8df78b 100644 --- a/apps/frontend-v2/src/hooks/useBorrowRate.ts +++ b/apps/frontend-v2/src/hooks/useBorrowRate.ts @@ -1,27 +1,33 @@ import { Market } from '@/contract-types'; -import { CONTRACT_ADDRESSES } from '@/utils'; +import { useMarketStore } from '@/stores'; +import { DEPLOYED_MARKETS } from '@/utils'; import { useQuery } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; -import type { BN } from 'fuels'; import { useProvider } from './useProvider'; import { useUtilization } from './useUtilization'; export const useBorrowRate = () => { const provider = useProvider(); const { data: utilization } = useUtilization(); + const { market } = useMarketStore(); - const fetchBorrowRate = async (utilization: BN | undefined) => { - if (!provider || !utilization) return; - const marketContract = new Market(CONTRACT_ADDRESSES.market, provider); - const { value } = await marketContract.functions - .get_borrow_rate(utilization) - .get(); - if (!value) throw new Error('Failed to fetch borrowRate'); - return new BigNumber(value.toString()); - }; return useQuery({ - queryKey: ['borrowRate', utilization], - queryFn: () => fetchBorrowRate(utilization), - enabled: !!utilization, + queryKey: ['borrowRate', utilization?.toString(), market], + queryFn: async () => { + if (!provider || !utilization) return null; + + const marketContract = new Market( + DEPLOYED_MARKETS[market].marketAddress, + provider + ); + + const { value } = await marketContract.functions + .get_borrow_rate(utilization) + .get(); + + if (!value) throw new Error('Failed to fetch borrowRate'); + return new BigNumber(value.toString()); + }, + enabled: !!utilization && !!provider, }); }; diff --git a/apps/frontend-v2/src/hooks/useCollateralConfigurations.ts b/apps/frontend-v2/src/hooks/useCollateralConfigurations.ts index 43f0cdfc..e5cbc82d 100644 --- a/apps/frontend-v2/src/hooks/useCollateralConfigurations.ts +++ b/apps/frontend-v2/src/hooks/useCollateralConfigurations.ts @@ -1,12 +1,15 @@ import type { CollateralConfigurationOutput } from '@/contract-types/Market'; import { getCollateralConfigurations } from '@/lib/queries'; +import { useMarketStore } from '@/stores'; import { useQuery } from '@tanstack/react-query'; export const useCollateralConfigurations = () => { + const { market } = useMarketStore(); + return useQuery({ - queryKey: ['collateralConfigurations'], + queryKey: ['collateralConfigurations', market], queryFn: async () => { - const configurations = await getCollateralConfigurations(); + const configurations = await getCollateralConfigurations(market); const formattedConfigurations: Record< string, @@ -28,5 +31,6 @@ export const useCollateralConfigurations = () => { return formattedConfigurations; }, + refetchInterval: 1000 * 100, }); }; diff --git a/apps/frontend-v2/src/hooks/useMarketConfiguration.ts b/apps/frontend-v2/src/hooks/useMarketConfiguration.ts new file mode 100644 index 00000000..a9aa9983 --- /dev/null +++ b/apps/frontend-v2/src/hooks/useMarketConfiguration.ts @@ -0,0 +1,16 @@ +import { getMarketConfiguration } from '@/lib/queries'; +import { useMarketStore } from '@/stores'; +import { useQuery } from '@tanstack/react-query'; + +export const useMarketConfiguration = () => { + const { market } = useMarketStore(); + + return useQuery({ + queryKey: ['marketConfiguration', market], + queryFn: async () => { + const configuration = await getMarketConfiguration(market); + + return configuration[0]; + }, + }); +}; diff --git a/apps/frontend-v2/src/hooks/useMintToken.tsx b/apps/frontend-v2/src/hooks/useMintToken.ts similarity index 62% rename from apps/frontend-v2/src/hooks/useMintToken.tsx rename to apps/frontend-v2/src/hooks/useMintToken.ts index efd830f9..d7ded170 100644 --- a/apps/frontend-v2/src/hooks/useMintToken.tsx +++ b/apps/frontend-v2/src/hooks/useMintToken.ts @@ -1,5 +1,7 @@ +import { ErrorToast, TransactionSuccessToast } from '@/components/Toasts'; import { Token } from '@/contract-types'; -import { CONTRACT_ADDRESSES, EXPLORER_URL, FAUCET_AMOUNTS } from '@/utils'; +import { useMarketStore } from '@/stores'; +import { DEPLOYED_MARKETS, FAUCET_AMOUNTS } from '@/utils'; import { useAccount, useWallet } from '@fuels/react'; import { useMutation } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; @@ -9,13 +11,15 @@ import { toast } from 'react-toastify'; export const useMintToken = (symbol: string, decimals: number) => { const { wallet } = useWallet(); const { account } = useAccount(); + const { market } = useMarketStore(); return useMutation({ - mutationKey: ['mintToken', symbol, account], + mutationKey: ['mintToken', symbol, account, market], mutationFn: async () => { - if (!wallet || !account) return; + if (!wallet || !account) return null; + const tokenFactoryContract = new Token( - CONTRACT_ADDRESSES.tokenFactory, + DEPLOYED_MARKETS[market].tokenFactoryAddress, wallet ); @@ -38,28 +42,15 @@ export const useMintToken = (symbol: string, decimals: number) => { }, }); - return transactionResult; + return transactionResult.transactionId; }, onSuccess: (data) => { if (data) { - toast( -
- Transaction successful:{' '} - - {data.transactionId} - -
- ); + TransactionSuccessToast({ transactionId: data }); } }, onError: (error) => { - console.error('Error minting token:', error); - toast('Error'); + ErrorToast({ error: error.message }); }, }); }; diff --git a/apps/frontend-v2/src/hooks/usePrice.ts b/apps/frontend-v2/src/hooks/usePrice.ts index f04571f3..0814505d 100644 --- a/apps/frontend-v2/src/hooks/usePrice.ts +++ b/apps/frontend-v2/src/hooks/usePrice.ts @@ -1,9 +1,6 @@ import { Market, type PriceDataUpdateInput } from '@/contract-types/Market'; -import { - CONTRACT_ADDRESSES, - TOKENS_BY_ASSET_ID, - TOKENS_BY_PRICE_FEED, -} from '@/utils'; +import { useMarketStore } from '@/stores'; +import { DEPLOYED_MARKETS } from '@/utils'; import { HermesClient } from '@pythnetwork/hermes-client'; import { PYTH_CONTRACT_ADDRESS_SEPOLIA, @@ -12,21 +9,47 @@ import { import { useQuery } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; import { arrayify } from 'fuels'; +import { DateTime } from 'fuels'; +import { useMemo } from 'react'; +import { useCollateralConfigurations } from './useCollateralConfigurations'; +import { useMarketConfiguration } from './useMarketConfiguration'; import { useProvider } from './useProvider'; -export const usePrice = (assetIds: string[]) => { +export const usePrice = () => { const hermesClient = new HermesClient('https://hermes.pyth.network'); - const provider = useProvider(); + const { market } = useMarketStore(); + + const { data: marketConfiguration } = useMarketConfiguration(); + const { data: collateralConfigurations } = useCollateralConfigurations(); + + // Create a map of priceFeedId to assetId + const priceFeedIdToAssetId = useMemo(() => { + if (!marketConfiguration || !collateralConfigurations) return null; + + const assets: Map = new Map(); + + assets.set( + marketConfiguration.baseTokenPriceFeedId, + marketConfiguration.baseToken + ); + + for (const [assetId, collateralConfiguration] of Object.entries( + collateralConfigurations + )) { + assets.set(collateralConfiguration.price_feed_id, assetId); + } + + return assets; + }, [marketConfiguration, collateralConfigurations]); + return useQuery({ - queryKey: ['pythPrices', assetIds], + queryKey: ['pythPrices', priceFeedIdToAssetId, market], queryFn: async () => { - if (!provider) return; + if (!provider || !priceFeedIdToAssetId) return null; - const priceFeedIds = assetIds.map( - (assetId) => TOKENS_BY_ASSET_ID[assetId].priceFeed - ); + const priceFeedIds = Array.from(priceFeedIdToAssetId.keys()); // Fetch price udpates from Hermes client const priceUpdates = @@ -45,7 +68,11 @@ export const usePrice = (assetIds: string[]) => { PYTH_CONTRACT_ADDRESS_SEPOLIA, provider ); - const marketContract = new Market(CONTRACT_ADDRESSES.market, provider); + + const marketContract = new Market( + DEPLOYED_MARKETS[market].marketAddress, + provider + ); const buffer = Buffer.from(priceUpdates.binary.data[0], 'hex'); const updateData = [arrayify(buffer)]; @@ -58,22 +85,22 @@ export const usePrice = (assetIds: string[]) => { // Prepare the PriceDateUpdateInput object const priceUpdateData: PriceDataUpdateInput = { update_fee: fee, - publish_times: priceUpdates.parsed.map( - (parsedPrice) => parsedPrice.price.publish_time + publish_times: priceUpdates.parsed.map((parsedPrice) => + DateTime.fromUnixSeconds(parsedPrice.price.publish_time).toTai64() ), price_feed_ids: priceFeedIds, update_data: updateData, }; // Format prices to BigNumber - const prices: Record = {}; - - priceUpdates.parsed.forEach((parsedPrice) => { - const currentAssetId = TOKENS_BY_PRICE_FEED[parsedPrice.id].assetId; - prices[currentAssetId] = BigNumber(parsedPrice.price.price).times( - BigNumber(10).pow(BigNumber(parsedPrice.price.expo)) - ); - }); + const prices = Object.fromEntries( + priceUpdates.parsed.map((parsedPrice) => [ + priceFeedIdToAssetId.get(`0x${parsedPrice.id}`)!, + BigNumber(parsedPrice.price.price).times( + BigNumber(10).pow(BigNumber(parsedPrice.price.expo)) + ), + ]) + ); return { prices, @@ -81,6 +108,6 @@ export const usePrice = (assetIds: string[]) => { }; }, refetchInterval: 5000, - enabled: !!provider, + enabled: !!provider && !!priceFeedIdToAssetId, }); }; diff --git a/apps/frontend-v2/src/hooks/useSupplyBase.tsx b/apps/frontend-v2/src/hooks/useSupplyBase.ts similarity index 55% rename from apps/frontend-v2/src/hooks/useSupplyBase.tsx rename to apps/frontend-v2/src/hooks/useSupplyBase.ts index e4bce0c7..6b2ddc41 100644 --- a/apps/frontend-v2/src/hooks/useSupplyBase.tsx +++ b/apps/frontend-v2/src/hooks/useSupplyBase.ts @@ -1,32 +1,40 @@ +import { ErrorToast, TransactionSuccessToast } from '@/components/Toasts'; import { Market } from '@/contract-types'; -import { CONTRACT_ADDRESSES, EXPLORER_URL, TOKENS_BY_SYMBOL } from '@/utils'; +import { useMarketStore } from '@/stores'; +import { DEPLOYED_MARKETS } from '@/utils'; import { useAccount, useWallet } from '@fuels/react'; import { useMutation } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; import { toast } from 'react-toastify'; +import { useMarketConfiguration } from './useMarketConfiguration'; export const useSupplyBase = () => { const { wallet } = useWallet(); const { account } = useAccount(); + const { market } = useMarketStore(); + const { data: marketConfiguration } = useMarketConfiguration(); return useMutation({ - mutationKey: ['supplyBase', account], + mutationKey: ['supplyBase', account, marketConfiguration, market], mutationFn: async (tokenAmount: BigNumber) => { - if (!wallet || !account) { - return; + if (!wallet || !account || !marketConfiguration) { + return null; } - const marketContract = new Market(CONTRACT_ADDRESSES.market, wallet); + const marketContract = new Market( + DEPLOYED_MARKETS[market].marketAddress, + wallet + ); const amount = new BigNumber(tokenAmount).times( - 10 ** TOKENS_BY_SYMBOL.USDC.decimals + 10 ** marketConfiguration.baseTokenDecimals ); const { waitForResult } = await marketContract.functions .supply_base() .callParams({ forward: { - assetId: TOKENS_BY_SYMBOL.USDC.assetId, + assetId: marketConfiguration.baseToken, amount: amount.toString(), }, }) @@ -42,24 +50,11 @@ export const useSupplyBase = () => { }, onSuccess: (data) => { if (data) { - toast( -
- Transaction successful:{' '} - - {data} - -
- ); + TransactionSuccessToast({ transactionId: data }); } }, onError: (error) => { - console.log(error); - toast('Error'); + ErrorToast({ error: error.message }); }, }); }; diff --git a/apps/frontend-v2/src/hooks/useSupplyCollateral.tsx b/apps/frontend-v2/src/hooks/useSupplyCollateral.ts similarity index 54% rename from apps/frontend-v2/src/hooks/useSupplyCollateral.tsx rename to apps/frontend-v2/src/hooks/useSupplyCollateral.ts index 99e1cb09..8f87adf6 100644 --- a/apps/frontend-v2/src/hooks/useSupplyCollateral.tsx +++ b/apps/frontend-v2/src/hooks/useSupplyCollateral.ts @@ -1,12 +1,15 @@ +import { ErrorToast, TransactionSuccessToast } from '@/components/Toasts'; import { Market } from '@/contract-types'; -import { CONTRACT_ADDRESSES, EXPLORER_URL, TOKENS_BY_ASSET_ID } from '@/utils'; +import { useMarketStore } from '@/stores'; +import { DEPLOYED_MARKETS } from '@/utils'; import { useAccount, useWallet } from '@fuels/react'; import { useMutation } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; import { toast } from 'react-toastify'; +import { useCollateralConfigurations } from './useCollateralConfigurations'; type useSupplyCollateralProps = { - actionTokenAssetId: string | null; + actionTokenAssetId: string | null | undefined; }; export const useSupplyCollateral = ({ @@ -14,18 +17,34 @@ export const useSupplyCollateral = ({ }: useSupplyCollateralProps) => { const { wallet } = useWallet(); const { account } = useAccount(); + const { market } = useMarketStore(); + const { data: collateralConfigurations } = useCollateralConfigurations(); return useMutation({ - mutationKey: ['supplyCollateral', actionTokenAssetId, account], + mutationKey: [ + 'supplyCollateral', + actionTokenAssetId, + account, + market, + collateralConfigurations, + ], mutationFn: async (tokenAmount: BigNumber) => { - if (!wallet || !account || !actionTokenAssetId) { - return; + if ( + !wallet || + !account || + !actionTokenAssetId || + !collateralConfigurations + ) { + return null; } - const marketContract = new Market(CONTRACT_ADDRESSES.market, wallet); + const marketContract = new Market( + DEPLOYED_MARKETS[market].marketAddress, + wallet + ); const amount = new BigNumber(tokenAmount).times( - 10 ** TOKENS_BY_ASSET_ID[actionTokenAssetId].decimals + 10 ** collateralConfigurations[actionTokenAssetId].decimals ); const { waitForResult } = await marketContract.functions @@ -48,24 +67,11 @@ export const useSupplyCollateral = ({ }, onSuccess: (data) => { if (data) { - toast( -
- Transaction successful:{' '} - - {data} - -
- ); + TransactionSuccessToast({ transactionId: data }); } }, onError: (error) => { - console.log(error); - toast('Error'); + ErrorToast({ error: error.message }); }, }); }; diff --git a/apps/frontend-v2/src/hooks/useSupplyRate.ts b/apps/frontend-v2/src/hooks/useSupplyRate.ts index b3c6ccd6..a72515a8 100644 --- a/apps/frontend-v2/src/hooks/useSupplyRate.ts +++ b/apps/frontend-v2/src/hooks/useSupplyRate.ts @@ -1,27 +1,33 @@ import { Market } from '@/contract-types'; -import { CONTRACT_ADDRESSES } from '@/utils'; +import { useMarketStore } from '@/stores'; +import { DEPLOYED_MARKETS } from '@/utils'; import { useQuery } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; -import type { BN } from 'fuels'; import { useProvider } from './useProvider'; import { useUtilization } from './useUtilization'; export const useSupplyRate = () => { const provider = useProvider(); const { data: utilization } = useUtilization(); + const { market } = useMarketStore(); - const fetchSupplyRate = async (utilization: BN | undefined) => { - if (!provider || !utilization) return; - const marketContract = new Market(CONTRACT_ADDRESSES.market, provider); - const { value } = await marketContract.functions - .get_supply_rate(utilization) - .get(); - if (!value) throw new Error('Failed to fetch supplyRate'); - return new BigNumber(value.toString()); - }; return useQuery({ - queryKey: ['supplyRate', utilization], - queryFn: () => fetchSupplyRate(utilization), - enabled: !!utilization, + queryKey: ['supplyRate', utilization?.toString(), market], + queryFn: async () => { + if (!provider || !utilization) return null; + + const marketContract = new Market( + DEPLOYED_MARKETS[market].marketAddress, + provider + ); + + const { value } = await marketContract.functions + .get_supply_rate(utilization) + .get(); + + if (!value) throw new Error('Failed to fetch supplyRate'); + return new BigNumber(value.toString()); + }, + enabled: !!utilization && !!provider, }); }; diff --git a/apps/frontend-v2/src/hooks/useTotalCollateral.ts b/apps/frontend-v2/src/hooks/useTotalCollateral.ts index 9751c73e..47a36424 100644 --- a/apps/frontend-v2/src/hooks/useTotalCollateral.ts +++ b/apps/frontend-v2/src/hooks/useTotalCollateral.ts @@ -1,20 +1,33 @@ import { Market } from '@/contract-types'; -import { CONTRACT_ADDRESSES, collaterals } from '@/utils'; +import { useMarketStore } from '@/stores'; +import { DEPLOYED_MARKETS } from '@/utils'; import { useQuery } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; +import { useCollateralConfigurations } from './useCollateralConfigurations'; import { useProvider } from './useProvider'; export const useTotalCollateral = () => { const provider = useProvider(); + const { market } = useMarketStore(); + const { data: collateralConfigurations } = useCollateralConfigurations(); return useQuery({ - queryKey: ['totalCollateral'], + queryKey: ['totalCollateral', market, collateralConfigurations], queryFn: async () => { - if (!provider) return; - const marketContract = new Market(CONTRACT_ADDRESSES.market, provider); + if (!provider || !collateralConfigurations) return null; - const promises = collaterals.map((b) => - marketContract.functions.totals_collateral(b.assetId).get() + const marketContract = new Market( + DEPLOYED_MARKETS[market].marketAddress, + provider + ); + + const promises = Object.keys(collateralConfigurations).map( + async (assetId) => ({ + assetId, + value: await marketContract.functions + .totals_collateral(assetId) + .get(), + }) ); const data = await Promise.all(promises); @@ -23,15 +36,15 @@ export const useTotalCollateral = () => { throw new Error('Failed to fetch totalsCollateral'); } - const v = data.reduce((acc: Record, res, index) => { - if (res == null) return acc; - const assetId = collaterals[index].assetId; - acc[assetId] = new BigNumber(res.value.toString()); - return acc; - }, {}); + const totals = new Map( + data.map(({ assetId, value }) => [ + assetId, + new BigNumber(value.toString()), + ]) + ); - return v; + return totals; }, - enabled: !!provider, + enabled: !!provider && !!collateralConfigurations, }); }; diff --git a/apps/frontend-v2/src/hooks/useUserCollateralAssets.ts b/apps/frontend-v2/src/hooks/useUserCollateralAssets.ts index 8f293ea4..d85083d3 100644 --- a/apps/frontend-v2/src/hooks/useUserCollateralAssets.ts +++ b/apps/frontend-v2/src/hooks/useUserCollateralAssets.ts @@ -1,25 +1,29 @@ import { getCollateralAssets } from '@/lib/queries'; +import { useMarketStore } from '@/stores'; import { useAccount } from '@fuels/react'; import { useQuery } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; export const useUserCollateralAssets = () => { const { account } = useAccount(); + const { market } = useMarketStore(); return useQuery({ - queryKey: ['collateralAssets', account], + queryKey: ['collateralAssets', account, market], queryFn: async () => { - if (!account) return; + if (!account) return null; - const assets = await getCollateralAssets(account); - if (assets.length < 1) throw Error('Cant get user assets'); + const assets = await getCollateralAssets(account, market); const formattedCollaterals: Record = {}; - assets[0].collateralAssets.forEach((asset) => { - formattedCollaterals[asset.collateralAsset_id] = new BigNumber( - asset.amount - ); - }); + + if (assets.length > 0) { + assets[0].collateralAssets.forEach((asset) => { + formattedCollaterals[asset.collateralAsset_id] = new BigNumber( + asset.amount + ); + }); + } return formattedCollaterals; }, diff --git a/apps/frontend-v2/src/hooks/useUserSupplyBorrow.ts b/apps/frontend-v2/src/hooks/useUserSupplyBorrow.ts index 4e5973ac..805f7789 100644 --- a/apps/frontend-v2/src/hooks/useUserSupplyBorrow.ts +++ b/apps/frontend-v2/src/hooks/useUserSupplyBorrow.ts @@ -1,28 +1,34 @@ import { Market } from '@/contract-types'; -import { CONTRACT_ADDRESSES } from '@/utils'; -import { useWallet } from '@fuels/react'; +import { useMarketStore } from '@/stores'; +import { DEPLOYED_MARKETS } from '@/utils'; +import { useAccount, useWallet } from '@fuels/react'; import { useQuery } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; export const useUserSupplyBorrow = () => { const { wallet } = useWallet(); + const { account } = useAccount(); + const { market } = useMarketStore(); - const fetchUserSupplyBorrow = async () => { - if (!wallet) return; - const marketContract = new Market(CONTRACT_ADDRESSES.market, wallet); + return useQuery({ + queryKey: ['userSupplyBorrow', account, market], + queryFn: async () => { + if (!wallet || !account) return null; - const { value } = await marketContract.functions - .get_user_supply_borrow({ bits: wallet.address.toB256() }) - .get(); - return [ - new BigNumber(value[0].toString()), - new BigNumber(value[1].toString()), - ]; - }; + const marketContract = new Market( + DEPLOYED_MARKETS[market].marketAddress, + wallet + ); - return useQuery({ - queryKey: ['userSupplyBorrow', wallet?.address.toHexString()], - queryFn: () => fetchUserSupplyBorrow(), - enabled: !!wallet, + const { value } = await marketContract.functions + .get_user_supply_borrow({ bits: wallet.address.toB256() }) + .get(); + + return { + supplied: new BigNumber(value[0].toString()), + borrowed: new BigNumber(value[1].toString()), + }; + }, + enabled: !!wallet && !!account, }); }; diff --git a/apps/frontend-v2/src/hooks/useUtilization.ts b/apps/frontend-v2/src/hooks/useUtilization.ts index 0487d72a..3f9bada4 100644 --- a/apps/frontend-v2/src/hooks/useUtilization.ts +++ b/apps/frontend-v2/src/hooks/useUtilization.ts @@ -1,21 +1,29 @@ import { Market } from '@/contract-types'; -import { CONTRACT_ADDRESSES } from '@/utils'; +import { useMarketStore } from '@/stores'; +import { DEPLOYED_MARKETS } from '@/utils'; import { useQuery } from '@tanstack/react-query'; import { useProvider } from './useProvider'; export const useUtilization = () => { const provider = useProvider(); - const fetchUtilization = async () => { - if (!provider) return; - const marketContract = new Market(CONTRACT_ADDRESSES.market, provider); - const { value } = await marketContract.functions.get_utilization().get(); - if (!value) throw new Error('Failed to fetch utilization'); - return value; - }; + const { market } = useMarketStore(); + return useQuery({ - queryKey: ['utilization'], - queryFn: fetchUtilization, + queryKey: ['utilization', market], + queryFn: async () => { + if (!provider) return null; + + const marketContract = new Market( + DEPLOYED_MARKETS[market].marketAddress, + provider + ); + + const { value } = await marketContract.functions.get_utilization().get(); + + if (!value) throw new Error('Failed to fetch utilization'); + return value; + }, enabled: !!provider, }); }; diff --git a/apps/frontend-v2/src/hooks/useWithdrawBase.tsx b/apps/frontend-v2/src/hooks/useWithdrawBase.ts similarity index 66% rename from apps/frontend-v2/src/hooks/useWithdrawBase.tsx rename to apps/frontend-v2/src/hooks/useWithdrawBase.ts index a24aa148..ce32b116 100644 --- a/apps/frontend-v2/src/hooks/useWithdrawBase.tsx +++ b/apps/frontend-v2/src/hooks/useWithdrawBase.ts @@ -1,11 +1,8 @@ +import { ErrorToast, TransactionSuccessToast } from '@/components/Toasts'; import { Market } from '@/contract-types'; import type { PriceDataUpdateInput } from '@/contract-types/Market'; -import { - CONTRACT_ADDRESSES, - EXPLORER_URL, - FUEL_ETH_BASE_ASSET_ID, - TOKENS_BY_SYMBOL, -} from '@/utils'; +import { useMarketStore } from '@/stores'; +import { DEPLOYED_MARKETS, FUEL_ETH_BASE_ASSET_ID } from '@/utils'; import { useAccount, useWallet } from '@fuels/react'; import { PYTH_CONTRACT_ADDRESS_SEPOLIA, @@ -14,13 +11,16 @@ import { import { useMutation } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; import { toast } from 'react-toastify'; +import { useMarketConfiguration } from './useMarketConfiguration'; export const useWithdrawBase = () => { const { wallet } = useWallet(); const { account } = useAccount(); + const { market } = useMarketStore(); + const { data: marketConfiguration } = useMarketConfiguration(); return useMutation({ - mutationKey: ['withdrawBase', account], + mutationKey: ['withdrawBase', account, market, marketConfiguration], mutationFn: async ({ tokenAmount, priceUpdateData, @@ -28,18 +28,22 @@ export const useWithdrawBase = () => { tokenAmount: BigNumber; priceUpdateData: PriceDataUpdateInput; }) => { - if (!wallet || !account) { - return; + if (!wallet || !account || !marketConfiguration) { + return null; } + const pythContract = new PythContract( PYTH_CONTRACT_ADDRESS_SEPOLIA, wallet ); - const marketContract = new Market(CONTRACT_ADDRESSES.market, wallet); + const marketContract = new Market( + DEPLOYED_MARKETS[market].marketAddress, + wallet + ); const amount = new BigNumber(tokenAmount).times( - 10 ** TOKENS_BY_SYMBOL.USDC.decimals + 10 ** marketConfiguration.baseTokenDecimals ); const { waitForResult } = await marketContract.functions @@ -63,24 +67,11 @@ export const useWithdrawBase = () => { }, onSuccess: (data) => { if (data) { - toast( -
- Transaction successful:{' '} - - {data} - -
- ); + TransactionSuccessToast({ transactionId: data }); } }, onError: (error) => { - console.log(error); - toast('Error'); + ErrorToast({ error: error.message }); }, }); }; diff --git a/apps/frontend-v2/src/hooks/useWithdrawCollateral.tsx b/apps/frontend-v2/src/hooks/useWithdrawCollateral.ts similarity index 66% rename from apps/frontend-v2/src/hooks/useWithdrawCollateral.tsx rename to apps/frontend-v2/src/hooks/useWithdrawCollateral.ts index 396d572c..ca9b470d 100644 --- a/apps/frontend-v2/src/hooks/useWithdrawCollateral.tsx +++ b/apps/frontend-v2/src/hooks/useWithdrawCollateral.ts @@ -1,11 +1,8 @@ +import { ErrorToast, TransactionSuccessToast } from '@/components/Toasts'; import { Market } from '@/contract-types'; import type { PriceDataUpdateInput } from '@/contract-types/Market'; -import { - CONTRACT_ADDRESSES, - EXPLORER_URL, - FUEL_ETH_BASE_ASSET_ID, - TOKENS_BY_ASSET_ID, -} from '@/utils'; +import { useMarketStore } from '@/stores'; +import { DEPLOYED_MARKETS, FUEL_ETH_BASE_ASSET_ID } from '@/utils'; import { useAccount, useWallet } from '@fuels/react'; import { PYTH_CONTRACT_ADDRESS_SEPOLIA, @@ -14,9 +11,10 @@ import { import { useMutation } from '@tanstack/react-query'; import BigNumber from 'bignumber.js'; import { toast } from 'react-toastify'; +import { useCollateralConfigurations } from './useCollateralConfigurations'; type useWithdrawCollateralProps = { - actionTokenAssetId: string | null; + actionTokenAssetId: string | null | undefined; }; export const useWithdrawCollateral = ({ @@ -24,9 +22,11 @@ export const useWithdrawCollateral = ({ }: useWithdrawCollateralProps) => { const { wallet } = useWallet(); const { account } = useAccount(); + const { market } = useMarketStore(); + const { data: collateralConfigurations } = useCollateralConfigurations(); return useMutation({ - mutationKey: ['withdrawCollateral', actionTokenAssetId, account], + mutationKey: ['withdrawCollateral', actionTokenAssetId, account, market], mutationFn: async ({ tokenAmount, priceUpdateData, @@ -34,18 +34,27 @@ export const useWithdrawCollateral = ({ tokenAmount: BigNumber; priceUpdateData: PriceDataUpdateInput; }) => { - if (!wallet || !account || !actionTokenAssetId) { - return; + if ( + !wallet || + !account || + !actionTokenAssetId || + !collateralConfigurations + ) { + return null; } + const pythContract = new PythContract( PYTH_CONTRACT_ADDRESS_SEPOLIA, wallet ); - const marketContract = new Market(CONTRACT_ADDRESSES.market, wallet); + const marketContract = new Market( + DEPLOYED_MARKETS[market].marketAddress, + wallet + ); const amount = new BigNumber(tokenAmount).times( - 10 ** TOKENS_BY_ASSET_ID[actionTokenAssetId].decimals + 10 ** collateralConfigurations[actionTokenAssetId].decimals ); const { waitForResult } = await marketContract.functions @@ -73,24 +82,11 @@ export const useWithdrawCollateral = ({ }, onSuccess: (data) => { if (data) { - toast( -
- Transaction successful:{' '} - - {data} - -
- ); + TransactionSuccessToast({ transactionId: data }); } }, onError: (error) => { - console.log(error); - toast('Error'); + ErrorToast({ error: error.message }); }, }); }; diff --git a/apps/frontend-v2/src/lib/graphql/getMarketConfiguration.query.graphql b/apps/frontend-v2/src/lib/graphql/getMarketConfiguration.query.graphql new file mode 100644 index 00000000..0aadc744 --- /dev/null +++ b/apps/frontend-v2/src/lib/graphql/getMarketConfiguration.query.graphql @@ -0,0 +1,8 @@ +query GetMarketConfiguration { + MarketConfiguartion { + baseToken + baseTokenDecimals + baseTokenPriceFeedId + baseBorrowMin + } +} \ No newline at end of file diff --git a/apps/frontend-v2/src/lib/queries/getCollateralAssets.ts b/apps/frontend-v2/src/lib/queries/getCollateralAssets.ts index 8fbb097a..e2efdf53 100644 --- a/apps/frontend-v2/src/lib/queries/getCollateralAssets.ts +++ b/apps/frontend-v2/src/lib/queries/getCollateralAssets.ts @@ -2,10 +2,15 @@ import { GetCollateralAssetsDocument, type GetCollateralAssetsQuery, } from '@/__generated__/swaylend/graphql'; -import { GRAPHQL_URL } from '@/utils'; +import { DEPLOYED_MARKETS, type DeployedMarket } from '@/utils'; -export const getCollateralAssets = async (address: string) => { - const response = await fetch(GRAPHQL_URL, { +export const getCollateralAssets = async ( + address: string, + market: DeployedMarket +) => { + const url = DEPLOYED_MARKETS[market].graphqlUrl; + + const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/apps/frontend-v2/src/lib/queries/getCollateralConfigurations.ts b/apps/frontend-v2/src/lib/queries/getCollateralConfigurations.ts index d7344822..c4028a6e 100644 --- a/apps/frontend-v2/src/lib/queries/getCollateralConfigurations.ts +++ b/apps/frontend-v2/src/lib/queries/getCollateralConfigurations.ts @@ -2,10 +2,12 @@ import { GetCollateralConfigurationsDocument, type GetCollateralConfigurationsQuery, } from '@/__generated__/swaylend/graphql'; -import { GRAPHQL_URL } from '@/utils'; +import { DEPLOYED_MARKETS, type DeployedMarket } from '@/utils'; -export const getCollateralConfigurations = async () => { - const response = await fetch(GRAPHQL_URL, { +export const getCollateralConfigurations = async (market: DeployedMarket) => { + const url = DEPLOYED_MARKETS[market].graphqlUrl; + + const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/apps/frontend-v2/src/lib/queries/getMarketConfiguration.ts b/apps/frontend-v2/src/lib/queries/getMarketConfiguration.ts new file mode 100644 index 00000000..b59e72e8 --- /dev/null +++ b/apps/frontend-v2/src/lib/queries/getMarketConfiguration.ts @@ -0,0 +1,26 @@ +import { + GetMarketConfigurationDocument, + type GetMarketConfigurationQuery, +} from '@/__generated__/swaylend/graphql'; +import { DEPLOYED_MARKETS, type DeployedMarket } from '@/utils'; + +export const getMarketConfiguration = async (market: DeployedMarket) => { + const url = DEPLOYED_MARKETS[market].graphqlUrl; + + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query: GetMarketConfigurationDocument, + }), + }); + + const jsonResponse = await response.json(); + + const data = (jsonResponse.data as GetMarketConfigurationQuery) + .MarketConfiguartion; + + return data; +}; diff --git a/apps/frontend-v2/src/lib/queries/getMarketState.ts b/apps/frontend-v2/src/lib/queries/getMarketState.ts index 8d83a35a..0f0d9c03 100644 --- a/apps/frontend-v2/src/lib/queries/getMarketState.ts +++ b/apps/frontend-v2/src/lib/queries/getMarketState.ts @@ -2,10 +2,12 @@ import { GetMarketStateDocument, type GetMarketStateQuery, } from '@/__generated__/swaylend/graphql'; -import { GRAPHQL_URL } from '@/utils'; +import { DEPLOYED_MARKETS, type DeployedMarket } from '@/utils'; -export const getMarketState = async () => { - const response = await fetch(GRAPHQL_URL, { +export const getMarketState = async (market: DeployedMarket) => { + const url = DEPLOYED_MARKETS[market].graphqlUrl; + + const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/apps/frontend-v2/src/lib/queries/index.ts b/apps/frontend-v2/src/lib/queries/index.ts index 359367c4..097d7848 100644 --- a/apps/frontend-v2/src/lib/queries/index.ts +++ b/apps/frontend-v2/src/lib/queries/index.ts @@ -1,3 +1,4 @@ export * from './getMarketState'; export * from './getCollateralAssets'; export * from './getCollateralConfigurations'; +export * from './getMarketConfiguration'; diff --git a/apps/frontend-v2/src/stores/marketStore.ts b/apps/frontend-v2/src/stores/marketStore.ts index ccb8cdb3..a94de812 100644 --- a/apps/frontend-v2/src/stores/marketStore.ts +++ b/apps/frontend-v2/src/stores/marketStore.ts @@ -1,3 +1,4 @@ +import { DeployedMarket } from '@/utils'; import BigNumber from 'bignumber.js'; import { shallow } from 'zustand/shallow'; import { createWithEqualityFn } from 'zustand/traditional'; @@ -15,18 +16,22 @@ export enum ACTION_MODE { } interface MarketStore { + market: DeployedMarket; + mode: ACTION_MODE; - action: ACTION_TYPE | null; + action: ACTION_TYPE | null | undefined; tokenAmount: BigNumber; - actionTokenAssetId: string | null; + actionTokenAssetId: string | null | undefined; + changeMarket: (market: DeployedMarket) => void; changeMode: (mode: ACTION_MODE) => void; - changeAction: (action: ACTION_TYPE | null) => void; + changeAction: (action: ACTION_TYPE | null | undefined) => void; changeTokenAmount: (tokenAmount: BigNumber) => void; - changeActionTokenAssetId: (assetId: string | null) => void; + changeActionTokenAssetId: (assetId: string | null | undefined) => void; } export const marketStoreInitialState = { + market: DeployedMarket.USDC, mode: 0, action: null, tokenAmount: new BigNumber(0), @@ -37,10 +42,11 @@ export const useMarketStore = createWithEqualityFn()( (set) => ({ ...marketStoreInitialState, + changeMarket: (market: DeployedMarket) => set({ market }), changeMode: (mode: ACTION_MODE) => set({ mode }), - changeAction: (action: ACTION_TYPE | null) => set({ action }), + changeAction: (action: ACTION_TYPE | null | undefined) => set({ action }), changeTokenAmount: (tokenAmount: BigNumber) => set({ tokenAmount }), - changeActionTokenAssetId: (assetId: string | null) => + changeActionTokenAssetId: (assetId: string | null | undefined) => set({ actionTokenAssetId: assetId }), }), shallow diff --git a/apps/frontend-v2/src/utils/constants.ts b/apps/frontend-v2/src/utils/constants.ts index 7a3c1e0c..39c14c84 100644 --- a/apps/frontend-v2/src/utils/constants.ts +++ b/apps/frontend-v2/src/utils/constants.ts @@ -1,6 +1,3 @@ -import tokenLogos from './tokenLogos'; -import tokens from './tokens.testnet.json'; - export interface IToken { logo: string; assetId: string; @@ -12,21 +9,40 @@ export interface IToken { } // Indexer URL -export const GRAPHQL_URL = process.env.NEXT_PUBLIC_GRAPHQL_URL!; export const NODE_URL = 'https://testnet.fuel.network/v1/graphql'; + // Contract addresses -export interface IContractsConfig { - priceOracle: string; - market: string; - tokenFactory: string; +export type MarketConfiguration = { + oracleAddress: string; + marketAddress: string; + tokenFactoryAddress: string; + graphqlUrl: string; +}; + +export enum DeployedMarket { + USDC = 'USDC', + USDT = 'USDT', } -export const CONTRACT_ADDRESSES: IContractsConfig = { - priceOracle: - '0xc3c47cdeaec412778fc86842b44fb061b350db57f9d52def4f73036156f71506', - market: '0x40306bb23caad2dceb3907d62f50d75a0d8cd5e7a01b2f3e4189d3a54be42e40', - tokenFactory: - '0xcbfa9f158e1ef6ba2f7c6696a47dea7f42e9c229f96dd9184a318f9bb5610665', +export const DEPLOYED_MARKETS: Record = { + USDC: { + oracleAddress: + '0xc3c47cdeaec412778fc86842b44fb061b350db57f9d52def4f73036156f71506', + marketAddress: + '0x5cd28d44008ab5f81b6a8bb684ac698c4e350bf99855004769b73097587185ed', + tokenFactoryAddress: + '0xc42945559a1d489c02849be67f601d8723f11881a167645ea64417b0306f68e3', + graphqlUrl: 'https://indexer.bigdevenergy.link/c755070/v1/graphql', + }, + USDT: { + oracleAddress: + '0xc3c47cdeaec412778fc86842b44fb061b350db57f9d52def4f73036156f71506', + marketAddress: + '0xa6ea42b91f28e4937457dd2b74285b81343d517196d0a86e5e91d7247cffe4e0', + tokenFactoryAddress: + '0xf25ccea490d84d013dc660b0cd7b7ea4d8cf525c83df79cddc78264c0f5295cb', + graphqlUrl: 'https://indexer.bigdevenergy.link/8ce655e/v1/graphql', + }, }; // Explorer URL @@ -34,48 +50,24 @@ export const EXPLORER_URL = 'https://app.fuel.network/tx'; // Faucet configuration export const FAUCET_URL = 'https://faucet-testnet.fuel.network/'; -export const TOKENS_LIST: Array = Object.values(tokens).map( - (t) => - ({ - ...t, - logo: tokenLogos[t.symbol], - }) as IToken -); -export const TOKENS_BY_SYMBOL: Record = TOKENS_LIST.reduce( - (acc: Record, t) => { - acc[t.symbol] = { ...t, priceFeed: `0x${t.priceFeed}` }; - return acc; - }, - {} -); - -export const TOKENS_BY_ASSET_ID: Record = TOKENS_LIST.reduce( - (acc: Record, t) => { - acc[t.assetId] = { ...t, priceFeed: `0x${t.priceFeed}` }; - return acc; - }, - {} -); - -export const TOKENS_BY_PRICE_FEED: Record = TOKENS_LIST.reduce( - (acc: Record, t) => { - acc[t.priceFeed] = { ...t, priceFeed: `0x${t.priceFeed}` }; - return acc; - }, - {} -); export const FAUCET_AMOUNTS: Record = { UNI: 50, BTC: 1, USDC: 300, + USDT: 300, + BNB: 300, }; -export const collaterals: IToken[] = [ - TOKENS_BY_SYMBOL.ETH, - TOKENS_BY_SYMBOL.BTC, - TOKENS_BY_SYMBOL.UNI, -]; - export const FUEL_ETH_BASE_ASSET_ID = '0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07'; + +export const ASSET_ID_TO_SYMBOL: Record = { + '0x2d52ecf6fa0a222ff796a748b61ef4e3ef844c2078afe4df6399e264a4f993ad': 'USDC', + '0x04f9a75b617ff67856b05d96b00d070c2041db5c6563bb7e9ad09f6e12a2d57a': 'USDT', + '0xf8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07': 'ETH', + '0xfb5a7c0184ed850bbbdfc73c09b0885603bc81048f2481f3032b6c1398290021': 'BTC', + '0x170ae7a2535154a5981db6cd0084689495849ad80a0b0dccdd7c579c9cfb7572': 'UNI', + '0x84ebfaf29d43e88f74a1573830c27d06e69112f0f0cb0694a10e3cf94b011cfd': 'BTC', + '0xaf0fb56ec3dbc594ea514e36042abdea14630be1569792ef73f09c09beac77cb': 'BNB', +}; diff --git a/apps/frontend-v2/src/utils/market.ts b/apps/frontend-v2/src/utils/market.ts index dd76a1f7..ab7e1254 100644 --- a/apps/frontend-v2/src/utils/market.ts +++ b/apps/frontend-v2/src/utils/market.ts @@ -1,6 +1,5 @@ import BigNumber from 'bignumber.js'; import { formatUnits } from './BigNumber'; -import { TOKENS_BY_ASSET_ID, TOKENS_BY_SYMBOL } from './constants'; export function getBorrowApr(borrowRate: BigNumber | null | undefined) { if (borrowRate == null) return '0.00'; @@ -23,64 +22,3 @@ export function getSupplyApr(supplyRate: BigNumber | null | undefined) { .times(100); return `${formatUnits(rate.times(coefficient), 18).toFormat(2)}%`; } - -// export function getTrueTotalCollateralBalance( -// collateralBalances: Record | undefined, -// assetsConfigs: Record | undefined, -// getTokenPrice: (assetId: string) => BigNumber -// ) { -// if (collateralBalances == null || assetsConfigs == null) return BigNumber.ZERO; -// const trueCollateralsValue = Object.entries(collateralBalances).reduce( -// (acc, [assetId, v]) => { -// const token = TOKENS_BY_ASSET_ID[assetId]; -// const liquidationFactor = BigNumber.formatUnits( -// assetsConfigs[assetId].liquidate_collateral_factor.toString(), -// 18 -// ); -// const balance = BigNumber.formatUnits(v, token.decimals); -// const dollBalance = getTokenPrice(assetId).times(balance); -// const trueDollBalance = dollBalance.times(liquidationFactor); -// return acc.plus(trueDollBalance); -// }, -// BigNumber.ZERO -// ); -// return trueCollateralsValue; -// } - -export function getTotalCollateralBalance( - collateralBalances: Record, - prices: Record -) { - if (collateralBalances == null) return new BigNumber(0); - const totalCollateralBalance = Object.entries(collateralBalances).reduce( - (acc, [assetId, v]) => { - const token = TOKENS_BY_ASSET_ID[assetId]; - const balance = formatUnits(v, token.decimals); - const dollBalance = (prices[assetId] ?? new BigNumber(0)).times(balance); - return acc.plus(dollBalance); - }, - new BigNumber(0) - ); - return totalCollateralBalance; -} - -export function getTotalSuppliedBalance( - suppliedBalance: BigNumber | null, - collateralBalances: Record, - prices: Record -) { - const baseTokenBalance = formatUnits( - suppliedBalance ?? new BigNumber(0), - TOKENS_BY_SYMBOL.USDC.decimals - ); - const baseTokenPrice = - prices[TOKENS_BY_SYMBOL.USDC.assetId] ?? new BigNumber(0); - const totalCollBalance = getTotalCollateralBalance( - collateralBalances, - prices - ); - return baseTokenBalance - .times(baseTokenPrice) - .plus(totalCollBalance) - .toFormat(2); -} diff --git a/package.json b/package.json index 0bf97d8c..5711ad3b 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,8 @@ "pnpm": "9.1.1" }, "pnpm": { - "patchedDependencies": {} + "patchedDependencies": { + "@fuel-ts/account@0.94.3": "patches/@fuel-ts__account@0.94.3.patch" + } } } diff --git a/patches/@fuel-ts__account@0.94.3.patch b/patches/@fuel-ts__account@0.94.3.patch new file mode 100644 index 00000000..3fe8f7fe --- /dev/null +++ b/patches/@fuel-ts__account@0.94.3.patch @@ -0,0 +1,50 @@ +diff --git a/dist/index.js b/dist/index.js +index 43910974d9634d34b2a296cc6cb7190d3edfadcc..80faba5cebcb69397f3d1b22af12c44c616ad9fe 100644 +--- a/dist/index.js ++++ b/dist/index.js +@@ -2018,17 +2018,17 @@ var assembleRevertError = (receipts, logs, metadata) => { + switch (reasonHex) { + case import_configs5.FAILED_REQUIRE_SIGNAL: { + reason = "require"; +- errorMessage = `The transaction reverted because a "require" statement has thrown ${logs.length ? stringify(logs[0]) : "an error."}.`; ++ errorMessage = `The transaction reverted because a "require" statement has thrown ${logs.length ? stringify(logs[logs.length - 1]) : "an error."}.`; + break; + } + case import_configs5.FAILED_ASSERT_EQ_SIGNAL: { +- const sufix = logs.length >= 2 ? ` comparing ${stringify(logs[1])} and ${stringify(logs[0])}.` : "."; ++ const sufix = logs.length >= 2 ? ` comparing ${stringify(logs[1])} and ${stringify(logs[logs.length - 1])}.` : "."; + reason = "assert_eq"; + errorMessage = `The transaction reverted because of an "assert_eq" statement${sufix}`; + break; + } + case import_configs5.FAILED_ASSERT_NE_SIGNAL: { +- const sufix = logs.length >= 2 ? ` comparing ${stringify(logs[1])} and ${stringify(logs[0])}.` : "."; ++ const sufix = logs.length >= 2 ? ` comparing ${stringify(logs[1])} and ${stringify(logs[logs.length - 1])}.` : "."; + reason = "assert_ne"; + errorMessage = `The transaction reverted because of an "assert_ne" statement${sufix}`; + break; +diff --git a/dist/index.mjs b/dist/index.mjs +index 92b01116b2c4aef3d503ab78c7008abd83992f18..edcd8ad72daf27a3b96f8f784c7bbbf9924eccd4 100644 +--- a/dist/index.mjs ++++ b/dist/index.mjs +@@ -1860,17 +1860,17 @@ var assembleRevertError = (receipts, logs, metadata) => { + switch (reasonHex) { + case FAILED_REQUIRE_SIGNAL: { + reason = "require"; +- errorMessage = `The transaction reverted because a "require" statement has thrown ${logs.length ? stringify(logs[0]) : "an error."}.`; ++ errorMessage = `The transaction reverted because a "require" statement has thrown ${logs.length ? stringify(logs[logs.length - 1]) : "an error."}.`; + break; + } + case FAILED_ASSERT_EQ_SIGNAL: { +- const sufix = logs.length >= 2 ? ` comparing ${stringify(logs[1])} and ${stringify(logs[0])}.` : "."; ++ const sufix = logs.length >= 2 ? ` comparing ${stringify(logs[1])} and ${stringify(logs[logs.length - 1])}.` : "."; + reason = "assert_eq"; + errorMessage = `The transaction reverted because of an "assert_eq" statement${sufix}`; + break; + } + case FAILED_ASSERT_NE_SIGNAL: { +- const sufix = logs.length >= 2 ? ` comparing ${stringify(logs[1])} and ${stringify(logs[0])}.` : "."; ++ const sufix = logs.length >= 2 ? ` comparing ${stringify(logs[1])} and ${stringify(logs[logs.length - 1])}.` : "."; + reason = "assert_ne"; + errorMessage = `The transaction reverted because of an "assert_ne" statement${sufix}`; + break; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 758a2240..33769d93 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,11 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +patchedDependencies: + '@fuel-ts/account@0.94.3': + hash: ehqly2kbszritzxealzee2drjm + path: patches/@fuel-ts__account@0.94.3.patch + importers: .: @@ -12793,7 +12798,7 @@ snapshots: - encoding - supports-color - '@fuel-ts/account@0.94.3(encoding@0.1.13)': + '@fuel-ts/account@0.94.3(patch_hash=ehqly2kbszritzxealzee2drjm)(encoding@0.1.13)': dependencies: '@fuel-ts/abi-coder': 0.94.3 '@fuel-ts/address': 0.94.3 @@ -12893,7 +12898,7 @@ snapshots: '@fuel-ts/contract@0.94.3(encoding@0.1.13)': dependencies: '@fuel-ts/abi-coder': 0.94.3 - '@fuel-ts/account': 0.94.3(encoding@0.1.13) + '@fuel-ts/account': 0.94.3(patch_hash=ehqly2kbszritzxealzee2drjm)(encoding@0.1.13) '@fuel-ts/crypto': 0.94.3 '@fuel-ts/errors': 0.94.3 '@fuel-ts/hasher': 0.94.3 @@ -13068,7 +13073,7 @@ snapshots: '@fuel-ts/program@0.94.3(encoding@0.1.13)': dependencies: '@fuel-ts/abi-coder': 0.94.3 - '@fuel-ts/account': 0.94.3(encoding@0.1.13) + '@fuel-ts/account': 0.94.3(patch_hash=ehqly2kbszritzxealzee2drjm)(encoding@0.1.13) '@fuel-ts/address': 0.94.3 '@fuel-ts/errors': 0.94.3 '@fuel-ts/interfaces': 0.94.3 @@ -13114,7 +13119,7 @@ snapshots: '@fuel-ts/script@0.94.3(encoding@0.1.13)': dependencies: '@fuel-ts/abi-coder': 0.94.3 - '@fuel-ts/account': 0.94.3(encoding@0.1.13) + '@fuel-ts/account': 0.94.3(patch_hash=ehqly2kbszritzxealzee2drjm)(encoding@0.1.13) '@fuel-ts/address': 0.94.3 '@fuel-ts/errors': 0.94.3 '@fuel-ts/interfaces': 0.94.3 @@ -19645,7 +19650,7 @@ snapshots: dependencies: '@fuel-ts/abi-coder': 0.94.3 '@fuel-ts/abi-typegen': 0.94.3 - '@fuel-ts/account': 0.94.3(encoding@0.1.13) + '@fuel-ts/account': 0.94.3(patch_hash=ehqly2kbszritzxealzee2drjm)(encoding@0.1.13) '@fuel-ts/address': 0.94.3 '@fuel-ts/contract': 0.94.3(encoding@0.1.13) '@fuel-ts/crypto': 0.94.3