feat(transaction broadcasting layer): added on the fly fee estimation functionality to all of the transactions (#352)

This commit is contained in:
Yusuf Seyrek 2023-08-09 11:09:42 +03:00 committed by GitHub
parent d494bce26a
commit 9d31122636
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 132 additions and 183 deletions

View File

@ -7,7 +7,6 @@ import DisplayCurrency from 'components/DisplayCurrency'
import VaultBorrowings, { VaultBorrowingsProps } from 'components/Modals/Vault/VaultBorrowings' import VaultBorrowings, { VaultBorrowingsProps } from 'components/Modals/Vault/VaultBorrowings'
import { TESTNET_VAULTS_META_DATA } from 'constants/vaults' import { TESTNET_VAULTS_META_DATA } from 'constants/vaults'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { hardcodedFee } from 'utils/constants'
jest.mock('hooks/usePrices', () => jest.mock('hooks/usePrices', () =>
jest.fn(() => ({ jest.fn(() => ({
@ -62,7 +61,6 @@ describe('<VaultBorrowings />', () => {
deposits: [], deposits: [],
onChangeBorrowings: jest.fn(), onChangeBorrowings: jest.fn(),
depositActions: [], depositActions: [],
depositFee: hardcodedFee,
} }
beforeAll(() => { beforeAll(() => {

View File

@ -6,7 +6,6 @@ import FullOverlayContent from 'components/FullOverlayContent'
import WalletSelect from 'components/Wallet/WalletSelect' import WalletSelect from 'components/Wallet/WalletSelect'
import useToggle from 'hooks/useToggle' import useToggle from 'hooks/useToggle'
import useStore from 'store' import useStore from 'store'
import { hardcodedFee } from 'utils/constants'
import { getPage, getRoute } from 'utils/route' import { getPage, getRoute } from 'utils/route'
export default function AccountCreateFirst() { export default function AccountCreateFirst() {
@ -22,7 +21,7 @@ export default function AccountCreateFirst() {
const handleClick = useCallback(async () => { const handleClick = useCallback(async () => {
setIsCreating(true) setIsCreating(true)
const accountId = await createAccount({ fee: hardcodedFee }) const accountId = await createAccount()
setIsCreating(false) setIsCreating(false)
if (accountId) { if (accountId) {
navigate(getRoute(getPage(pathname), address, accountId)) navigate(getRoute(getPage(pathname), address, accountId))

View File

@ -18,7 +18,7 @@ import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { byDenom } from 'utils/array' import { byDenom } from 'utils/array'
import { getAssetByDenom, getBaseAsset } from 'utils/assets' import { getAssetByDenom, getBaseAsset } from 'utils/assets'
import { hardcodedFee } from 'utils/constants' import { defaultFee } from 'utils/constants'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
export default function AccountFund() { export default function AccountFund() {
@ -50,7 +50,6 @@ export default function AccountFund() {
setIsFunding(true) setIsFunding(true)
if (!accountId) return if (!accountId) return
const result = await deposit({ const result = await deposit({
fee: hardcodedFee,
accountId, accountId,
coins: fundingAssets, coins: fundingAssets,
}) })
@ -95,7 +94,7 @@ export default function AccountFund() {
) )
useEffect(() => { useEffect(() => {
if (BN(baseBalance).isLessThan(hardcodedFee.amount[0].amount)) { if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) {
useStore.setState({ focusComponent: { component: <WalletBridges /> } }) useStore.setState({ focusComponent: { component: <WalletBridges /> } })
} }
}, [baseBalance]) }, [baseBalance])

View File

@ -14,7 +14,7 @@ import WalletBridges from 'components/Wallet/WalletBridges'
import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance' import useCurrentWalletBalance from 'hooks/useCurrentWalletBalance'
import useToggle from 'hooks/useToggle' import useToggle from 'hooks/useToggle'
import useStore from 'store' import useStore from 'store'
import { hardcodedFee } from 'utils/constants' import { defaultFee } from 'utils/constants'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
import { isNumber } from 'utils/parsers' import { isNumber } from 'utils/parsers'
import { getPage, getRoute } from 'utils/route' import { getPage, getRoute } from 'utils/route'
@ -45,14 +45,14 @@ export default function AccountMenuContent(props: Props) {
const checkHasFunds = useCallback(() => { const checkHasFunds = useCallback(() => {
return ( return (
transactionFeeCoinBalance && transactionFeeCoinBalance &&
BN(transactionFeeCoinBalance.amount).isGreaterThan(hardcodedFee.amount[0].amount) BN(transactionFeeCoinBalance.amount).isGreaterThan(defaultFee.amount[0].amount)
) )
}, [transactionFeeCoinBalance]) }, [transactionFeeCoinBalance])
const performCreateAccount = useCallback(async () => { const performCreateAccount = useCallback(async () => {
setShowMenu(true) setShowMenu(true)
setIsCreating(true) setIsCreating(true)
const accountId = await createAccount({ fee: hardcodedFee }) const accountId = await createAccount()
setIsCreating(false) setIsCreating(false)
if (accountId) { if (accountId) {

View File

@ -8,7 +8,6 @@ import { AccountArrowDown, LockLocked, LockUnlocked, Plus } from 'components/Ico
import { Tooltip } from 'components/Tooltip' import { Tooltip } from 'components/Tooltip'
import useStore from 'store' import useStore from 'store'
import { VaultStatus } from 'types/enums/vault' import { VaultStatus } from 'types/enums/vault'
import { hardcodedFee } from 'utils/constants'
interface Props { interface Props {
row: Row<Vault | DepositedVault> row: Row<Vault | DepositedVault>
@ -40,7 +39,6 @@ export default function VaultExpanded(props: Props) {
const vaults = [props.row.original as DepositedVault] const vaults = [props.row.original as DepositedVault]
setIsConfirming(true) setIsConfirming(true)
await withdrawFromVaults({ await withdrawFromVaults({
fee: hardcodedFee,
accountId: accountId, accountId: accountId,
vaults, vaults,
}) })

View File

@ -5,7 +5,6 @@ import Button from 'components/Button'
import { ChevronRight } from 'components/Icons' import { ChevronRight } from 'components/Icons'
import NotificationBanner from 'components/NotificationBanner' import NotificationBanner from 'components/NotificationBanner'
import useStore from 'store' import useStore from 'store'
import { hardcodedFee } from 'utils/constants'
interface Props { interface Props {
vaults: DepositedVault[] vaults: DepositedVault[]
@ -25,7 +24,6 @@ export default function VaultUnlockBanner(props: Props) {
} else { } else {
setIsConfirming(true) setIsConfirming(true)
await withdrawFromVaults({ await withdrawFromVaults({
fee: hardcodedFee,
accountId: accountId, accountId: accountId,
vaults: props.vaults, vaults: props.vaults,
}) })

View File

@ -10,7 +10,6 @@ import Text from 'components/Text'
import useStore from 'store' import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { getAssetByDenom } from 'utils/assets' import { getAssetByDenom } from 'utils/assets'
import { hardcodedFee } from 'utils/constants'
import { combineBNCoins } from 'utils/parsers' import { combineBNCoins } from 'utils/parsers'
import { getPage, getRoute } from 'utils/route' import { getPage, getRoute } from 'utils/route'
@ -41,7 +40,7 @@ function AccountDeleteModal(props: Props) {
const deleteAccountHandler = useCallback(async () => { const deleteAccountHandler = useCallback(async () => {
setIsConfirming(true) 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) const isSuccess = await deleteAccount(options)
setIsConfirming(false) setIsConfirming(false)
if (isSuccess) { if (isSuccess) {

View File

@ -19,7 +19,6 @@ import useHealthComputer from 'hooks/useHealthComputer'
import useToggle from 'hooks/useToggle' import useToggle from 'hooks/useToggle'
import useStore from 'store' import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { hardcodedFee } from 'utils/constants'
import { formatPercent, formatValue } from 'utils/formatters' import { formatPercent, formatValue } from 'utils/formatters'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
@ -70,14 +69,12 @@ function BorrowModal(props: Props) {
let result let result
if (isRepay) { if (isRepay) {
result = await repay({ result = await repay({
fee: hardcodedFee,
accountId: props.account.id, accountId: props.account.id,
coin: BNCoin.fromDenomAndBigNumber(modal.asset.denom, amount), coin: BNCoin.fromDenomAndBigNumber(modal.asset.denom, amount),
accountBalance: percentage === 100, accountBalance: percentage === 100,
}) })
} else { } else {
result = await borrow({ result = await borrow({
fee: hardcodedFee,
accountId: props.account.id, accountId: props.account.id,
coin: { denom: modal.asset.denom, amount: amount.toString() }, coin: { denom: modal.asset.denom, amount: amount.toString() },
borrowToWallet, borrowToWallet,

View File

@ -13,8 +13,8 @@ import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { byDenom } from 'utils/array' import { byDenom } from 'utils/array'
import { getAssetByDenom, getBaseAsset } from 'utils/assets' import { getAssetByDenom, getBaseAsset } from 'utils/assets'
import { hardcodedFee } from 'utils/constants'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
import { defaultFee } from 'utils/constants'
interface Props { interface Props {
account: Account account: Account
@ -48,7 +48,6 @@ export default function FundAccount(props: Props) {
setIsFunding(true) setIsFunding(true)
if (!accountId) return if (!accountId) return
const result = await deposit({ const result = await deposit({
fee: hardcodedFee,
accountId, accountId,
coins: fundingAssets, coins: fundingAssets,
}) })
@ -94,7 +93,7 @@ export default function FundAccount(props: Props) {
) )
useEffect(() => { useEffect(() => {
if (BN(baseBalance).isLessThan(hardcodedFee.amount[0].amount)) { if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) {
useStore.setState({ focusComponent: { component: <WalletBridges /> } }) useStore.setState({ focusComponent: { component: <WalletBridges /> } })
} }
}, [baseBalance]) }, [baseBalance])

View File

@ -15,7 +15,6 @@ import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
import useStore from 'store' import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { byDenom } from 'utils/array' import { byDenom } from 'utils/array'
import { hardcodedFee } from 'utils/constants'
interface Props { interface Props {
account: Account account: Account
@ -64,7 +63,6 @@ export default function WithdrawFromAccount(props: Props) {
async function onConfirm() { async function onConfirm() {
setIsConfirming(true) setIsConfirming(true)
const result = await withdraw({ const result = await withdraw({
fee: hardcodedFee,
accountId: account.id, accountId: account.id,
coins: [BNCoin.fromDenomAndBigNumber(currentAsset.denom, amount)], coins: [BNCoin.fromDenomAndBigNumber(currentAsset.denom, amount)],
borrow: debtAmount.isZero() borrow: debtAmount.isZero()

View File

@ -2,7 +2,6 @@ import { useCallback, useState } from 'react'
import useStore from 'store' import useStore from 'store'
import useToggle from 'hooks/useToggle' import useToggle from 'hooks/useToggle'
import { hardcodedFee } from 'utils/constants'
import useCurrentAccount from 'hooks/useCurrentAccount' import useCurrentAccount from 'hooks/useCurrentAccount'
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal' import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader' import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
@ -50,7 +49,6 @@ function LendAndReclaimModal({ currentAccount, config }: Props) {
const coin = BNCoin.fromDenomAndBigNumber(asset.denom, value) const coin = BNCoin.fromDenomAndBigNumber(asset.denom, value)
const options = { const options = {
fee: hardcodedFee,
accountId: currentAccount.id, accountId: currentAccount.id,
coin, coin,
isMax, isMax,

View File

@ -5,7 +5,6 @@ import Button from 'components/Button'
import { NoIcon, YesIcon } from 'components/Modals/AlertDialog/ButtonIcons' import { NoIcon, YesIcon } from 'components/Modals/AlertDialog/ButtonIcons'
import Text from 'components/Text' import Text from 'components/Text'
import useStore from 'store' import useStore from 'store'
import { hardcodedFee } from 'utils/constants'
interface Props { interface Props {
depositedVault: DepositedVault depositedVault: DepositedVault
@ -21,7 +20,6 @@ export default function UnlockModalContent(props: Props) {
if (!accountId) return if (!accountId) return
setIsConfirming(true) setIsConfirming(true)
await unlock({ await unlock({
fee: hardcodedFee,
accountId: accountId, accountId: accountId,
vault: props.depositedVault, vault: props.depositedVault,
amount: props.depositedVault.amounts.locked.toString(), amount: props.depositedVault.amounts.locked.toString(),

View File

@ -27,7 +27,6 @@ export interface VaultBorrowingsProps {
secondaryAsset: Asset secondaryAsset: Asset
vault: Vault vault: Vault
depositActions: Action[] depositActions: Action[]
depositFee: StdFee
onChangeBorrowings: (borrowings: BNCoin[]) => void onChangeBorrowings: (borrowings: BNCoin[]) => void
} }
@ -144,7 +143,6 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
async function onConfirm() { async function onConfirm() {
setIsConfirming(true) setIsConfirming(true)
const isSuccess = await depositIntoVault({ const isSuccess = await depositIntoVault({
fee: props.depositFee,
accountId: props.updatedAccount.id, accountId: props.updatedAccount.id,
actions: props.depositActions, actions: props.depositActions,
}) })

View File

@ -26,11 +26,7 @@ export default function VaultModalContent(props: Props) {
const [isOpen, toggleOpen] = useIsOpenArray(2, false) const [isOpen, toggleOpen] = useIsOpenArray(2, false)
const [isCustomRatio, setIsCustomRatio] = useState(false) const [isCustomRatio, setIsCustomRatio] = useState(false)
const { const { actions: depositActions, totalValue } = useDepositVault({
actions: depositActions,
fee: depositFee,
totalValue,
} = useDepositVault({
vault: props.vault, vault: props.vault,
deposits: removedDeposits, deposits: removedDeposits,
borrowings: addedDebt, borrowings: addedDebt,
@ -114,7 +110,6 @@ export default function VaultModalContent(props: Props) {
onChangeBorrowings={addDebt} onChangeBorrowings={addDebt}
vault={props.vault} vault={props.vault}
depositActions={depositActions} depositActions={depositActions}
depositFee={depositFee}
/> />
), ),
title: 'Borrow', title: 'Borrow',

View File

@ -11,7 +11,6 @@ import Text from 'components/Text'
import useStore from 'store' import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { getAssetByDenom } from 'utils/assets' import { getAssetByDenom } from 'utils/assets'
import { hardcodedFee } from 'utils/constants'
import { demagnify } from 'utils/formatters' import { demagnify } from 'utils/formatters'
export default function WithdrawFromVaultsModal() { export default function WithdrawFromVaultsModal() {
@ -29,7 +28,6 @@ export default function WithdrawFromVaultsModal() {
if (!accountId || !modal) return if (!accountId || !modal) return
setIsConfirming(true) setIsConfirming(true)
await withdrawFromVaults({ await withdrawFromVaults({
fee: hardcodedFee,
accountId: accountId, accountId: accountId,
vaults: modal, vaults: modal,
}) })

View File

@ -4,7 +4,6 @@ import { useMemo } from 'react'
import ActionButton from 'components/Button/ActionButton' import ActionButton from 'components/Button/ActionButton'
import useSwapRoute from 'hooks/useSwapRoute' import useSwapRoute from 'hooks/useSwapRoute'
import { getAssetByDenom } from 'utils/assets' import { getAssetByDenom } from 'utils/assets'
import { hardcodedFee } from 'utils/constants'
import { formatAmountWithSymbol, formatPercent } from 'utils/formatters' import { formatAmountWithSymbol, formatPercent } from 'utils/formatters'
interface Props { interface Props {
@ -16,6 +15,7 @@ interface Props {
showProgressIndicator: boolean showProgressIndicator: boolean
isMargin?: boolean isMargin?: boolean
borrowAmount: BigNumber borrowAmount: BigNumber
estimatedFee: StdFee
buyAction: () => void buyAction: () => void
} }
@ -29,6 +29,7 @@ export default function TradeSummary(props: Props) {
containerClassName, containerClassName,
isMargin, isMargin,
borrowAmount, borrowAmount,
estimatedFee,
showProgressIndicator, showProgressIndicator,
} = props } = props
const { data: routes, isLoading: isRouteLoading } = useSwapRoute(sellAsset.denom, buyAsset.denom) const { data: routes, isLoading: isRouteLoading } = useSwapRoute(sellAsset.denom, buyAsset.denom)
@ -53,7 +54,7 @@ export default function TradeSummary(props: Props) {
<span className={className.title}>Summary</span> <span className={className.title}>Summary</span>
<div className={className.infoLine}> <div className={className.infoLine}>
<span className={className.infoLineLabel}>Fees</span> <span className={className.infoLineLabel}>Fees</span>
<span>{formatAmountWithSymbol(hardcodedFee.amount[0])}</span> <span>{formatAmountWithSymbol(estimatedFee.amount[0])}</span>
</div> </div>
{isMargin && ( {isMargin && (
<> <>

View File

@ -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 Divider from 'components/Divider'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings' import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
@ -8,8 +8,8 @@ import useCurrentAccount from 'hooks/useCurrentAccount'
import useLocalStorage from 'hooks/useLocalStorage' import useLocalStorage from 'hooks/useLocalStorage'
import usePrices from 'hooks/usePrices' import usePrices from 'hooks/usePrices'
import useStore from 'store' import useStore from 'store'
import { byDenom, byTokenDenom } from 'utils/array' import { byDenom } from 'utils/array'
import { hardcodedFee } from 'utils/constants' import { defaultFee } from 'utils/constants'
import RangeInput from 'components/RangeInput' import RangeInput from 'components/RangeInput'
import { asyncThrottle, BN } from 'utils/helpers' import { asyncThrottle, BN } from 'utils/helpers'
import AssetAmountInput from 'components/Trade/TradeModule/SwapForm/AssetAmountInput' 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 [maxBuyableAmountEstimation, setMaxBuyableAmountEstimation] = useState(BN_ZERO)
const [selectedOrderType, setSelectedOrderType] = useState<AvailableOrderType>('Market') const [selectedOrderType, setSelectedOrderType] = useState<AvailableOrderType>('Market')
const [isConfirming, setIsConfirming] = useState(false) const [isConfirming, setIsConfirming] = useState(false)
const [estimatedFee, setEstimatedFee] = useState(defaultFee)
const throttledEstimateExactIn = useMemo(() => asyncThrottle(estimateExactIn, 250), []) const throttledEstimateExactIn = useMemo(() => asyncThrottle(estimateExactIn, 250), [])
@ -124,41 +125,50 @@ export default function SwapForm(props: Props) {
sellAssetAmount, 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(() => { useEffect(() => {
setBuyAssetAmount(BN_ZERO) setBuyAssetAmount(BN_ZERO)
setSellAssetAmount(BN_ZERO) setSellAssetAmount(BN_ZERO)
}, [buyAsset.denom, sellAsset.denom]) }, [buyAsset.denom, sellAsset.denom])
useEffect(() => {
swapTx.estimateFee().then(setEstimatedFee)
}, [swapTx])
const handleBuyClick = useCallback(async () => { const handleBuyClick = useCallback(async () => {
if (account?.id) { if (account?.id) {
setIsConfirming(true) setIsConfirming(true)
const borrowCoin = sellAssetAmount.isGreaterThan(marginThreshold)
? BNCoin.fromDenomAndBigNumber(sellAsset.denom, sellAssetAmount.minus(marginThreshold))
: undefined
const isSucceeded = await swap({ const isSucceeded = await swapTx.execute()
fee: hardcodedFee,
accountId: account.id,
coinIn: BNCoin.fromDenomAndBigNumber(sellAsset.denom, sellAssetAmount.integerValue()),
borrow: borrowCoin,
denomOut: buyAsset.denom,
slippage,
})
if (isSucceeded) { if (isSucceeded) {
setSellAssetAmount(BN_ZERO) setSellAssetAmount(BN_ZERO)
setBuyAssetAmount(BN_ZERO) setBuyAssetAmount(BN_ZERO)
} }
setIsConfirming(false) setIsConfirming(false)
} }
}, [ }, [account?.id, swapTx])
account?.id,
buyAsset.denom,
sellAsset.denom,
sellAssetAmount,
slippage,
swap,
marginThreshold,
])
return ( return (
<> <>
@ -220,6 +230,7 @@ export default function SwapForm(props: Props) {
? sellAssetAmount.minus(marginThreshold) ? sellAssetAmount.minus(marginThreshold)
: BN_ZERO : BN_ZERO
} }
estimatedFee={estimatedFee}
/> />
</> </>
) )

View File

@ -17,7 +17,7 @@ import useWalletBalances from 'hooks/useWalletBalances'
import useStore from 'store' import useStore from 'store'
import { byDenom } from 'utils/array' import { byDenom } from 'utils/array'
import { getBaseAsset } from 'utils/assets' import { getBaseAsset } from 'utils/assets'
import { hardcodedFee } from 'utils/constants' import { defaultFee } from 'utils/constants'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
const currentChainId = ENV.CHAIN_ID const currentChainId = ENV.CHAIN_ID
@ -64,7 +64,7 @@ export default function WalletBridges() {
return return
} }
if (BN(baseBalance).isGreaterThanOrEqualTo(hardcodedFee.amount[0].amount) && !isLoading) if (BN(baseBalance).isGreaterThanOrEqualTo(defaultFee.amount[0].amount) && !isLoading)
setHasFunds(true) setHasFunds(true)
}, [baseBalance, isLoading, hasFunds, setHasFunds]) }, [baseBalance, isLoading, hasFunds, setHasFunds])

View File

@ -10,7 +10,7 @@ import useWalletBalances from 'hooks/useWalletBalances'
import useStore from 'store' import useStore from 'store'
import { byDenom } from 'utils/array' import { byDenom } from 'utils/array'
import { getBaseAsset } from 'utils/assets' import { getBaseAsset } from 'utils/assets'
import { hardcodedFee } from 'utils/constants' import { defaultFee } from 'utils/constants'
import { BN } from 'utils/helpers' import { BN } from 'utils/helpers'
import { getPage, getRoute } from 'utils/route' import { getPage, getRoute } from 'utils/route'
@ -41,7 +41,7 @@ function Content() {
useEffect(() => { useEffect(() => {
if ( if (
accounts.length !== 0 && 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)) navigate(getRoute(getPage(pathname), address, accounts[0].id))
useStore.setState({ accounts: accounts, balances: walletBalances, focusComponent: null }) useStore.setState({ accounts: accounts, balances: walletBalances, focusComponent: null })
@ -49,7 +49,7 @@ function Content() {
}, [accounts, baseBalance, navigate, pathname, address, walletBalances]) }, [accounts, baseBalance, navigate, pathname, address, walletBalances])
if (isLoading) return <FetchLoading /> if (isLoading) return <FetchLoading />
if (BN(baseBalance).isLessThan(hardcodedFee.amount[0].amount)) return <WalletBridges /> if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) return <WalletBridges />
if (accounts.length === 0) return <AccountCreateFirst /> if (accounts.length === 0) return <AccountCreateFirst />
return null return null
} }

View File

@ -8,7 +8,6 @@ import useLocalStorage from 'hooks/useLocalStorage'
import usePrices from 'hooks/usePrices' import usePrices from 'hooks/usePrices'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { Action } from 'types/generated/mars-credit-manager/MarsCreditManager.types' import { Action } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
import { hardcodedFee } from 'utils/constants'
import { import {
getEnterVaultActions, getEnterVaultActions,
getVaultDepositCoinsAndValue, getVaultDepositCoinsAndValue,
@ -23,7 +22,6 @@ interface Props {
} }
export default function useDepositVault(props: Props): { export default function useDepositVault(props: Props): {
actions: Action[] actions: Action[]
fee: StdFee
minLpToReceive: string minLpToReceive: string
totalValue: BigNumber totalValue: BigNumber
} { } {
@ -92,7 +90,6 @@ export default function useDepositVault(props: Props): {
return { return {
actions, actions,
fee: hardcodedFee,
minLpToReceive: minLpToReceive.toString(), minLpToReceive: minLpToReceive.toString(),
totalValue, totalValue,
} }

View File

@ -14,15 +14,15 @@ import {
import { getSingleValueFromBroadcastResult } from 'utils/broadcast' import { getSingleValueFromBroadcastResult } from 'utils/broadcast'
import { formatAmountWithSymbol } from 'utils/formatters' import { formatAmountWithSymbol } from 'utils/formatters'
import getTokenOutFromSwapResponse from 'utils/getTokenOutFromSwapResponse' import getTokenOutFromSwapResponse from 'utils/getTokenOutFromSwapResponse'
import { BN } from 'utils/helpers'
import { defaultFee } from 'utils/constants'
function generateExecutionMessage( function generateExecutionMessage(
sender: string | undefined, sender: string | undefined = '',
contract: string, contract: string,
msg: CreditManagerExecuteMsg | AccountNftExecuteMsg, msg: CreditManagerExecuteMsg | AccountNftExecuteMsg,
funds: Coin[], funds: Coin[],
) { ) {
if (!sender) return
return new MsgExecuteContract({ return new MsgExecuteContract({
sender, sender,
contract, 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 { return {
toast: null, toast: null,
borrow: async (options: { borrow: async (options: { accountId: string; coin: Coin; borrowToWallet: boolean }) => {
fee: StdFee
accountId: string
coin: Coin
borrowToWallet: boolean
}) => {
const borrowAction: Action = { borrow: options.coin } const borrowAction: Action = { borrow: options.coin }
const withdrawAction: Action = { withdraw: options.coin } const withdrawAction: Action = { withdraw: options.coin }
const actions = options.borrowToWallet ? [borrowAction, withdrawAction] : [borrowAction] const actions = options.borrowToWallet ? [borrowAction, withdrawAction] : [borrowAction]
@ -78,7 +98,6 @@ export default function createBroadcastSlice(
const response = await get().executeMsg({ const response = await get().executeMsg({
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
fee: options.fee,
}) })
handleResponseMessages( handleResponseMessages(
@ -89,14 +108,13 @@ export default function createBroadcastSlice(
) )
return !!response.result return !!response.result
}, },
createAccount: async (options: { fee: StdFee }) => { createAccount: async () => {
const msg: CreditManagerExecuteMsg = { const msg: CreditManagerExecuteMsg = {
create_credit_account: 'default', create_credit_account: 'default',
} }
const response = await get().executeMsg({ const response = await get().executeMsg({
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
fee: options.fee,
}) })
if (response.result) { if (response.result) {
@ -115,7 +133,7 @@ export default function createBroadcastSlice(
return null return null
} }
}, },
deleteAccount: async (options: { fee: StdFee; accountId: string; lends: BNCoin[] }) => { deleteAccount: async (options: { accountId: string; lends: BNCoin[] }) => {
const reclaimMsg = options.lends.map((coin) => { const reclaimMsg = options.lends.map((coin) => {
return { return {
reclaim: coin.toActionCoin(true), 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_CREDIT_MANAGER, refundMessage, []),
generateExecutionMessage(get().address, ENV.ADDRESS_ACCOUNT_NFT, burnMessage, []), generateExecutionMessage(get().address, ENV.ADDRESS_ACCOUNT_NFT, burnMessage, []),
], ],
fee: options.fee,
}) })
handleResponseMessages(response, `Account ${options.accountId} deleted`) handleResponseMessages(response, `Account ${options.accountId} deleted`)
return !!response.result return !!response.result
}, },
deposit: async (options: { fee: StdFee; accountId: string; coins: BNCoin[] }) => { deposit: async (options: { accountId: string; coins: BNCoin[] }) => {
const msg: CreditManagerExecuteMsg = { const msg: CreditManagerExecuteMsg = {
update_credit_account: { update_credit_account: {
account_id: options.accountId, account_id: options.accountId,
@ -161,7 +178,6 @@ export default function createBroadcastSlice(
const response = await get().executeMsg({ const response = await get().executeMsg({
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, funds)], messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, funds)],
fee: options.fee,
}) })
const depositString = options.coins const depositString = options.coins
@ -170,12 +186,7 @@ export default function createBroadcastSlice(
handleResponseMessages(response, `Deposited ${depositString} to Account ${options.accountId}`) handleResponseMessages(response, `Deposited ${depositString} to Account ${options.accountId}`)
return !!response.result return !!response.result
}, },
unlock: async (options: { unlock: async (options: { accountId: string; vault: DepositedVault; amount: string }) => {
fee: StdFee
accountId: string
vault: DepositedVault
amount: string
}) => {
const msg: CreditManagerExecuteMsg = { const msg: CreditManagerExecuteMsg = {
update_credit_account: { update_credit_account: {
account_id: options.accountId, account_id: options.accountId,
@ -192,18 +203,13 @@ export default function createBroadcastSlice(
const response = await get().executeMsg({ const response = await get().executeMsg({
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
fee: options.fee,
}) })
handleResponseMessages(response, `Requested unlock for ${options.vault.name}`) handleResponseMessages(response, `Requested unlock for ${options.vault.name}`)
return !!response.result return !!response.result
}, },
withdrawFromVaults: async (options: { withdrawFromVaults: async (options: { accountId: string; vaults: DepositedVault[] }) => {
fee: StdFee
accountId: string
vaults: DepositedVault[]
}) => {
const actions: CreditManagerAction[] = [] const actions: CreditManagerAction[] = []
options.vaults.forEach((vault) => { options.vaults.forEach((vault) => {
if (vault.unlockId) if (vault.unlockId)
@ -223,7 +229,6 @@ export default function createBroadcastSlice(
const response = await get().executeMsg({ const response = await get().executeMsg({
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
fee: options.fee,
}) })
const vaultsString = options.vaults.length === 1 ? 'vault' : 'vaults' const vaultsString = options.vaults.length === 1 ? 'vault' : 'vaults'
@ -233,7 +238,7 @@ export default function createBroadcastSlice(
) )
return !!response.result return !!response.result
}, },
depositIntoVault: async (options: { fee: StdFee; accountId: string; actions: Action[] }) => { depositIntoVault: async (options: { accountId: string; actions: Action[] }) => {
const msg: CreditManagerExecuteMsg = { const msg: CreditManagerExecuteMsg = {
update_credit_account: { update_credit_account: {
account_id: options.accountId, account_id: options.accountId,
@ -243,18 +248,12 @@ export default function createBroadcastSlice(
const response = await get().executeMsg({ const response = await get().executeMsg({
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
fee: options.fee,
}) })
handleResponseMessages(response, `Deposited into vault`) handleResponseMessages(response, `Deposited into vault`)
return !!response.result return !!response.result
}, },
withdraw: async (options: { withdraw: async (options: { accountId: string; coins: BNCoin[]; borrow: BNCoin[] }) => {
fee: StdFee
accountId: string
coins: BNCoin[]
borrow: BNCoin[]
}) => {
const withdrawActions = options.coins.map((coin) => ({ const withdrawActions = options.coins.map((coin) => ({
withdraw: coin.toCoin(), withdraw: coin.toCoin(),
})) }))
@ -271,7 +270,6 @@ export default function createBroadcastSlice(
const response = await get().executeMsg({ const response = await get().executeMsg({
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
fee: options.fee,
}) })
const withdrawString = options.coins const withdrawString = options.coins
@ -283,12 +281,7 @@ export default function createBroadcastSlice(
) )
return !!response.result return !!response.result
}, },
repay: async (options: { repay: async (options: { accountId: string; coin: BNCoin; accountBalance?: boolean }) => {
fee: StdFee
accountId: string
coin: BNCoin
accountBalance?: boolean
}) => {
const msg: CreditManagerExecuteMsg = { const msg: CreditManagerExecuteMsg = {
update_credit_account: { update_credit_account: {
account_id: options.accountId, account_id: options.accountId,
@ -304,7 +297,6 @@ export default function createBroadcastSlice(
const response = await get().executeMsg({ const response = await get().executeMsg({
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
fee: options.fee,
}) })
handleResponseMessages( handleResponseMessages(
@ -313,7 +305,7 @@ export default function createBroadcastSlice(
) )
return !!response.result 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 = { const msg: CreditManagerExecuteMsg = {
update_credit_account: { update_credit_account: {
account_id: options.accountId, account_id: options.accountId,
@ -327,7 +319,6 @@ export default function createBroadcastSlice(
const response = await get().executeMsg({ const response = await get().executeMsg({
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
fee: options.fee,
}) })
handleResponseMessages( handleResponseMessages(
@ -336,7 +327,7 @@ export default function createBroadcastSlice(
) )
return !!response.result 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 = { const msg: CreditManagerExecuteMsg = {
update_credit_account: { update_credit_account: {
account_id: options.accountId, account_id: options.accountId,
@ -350,7 +341,6 @@ export default function createBroadcastSlice(
const response = await get().executeMsg({ const response = await get().executeMsg({
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
fee: options.fee,
}) })
handleResponseMessages( handleResponseMessages(
@ -359,8 +349,7 @@ export default function createBroadcastSlice(
) )
return !!response.result return !!response.result
}, },
swap: async (options: { swap: (options: {
fee: StdFee
accountId: string accountId: string
coinIn: BNCoin coinIn: BNCoin
borrow?: BNCoin borrow?: BNCoin
@ -383,31 +372,38 @@ export default function createBroadcastSlice(
}, },
} }
const response = await get().executeMsg({ const messages = [
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])], generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, []),
fee: options.fee, ]
})
const coinOut = getTokenOutFromSwapResponse(response, options.denomOut) const estimateFee = () => getEstimatedFee(messages)
const successMessage = `Swapped ${formatAmountWithSymbol(
options.coinIn.toCoin(),
)} for ${formatAmountWithSymbol(coinOut)}`
handleResponseMessages(response, successMessage) const execute = async () => {
return !!response.result 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: { executeMsg: async (options: { messages: MsgExecuteContract[] }): Promise<BroadcastResult> => {
messages: MsgExecuteContract[]
fee: StdFee
}): Promise<BroadcastResult> => {
try { try {
const client = get().client const client = get().client
if (!client) return { error: 'no client detected' } if (!client) return { error: 'no client detected' }
const fee = await getEstimatedFee(options.messages)
const broadcastOptions = { const broadcastOptions = {
messages: options.messages, messages: options.messages,
feeAmount: options.fee.amount[0].amount, feeAmount: fee.amount[0].amount,
gasLimit: options.fee.gas, gasLimit: fee.gas,
memo: undefined, memo: undefined,
wallet: client.connectedWallet, wallet: client.connectedWallet,
mobile: isMobile, mobile: isMobile,

View File

@ -5,64 +5,38 @@ interface BroadcastResult {
error?: string error?: string
} }
interface ExecutableTx {
execute: () => Promise<boolean>
estimateFee: () => Promise<StdFee>
}
interface BroadcastSlice { interface BroadcastSlice {
toast: { message: string; isError?: boolean; title?: string } | null toast: { message: string; isError?: boolean; title?: string } | null
executeMsg: (options: { messages: MsgExecuteContract[]; fee: StdFee }) => Promise<BroadcastResult> executeMsg: (options: { messages: MsgExecuteContract[] }) => Promise<BroadcastResult>
borrow: (options: { borrow: (options: { accountId: string; coin: Coin; borrowToWallet: boolean }) => Promise<boolean>
fee: StdFee createAccount: () => Promise<string | null>
accountId: string deleteAccount: (options: { accountId: string; lends: BNCoin[] }) => Promise<boolean>
coin: Coin deposit: (options: { accountId: string; coins: BNCoin[] }) => Promise<boolean>
borrowToWallet: boolean
}) => Promise<boolean>
createAccount: (options: { fee: StdFee }) => Promise<string | null>
deleteAccount: (options: { fee: StdFee; accountId: string; lends: BNCoin[] }) => Promise<boolean>
deposit: (options: { fee: StdFee; accountId: string; coins: BNCoin[] }) => Promise<boolean>
unlock: (options: { unlock: (options: {
fee: StdFee
accountId: string accountId: string
vault: DepositedVault vault: DepositedVault
amount: string amount: string
}) => Promise<boolean> }) => Promise<boolean>
withdrawFromVaults: (options: { withdrawFromVaults: (options: { accountId: string; vaults: DepositedVault[] }) => Promise<boolean>
fee: StdFee depositIntoVault: (options: { accountId: string; actions: Action[] }) => Promise<boolean>
accountId: string withdraw: (options: { accountId: string; coins: BNCoin[]; borrow: BNCoin[] }) => Promise<boolean>
vaults: DepositedVault[] lend: (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => Promise<boolean>
}) => Promise<boolean> reclaim: (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => Promise<boolean>
depositIntoVault: (options: {
fee: StdFee
accountId: string
actions: Action[]
}) => Promise<boolean>
withdraw: (options: {
fee: StdFee
accountId: string
coins: BNCoin[]
borrow: BNCoin[]
}) => Promise<boolean>
lend: (options: {
fee: StdFee
accountId: string
coin: BNCoin
isMax?: boolean
}) => Promise<boolean>
reclaim: (options: {
fee: StdFee
accountId: string
coin: BNCoin
isMax?: boolean
}) => Promise<boolean>
repay: (options: { repay: (options: {
fee: StdFee
accountId: string accountId: string
coin: BNCoin coin: BNCoin
accountBalance?: boolean accountBalance?: boolean
}) => Promise<boolean> }) => Promise<boolean>
swap: (options: { swap: (options: {
fee: StdFee
accountId: string accountId: string
coinIn: BNCoin coinIn: BNCoin
borrow: BNCoin borrow: BNCoin
denomOut: string denomOut: string
slippage: number slippage: number
}) => Promise<boolean> }) => ExecutableTx
} }

View File

@ -1,6 +1,4 @@
// StdFee export const defaultFee: StdFee = {
// TODO: decide some strategy to handle fees
export const hardcodedFee = {
amount: [ amount: [
{ {
denom: 'uosmo', denom: 'uosmo',