Skip to content

Commit

Permalink
Swap UI: Refactoring & fixes (#146)
Browse files Browse the repository at this point in the history
* refactoring & fixes

* type fix

* remove unused imports

* wip refactoring views

* refactoring

* fix hasInsufficientXorForFee

Co-authored-by: Stefan Popov <[email protected]>
  • Loading branch information
Nikita-Polyakov and stefashkaa authored Apr 2, 2021
1 parent daedf58 commit 7517aa7
Show file tree
Hide file tree
Showing 12 changed files with 121 additions and 166 deletions.
28 changes: 0 additions & 28 deletions src/components/mixins/InputFormatterMixin.ts

This file was deleted.

5 changes: 3 additions & 2 deletions src/components/mixins/TokenPairMixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const CreateTokenPairMixin = (namespace: string) => {
class TokenPairMixin extends Mixins(TransactionMixin, LoadingMixin, ConfirmDialogMixin) {
readonly KnownSymbols = KnownSymbols

@Getter('tokenXOR', { namespace: 'assets' }) tokenXOR!: any
@Getter('firstToken', { namespace }) firstToken!: any
@Getter('secondToken', { namespace }) secondToken!: any
@Getter('firstTokenValue', { namespace }) firstTokenValue!: number
Expand Down Expand Up @@ -76,11 +77,11 @@ const CreateTokenPairMixin = (namespace: string) => {
}

get isFirstMaxButtonAvailable (): boolean {
return isMaxButtonAvailable(this.areTokensSelected, this.firstToken, this.firstTokenValue, this.fee)
return isMaxButtonAvailable(this.areTokensSelected, this.firstToken, this.firstTokenValue, this.fee, this.tokenXOR)
}

get isSecondMaxButtonAvailable (): boolean {
return isMaxButtonAvailable(this.areTokensSelected, this.secondToken, this.secondTokenValue, this.fee)
return isMaxButtonAvailable(this.areTokensSelected, this.secondToken, this.secondTokenValue, this.fee, this.tokenXOR)
}

get isInsufficientBalance (): boolean {
Expand Down
11 changes: 5 additions & 6 deletions src/store/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import map from 'lodash/fp/map'
import flatMap from 'lodash/fp/flatMap'
import fromPairs from 'lodash/fp/fromPairs'
import flow from 'lodash/fp/flow'
import { Asset, AccountAsset, RegisteredAccountAsset } from '@sora-substrate/util'
import { KnownAssets, KnownSymbols, Asset, AccountAsset, RegisteredAccountAsset } from '@sora-substrate/util'
import { api } from '@soramitsu/soraneo-wallet-web'

import { isXorAccountAsset, findAssetInCollection } from '@/utils'
Expand Down Expand Up @@ -32,11 +32,10 @@ const getters = {
assets (state) {
return state.assets
},
xorAsset (state) {
return api.accountAssets.find(a => isXorAccountAsset(a)) || {}
},
xorBalance (state, getters) {
return getters.xorAsset.balance || 0
tokenXOR (state, getters, rootState, rootGetters) {
const token = KnownAssets.get(KnownSymbols.XOR)

return rootGetters['assets/getAssetDataByAddress'](token?.address)
},
registeredAssets (state) {
return state.registeredAssets
Expand Down
2 changes: 1 addition & 1 deletion src/store/createPair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import fromPairs from 'lodash/fp/fromPairs'
import flow from 'lodash/fp/flow'
import concat from 'lodash/fp/concat'
import { api } from '@soramitsu/soraneo-wallet-web'
import { Asset, AccountAsset, CodecString } from '@sora-substrate/util'
import { CodecString } from '@sora-substrate/util'

import { ZeroStringValue } from '@/consts'

Expand Down
5 changes: 0 additions & 5 deletions src/store/rewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ function initialState (): RewardsState {
const state = initialState()

const getters = {
tokenXOR (state, getters, rootState, rootGetters): AccountAsset {
const token = KnownAssets.get(KnownSymbols.XOR)

return rootGetters['assets/getAssetDataByAddress'](token?.address)
},
claimableRewards (state: RewardsState): Array<RewardInfo> {
return state.rewards.reduce((claimableList: Array<RewardInfo>, item: RewardInfo) => {
if (FPNumber.fromCodecValue(item.amount, item.asset.decimals).isZero()) return claimableList
Expand Down
7 changes: 1 addition & 6 deletions src/store/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import flatMap from 'lodash/fp/flatMap'
import fromPairs from 'lodash/fp/fromPairs'
import flow from 'lodash/fp/flow'
import concat from 'lodash/fp/concat'
import { KnownAssets, KnownSymbols, CodecString } from '@sora-substrate/util'
import { KnownAssets, CodecString } from '@sora-substrate/util'
import { isXorAccountAsset } from '@/utils'

const types = flow(
Expand Down Expand Up @@ -52,11 +52,6 @@ function initialState (): SwapState {
const state = initialState()

const getters = {
tokenXOR (state: SwapState, getters, rootState, rootGetters) {
const token = KnownAssets.get(KnownSymbols.XOR)

return rootGetters['assets/getAssetDataByAddress'](token?.address)
},
tokenFrom (state: SwapState, getters, rootState, rootGetters) {
return rootGetters['assets/getAssetDataByAddress'](state.tokenFromAddress)
},
Expand Down
104 changes: 62 additions & 42 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { EthSymbol } from '@/consts'
import { Asset, AccountAsset, RegisteredAccountAsset, KnownSymbols, FPNumber, CodecString, KnownAssets } from '@sora-substrate/util'
import storage from './storage'

const FpZeroValue = new FPNumber(0)

export const copyToClipboard = async (text: string): Promise<void> => {
try {
return navigator.clipboard.writeText(text)
Expand All @@ -18,54 +19,75 @@ export const isXorAccountAsset = (asset: Asset | AccountAsset | RegisteredAccoun
return asset ? asset.address === KnownAssets.get(KnownSymbols.XOR).address : false
}

export const isMaxButtonAvailable = (areAssetsSelected: boolean, asset: AccountAsset, amount: string | number, fee: CodecString): boolean => {
if (!isWalletConnected() || !areAssetsSelected || +asset.balance === 0) {
export const isMaxButtonAvailable = (
areAssetsSelected: boolean,
asset: AccountAsset | RegisteredAccountAsset,
amount: string | number,
fee: CodecString,
xorAsset: AccountAsset | RegisteredAccountAsset
): boolean => {
if (
!isWalletConnected() ||
!asset ||
!areAssetsSelected ||
!fee ||
!xorAsset ||
asZeroValue(asset.balance)) {
return false
}
const decimals = asset.decimals
const fpBalance = FPNumber.fromCodecValue(asset.balance, decimals)
const fpAmount = new FPNumber(amount, decimals)
if (isXorAccountAsset(asset)) {
if (+fee === 0) {
return false
}
const fpFee = FPNumber.fromCodecValue(fee, decimals)
return !FPNumber.eq(fpFee, fpBalance.sub(fpAmount)) && FPNumber.gt(fpBalance, fpFee)
}
return !FPNumber.eq(fpBalance, fpAmount)
}

export const getMaxValue = (asset: AccountAsset, fee: CodecString, isExternalBalance?: boolean): string => {
const decimals = asset.decimals
const fpBalance = FPNumber.fromCodecValue(asset[isExternalBalance ? 'externalBalance' : 'balance'], decimals)
if (isXorAccountAsset(asset)) {
const fpFee = FPNumber.fromCodecValue(fee, decimals)
return fpBalance.sub(fpFee).toString()
}
return fpBalance.toString()
const fpAmount = new FPNumber(amount, asset.decimals)
const fpMaxBalance = getMaxBalance(asset, fee)

return !FPNumber.eq(fpMaxBalance, fpAmount) && !hasInsufficientXorForFee(xorAsset, fee)
}

export const hasInsufficientBalance = (asset: AccountAsset | RegisteredAccountAsset, amount: string | number, fee: CodecString, isExternalBalance = false): boolean => {
const getMaxBalance = (
asset: AccountAsset | RegisteredAccountAsset,
fee: CodecString,
isExternalBalance = false
): FPNumber => {
const balanceField = isExternalBalance ? 'externalBalance' : 'balance'
if (+asset[balanceField] === 0) {
return true
}
const decimals = asset.decimals
const fpBalance = FPNumber.fromCodecValue(asset[balanceField], decimals)
const fpAmount = new FPNumber(amount, decimals)
if (isXorAccountAsset(asset)) {
const fpFee = FPNumber.fromCodecValue(fee, decimals)
return FPNumber.lt(fpBalance, fpAmount.add(fpFee))

if (!asset || asZeroValue(asset[balanceField])) return FpZeroValue

let fpResult = FPNumber.fromCodecValue(asset[balanceField], asset.decimals)

if (isXorAccountAsset(asset) && !asZeroValue(fee)) {
const fpFee = FPNumber.fromCodecValue(fee, asset.decimals)
fpResult = fpResult.sub(fpFee)
}
return FPNumber.lt(fpBalance, fpAmount)

return FPNumber.lt(fpResult, FpZeroValue) ? FpZeroValue : fpResult
}

export const getMaxValue = (
asset: AccountAsset | RegisteredAccountAsset,
fee: CodecString,
isExternalBalance = false
): string => {
return getMaxBalance(asset, fee, isExternalBalance).toString()
}

export const hasInsufficientXorForFee = (asset: AccountAsset | RegisteredAccountAsset | null, fee: CodecString): boolean => {
if (!asset) return true
export const hasInsufficientBalance = (
asset: AccountAsset | RegisteredAccountAsset,
amount: string | number,
fee: CodecString,
isExternalBalance = false
): boolean => {
const fpAmount = new FPNumber(amount, asset.decimals)
const fpMaxBalance = getMaxBalance(asset, fee, isExternalBalance)

const decimals = asset.decimals
const fpBalance = FPNumber.fromCodecValue(asset.balance, decimals)
return FPNumber.lt(fpMaxBalance, fpAmount)
}

export const hasInsufficientXorForFee = (xorAsset: AccountAsset | RegisteredAccountAsset | null, fee: CodecString): boolean => {
if (!xorAsset || !fee) return true

const decimals = xorAsset.decimals
const fpBalance = FPNumber.fromCodecValue(xorAsset.balance, decimals)
const fpFee = FPNumber.fromCodecValue(fee, decimals)

return FPNumber.lt(fpBalance, fpFee)
}

Expand Down Expand Up @@ -113,10 +135,8 @@ export const formatDateItem = (date: number): number | string => {
return date < 10 ? '0' + date : date
}

// We could use this method to check if the user enters a text value in a numeric field (we could do this by copy and paste)
export const isNumberValue = (value: any): boolean => {
const numberValue = +value
return typeof numberValue === 'number' && !isNaN(numberValue)
export const asZeroValue = (value: any): boolean => {
return !Number.isFinite(+value) || +value === 0
}

export const findAssetInCollection = (asset, collection) => {
Expand Down
6 changes: 2 additions & 4 deletions src/views/Bridge.vue
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ import WalletConnectMixin from '@/components/mixins/WalletConnectMixin'
import NetworkFormatterMixin from '@/components/mixins/NetworkFormatterMixin'
import TranslationMixin from '@/components/mixins/TranslationMixin'
import LoadingMixin from '@/components/mixins/LoadingMixin'
import InputFormatterMixin from '@/components/mixins/InputFormatterMixin'
import NumberFormatterMixin from '@/components/mixins/NumberFormatterMixin'
import router, { lazyComponent } from '@/router'
import { Components, PageNames, EthSymbol, ZeroStringValue } from '@/consts'
Expand All @@ -209,7 +208,6 @@ const namespace = 'bridge'
export default class Bridge extends Mixins(
TranslationMixin,
LoadingMixin,
InputFormatterMixin,
NetworkFormatterMixin,
NumberFormatterMixin,
WalletConnectMixin
Expand All @@ -230,7 +228,7 @@ export default class Bridge extends Mixins(
@Getter('isSoraToEthereum', { namespace }) isSoraToEthereum!: boolean
@Getter('registeredAssets', { namespace: 'assets' }) registeredAssets!: Array<RegisteredAccountAsset>
@Getter('asset', { namespace }) asset!: any
@Getter('xorAsset', { namespace: 'assets' }) xorAsset!: any
@Getter('tokenXOR', { namespace: 'assets' }) tokenXOR!: any
@Getter('amount', { namespace }) amount!: string
@Getter('soraNetworkFee', { namespace }) soraNetworkFee!: CodecString
@Getter('ethereumNetworkFee', { namespace }) ethereumNetworkFee!: string
Expand Down Expand Up @@ -281,7 +279,7 @@ export default class Bridge extends Mixins(
}
get isInsufficientXorForFee (): boolean {
return hasInsufficientXorForFee(this.xorAsset, this.soraNetworkFee)
return hasInsufficientXorForFee(this.tokenXOR, this.soraNetworkFee)
}
get isInsufficientEthereumForFee (): boolean {
Expand Down
4 changes: 2 additions & 2 deletions src/views/BridgeTransaction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export default class BridgeTransaction extends Mixins(WalletConnectMixin, Loadin
@Getter('isSoraToEthereum', { namespace }) isSoraToEthereum!: boolean
@Getter('asset', { namespace }) asset!: AccountAsset | RegisteredAccountAsset | null
@Getter('xorAsset', { namespace: 'assets' }) xorAsset!: any
@Getter('tokenXOR', { namespace: 'assets' }) tokenXOR!: any
@Getter('amount', { namespace }) amount!: string
@Getter('ethBalance', { namespace: 'web3' }) ethBalance!: string | number
@Getter('soraNetworkFee', { namespace }) soraNetworkFee!: CodecString
Expand Down Expand Up @@ -383,7 +383,7 @@ export default class BridgeTransaction extends Mixins(WalletConnectMixin, Loadin
}
get isInsufficientXorForFee (): boolean {
return hasInsufficientXorForFee(this.xorAsset, this.soraNetworkFee)
return hasInsufficientXorForFee(this.tokenXOR, this.soraNetworkFee)
}
get isInsufficientEthereumForFee (): boolean {
Expand Down
27 changes: 9 additions & 18 deletions src/views/RemoveLiquidity.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,16 @@
/>
</div>

<s-button type="primary" border-radius="small" :disabled="isEmptyAmount || isInsufficientBalance" @click="openConfirmDialog">
<s-button type="primary" border-radius="small" :disabled="isEmptyAmount || isInsufficientBalance || isInsufficientXorForFee" @click="openConfirmDialog">
<template v-if="isEmptyAmount">
{{ t('buttons.enterAmount') }}
</template>
<template v-else-if="isInsufficientBalance">
{{ t('exchange.insufficientBalance', { tokenSymbol: t('removeLiquidity.liquidity') }) }}
</template>
<template v-else-if="isInsufficientXorForFee">
{{ t('exchange.insufficientBalance', { tokenSymbol: KnownSymbols.XOR }) }}
</template>
<template v-else>
{{ t('removeLiquidity.remove') }}
</template>
Expand All @@ -164,6 +167,7 @@ import ConfirmDialogMixin from '@/components/mixins/ConfirmDialogMixin'
import router, { lazyComponent } from '@/router'
import { Components, PageNames } from '@/consts'
import { isMaxButtonAvailable, hasInsufficientXorForFee } from '@/utils'
const namespace = 'removeLiquidity'
Expand Down Expand Up @@ -194,8 +198,7 @@ export default class RemoveLiquidity extends Mixins(TransactionMixin, LoadingMix
@Getter('secondTokenAmount', { namespace }) secondTokenAmount!: any
@Getter('secondTokenBalance', { namespace }) secondTokenBalance!: CodecString
@Getter('fee', { namespace }) fee!: CodecString
@Getter('xorBalance', { namespace: 'assets' }) xorBalance!: any
@Getter('xorAsset', { namespace: 'assets' }) xorAsset!: any
@Getter('tokenXOR', { namespace: 'assets' }) tokenXOR!: any
@Getter('price', { namespace: 'prices' }) price!: string
@Getter('priceReversed', { namespace: 'prices' }) priceReversed!: string
Expand Down Expand Up @@ -261,12 +264,7 @@ export default class RemoveLiquidity extends Mixins(TransactionMixin, LoadingMix
}
get isMaxButtonAvailable (): boolean {
if (!this.isWalletConnected || +this.liquidityBalance === 0) {
return false
}
const balance = this.getFPNumberFromCodec(this.liquidityBalance)
const amount = this.getFPNumber(this.liquidityAmount)
return !FPNumber.eq(balance, amount)
return isMaxButtonAvailable(this.areTokensSelected, this.liquidity, this.liquidityAmount, this.fee, this.tokenXOR)
}
get isEmptyAmount (): boolean {
Expand All @@ -287,15 +285,8 @@ export default class RemoveLiquidity extends Mixins(TransactionMixin, LoadingMix
)
}
get isInsufficientXorBalance (): boolean {
if (this.areTokensSelected) {
const xorValue = this.getFPNumberFromCodec(this.fee, this.xorAsset.decimals)
const xorBalance = this.getFPNumberFromCodec(this.xorBalance, this.xorAsset.decimals)
return FPNumber.gt(xorValue, xorBalance)
}
return true
get isInsufficientXorForFee (): boolean {
return hasInsufficientXorForFee(this.tokenXOR, this.fee)
}
get removePartCharClass (): string {
Expand Down
Loading

0 comments on commit 7517aa7

Please sign in to comment.