diff --git a/__tests__/components/Modals/vault/VaultBorrowings.test.tsx b/__tests__/components/Modals/vault/VaultBorrowings.test.tsx index 43285e52..5b61807e 100644 --- a/__tests__/components/Modals/vault/VaultBorrowings.test.tsx +++ b/__tests__/components/Modals/vault/VaultBorrowings.test.tsx @@ -7,7 +7,6 @@ import DisplayCurrency from 'components/DisplayCurrency' import VaultBorrowings, { VaultBorrowingsProps } from 'components/Modals/Vault/VaultBorrowings' import { TESTNET_VAULTS_META_DATA } from 'constants/vaults' import { BNCoin } from 'types/classes/BNCoin' -import { hardcodedFee } from 'utils/constants' jest.mock('hooks/usePrices', () => jest.fn(() => ({ @@ -62,7 +61,6 @@ describe('', () => { deposits: [], onChangeBorrowings: jest.fn(), depositActions: [], - depositFee: hardcodedFee, } beforeAll(() => { diff --git a/src/components/Account/AccountCreateFirst.tsx b/src/components/Account/AccountCreateFirst.tsx index aef52760..007a750a 100644 --- a/src/components/Account/AccountCreateFirst.tsx +++ b/src/components/Account/AccountCreateFirst.tsx @@ -6,7 +6,6 @@ import FullOverlayContent from 'components/FullOverlayContent' import WalletSelect from 'components/Wallet/WalletSelect' import useToggle from 'hooks/useToggle' import useStore from 'store' -import { hardcodedFee } from 'utils/constants' import { getPage, getRoute } from 'utils/route' export default function AccountCreateFirst() { @@ -22,7 +21,7 @@ export default function AccountCreateFirst() { const handleClick = useCallback(async () => { setIsCreating(true) - const accountId = await createAccount({ fee: hardcodedFee }) + const accountId = await createAccount() setIsCreating(false) if (accountId) { navigate(getRoute(getPage(pathname), address, accountId)) diff --git a/src/components/Account/AccountFund.tsx b/src/components/Account/AccountFund.tsx index e2ada6cb..59eaf26b 100644 --- a/src/components/Account/AccountFund.tsx +++ b/src/components/Account/AccountFund.tsx @@ -18,7 +18,7 @@ import useStore from 'store' import { BNCoin } from 'types/classes/BNCoin' import { byDenom } from 'utils/array' import { getAssetByDenom, getBaseAsset } from 'utils/assets' -import { hardcodedFee } from 'utils/constants' +import { defaultFee } from 'utils/constants' import { BN } from 'utils/helpers' export default function AccountFund() { @@ -50,7 +50,6 @@ export default function AccountFund() { setIsFunding(true) if (!accountId) return const result = await deposit({ - fee: hardcodedFee, accountId, coins: fundingAssets, }) @@ -95,7 +94,7 @@ export default function AccountFund() { ) useEffect(() => { - if (BN(baseBalance).isLessThan(hardcodedFee.amount[0].amount)) { + if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) { useStore.setState({ focusComponent: { component: } }) } }, [baseBalance]) diff --git a/src/components/Account/AccountMenuContent.tsx b/src/components/Account/AccountMenuContent.tsx index 3fcda45d..9a42633b 100644 --- a/src/components/Account/AccountMenuContent.tsx +++ b/src/components/Account/AccountMenuContent.tsx @@ -14,7 +14,7 @@ import WalletBridges from 'components/Wallet/WalletBridges' import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance' import useToggle from 'hooks/useToggle' import useStore from 'store' -import { hardcodedFee } from 'utils/constants' +import { defaultFee } from 'utils/constants' import { BN } from 'utils/helpers' import { isNumber } from 'utils/parsers' import { getPage, getRoute } from 'utils/route' @@ -45,14 +45,14 @@ export default function AccountMenuContent(props: Props) { const checkHasFunds = useCallback(() => { return ( transactionFeeCoinBalance && - BN(transactionFeeCoinBalance.amount).isGreaterThan(hardcodedFee.amount[0].amount) + BN(transactionFeeCoinBalance.amount).isGreaterThan(defaultFee.amount[0].amount) ) }, [transactionFeeCoinBalance]) const performCreateAccount = useCallback(async () => { setShowMenu(true) setIsCreating(true) - const accountId = await createAccount({ fee: hardcodedFee }) + const accountId = await createAccount() setIsCreating(false) if (accountId) { diff --git a/src/components/Earn/Farm/VaultExpanded.tsx b/src/components/Earn/Farm/VaultExpanded.tsx index a0e88715..670f4624 100644 --- a/src/components/Earn/Farm/VaultExpanded.tsx +++ b/src/components/Earn/Farm/VaultExpanded.tsx @@ -8,7 +8,6 @@ import { AccountArrowDown, LockLocked, LockUnlocked, Plus } from 'components/Ico import { Tooltip } from 'components/Tooltip' import useStore from 'store' import { VaultStatus } from 'types/enums/vault' -import { hardcodedFee } from 'utils/constants' interface Props { row: Row @@ -40,7 +39,6 @@ export default function VaultExpanded(props: Props) { const vaults = [props.row.original as DepositedVault] setIsConfirming(true) await withdrawFromVaults({ - fee: hardcodedFee, accountId: accountId, vaults, }) diff --git a/src/components/Earn/Farm/VaultUnlockBanner.tsx b/src/components/Earn/Farm/VaultUnlockBanner.tsx index 037863ea..85af3f3c 100644 --- a/src/components/Earn/Farm/VaultUnlockBanner.tsx +++ b/src/components/Earn/Farm/VaultUnlockBanner.tsx @@ -5,7 +5,6 @@ import Button from 'components/Button' import { ChevronRight } from 'components/Icons' import NotificationBanner from 'components/NotificationBanner' import useStore from 'store' -import { hardcodedFee } from 'utils/constants' interface Props { vaults: DepositedVault[] @@ -25,7 +24,6 @@ export default function VaultUnlockBanner(props: Props) { } else { setIsConfirming(true) await withdrawFromVaults({ - fee: hardcodedFee, accountId: accountId, vaults: props.vaults, }) diff --git a/src/components/Modals/Account/AccountDeleteModal.tsx b/src/components/Modals/Account/AccountDeleteModal.tsx index 105fb129..51930b87 100644 --- a/src/components/Modals/Account/AccountDeleteModal.tsx +++ b/src/components/Modals/Account/AccountDeleteModal.tsx @@ -10,7 +10,6 @@ import Text from 'components/Text' import useStore from 'store' import { BNCoin } from 'types/classes/BNCoin' import { getAssetByDenom } from 'utils/assets' -import { hardcodedFee } from 'utils/constants' import { combineBNCoins } from 'utils/parsers' import { getPage, getRoute } from 'utils/route' @@ -41,7 +40,7 @@ function AccountDeleteModal(props: Props) { const deleteAccountHandler = useCallback(async () => { setIsConfirming(true) - const options = { fee: hardcodedFee, accountId: modal.id, lends: modal.lends } + const options = { accountId: modal.id, lends: modal.lends } const isSuccess = await deleteAccount(options) setIsConfirming(false) if (isSuccess) { diff --git a/src/components/Modals/BorrowModal.tsx b/src/components/Modals/BorrowModal.tsx index 31f91bbb..c28deed3 100644 --- a/src/components/Modals/BorrowModal.tsx +++ b/src/components/Modals/BorrowModal.tsx @@ -19,7 +19,6 @@ import useHealthComputer from 'hooks/useHealthComputer' import useToggle from 'hooks/useToggle' import useStore from 'store' import { BNCoin } from 'types/classes/BNCoin' -import { hardcodedFee } from 'utils/constants' import { formatPercent, formatValue } from 'utils/formatters' import { BN } from 'utils/helpers' @@ -70,14 +69,12 @@ function BorrowModal(props: Props) { let result if (isRepay) { result = await repay({ - fee: hardcodedFee, accountId: props.account.id, coin: BNCoin.fromDenomAndBigNumber(modal.asset.denom, amount), accountBalance: percentage === 100, }) } else { result = await borrow({ - fee: hardcodedFee, accountId: props.account.id, coin: { denom: modal.asset.denom, amount: amount.toString() }, borrowToWallet, diff --git a/src/components/Modals/FundWithdraw/FundAccount.tsx b/src/components/Modals/FundWithdraw/FundAccount.tsx index e2bfcfdf..360e78e6 100644 --- a/src/components/Modals/FundWithdraw/FundAccount.tsx +++ b/src/components/Modals/FundWithdraw/FundAccount.tsx @@ -13,8 +13,8 @@ import useStore from 'store' import { BNCoin } from 'types/classes/BNCoin' import { byDenom } from 'utils/array' import { getAssetByDenom, getBaseAsset } from 'utils/assets' -import { hardcodedFee } from 'utils/constants' import { BN } from 'utils/helpers' +import { defaultFee } from 'utils/constants' interface Props { account: Account @@ -48,7 +48,6 @@ export default function FundAccount(props: Props) { setIsFunding(true) if (!accountId) return const result = await deposit({ - fee: hardcodedFee, accountId, coins: fundingAssets, }) @@ -94,7 +93,7 @@ export default function FundAccount(props: Props) { ) useEffect(() => { - if (BN(baseBalance).isLessThan(hardcodedFee.amount[0].amount)) { + if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) { useStore.setState({ focusComponent: { component: } }) } }, [baseBalance]) diff --git a/src/components/Modals/FundWithdraw/WithdrawFromAccount.tsx b/src/components/Modals/FundWithdraw/WithdrawFromAccount.tsx index 42eaa920..fa56cac7 100644 --- a/src/components/Modals/FundWithdraw/WithdrawFromAccount.tsx +++ b/src/components/Modals/FundWithdraw/WithdrawFromAccount.tsx @@ -15,7 +15,6 @@ import { useUpdatedAccount } from 'hooks/useUpdatedAccount' import useStore from 'store' import { BNCoin } from 'types/classes/BNCoin' import { byDenom } from 'utils/array' -import { hardcodedFee } from 'utils/constants' interface Props { account: Account @@ -64,7 +63,6 @@ export default function WithdrawFromAccount(props: Props) { async function onConfirm() { setIsConfirming(true) const result = await withdraw({ - fee: hardcodedFee, accountId: account.id, coins: [BNCoin.fromDenomAndBigNumber(currentAsset.denom, amount)], borrow: debtAmount.isZero() diff --git a/src/components/Modals/LendAndReclaim/index.tsx b/src/components/Modals/LendAndReclaim/index.tsx index cdbabff9..52b2310b 100644 --- a/src/components/Modals/LendAndReclaim/index.tsx +++ b/src/components/Modals/LendAndReclaim/index.tsx @@ -2,7 +2,6 @@ import { useCallback, useState } from 'react' import useStore from 'store' import useToggle from 'hooks/useToggle' -import { hardcodedFee } from 'utils/constants' import useCurrentAccount from 'hooks/useCurrentAccount' import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal' import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader' @@ -50,7 +49,6 @@ function LendAndReclaimModal({ currentAccount, config }: Props) { const coin = BNCoin.fromDenomAndBigNumber(asset.denom, value) const options = { - fee: hardcodedFee, accountId: currentAccount.id, coin, isMax, diff --git a/src/components/Modals/Unlock/UnlockModalContent.tsx b/src/components/Modals/Unlock/UnlockModalContent.tsx index 9bbf4bb2..9495f2ab 100644 --- a/src/components/Modals/Unlock/UnlockModalContent.tsx +++ b/src/components/Modals/Unlock/UnlockModalContent.tsx @@ -5,7 +5,6 @@ import Button from 'components/Button' import { NoIcon, YesIcon } from 'components/Modals/AlertDialog/ButtonIcons' import Text from 'components/Text' import useStore from 'store' -import { hardcodedFee } from 'utils/constants' interface Props { depositedVault: DepositedVault @@ -21,7 +20,6 @@ export default function UnlockModalContent(props: Props) { if (!accountId) return setIsConfirming(true) await unlock({ - fee: hardcodedFee, accountId: accountId, vault: props.depositedVault, amount: props.depositedVault.amounts.locked.toString(), diff --git a/src/components/Modals/Vault/VaultBorrowings.tsx b/src/components/Modals/Vault/VaultBorrowings.tsx index dde4465e..55fd0dcf 100644 --- a/src/components/Modals/Vault/VaultBorrowings.tsx +++ b/src/components/Modals/Vault/VaultBorrowings.tsx @@ -27,7 +27,6 @@ export interface VaultBorrowingsProps { secondaryAsset: Asset vault: Vault depositActions: Action[] - depositFee: StdFee onChangeBorrowings: (borrowings: BNCoin[]) => void } @@ -144,7 +143,6 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) { async function onConfirm() { setIsConfirming(true) const isSuccess = await depositIntoVault({ - fee: props.depositFee, accountId: props.updatedAccount.id, actions: props.depositActions, }) diff --git a/src/components/Modals/Vault/VaultModalContent.tsx b/src/components/Modals/Vault/VaultModalContent.tsx index a08e6881..4e7ba6b1 100644 --- a/src/components/Modals/Vault/VaultModalContent.tsx +++ b/src/components/Modals/Vault/VaultModalContent.tsx @@ -26,11 +26,7 @@ export default function VaultModalContent(props: Props) { const [isOpen, toggleOpen] = useIsOpenArray(2, false) const [isCustomRatio, setIsCustomRatio] = useState(false) - const { - actions: depositActions, - fee: depositFee, - totalValue, - } = useDepositVault({ + const { actions: depositActions, totalValue } = useDepositVault({ vault: props.vault, deposits: removedDeposits, borrowings: addedDebt, @@ -114,7 +110,6 @@ export default function VaultModalContent(props: Props) { onChangeBorrowings={addDebt} vault={props.vault} depositActions={depositActions} - depositFee={depositFee} /> ), title: 'Borrow', diff --git a/src/components/Modals/WithdrawFromVaultsModal.tsx b/src/components/Modals/WithdrawFromVaultsModal.tsx index fff0c598..4ada4cae 100644 --- a/src/components/Modals/WithdrawFromVaultsModal.tsx +++ b/src/components/Modals/WithdrawFromVaultsModal.tsx @@ -11,7 +11,6 @@ import Text from 'components/Text' import useStore from 'store' import { BNCoin } from 'types/classes/BNCoin' import { getAssetByDenom } from 'utils/assets' -import { hardcodedFee } from 'utils/constants' import { demagnify } from 'utils/formatters' export default function WithdrawFromVaultsModal() { @@ -29,7 +28,6 @@ export default function WithdrawFromVaultsModal() { if (!accountId || !modal) return setIsConfirming(true) await withdrawFromVaults({ - fee: hardcodedFee, accountId: accountId, vaults: modal, }) diff --git a/src/components/Trade/TradeModule/SwapForm/TradeSummary.tsx b/src/components/Trade/TradeModule/SwapForm/TradeSummary.tsx index 1431580e..bbc0f45e 100644 --- a/src/components/Trade/TradeModule/SwapForm/TradeSummary.tsx +++ b/src/components/Trade/TradeModule/SwapForm/TradeSummary.tsx @@ -4,7 +4,6 @@ import { useMemo } from 'react' import ActionButton from 'components/Button/ActionButton' import useSwapRoute from 'hooks/useSwapRoute' import { getAssetByDenom } from 'utils/assets' -import { hardcodedFee } from 'utils/constants' import { formatAmountWithSymbol, formatPercent } from 'utils/formatters' interface Props { @@ -16,6 +15,7 @@ interface Props { showProgressIndicator: boolean isMargin?: boolean borrowAmount: BigNumber + estimatedFee: StdFee buyAction: () => void } @@ -29,6 +29,7 @@ export default function TradeSummary(props: Props) { containerClassName, isMargin, borrowAmount, + estimatedFee, showProgressIndicator, } = props const { data: routes, isLoading: isRouteLoading } = useSwapRoute(sellAsset.denom, buyAsset.denom) @@ -53,7 +54,7 @@ export default function TradeSummary(props: Props) { Summary
Fees - {formatAmountWithSymbol(hardcodedFee.amount[0])} + {formatAmountWithSymbol(estimatedFee.amount[0])}
{isMargin && ( <> diff --git a/src/components/Trade/TradeModule/SwapForm/index.tsx b/src/components/Trade/TradeModule/SwapForm/index.tsx index 6caa40ea..b366649c 100644 --- a/src/components/Trade/TradeModule/SwapForm/index.tsx +++ b/src/components/Trade/TradeModule/SwapForm/index.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' import Divider from 'components/Divider' import { DEFAULT_SETTINGS } from 'constants/defaultSettings' @@ -8,8 +8,8 @@ import useCurrentAccount from 'hooks/useCurrentAccount' import useLocalStorage from 'hooks/useLocalStorage' import usePrices from 'hooks/usePrices' import useStore from 'store' -import { byDenom, byTokenDenom } from 'utils/array' -import { hardcodedFee } from 'utils/constants' +import { byDenom } from 'utils/array' +import { defaultFee } from 'utils/constants' import RangeInput from 'components/RangeInput' import { asyncThrottle, BN } from 'utils/helpers' import AssetAmountInput from 'components/Trade/TradeModule/SwapForm/AssetAmountInput' @@ -42,6 +42,7 @@ export default function SwapForm(props: Props) { const [maxBuyableAmountEstimation, setMaxBuyableAmountEstimation] = useState(BN_ZERO) const [selectedOrderType, setSelectedOrderType] = useState('Market') const [isConfirming, setIsConfirming] = useState(false) + const [estimatedFee, setEstimatedFee] = useState(defaultFee) const throttledEstimateExactIn = useMemo(() => asyncThrottle(estimateExactIn, 250), []) @@ -124,41 +125,50 @@ export default function SwapForm(props: Props) { sellAssetAmount, ]) + const swapTx = useMemo(() => { + const borrowCoin = sellAssetAmount.isGreaterThan(marginThreshold) + ? BNCoin.fromDenomAndBigNumber(sellAsset.denom, sellAssetAmount.minus(marginThreshold)) + : undefined + + return swap({ + accountId: account?.id || '', + coinIn: BNCoin.fromDenomAndBigNumber(sellAsset.denom, sellAssetAmount.integerValue()), + borrow: borrowCoin, + denomOut: buyAsset.denom, + slippage, + }) + }, [ + account?.id, + buyAsset.denom, + marginThreshold, + sellAsset.denom, + sellAssetAmount, + slippage, + swap, + ]) + useEffect(() => { setBuyAssetAmount(BN_ZERO) setSellAssetAmount(BN_ZERO) }, [buyAsset.denom, sellAsset.denom]) + useEffect(() => { + swapTx.estimateFee().then(setEstimatedFee) + }, [swapTx]) + const handleBuyClick = useCallback(async () => { if (account?.id) { setIsConfirming(true) - const borrowCoin = sellAssetAmount.isGreaterThan(marginThreshold) - ? BNCoin.fromDenomAndBigNumber(sellAsset.denom, sellAssetAmount.minus(marginThreshold)) - : undefined - const isSucceeded = await swap({ - fee: hardcodedFee, - accountId: account.id, - coinIn: BNCoin.fromDenomAndBigNumber(sellAsset.denom, sellAssetAmount.integerValue()), - borrow: borrowCoin, - denomOut: buyAsset.denom, - slippage, - }) + const isSucceeded = await swapTx.execute() + if (isSucceeded) { setSellAssetAmount(BN_ZERO) setBuyAssetAmount(BN_ZERO) } setIsConfirming(false) } - }, [ - account?.id, - buyAsset.denom, - sellAsset.denom, - sellAssetAmount, - slippage, - swap, - marginThreshold, - ]) + }, [account?.id, swapTx]) return ( <> @@ -220,6 +230,7 @@ export default function SwapForm(props: Props) { ? sellAssetAmount.minus(marginThreshold) : BN_ZERO } + estimatedFee={estimatedFee} /> ) diff --git a/src/components/Wallet/WalletBridges.tsx b/src/components/Wallet/WalletBridges.tsx index 6308bf5b..f4a406bd 100644 --- a/src/components/Wallet/WalletBridges.tsx +++ b/src/components/Wallet/WalletBridges.tsx @@ -17,7 +17,7 @@ import useWalletBalances from 'hooks/useWalletBalances' import useStore from 'store' import { byDenom } from 'utils/array' import { getBaseAsset } from 'utils/assets' -import { hardcodedFee } from 'utils/constants' +import { defaultFee } from 'utils/constants' import { BN } from 'utils/helpers' const currentChainId = ENV.CHAIN_ID @@ -64,7 +64,7 @@ export default function WalletBridges() { return } - if (BN(baseBalance).isGreaterThanOrEqualTo(hardcodedFee.amount[0].amount) && !isLoading) + if (BN(baseBalance).isGreaterThanOrEqualTo(defaultFee.amount[0].amount) && !isLoading) setHasFunds(true) }, [baseBalance, isLoading, hasFunds, setHasFunds]) diff --git a/src/components/Wallet/WalletFetchBalancesAndAccounts.tsx b/src/components/Wallet/WalletFetchBalancesAndAccounts.tsx index 51dfbeb3..1d66dc97 100644 --- a/src/components/Wallet/WalletFetchBalancesAndAccounts.tsx +++ b/src/components/Wallet/WalletFetchBalancesAndAccounts.tsx @@ -10,7 +10,7 @@ import useWalletBalances from 'hooks/useWalletBalances' import useStore from 'store' import { byDenom } from 'utils/array' import { getBaseAsset } from 'utils/assets' -import { hardcodedFee } from 'utils/constants' +import { defaultFee } from 'utils/constants' import { BN } from 'utils/helpers' import { getPage, getRoute } from 'utils/route' @@ -41,7 +41,7 @@ function Content() { useEffect(() => { if ( accounts.length !== 0 && - BN(baseBalance).isGreaterThanOrEqualTo(hardcodedFee.amount[0].amount) + BN(baseBalance).isGreaterThanOrEqualTo(defaultFee.amount[0].amount) ) { navigate(getRoute(getPage(pathname), address, accounts[0].id)) useStore.setState({ accounts: accounts, balances: walletBalances, focusComponent: null }) @@ -49,7 +49,7 @@ function Content() { }, [accounts, baseBalance, navigate, pathname, address, walletBalances]) if (isLoading) return - if (BN(baseBalance).isLessThan(hardcodedFee.amount[0].amount)) return + if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) return if (accounts.length === 0) return return null } diff --git a/src/hooks/broadcast/useDepositVault.ts b/src/hooks/broadcast/useDepositVault.ts index a59a2a71..c3e02009 100644 --- a/src/hooks/broadcast/useDepositVault.ts +++ b/src/hooks/broadcast/useDepositVault.ts @@ -8,7 +8,6 @@ import useLocalStorage from 'hooks/useLocalStorage' import usePrices from 'hooks/usePrices' import { BNCoin } from 'types/classes/BNCoin' import { Action } from 'types/generated/mars-credit-manager/MarsCreditManager.types' -import { hardcodedFee } from 'utils/constants' import { getEnterVaultActions, getVaultDepositCoinsAndValue, @@ -23,7 +22,6 @@ interface Props { } export default function useDepositVault(props: Props): { actions: Action[] - fee: StdFee minLpToReceive: string totalValue: BigNumber } { @@ -92,7 +90,6 @@ export default function useDepositVault(props: Props): { return { actions, - fee: hardcodedFee, minLpToReceive: minLpToReceive.toString(), totalValue, } diff --git a/src/store/slices/broadcast.ts b/src/store/slices/broadcast.ts index 4938d919..00539b1d 100644 --- a/src/store/slices/broadcast.ts +++ b/src/store/slices/broadcast.ts @@ -14,15 +14,15 @@ import { import { getSingleValueFromBroadcastResult } from 'utils/broadcast' import { formatAmountWithSymbol } from 'utils/formatters' import getTokenOutFromSwapResponse from 'utils/getTokenOutFromSwapResponse' +import { BN } from 'utils/helpers' +import { defaultFee } from 'utils/constants' function generateExecutionMessage( - sender: string | undefined, + sender: string | undefined = '', contract: string, msg: CreditManagerExecuteMsg | AccountNftExecuteMsg, funds: Coin[], ) { - if (!sender) return - return new MsgExecuteContract({ sender, contract, @@ -57,14 +57,34 @@ export default function createBroadcastSlice( } } + const getEstimatedFee = async (messages: MsgExecuteContract[]) => { + try { + const simulateResult = await get().client?.simulate({ + messages, + wallet: get().client?.connectedWallet, + }) + + if (simulateResult) { + const { success, fee } = simulateResult + + if (success) { + return { + amount: fee ? fee.amount : [], + gas: BN(fee ? fee.gas : 0).toFixed(0), + } + } + } + + throw 'Simulation failed' + } catch (ex) { + console.error('Can not estimate the fee:', ex) + return defaultFee + } + } + return { toast: null, - borrow: async (options: { - fee: StdFee - accountId: string - coin: Coin - borrowToWallet: boolean - }) => { + borrow: async (options: { accountId: string; coin: Coin; borrowToWallet: boolean }) => { const borrowAction: Action = { borrow: options.coin } const withdrawAction: Action = { withdraw: options.coin } const actions = options.borrowToWallet ? [borrowAction, withdrawAction] : [borrowAction] @@ -78,7 +98,6 @@ export default function createBroadcastSlice( const response = await get().executeMsg({ messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], - fee: options.fee, }) handleResponseMessages( @@ -89,14 +108,13 @@ export default function createBroadcastSlice( ) return !!response.result }, - createAccount: async (options: { fee: StdFee }) => { + createAccount: async () => { const msg: CreditManagerExecuteMsg = { create_credit_account: 'default', } const response = await get().executeMsg({ messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], - fee: options.fee, }) if (response.result) { @@ -115,7 +133,7 @@ export default function createBroadcastSlice( return null } }, - deleteAccount: async (options: { fee: StdFee; accountId: string; lends: BNCoin[] }) => { + deleteAccount: async (options: { accountId: string; lends: BNCoin[] }) => { const reclaimMsg = options.lends.map((coin) => { return { reclaim: coin.toActionCoin(true), @@ -140,14 +158,13 @@ export default function createBroadcastSlice( generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, refundMessage, []), generateExecutionMessage(get().address, ENV.ADDRESS_ACCOUNT_NFT, burnMessage, []), ], - fee: options.fee, }) handleResponseMessages(response, `Account ${options.accountId} deleted`) return !!response.result }, - deposit: async (options: { fee: StdFee; accountId: string; coins: BNCoin[] }) => { + deposit: async (options: { accountId: string; coins: BNCoin[] }) => { const msg: CreditManagerExecuteMsg = { update_credit_account: { account_id: options.accountId, @@ -161,7 +178,6 @@ export default function createBroadcastSlice( const response = await get().executeMsg({ messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, funds)], - fee: options.fee, }) const depositString = options.coins @@ -170,12 +186,7 @@ export default function createBroadcastSlice( handleResponseMessages(response, `Deposited ${depositString} to Account ${options.accountId}`) return !!response.result }, - unlock: async (options: { - fee: StdFee - accountId: string - vault: DepositedVault - amount: string - }) => { + unlock: async (options: { accountId: string; vault: DepositedVault; amount: string }) => { const msg: CreditManagerExecuteMsg = { update_credit_account: { account_id: options.accountId, @@ -192,18 +203,13 @@ export default function createBroadcastSlice( const response = await get().executeMsg({ messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], - fee: options.fee, }) handleResponseMessages(response, `Requested unlock for ${options.vault.name}`) return !!response.result }, - withdrawFromVaults: async (options: { - fee: StdFee - accountId: string - vaults: DepositedVault[] - }) => { + withdrawFromVaults: async (options: { accountId: string; vaults: DepositedVault[] }) => { const actions: CreditManagerAction[] = [] options.vaults.forEach((vault) => { if (vault.unlockId) @@ -223,7 +229,6 @@ export default function createBroadcastSlice( const response = await get().executeMsg({ messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], - fee: options.fee, }) const vaultsString = options.vaults.length === 1 ? 'vault' : 'vaults' @@ -233,7 +238,7 @@ export default function createBroadcastSlice( ) return !!response.result }, - depositIntoVault: async (options: { fee: StdFee; accountId: string; actions: Action[] }) => { + depositIntoVault: async (options: { accountId: string; actions: Action[] }) => { const msg: CreditManagerExecuteMsg = { update_credit_account: { account_id: options.accountId, @@ -243,18 +248,12 @@ export default function createBroadcastSlice( const response = await get().executeMsg({ messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], - fee: options.fee, }) handleResponseMessages(response, `Deposited into vault`) return !!response.result }, - withdraw: async (options: { - fee: StdFee - accountId: string - coins: BNCoin[] - borrow: BNCoin[] - }) => { + withdraw: async (options: { accountId: string; coins: BNCoin[]; borrow: BNCoin[] }) => { const withdrawActions = options.coins.map((coin) => ({ withdraw: coin.toCoin(), })) @@ -271,7 +270,6 @@ export default function createBroadcastSlice( const response = await get().executeMsg({ messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], - fee: options.fee, }) const withdrawString = options.coins @@ -283,12 +281,7 @@ export default function createBroadcastSlice( ) return !!response.result }, - repay: async (options: { - fee: StdFee - accountId: string - coin: BNCoin - accountBalance?: boolean - }) => { + repay: async (options: { accountId: string; coin: BNCoin; accountBalance?: boolean }) => { const msg: CreditManagerExecuteMsg = { update_credit_account: { account_id: options.accountId, @@ -304,7 +297,6 @@ export default function createBroadcastSlice( const response = await get().executeMsg({ messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], - fee: options.fee, }) handleResponseMessages( @@ -313,7 +305,7 @@ export default function createBroadcastSlice( ) return !!response.result }, - lend: async (options: { fee: StdFee; accountId: string; coin: BNCoin; isMax?: boolean }) => { + lend: async (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => { const msg: CreditManagerExecuteMsg = { update_credit_account: { account_id: options.accountId, @@ -327,7 +319,6 @@ export default function createBroadcastSlice( const response = await get().executeMsg({ messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], - fee: options.fee, }) handleResponseMessages( @@ -336,7 +327,7 @@ export default function createBroadcastSlice( ) return !!response.result }, - reclaim: async (options: { fee: StdFee; accountId: string; coin: BNCoin; isMax?: boolean }) => { + reclaim: async (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => { const msg: CreditManagerExecuteMsg = { update_credit_account: { account_id: options.accountId, @@ -350,7 +341,6 @@ export default function createBroadcastSlice( const response = await get().executeMsg({ messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], - fee: options.fee, }) handleResponseMessages( @@ -359,8 +349,7 @@ export default function createBroadcastSlice( ) return !!response.result }, - swap: async (options: { - fee: StdFee + swap: (options: { accountId: string coinIn: BNCoin borrow?: BNCoin @@ -383,31 +372,38 @@ export default function createBroadcastSlice( }, } - const response = await get().executeMsg({ - messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], - fee: options.fee, - }) + const messages = [ + generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, []), + ] - const coinOut = getTokenOutFromSwapResponse(response, options.denomOut) - const successMessage = `Swapped ${formatAmountWithSymbol( - options.coinIn.toCoin(), - )} for ${formatAmountWithSymbol(coinOut)}` + const estimateFee = () => getEstimatedFee(messages) - handleResponseMessages(response, successMessage) - return !!response.result + const execute = async () => { + const response = await get().executeMsg({ + messages, + }) + + const coinOut = getTokenOutFromSwapResponse(response, options.denomOut) + const successMessage = `Swapped ${formatAmountWithSymbol( + options.coinIn.toCoin(), + )} for ${formatAmountWithSymbol(coinOut)}` + + handleResponseMessages(response, successMessage) + return !!response.result + } + + return { estimateFee, execute } }, - executeMsg: async (options: { - messages: MsgExecuteContract[] - fee: StdFee - }): Promise => { + executeMsg: async (options: { messages: MsgExecuteContract[] }): Promise => { try { const client = get().client if (!client) return { error: 'no client detected' } + const fee = await getEstimatedFee(options.messages) const broadcastOptions = { messages: options.messages, - feeAmount: options.fee.amount[0].amount, - gasLimit: options.fee.gas, + feeAmount: fee.amount[0].amount, + gasLimit: fee.gas, memo: undefined, wallet: client.connectedWallet, mobile: isMobile, diff --git a/src/types/interfaces/store/broadcast.d.ts b/src/types/interfaces/store/broadcast.d.ts index a0aa113e..549d8b74 100644 --- a/src/types/interfaces/store/broadcast.d.ts +++ b/src/types/interfaces/store/broadcast.d.ts @@ -5,64 +5,38 @@ interface BroadcastResult { error?: string } +interface ExecutableTx { + execute: () => Promise + estimateFee: () => Promise +} + interface BroadcastSlice { toast: { message: string; isError?: boolean; title?: string } | null - executeMsg: (options: { messages: MsgExecuteContract[]; fee: StdFee }) => Promise - borrow: (options: { - fee: StdFee - accountId: string - coin: Coin - borrowToWallet: boolean - }) => Promise - createAccount: (options: { fee: StdFee }) => Promise - deleteAccount: (options: { fee: StdFee; accountId: string; lends: BNCoin[] }) => Promise - deposit: (options: { fee: StdFee; accountId: string; coins: BNCoin[] }) => Promise + executeMsg: (options: { messages: MsgExecuteContract[] }) => Promise + borrow: (options: { accountId: string; coin: Coin; borrowToWallet: boolean }) => Promise + createAccount: () => Promise + deleteAccount: (options: { accountId: string; lends: BNCoin[] }) => Promise + deposit: (options: { accountId: string; coins: BNCoin[] }) => Promise unlock: (options: { - fee: StdFee accountId: string vault: DepositedVault amount: string }) => Promise - withdrawFromVaults: (options: { - fee: StdFee - accountId: string - vaults: DepositedVault[] - }) => Promise - depositIntoVault: (options: { - fee: StdFee - accountId: string - actions: Action[] - }) => Promise - withdraw: (options: { - fee: StdFee - accountId: string - coins: BNCoin[] - borrow: BNCoin[] - }) => Promise - lend: (options: { - fee: StdFee - accountId: string - coin: BNCoin - isMax?: boolean - }) => Promise - reclaim: (options: { - fee: StdFee - accountId: string - coin: BNCoin - isMax?: boolean - }) => Promise + withdrawFromVaults: (options: { accountId: string; vaults: DepositedVault[] }) => Promise + depositIntoVault: (options: { accountId: string; actions: Action[] }) => Promise + withdraw: (options: { accountId: string; coins: BNCoin[]; borrow: BNCoin[] }) => Promise + lend: (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => Promise + reclaim: (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => Promise repay: (options: { - fee: StdFee accountId: string coin: BNCoin accountBalance?: boolean }) => Promise swap: (options: { - fee: StdFee accountId: string coinIn: BNCoin borrow: BNCoin denomOut: string slippage: number - }) => Promise + }) => ExecutableTx } diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 3819e4cb..fb59eac3 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -1,6 +1,4 @@ -// StdFee -// TODO: decide some strategy to handle fees -export const hardcodedFee = { +export const defaultFee: StdFee = { amount: [ { denom: 'uosmo',