feat: refactored the toast responses (#442)

* feat: refactored the toast responses

* fix: fixed the map return

* feat: added a recent transaction center

* tidy: removed logs

* fix: fixed autolend

* feat: added global lending on first account funding

* fix: added endOfLine setting

* feat: added eslint warnings for lineEnds

* fix: made the vault message generic
This commit is contained in:
Linkie Link 2023-09-11 10:35:13 +02:00 committed by GitHub
parent 7b7c25a07a
commit 609be9eb64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 418 additions and 108 deletions

View File

@ -1,6 +1,7 @@
{
"extends": "next/core-web-vitals",
"rules": {
"linebreak-style": ["warn", "unix"],
"sort-imports": [
"warn",
{

View File

@ -3,5 +3,6 @@
"jsxSingleQuote": true,
"semi": false,
"printWidth": 100,
"trailingComma": "all"
"trailingComma": "all",
"endOfLine": "lf"
}

View File

@ -1,5 +1,5 @@
import classNames from 'classnames'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import Button from 'components/Button'
import DepositCapMessage from 'components/DepositCapMessage'
@ -8,8 +8,11 @@ import SwitchAutoLend from 'components/Switch/SwitchAutoLend'
import Text from 'components/Text'
import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
import WalletBridges from 'components/Wallet/WalletBridges'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { LEND_ASSETS_KEY } from 'constants/localStore'
import { BN_ZERO } from 'constants/math'
import useAutoLend from 'hooks/useAutoLend'
import useLocalStorage from 'hooks/useLocalStorage'
import useMarketAssets from 'hooks/useMarketAssets'
import useToggle from 'hooks/useToggle'
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
@ -31,8 +34,12 @@ interface Props {
export default function AccountFundContent(props: Props) {
const deposit = useStore((s) => s.deposit)
const accounts = useStore((s) => s.accounts)
const walletAssetModal = useStore((s) => s.walletAssetsModal)
const [lendAssets, setLendAssets] = useLocalStorage<boolean>(
LEND_ASSETS_KEY,
DEFAULT_SETTINGS.lendAssets,
)
const [isFunding, setIsFunding] = useToggle(false)
const [fundingAssets, setFundingAssets] = useState<BNCoin[]>([])
const { data: marketAssets } = useMarketAssets()
@ -124,6 +131,10 @@ export default function AccountFundContent(props: Props) {
toggleIsLending(autoLendEnabledAccountIds.includes(props.accountId))
}, [props.accountId, autoLendEnabledAccountIds, toggleIsLending])
useEffect(() => {
if (accounts?.length === 1 && isLending && !lendAssets) setLendAssets(true)
}, [isLending, accounts, lendAssets, setLendAssets])
const depositCapReachedCoins = useMemo(() => {
const depositCapReachedCoins: BNCoin[] = []
fundingAssets.forEach((asset) => {
@ -180,7 +191,7 @@ export default function AccountFundContent(props: Props) {
<DepositCapMessage
action='fund'
coins={depositCapReachedCoins}
className='pr-4 py-2 mt-4'
className='py-2 pr-4 mt-4'
showIcon
/>
<SwitchAutoLend

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
import AccountFundContent from 'components/Account/AccountFund/AccountFundContent'
@ -17,8 +17,8 @@ export default function AccountFundFullPage() {
const [selectedAccountId, setSelectedAccountId] = useState<null | string>(null)
useEffect(() => {
if (accounts && !selectedAccountId && accountId)
setSelectedAccountId(currentAccount?.id ?? accountId)
if (accounts && !selectedAccountId && accountId) setSelectedAccountId(accountId)
if (accountId && selectedAccountId !== accountId) setSelectedAccountId(accountId)
}, [accounts, selectedAccountId, accountId, currentAccount])
if (!selectedAccountId || !address) return null

View File

@ -121,7 +121,7 @@ function BorrowModal(props: Props) {
simulateRepay(repayCoin)
}
},
[asset, amount, isRepay, simulateRepay],
[asset, amount, isRepay, simulateRepay, modal],
)
useEffect(() => {
@ -145,7 +145,7 @@ function BorrowModal(props: Props) {
)
setMax(BigNumber.min(maxBorrowAmount, modal.marketData?.liquidity?.amount || 0))
}, [account, isRepay, modal, asset.denom, computeMaxBorrowAmount, borrowToWallet])
}, [account, isRepay, modal, asset.denom, computeMaxBorrowAmount, borrowToWallet, apr])
useEffect(() => {
if (amount.isGreaterThan(max)) {

View File

@ -149,6 +149,8 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
const isSuccess = await depositIntoVault({
accountId: updatedAccount.id,
actions: props.depositActions,
deposits: props.deposits,
borrowings: props.borrowings,
})
setIsConfirming(false)
if (isSuccess) {
@ -237,4 +239,4 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
/>
</div>
)
}
}

View File

@ -1,9 +1,9 @@
import BigNumber from 'bignumber.js'
import { useMemo, useState } from 'react'
import DisplayCurrency from 'components/DisplayCurrency'
import Button from 'components/Button'
import DepositCapMessage from 'components/DepositCapMessage'
import DisplayCurrency from 'components/DisplayCurrency'
import Divider from 'components/Divider'
import { Gauge } from 'components/Gauge'
import { ArrowRight, ExclamationMarkCircled } from 'components/Icons'
@ -11,14 +11,13 @@ import Slider from 'components/Slider'
import Switch from 'components/Switch'
import Text from 'components/Text'
import TokenInput from 'components/TokenInput'
import { ASSETS } from 'constants/assets'
import { BN_ZERO } from 'constants/math'
import { ORACLE_DENOM } from 'constants/oracle'
import usePrices from 'hooks/usePrices'
import { BNCoin } from 'types/classes/BNCoin'
import { accumulateAmounts } from 'utils/accounts'
import { byDenom } from 'utils/array'
import { BN, getValueFromBNCoins } from 'utils/helpers'
import { ORACLE_DENOM } from 'constants/oracle'
interface Props {
deposits: BNCoin[]
@ -36,7 +35,6 @@ interface Props {
export default function VaultDeposit(props: Props) {
const { deposits, primaryAsset, secondaryAsset, account, onChangeDeposits, displayCurrency } =
props
const displayCurrencyAsset = ASSETS.find(byDenom(displayCurrency)) ?? ASSETS[0]
const [availablePrimaryAmount, availableSecondaryAmount] = useMemo(
() => [
accumulateAmounts(primaryAsset.denom, [...account.deposits, ...account.lends]),
@ -160,7 +158,7 @@ export default function VaultDeposit(props: Props) {
return (
<div className='flex flex-col'>
<div className='flex gap-4 pl-3 p-4'>
<div className='flex gap-4 p-4 pl-3'>
<div className='flex flex-col items-center justify-between gap-1 pb-[30px] pt-2'>
<Gauge
percentage={primaryValuePercentage}

View File

@ -1,23 +1,48 @@
import classNames from 'classnames'
import { ReactNode } from 'react'
import { toast as createToast, Slide, ToastContainer } from 'react-toastify'
import { mutate } from 'swr'
import { CheckCircled, Cross, CrossCircled, ExternalLink } from 'components/Icons'
import Text from 'components/Text'
import { TextLink } from 'components/TextLink'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { EXPLORER_NAME, EXPLORER_TX_URL } from 'constants/explorer'
import { REDUCE_MOTION_KEY } from 'constants/localStore'
import useLocalStorage from 'hooks/useLocalStorage'
import useTransactionStore from 'hooks/useTransactionStore'
import useStore from 'store'
import { formatAmountWithSymbol } from 'utils/formatters'
import { TextLink } from './TextLink'
export function generateToastContent(content: ToastSuccess['content']): ReactNode {
return content.map((item, index) => (
<div className='flex flex-wrap w-full' key={index}>
{item.coins.length > 0 && (
<>
<Text size='sm' className='w-full mb-1 text-white'>
{item.text}
</Text>
<ul className='flex flex-wrap w-full gap-1 p-1 pl-4 list-disc'>
{item.coins.map((coin) => (
<li className='w-full p-0 text-sm text-white' key={coin.denom}>
{formatAmountWithSymbol(coin)}
</li>
))}
</ul>
</>
)}
</div>
))
}
export default function Toaster() {
const [reduceMotion] = useLocalStorage<boolean>(REDUCE_MOTION_KEY, DEFAULT_SETTINGS.reduceMotion)
const toast = useStore((s) => s.toast)
const isError = toast?.isError
const { addTransaction } = useTransactionStore()
if (toast) {
if (!isError) addTransaction(toast)
const Msg = () => (
<div
className={classNames(
@ -38,26 +63,33 @@ export default function Toaster() {
isError ? 'text-error' : 'text-success',
)}
>
{toast.title ? toast.title : isError ? 'Error' : 'Success'}
{isError ? (toast.title ? toast.title : 'Error') : 'Success'}
</Text>
</div>
<Text size='sm' className='font-bold text-white'>
{toast.message}
</Text>
{!isError && toast.accountId && (
<Text className='mb-1 font-bold text-white'>{`Credit Account ${toast.accountId}`}</Text>
)}
{toast.message && (
<Text size='sm' className='text-white'>
{toast.message}
</Text>
)}
{!isError && toast.content?.length > 0 && generateToastContent(toast.content)}
{toast.hash && (
<TextLink
href={`${EXPLORER_TX_URL}${toast.hash}`}
target='_blank'
className={classNames(
'leading-4 underline mt-4 hover:no-underline hover:text-white',
isError ? 'text-error' : 'text-success',
)}
title={`View on ${EXPLORER_NAME}`}
>
{`View on ${EXPLORER_NAME}`}
<ExternalLink className='-mt-0.5 ml-2 inline w-3.5' />
</TextLink>
<div className='w-full'>
<TextLink
href={`${EXPLORER_TX_URL}${toast.hash}`}
target='_blank'
className={classNames(
'leading-4 underline mt-4 hover:no-underline hover:text-white',
isError ? 'text-error' : 'text-success',
)}
title={`View on ${EXPLORER_NAME}`}
>
{`View on ${EXPLORER_NAME}`}
<ExternalLink className='-mt-0.5 ml-2 inline w-3.5' />
</TextLink>
</div>
)}
<div className='absolute right-6 top-8 '>
<Cross className={classNames('h-2 w-2', isError ? 'text-error' : 'text-success')} />

View File

@ -0,0 +1,81 @@
import classNames from 'classnames'
import moment from 'moment'
import Card from 'components/Card'
import Divider from 'components/Divider'
import Text from 'components/Text'
import { TextLink } from 'components/TextLink'
import { generateToastContent } from 'components/Toaster'
import { EXPLORER_TX_URL } from 'constants/explorer'
import { TRANSACTIONS_KEY } from 'constants/localStore'
import useLocalStorage from 'hooks/useLocalStorage'
import useStore from 'store'
export default function RecentTransactions() {
const address = useStore((s) => s.address)
const [transactions, setTransactions] = useLocalStorage<ToastStore>(TRANSACTIONS_KEY, {
recent: [],
})
const recentTransactions = transactions.recent
.filter((tx) => tx.address === address)
.sort((a, b) => (a.timestamp > b.timestamp ? -1 : 1))
return (
<div className='flex flex-col w-full gap-2 pb-4'>
<Divider className='mb-2' />
<Text size='sm' uppercase className='w-full text-center text-white/70'>
Recent Transactions
</Text>
{recentTransactions.length === 0 ? (
<Text size='sm' className='w-full pt-2 text-center text-white'>
No recent transactions
</Text>
) : (
<>
<div className='px-4 py-2 max-h-[400px] overflow-y-scroll scrollbar-hide'>
<div className='flex flex-col w-full gap-2'>
{recentTransactions.map((tx) => {
const { accountId, hash, content, message, timestamp } = tx
return (
<Card
className={classNames(
hash &&
'transitions-color duration-300 hover:cursor-pointer hover:bg-white/5',
)}
contentClassName='p-4'
onClick={() => {
if (hash) window.open(`${EXPLORER_TX_URL}${hash}`, '_blank')
}}
key={hash}
>
<div className='flex items-start justify-between w-full pb-2'>
<Text className='flex font-bold'>Credit Account {accountId}</Text>
<Text size='sm' className='text-white/70'>
{moment.unix(timestamp).format('lll')}
</Text>
</div>
{message && (
<Text size='sm' className='w-full text-white'>
{message}
</Text>
)}
{content?.length > 0 && generateToastContent(content)}
</Card>
)
})}
</div>
</div>
<div className='w-full pr-4 text-right'>
<TextLink
onClick={() => {
setTransactions({ recent: [] })
}}
className='underline text-white/70 hover:no-underline'
>
Clear all Transactions
</TextLink>
</div>
</>
)}
</div>
)
}

View File

@ -11,6 +11,7 @@ import { FormattedNumber } from 'components/FormattedNumber'
import { Check, Copy, ExternalLink, Osmo } from 'components/Icons'
import Overlay from 'components/Overlay'
import Text from 'components/Text'
import RecentTransactions from 'components/Wallet/RecentTransactions'
import { CHAINS } from 'constants/chains'
import { IS_TESTNET } from 'constants/env'
import { BN_ZERO } from 'constants/math'
@ -171,6 +172,7 @@ export default function WalletConnectedButton() {
</div>
</div>
</div>
<RecentTransactions />
</Overlay>
</div>
)

View File

@ -7,3 +7,4 @@ export const AUTO_LEND_ENABLED_ACCOUNT_IDS_KEY = 'autoLendEnabledAccountIds'
export const SLIPPAGE_KEY = 'slippage'
export const TERMS_OF_SERVICE_KEY = 'termsOfService'
export const TUTORIAL_KEY = 'tutorial'
export const TRANSACTIONS_KEY = 'transactions'

View File

@ -40,6 +40,7 @@ export default function useAutoLend(): {
const setOfAccountIds = new Set(autoLendEnabledAccountIds)
if (!setOfAccountIds.has(accountId)) setOfAccountIds.add(accountId)
setAutoLendEnabledAccountIds(Array.from(setOfAccountIds))
}
return {

View File

@ -0,0 +1,21 @@
import { TRANSACTIONS_KEY } from 'constants/localStore'
import useLocalStorage from 'hooks/useLocalStorage'
export default function useTransactionStore(): {
transactions: ToastStore
addTransaction: (transaction: ToastSuccess) => void
} {
const [transactions, setTransactions] = useLocalStorage<ToastStore>(TRANSACTIONS_KEY, {
recent: [],
})
const recentTransactions = transactions.recent
const addTransaction = (transaction: ToastSuccess) => {
recentTransactions.push(transaction)
setTransactions({ recent: recentTransactions })
}
return {
transactions,
addTransaction,
}
}

View File

@ -1,4 +1,5 @@
import { MsgExecuteContract } from '@delphi-labs/shuttle-react'
import moment from 'moment'
import { isMobile } from 'react-device-detect'
import { GetState, SetState } from 'zustand'
@ -20,6 +21,27 @@ import { formatAmountWithSymbol } from 'utils/formatters'
import getTokenOutFromSwapResponse from 'utils/getTokenOutFromSwapResponse'
import { BN } from 'utils/helpers'
interface HandleResponse {
response: BroadcastResult
action:
| 'deposit'
| 'withdraw'
| 'borrow'
| 'repay'
| 'vault'
| 'lend'
| 'create'
| 'delete'
| 'claim'
| 'unlock'
| 'swap'
lend?: boolean
accountId?: string
changes?: { debts?: BNCoin[]; deposits?: BNCoin[]; lends?: BNCoin[] }
target?: 'wallet' | 'account'
message?: string
}
function generateExecutionMessage(
sender: string | undefined = '',
contract: string,
@ -38,28 +60,93 @@ export default function createBroadcastSlice(
set: SetState<Store>,
get: GetState<Store>,
): BroadcastSlice {
const handleResponseMessages = (
response: BroadcastResult,
successMessage: string,
errorMessage?: string,
) => {
if (response.result?.response.code === 0) {
const handleResponseMessages = (props: HandleResponse) => {
const { accountId, response, action, lend, changes, target, message } = props
if (response.error || response.result?.response.code !== 0) {
set({
toast: {
message: successMessage,
hash: response.result.hash,
},
})
} else {
set({
toast: {
message: generateErrorMessage(response, errorMessage),
message: generateErrorMessage(response),
isError: true,
hash: response.result?.hash,
},
})
return
}
const toast: ToastResponse = {
accountId: accountId,
isError: false,
hash: response?.result?.hash,
content: [],
timestamp: moment().unix(),
address: get().address ?? '',
}
if (message) {
toast.message = message
set({ toast })
return
}
if (!changes) return
switch (action) {
case 'borrow':
const borrowCoin = changes.debts ? [changes.debts[0].toCoin()] : []
const action = lend ? 'Borrowed and lend' : 'Borrowed'
toast.content.push({
coins: borrowCoin,
text: target === 'wallet' ? 'Borrowed to wallet' : action,
})
break
case 'withdraw':
toast.content.push({
coins: changes.deposits?.map((deposit) => deposit.toCoin()) ?? [],
text: target === 'wallet' ? 'Withdrew to Wallet' : 'Withdrew from lend',
})
break
case 'deposit':
toast.content.push({
coins: changes.deposits?.map((deposit) => deposit.toCoin()) ?? [],
text: lend ? 'Deposited and lent' : 'Deposited',
})
break
case 'lend':
const lendCoin = changes.lends ? [changes.lends[0].toCoin()] : []
toast.content.push({
coins: lendCoin,
text: 'Lent',
})
break
case 'repay':
const repayCoin = changes.deposits ? [changes.deposits[0].toCoin()] : []
toast.content.push({
coins: repayCoin,
text: 'Repayed',
})
break
case 'vault':
toast.message = 'Add to Vault Position'
toast.content.push({
coins: changes.debts?.map((debt) => debt.toCoin()) ?? [],
text: 'Borrowed for the Vault Position',
})
toast.content.push({
coins: changes.deposits?.map((deposit) => deposit.toCoin()) ?? [],
text: 'Withdrew for the Vault Position',
})
}
set({ toast })
return
}
const getEstimatedFee = async (messages: MsgExecuteContract[]) => {
if (!get().client) {
return defaultFee
@ -115,12 +202,15 @@ export default function createBroadcastSlice(
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
})
handleResponseMessages(
handleResponseMessages({
response,
`Borrowed ${formatAmountWithSymbol(options.coin.toCoin())} to ${
options.borrowToWallet ? 'Wallet' : `Credit Account ${options.accountId}`
}`,
)
action: 'borrow',
lend: checkAutoLendEnabled(options.accountId),
target: options.borrowToWallet ? 'wallet' : 'account',
accountId: options.accountId,
changes: { debts: [options.coin] },
})
return !!response.result
},
createAccount: async () => {
@ -132,25 +222,24 @@ export default function createBroadcastSlice(
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
})
if (response.result && !response.error) {
set({ createAccountModal: false })
const id = getSingleValueFromBroadcastResult(response.result, 'wasm', 'token_id')
set({ createAccountModal: false })
const id = response.result
? getSingleValueFromBroadcastResult(response.result, 'wasm', 'token_id')
: null
handleResponseMessages({
response,
action: 'create',
accountId: id ?? undefined,
message: id ? `Created the Credit Account` : undefined,
})
if (id)
set({
fundAccountModal: true,
toast: { message: `Credit Account ${id} created`, hash: response.result.hash },
})
return id
} else {
set({
createAccountModal: false,
toast: {
message: generateErrorMessage(response),
hash: response?.result?.hash,
isError: true,
},
})
return null
}
return id
},
deleteAccount: async (options: { accountId: string; lends: BNCoin[] }) => {
const reclaimMsg = options.lends.map((coin) => {
@ -179,7 +268,12 @@ export default function createBroadcastSlice(
],
})
handleResponseMessages(response, `Credit Account ${options.accountId} deleted`)
handleResponseMessages({
response,
action: 'delete',
accountId: options.accountId,
message: `Deleted the Credit Account`,
})
return !!response.result
},
@ -205,9 +299,13 @@ export default function createBroadcastSlice(
messages,
})
const successMessage = `Claimed rewards for, ${options.accountId}`
handleResponseMessages({
response,
action: 'create',
accountId: options.accountId,
message: `Claimed rewards`,
})
handleResponseMessages(response, successMessage)
return !!response.result
}
@ -237,15 +335,14 @@ export default function createBroadcastSlice(
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, funds)],
})
const depositString = options.coins
.map((coin) => formatAmountWithSymbol(coin.toCoin()))
.join(' and ')
handleResponseMessages(
handleResponseMessages({
response,
`Deposited ${options.lend ? 'and lent ' : ''}${depositString} to Credit Account ${
options.accountId
}`,
)
action: 'deposit',
lend: options.lend,
accountId: options.accountId,
changes: { deposits: options.coins },
})
return !!response.result
},
unlock: async (options: { accountId: string; vault: DepositedVault; amount: string }) => {
@ -267,7 +364,12 @@ export default function createBroadcastSlice(
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
})
handleResponseMessages(response, `Requested unlock for ${options.vault.name}`)
handleResponseMessages({
response,
action: 'unlock',
accountId: options.accountId,
message: `Requested unlock for ${options.vault.name}`,
})
return !!response.result
},
@ -307,13 +409,20 @@ export default function createBroadcastSlice(
})
const vaultsString = options.vaults.length === 1 ? 'vault' : 'vaults'
handleResponseMessages(
handleResponseMessages({
response,
`You successfully withdrew ${options.vaults.length} unlocked ${vaultsString} to your account`,
)
action: 'withdraw',
accountId: options.accountId,
message: `Withdrew ${options.vaults.length} unlocked ${vaultsString} to the account`,
})
return !!response.result
},
depositIntoVault: async (options: { accountId: string; actions: Action[] }) => {
depositIntoVault: async (options: {
accountId: string
actions: Action[]
deposits: BNCoin[]
borrowings: BNCoin[]
}) => {
const msg: CreditManagerExecuteMsg = {
update_credit_account: {
account_id: options.accountId,
@ -325,7 +434,13 @@ export default function createBroadcastSlice(
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
})
handleResponseMessages(response, `Deposited into vault`)
handleResponseMessages({
response,
action: 'vault',
accountId: options.accountId,
changes: { deposits: options.deposits, debts: options.borrowings },
})
return !!response.result
},
withdraw: async (options: {
@ -355,13 +470,14 @@ export default function createBroadcastSlice(
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
})
const withdrawString = options.coins
.map(({ coin }) => formatAmountWithSymbol(coin.toCoin()))
.join('and ')
handleResponseMessages(
handleResponseMessages({
response,
`Withdrew ${withdrawString} from Credit Account ${options.accountId}`,
)
action: 'withdraw',
target: 'wallet',
accountId: options.accountId,
changes: { deposits: options.coins.map((coin) => coin.coin) },
})
return !!response.result
},
repay: async (options: {
@ -392,12 +508,13 @@ export default function createBroadcastSlice(
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
})
handleResponseMessages(
handleResponseMessages({
response,
`Repayed ${formatAmountWithSymbol(options.coin.toCoin())} to Credit Account ${
options.accountId
}`,
)
action: 'repay',
accountId: options.accountId,
changes: { deposits: [options.coin] },
})
return !!response.result
},
lend: async (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => {
@ -416,10 +533,13 @@ export default function createBroadcastSlice(
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
})
handleResponseMessages(
handleResponseMessages({
response,
`Successfully lent ${formatAmountWithSymbol(options.coin.toCoin())}`,
)
action: 'lend',
accountId: options.accountId,
changes: { lends: [options.coin] },
})
return !!response.result
},
reclaim: async (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => {
@ -438,10 +558,14 @@ export default function createBroadcastSlice(
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
})
handleResponseMessages(
handleResponseMessages({
response,
`Successfully withdrew ${formatAmountWithSymbol(options.coin.toCoin())}`,
)
action: 'withdraw',
target: 'account',
accountId: options.accountId,
changes: { deposits: [options.coin] },
})
return !!response.result
},
swap: (options: {
@ -495,7 +619,12 @@ export default function createBroadcastSlice(
options.coinIn.toCoin(),
)} for ${formatAmountWithSymbol(coinOut)}`
handleResponseMessages(response, successMessage)
handleResponseMessages({
response,
action: 'swap',
message: successMessage,
accountId: options.accountId,
})
return !!response.result
}

View File

@ -11,6 +11,30 @@ interface ExecutableTx {
estimateFee: () => Promise<StdFee>
}
type ToastResponse = {
hash?: string
title?: string
} & (ToastSuccess | ToastError)
interface ToastSuccess {
accountId?: string
content: { coins: Coin[]; text: string }[]
isError: false
message?: string
timestamp: number
address: string
hash: string
}
interface ToastError {
message: string
isError: true
}
interface ToastStore {
recent: ToastSuccess[]
}
interface BroadcastSlice {
borrow: (options: {
accountId: string
@ -21,7 +45,12 @@ interface BroadcastSlice {
createAccount: () => Promise<string | null>
deleteAccount: (options: { accountId: string; lends: BNCoin[] }) => Promise<boolean>
deposit: (options: { accountId: string; coins: BNCoin[]; lend: boolean }) => Promise<boolean>
depositIntoVault: (options: { accountId: string; actions: Action[] }) => Promise<boolean>
depositIntoVault: (options: {
accountId: string
actions: Action[]
deposits: BNCoin[]
borrowings: BNCoin[]
}) => Promise<boolean>
executeMsg: (options: { messages: MsgExecuteContract[] }) => Promise<BroadcastResult>
lend: (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => Promise<boolean>
reclaim: (options: { accountId: string; coin: BNCoin; isMax?: boolean }) => Promise<boolean>
@ -40,7 +69,7 @@ interface BroadcastSlice {
slippage: number
isMax?: boolean
}) => ExecutableTx
toast: { message: string; isError?: boolean; title?: string; hash?: string } | null
toast: ToastResponse | null
unlock: (options: {
accountId: string
vault: DepositedVault

View File

@ -1,6 +1,7 @@
import BigNumber from 'bignumber.js'
import moment from 'moment'
import { ASSETS } from 'constants/assets'
import { BN_ZERO } from 'constants/math'
import { ORACLE_DENOM } from 'constants/oracle'
import { BNCoin } from 'types/classes/BNCoin'
@ -149,12 +150,12 @@ export function formatPercent(percent: number | string, minDecimals?: number) {
}
export function formatAmountWithSymbol(coin: Coin) {
const marketAssets = getEnabledMarketAssets()
const asset = marketAssets.find((asset) => asset.denom === coin.denom)
const asset = ASSETS.find((asset) => asset.denom === coin.denom)
return formatValue(coin.amount, {
decimals: asset?.decimals,
maxDecimals: asset?.decimals,
minDecimals: 0,
suffix: ` ${asset?.symbol}`,
abbreviated: true,
rounded: true,