Skip to content
This repository has been archived by the owner on Oct 10, 2023. It is now read-only.

Commit

Permalink
[Deposit] Refactor fee + min. value handling (#1404)
Browse files Browse the repository at this point in the history
- [x] Refactor `symDeposit$`
- [x] Update types for sym deposit fees
- [x] Update `SymDeposit`
- [x] Helpers in `Deposit.helper`:  `priceFeeAmountForAsset`, `minAssetAmountToDepositMax1e8`, `sumFees`, `minRuneAmountToDeposit` (tests will be added with next PR - see #1409)
- [x] Add `poolsData: PoolsDataMap` to `poolsState$`
- [x] Update `AssetCard` to show deposit `minValue` 
- [x] Improvements for `Swap`
  • Loading branch information
veado authored May 10, 2021
1 parent 8676f59 commit a7cd753
Show file tree
Hide file tree
Showing 24 changed files with 560 additions and 517 deletions.
2 changes: 1 addition & 1 deletion src/renderer/components/deposit/Deposit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export const Deposit: React.FC<Props> = (props) => {
// content: <AsymWidthdrawContent asset={asset} poolShare={asymPoolShareAsset} />
// }
],
[intl, assetWD, SymDepositContent, hasSymPoolShare, WidthdrawContent, combinedPoolShare, poolDetailRD]
[intl, SymDepositContent, poolDetailRD, assetWD, hasSymPoolShare, WidthdrawContent, combinedPoolShare]
)

const alignTopShareContent: boolean = useMemo(
Expand Down
36 changes: 19 additions & 17 deletions src/renderer/components/deposit/add/Deposit.helper.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import * as RD from '@devexperts/remote-data-ts'
import { PoolData } from '@thorchain/asgardex-util'
import { baseAmount } from '@xchainjs/xchain-util'
import { AssetBNB, baseAmount } from '@xchainjs/xchain-util'
import * as O from 'fp-ts/Option'

import { eqBaseAmount, eqOptionBaseAmount } from '../../../helpers/fp/eq'
import { DepositFeesRD } from '../../../services/chain/types'
import { eqBaseAmount, eqODepositAssetFees, eqODepositFees } from '../../../helpers/fp/eq'
import { DepositAssetFees, DepositFees, SymDepositFeesRD } from '../../../services/chain/types'
import {
getAssetAmountToDeposit,
getRuneAmountToDeposit,
Expand Down Expand Up @@ -80,26 +80,28 @@ describe('deposit/Deposit.helper', () => {
})

describe('fees getters', () => {
const depositFeesRD: DepositFeesRD = RD.success({
thor: O.some(baseAmount(100)),
asset: baseAmount(123)
const runeFee: DepositFees = { inFee: baseAmount(10), outFee: baseAmount(11), refundFee: baseAmount(12) }
const assetFee: DepositAssetFees = {
inFee: baseAmount(20),
outFee: baseAmount(21),
refundFee: baseAmount(22),
asset: AssetBNB
}
const feesRD: SymDepositFeesRD = RD.success({
rune: runeFee,
asset: assetFee
})

it('should return chain fees', () => {
expect(eqOptionBaseAmount.equals(getAssetChainFee(depositFeesRD), O.some(baseAmount(123)))).toBeTruthy()
const result = getAssetChainFee(feesRD)
const expected = O.some(assetFee)
expect(eqODepositAssetFees.equals(result, expected)).toBeTruthy()
})

it('should return ThorChain fees', () => {
expect(eqOptionBaseAmount.equals(getThorchainFees(depositFeesRD), O.some(baseAmount(100)))).toBeTruthy()

expect(
getThorchainFees(
RD.success({
thor: O.none,
asset: baseAmount(123)
})
)
).toBeNone()
const result = getThorchainFees(feesRD)
const expected = O.some(runeFee)
expect(eqODepositFees.equals(result, expected)).toBeTruthy()
})
})
})
123 changes: 116 additions & 7 deletions src/renderer/components/deposit/add/Deposit.helper.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import * as RD from '@devexperts/remote-data-ts'
import { PoolData } from '@thorchain/asgardex-util'
import { baseAmount, BaseAmount } from '@xchainjs/xchain-util'
import { getValueOfAsset1InAsset2, PoolData } from '@thorchain/asgardex-util'
import { Asset, assetToString, baseAmount, BaseAmount } from '@xchainjs/xchain-util'
import BigNumber from 'bignumber.js'
import * as FP from 'fp-ts/function'
import * as O from 'fp-ts/Option'

import {
convertBaseAmountDecimal,
isChainAsset,
max1e8BaseAmount,
THORCHAIN_DECIMAL,
to1e8BaseAmount
} from '../../../helpers/assetHelper'
import { DepositFeesRD } from '../../../services/chain/types'
import { sequenceTOption } from '../../../helpers/fpHelpers'
import { DepositAssetFees, DepositFees, SymDepositFeesRD } from '../../../services/chain/types'
import { PoolsDataMap } from '../../../services/midgard/types'

/**
* Calculates max. value of RUNE to deposit
Expand Down Expand Up @@ -124,16 +127,122 @@ export const getAssetAmountToDeposit = ({
return max1e8BaseAmount(assetAmountToDeposit)
}

export const getAssetChainFee = (feesRD: DepositFeesRD): O.Option<BaseAmount> =>
export const getAssetChainFee = (feesRD: SymDepositFeesRD): O.Option<DepositAssetFees> =>
FP.pipe(
feesRD,
RD.map(({ asset }) => asset),
RD.toOption
)

export const getThorchainFees = (feesRD: DepositFeesRD): O.Option<BaseAmount> =>
export const getThorchainFees = (feesRD: SymDepositFeesRD): O.Option<DepositFees> =>
FP.pipe(
feesRD,
RD.map(({ thor }) => thor),
FP.flow(RD.toOption, O.flatten)
RD.map(({ rune }) => rune),
RD.toOption
)

export const sumFees = ({ inFee, outFee }: { inFee: BaseAmount; outFee: BaseAmount }) => inFee.plus(outFee)

export const priceFeeAmountForAsset = ({
feeAmount,
feeAsset,
asset,
assetDecimal,
poolsData
}: {
feeAmount: BaseAmount
feeAsset: Asset
asset: Asset
assetDecimal: number
poolsData: PoolsDataMap
}): BaseAmount => {
const oFeeAssetPoolData: O.Option<PoolData> = O.fromNullable(poolsData[assetToString(feeAsset)])
const oAssetPoolData: O.Option<PoolData> = O.fromNullable(poolsData[assetToString(asset)])

return FP.pipe(
sequenceTOption(oFeeAssetPoolData, oAssetPoolData),
O.map(([feeAssetPoolData, assetPoolData]) =>
// pool data are always 1e8 decimal based
// and we have to convert fees to 1e8, too
getValueOfAsset1InAsset2(to1e8BaseAmount(feeAmount), feeAssetPoolData, assetPoolData)
),
// convert decimal back to sourceAssetDecimal
O.map((amount) => convertBaseAmountDecimal(amount, feeAmount.decimal)),
O.map((amount) => convertBaseAmountDecimal(amount, assetDecimal)),
O.getOrElse(() => baseAmount(0, assetDecimal))
)
}

export const minAssetAmountToDepositMax1e8 = ({
fees,
asset,
assetDecimal,
poolsData
}: {
/* fee for deposit */
fees: DepositAssetFees
/* asset to deposit */
asset: Asset
assetDecimal: number
poolsData: PoolsDataMap
}): BaseAmount => {
const { asset: feeAsset, inFee, outFee, refundFee } = fees

const inFeeInAsset = isChainAsset(asset)
? inFee
: priceFeeAmountForAsset({
feeAmount: inFee,
feeAsset,
asset,
assetDecimal,
poolsData
})

const outFeeInAsset = isChainAsset(asset)
? outFee
: priceFeeAmountForAsset({
feeAmount: outFee,
feeAsset,
asset,
assetDecimal,
poolsData
})

const refundFeeInAsset = isChainAsset(asset)
? refundFee
: priceFeeAmountForAsset({
feeAmount: refundFee,
feeAsset,
asset,
assetDecimal,
poolsData
})

const successDepositFee = inFeeInAsset.plus(outFeeInAsset)
const failureDepositFee = inFeeInAsset.plus(refundFeeInAsset)

const feeToCover: BaseAmount = successDepositFee.gte(failureDepositFee) ? successDepositFee : failureDepositFee

return FP.pipe(
// Over-estimate fee by 50%
1.5,
feeToCover.times,
// transform decimal to be `max1e8`
max1e8BaseAmount
)
}

export const minRuneAmountToDeposit = ({ inFee, outFee, refundFee }: DepositFees): BaseAmount => {
const successDepositFee = inFee.plus(outFee)
const failureDepositFee = inFee.plus(refundFee)

const feeToCover: BaseAmount = successDepositFee.gte(failureDepositFee) ? successDepositFee : failureDepositFee

return FP.pipe(
// Over-estimate fee by 50%
1.5,
feeToCover.times,
// transform decimal to be `max1e8`
max1e8BaseAmount
)
}
4 changes: 0 additions & 4 deletions src/renderer/components/deposit/add/Deposit.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,3 @@ export const SubmitButton = styled(UIButton).attrs({
padding-left: 30px;
padding-right: 30px;
`
export const MinAmountLabel = styled(UILabel)`
padding-top: 0;
text-transform: uppercase;
`
36 changes: 30 additions & 6 deletions src/renderer/components/deposit/add/SymDeposit.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
AssetBTC,
AssetRuneNative,
Asset,
AssetETH
AssetETH,
assetToString
} from '@xchainjs/xchain-util'
import * as O from 'fp-ts/lib/Option'
import * as Rx from 'rxjs'
Expand Down Expand Up @@ -55,8 +56,17 @@ const defaultProps: SymDepositProps = {
fees$: () =>
Rx.of(
RD.success({
thor: O.some(assetToBase(assetAmount(0.2))),
asset: assetToBase(assetAmount(0.000075))
rune: {
inFee: assetToBase(assetAmount(0.2)),
outFee: assetToBase(assetAmount(0.6)),
refundFee: assetToBase(assetAmount(0.6))
},
asset: {
asset: AssetBNB,
inFee: assetToBase(assetAmount(0.000075)),
outFee: assetToBase(assetAmount(0.000225)),
refundFee: assetToBase(assetAmount(0.000225))
}
})
),
reloadApproveFee: () => console.log('reloadFees'),
Expand Down Expand Up @@ -98,7 +108,12 @@ const defaultProps: SymDepositProps = {
approveERC20Token$: () => Rx.of(RD.success('txHash')),
isApprovedERC20Token$: () => Rx.of(RD.success(true)),
fundsCap: O.none,
usdPricePool: O.none
poolsData: {
[assetToString(AssetBNB)]: {
assetBalance: baseAmount(1),
runeBalance: baseAmount(20)
}
}
}

export const Default: Story = () => <SymDeposit {...defaultProps} />
Expand All @@ -122,8 +137,17 @@ export const FeeError: Story = () => {
fees$: () =>
Rx.of(
RD.success({
thor: O.some(assetToBase(assetAmount(2))),
asset: assetToBase(assetAmount(1))
rune: {
inFee: assetToBase(assetAmount(2)),
outFee: assetToBase(assetAmount(6)),
refundFee: assetToBase(assetAmount(6))
},
asset: {
asset: AssetBNB,
inFee: assetToBase(assetAmount(1)),
outFee: assetToBase(assetAmount(3)),
refundFee: assetToBase(assetAmount(3))
}
})
),
assetBalance: O.some(assetToBase(assetAmount(0.5))),
Expand Down
Loading

0 comments on commit a7cd753

Please sign in to comment.