Skip to content

Commit

Permalink
fix: fallback fees for doge (#5853)
Browse files Browse the repository at this point in the history
  • Loading branch information
kaladinlight authored Dec 13, 2023
1 parent 8c02b07 commit ffbd40d
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 32 deletions.
29 changes: 8 additions & 21 deletions packages/chain-adapters/src/utxo/UtxoBaseAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,38 +383,25 @@ export abstract class UtxoBaseAdapter<T extends UtxoChainId> implements IChainAd
throw new Error('UtxoBaseAdapter: failed to get fee data')
}

// TODO: when does this happen and why?
if (!data.fast?.satsPerKiloByte || data.fast.satsPerKiloByte < 0) {
data.fast = data.average
}
// ensure higher confirmation speeds never have lower fees than lower confirmation speeds
if (data.slow.satsPerKiloByte > data.average.satsPerKiloByte)
data.average.satsPerKiloByte = data.slow.satsPerKiloByte
if (data.average.satsPerKiloByte > data.fast.satsPerKiloByte)
data.fast.satsPerKiloByte = data.average.satsPerKiloByte

const utxos = await this.providers.http.getUtxos({ pubkey })

const utxoSelectInput = { from, to, value, opReturnData, utxos, sendMax }

// We have to round because coinselect library uses sats per byte which cant be decimals
const fastPerByte = String(Math.round(data.fast.satsPerKiloByte / 1024))
const averagePerByte = String(Math.round(data.average.satsPerKiloByte / 1024))
const slowPerByte = String(Math.round(data.slow.satsPerKiloByte / 1024))
const fastPerByte = String(Math.round(data.fast.satsPerKiloByte / 1000))
const averagePerByte = String(Math.round(data.average.satsPerKiloByte / 1000))
const slowPerByte = String(Math.round(data.slow.satsPerKiloByte / 1000))

const { fee: fastFee } = utxoSelect({ ...utxoSelectInput, satoshiPerByte: fastPerByte })
const { fee: averageFee } = utxoSelect({ ...utxoSelectInput, satoshiPerByte: averagePerByte })
const { fee: slowFee } = utxoSelect({ ...utxoSelectInput, satoshiPerByte: slowPerByte })

// Special, temporary case for DOGE to provide a workable fee value when the node is struggling
const isDoge = pubkey.startsWith('dgub')
const allFeesDefined =
fastFee !== undefined && averageFee !== undefined && slowFee !== undefined
if (isDoge && !allFeesDefined) {
const satoshiPerByte = '20000'
const fee = utxoSelect({ ...utxoSelectInput, satoshiPerByte }).fee
return {
fast: { txFee: String(fee), chainSpecific: { satoshiPerByte } },
average: { txFee: String(fee), chainSpecific: { satoshiPerByte } },
slow: { txFee: String(fee), chainSpecific: { satoshiPerByte } },
} as FeeDataEstimate<T>
}

return {
fast: { txFee: String(fastFee), chainSpecific: { satoshiPerByte: fastPerByte } },
average: { txFee: String(averageFee), chainSpecific: { satoshiPerByte: averagePerByte } },
Expand Down
52 changes: 52 additions & 0 deletions packages/chain-adapters/src/utxo/dogecoin/DogecoinChainAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import type { BIP44Params } from '@shapeshiftoss/types'
import { KnownChainIds, UtxoAccountType } from '@shapeshiftoss/types'
import * as unchained from '@shapeshiftoss/unchained-client'

import type { FeeDataEstimate, GetFeeDataInput } from '../../types'
import { ChainAdapterDisplayName } from '../../types'
import type { ChainAdapterArgs } from '../UtxoBaseAdapter'
import { UtxoBaseAdapter } from '../UtxoBaseAdapter'
import { utxoSelect } from '../utxoSelect'

const SUPPORTED_CHAIN_IDS = [KnownChainIds.DogecoinMainnet]
const DEFAULT_CHAIN_ID = KnownChainIds.DogecoinMainnet
Expand Down Expand Up @@ -54,4 +56,54 @@ export class ChainAdapter extends UtxoBaseAdapter<KnownChainIds.DogecoinMainnet>
getFeeAssetId(): AssetId {
return this.assetId
}

async getFeeData({
to,
value,
chainSpecific: { from, pubkey, opReturnData },
sendMax = false,
}: GetFeeDataInput<KnownChainIds.DogecoinMainnet>): Promise<
FeeDataEstimate<KnownChainIds.DogecoinMainnet>
> {
if (!to) throw new Error('to is required')
if (!value) throw new Error('value is required')
if (!pubkey) throw new Error('pubkey is required')

const { fast, average, slow } = await this.providers.http.getNetworkFees()

if (!(fast?.satsPerKiloByte && average?.satsPerKiloByte && slow?.satsPerKiloByte)) {
throw new Error('UtxoBaseAdapter: failed to get fee data')
}

// sane default for invalid fee data from the node
// see: https://github.com/dogecoin/dogecoin/issues/3385
if (fast.satsPerKiloByte <= 0) fast.satsPerKiloByte = 500000000 // 5 DOGE per kB
if (average.satsPerKiloByte <= 0) average.satsPerKiloByte = 100000000 // 1 DOGE per kB
if (slow.satsPerKiloByte <= 0) slow.satsPerKiloByte = 50000000 // .5 DOGE per kB

// ensure higher confirmation speeds never have lower fees than lower confirmation speeds
if (slow.satsPerKiloByte > average.satsPerKiloByte)
average.satsPerKiloByte = slow.satsPerKiloByte
if (average.satsPerKiloByte > fast.satsPerKiloByte)
fast.satsPerKiloByte = average.satsPerKiloByte

const utxos = await this.providers.http.getUtxos({ pubkey })

const utxoSelectInput = { from, to, value, opReturnData, utxos, sendMax }

// We have to round because coinselect library uses sats per byte which cant be decimals
const fastPerByte = String(Math.round(fast.satsPerKiloByte / 1000))
const averagePerByte = String(Math.round(average.satsPerKiloByte / 1000))
const slowPerByte = String(Math.round(slow.satsPerKiloByte / 1000))

const { fee: fastFee } = utxoSelect({ ...utxoSelectInput, satoshiPerByte: fastPerByte })
const { fee: averageFee } = utxoSelect({ ...utxoSelectInput, satoshiPerByte: averagePerByte })
const { fee: slowFee } = utxoSelect({ ...utxoSelectInput, satoshiPerByte: slowPerByte })

return {
fast: { txFee: String(fastFee), chainSpecific: { satoshiPerByte: fastPerByte } },
average: { txFee: String(averageFee), chainSpecific: { satoshiPerByte: averagePerByte } },
slow: { txFee: String(slowFee), chainSpecific: { satoshiPerByte: slowPerByte } },
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ export const AssetChainDropdown: React.FC<ChainDropdownProps> = ({
borderRadius='full'
color='text.base'
isDisabled
variant='ghost'
isLoading={isLoading}
variant={!isLoading ? 'ghost' : undefined}
_disabled={disabled}
_hover={hover}
{...buttonProps}
Expand Down
11 changes: 9 additions & 2 deletions src/components/MultiHopTrade/components/AssetSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const TradeAssetAwaitingAsset = () => {
type TradeAssetSelectProps = {
assetId?: AssetId
isReadOnly?: boolean
isLoading: boolean
onAssetClick?: () => void
onAssetChange: (asset: Asset) => void
}
Expand All @@ -40,11 +41,16 @@ export const TradeAssetSelectWithAsset: React.FC<TradeAssetSelectProps> = ({
onAssetChange,
assetId,
isReadOnly,
isLoading,
}) => {
const assets = useAppSelector(selectAssets)
const asset = useAppSelector(state => selectAssetById(state, assetId ?? ''))

const { data, isLoading, isError } = useGetRelatedAssetIdsQuery(assetId ?? '')
const {
data,
isLoading: isRelatedAssetsLoading,
isError,
} = useGetRelatedAssetIdsQuery(assetId ?? '')

const handleAssetChange = useCallback(
(assetId: AssetId) => {
Expand Down Expand Up @@ -80,6 +86,7 @@ export const TradeAssetSelectWithAsset: React.FC<TradeAssetSelectProps> = ({
isDisabled={isReadOnly}
_disabled={disabledStyle}
rightIcon={rightIcon}
isLoading={isLoading || isRelatedAssetsLoading}
>
{icon}
{asset?.symbol}
Expand All @@ -89,7 +96,7 @@ export const TradeAssetSelectWithAsset: React.FC<TradeAssetSelectProps> = ({
assetIds={data}
assetId={assetId}
onClick={handleAssetChange}
isLoading={isLoading}
isLoading={isLoading || isRelatedAssetsLoading}
isError={isError}
/>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -557,9 +557,10 @@ export const TradeInput = memo(() => {
assetId={sellAsset.assetId}
onAssetClick={handleSellAssetClick}
onAssetChange={setSellAsset}
isLoading={isSupportedAssetsLoading}
/>
),
[handleSellAssetClick, sellAsset.assetId, setSellAsset],
[handleSellAssetClick, isSupportedAssetsLoading, sellAsset.assetId, setSellAsset],
)

const buyTradeAssetSelect = useMemo(
Expand All @@ -568,9 +569,10 @@ export const TradeInput = memo(() => {
assetId={buyAsset.assetId}
onAssetClick={handleBuyAssetClick}
onAssetChange={setBuyAsset}
isLoading={isSupportedAssetsLoading}
/>
),
[buyAsset.assetId, handleBuyAssetClick, setBuyAsset],
[buyAsset.assetId, handleBuyAssetClick, isSupportedAssetsLoading, setBuyAsset],
)

return (
Expand Down
14 changes: 11 additions & 3 deletions src/pages/Lending/Pool/components/Borrow/BorrowInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ export const BorrowInput = ({
const translate = useTranslate()
const history = useHistory()

const { data: borrowAssets } = useLendingSupportedAssets({ type: 'borrow' })
const { data: borrowAssets, isLoading: isLendingSupportedAssetsLoading } =
useLendingSupportedAssets({ type: 'borrow' })

const collateralAsset = useAppSelector(state => selectAssetById(state, collateralAssetId))

Expand Down Expand Up @@ -346,19 +347,26 @@ export const BorrowInput = ({
onAssetClick={noop}
onAssetChange={handleAssetChange}
isReadOnly
isLoading={isLendingSupportedAssetsLoading}
/>
)
}, [collateralAssetId, handleAssetChange])
}, [collateralAssetId, handleAssetChange, isLendingSupportedAssetsLoading])

const borrowAssetSelectComponent = useMemo(() => {
return (
<TradeAssetSelect
assetId={borrowAsset?.assetId ?? ''}
onAssetClick={handleBorrowAssetClick}
onAssetChange={handleAssetChange}
isLoading={isLendingSupportedAssetsLoading}
/>
)
}, [borrowAsset?.assetId, handleAssetChange, handleBorrowAssetClick])
}, [
borrowAsset?.assetId,
handleAssetChange,
handleBorrowAssetClick,
isLendingSupportedAssetsLoading,
])

const quoteErrorTranslation = useMemo(() => {
if (_isSmartContractAddress) return 'trade.errors.smartContractWalletNotSupported'
Expand Down
19 changes: 16 additions & 3 deletions src/pages/Lending/Pool/components/Repay/RepayInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ export const RepayInput = ({

const swapIcon = useMemo(() => <ArrowDownIcon />, [])

const { data: lendingSupportedAssets } = useLendingSupportedAssets({ type: 'borrow' })
const { data: lendingSupportedAssets, isLoading: isLendingSupportedAssetsLoading } =
useLendingSupportedAssets({ type: 'borrow' })

useEffect(() => {
if (!(lendingSupportedAssets && collateralAsset)) return
Expand Down Expand Up @@ -159,9 +160,15 @@ export const RepayInput = ({
// Users have the possibility to repay in any supported asset, not only their collateral/borrowed asset
// https://docs.thorchain.org/thorchain-finance/lending#loan-repayment-closeflow
isReadOnly={false}
isLoading={isLendingSupportedAssetsLoading}
/>
)
}, [handleAssetChange, handleRepaymentAssetClick, repaymentAsset?.assetId])
}, [
handleAssetChange,
handleRepaymentAssetClick,
isLendingSupportedAssetsLoading,
repaymentAsset?.assetId,
])

const collateralAssetSelectComponent = useMemo(() => {
return (
Expand All @@ -170,9 +177,15 @@ export const RepayInput = ({
onAssetClick={handleRepaymentAssetClick}
onAssetChange={handleAssetChange}
isReadOnly
isLoading={isLendingSupportedAssetsLoading}
/>
)
}, [collateralAssetId, handleAssetChange, handleRepaymentAssetClick])
}, [
collateralAssetId,
handleAssetChange,
handleRepaymentAssetClick,
isLendingSupportedAssetsLoading,
])

const handleSeenNotice = useCallback(() => setSeenNotice(true), [])

Expand Down

0 comments on commit ffbd40d

Please sign in to comment.