Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve bridge locked amount check #1381

Merged
merged 5 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -378,13 +378,13 @@ export default class App extends Mixins(mixins.TransactionMixin, NodeErrorMixin)
onReconnect: this.handleNodeConnect,
}),
]);

} catch (error) {
// we handled error using callback, do nothing
} finally {
// Wallet node connection dependent logic
if (!this.isWalletLoaded) {
await initWallet(walletOptions);
}
} catch (error) {
// we handled error using callback, do nothing
}
}
}
Expand Down
11 changes: 3 additions & 8 deletions src/components/mixins/BridgeMixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ import WalletConnectMixin from '@/components/mixins/WalletConnectMixin';
import { PageNames } from '@/consts';
import router from '@/router';
import { getter, state } from '@/store/decorators';
import { subBridgeApi } from '@/utils/bridge/sub/api';

import type { CodecString } from '@sora-substrate/util';
import type { RegisteredAccountAsset } from '@sora-substrate/util/build/assets/types';
import type { SubNetwork } from '@sora-substrate/util/build/bridgeProxy/sub/types';

@Component
export default class BridgeMixin extends Mixins(mixins.LoadingMixin, WalletConnectMixin) {
Expand All @@ -31,6 +29,7 @@ export default class BridgeMixin extends Mixins(mixins.LoadingMixin, WalletConne
@getter.bridge.recipient recipient!: string;
@getter.bridge.externalNetworkFee externalNetworkFee!: CodecString;
@getter.bridge.isNativeTokenSelected isNativeTokenSelected!: boolean;
@getter.bridge.isSidechainAsset isSidechainAsset!: boolean;
@getter.assets.xor xor!: RegisteredAccountAsset;

get nativeTokenSymbol(): string {
Expand All @@ -45,14 +44,10 @@ export default class BridgeMixin extends Mixins(mixins.LoadingMixin, WalletConne
return FPNumber.fromCodecValue(this.externalTransferFee, this.asset?.externalDecimals);
}

get assetLockedOnSora(): boolean {
return !subBridgeApi.isSoraParachain(this.networkSelected as SubNetwork);
}

get outgoingMaxAmount(): FPNumber | null {
const locks = [this.outgoingMaxLimit];

if (this.assetLockedOnSora) locks.push(this.assetLockedBalance);
if (this.isSidechainAsset) locks.push(this.assetLockedBalance);

const filtered = locks.filter((item) => !!item) as FPNumber[];

Expand All @@ -71,7 +66,7 @@ export default class BridgeMixin extends Mixins(mixins.LoadingMixin, WalletConne
}

get incomingMaxAmount(): FPNumber | null {
if (this.assetLockedOnSora) return null;
if (this.isSidechainAsset) return null;

return this.assetLockedBalance ?? null;
}
Expand Down
3 changes: 1 addition & 2 deletions src/components/pages/Moonpay/BridgeInitMixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { MoonpayEVMTransferAssetData, MoonpayApi } from '@/utils/moonpay';

import type { CodecString } from '@sora-substrate/util';
import type { RegisteredAccountAsset, AccountBalance } from '@sora-substrate/util/build/assets/types';
import type { EthAssetKind } from '@sora-substrate/util/build/bridgeProxy/eth/consts';
import type { EthHistory } from '@sora-substrate/util/build/bridgeProxy/eth/types';
import type { EvmNetwork } from '@sora-substrate/util/build/bridgeProxy/evm/types';
import type { BridgeNetworkId } from '@sora-substrate/util/build/bridgeProxy/types';
Expand Down Expand Up @@ -157,7 +156,7 @@ export default class MoonpayBridgeInitMixin extends Mixins(BridgeHistoryMixin, W

const evmNetworkFee: CodecString = await getEthNetworkFee(
asset,
registeredAsset.kind as EthAssetKind,
registeredAsset.kind,
this.contractAddress,
ethTransferData.amount,
false,
Expand Down
42 changes: 18 additions & 24 deletions src/store/bridge/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { FPNumber } from '@sora-substrate/util';
import { getAssetBalance } from '@sora-substrate/util/build/assets';
import { DAI } from '@sora-substrate/util/build/assets/consts';
import { BridgeTxStatus, BridgeTxDirection, BridgeNetworkType } from '@sora-substrate/util/build/bridgeProxy/consts';
import { EthAssetKind } from '@sora-substrate/util/build/bridgeProxy/eth/consts';
import { DexId } from '@sora-substrate/util/build/dex/consts';
import { api, WALLET_CONSTS } from '@soramitsu/soraneo-wallet-web';
import { defineActions } from 'direct-vuex';
Expand Down Expand Up @@ -142,7 +141,7 @@ async function getEvmNetworkFee(context: ActionContext<any, any>): Promise<void>

fee = await getEthNetworkFee(
asset,
bridgeRegisteredAsset.kind as EthAssetKind,
bridgeRegisteredAsset.kind,
contractAddress,
value,
state.isSoraToEvm,
Expand Down Expand Up @@ -235,33 +234,28 @@ async function updateEthHistory(context: ActionContext<any, any>, clearHistory =

async function updateEthLockedBalance(context: ActionContext<any, any>): Promise<void> {
const { commit, getters, rootGetters, rootState } = bridgeActionContext(context);
const { address, decimals, externalAddress } = getters.asset ?? {};
const { isRegisteredAsset, isSidechainAsset, asset } = getters;
const { address, decimals, externalAddress, externalDecimals } = asset ?? {};
const { networkSelected } = rootState.web3;
const { isValidNetwork, contractAddress } = rootGetters.web3;
const bridgeContractAddress = contractAddress(KnownEthBridgeAsset.Other);

if (address && networkSelected && isValidNetwork && externalAddress && bridgeContractAddress) {
const registeredAsset = rootState.assets.registeredAssets[address];

if (registeredAsset) {
const { kind, decimals: externalDecimals } = registeredAsset;

if (kind === EthAssetKind.Sidechain) {
const [lockedValue, bridgeValue] = await Promise.all([
ethBridgeApi.getLockedAssets(networkSelected as number, address),
ethersUtil.getAccountAssetBalance(bridgeContractAddress, externalAddress),
]);
const balance = FPNumber.min(
FPNumber.fromCodecValue(lockedValue, decimals),
FPNumber.fromCodecValue(bridgeValue, externalDecimals)
);
commit.setAssetLockedBalance(balance);
return;
}
}
}
const hasNetworkData = !!networkSelected && isValidNetwork && !!bridgeContractAddress;
const hasAssetData = !!address && !!externalAddress && isRegisteredAsset;

commit.setAssetLockedBalance();
if (hasNetworkData && hasAssetData && isSidechainAsset) {
const [lockedValue, bridgeValue] = await Promise.all([
ethBridgeApi.getLockedAssets(networkSelected as number, address),
ethersUtil.getAccountAssetBalance(bridgeContractAddress, externalAddress),
]);
const balance = FPNumber.min(
FPNumber.fromCodecValue(lockedValue, decimals),
FPNumber.fromCodecValue(bridgeValue, externalDecimals)
);
commit.setAssetLockedBalance(balance);
} else {
commit.setAssetLockedBalance();
}
}

async function updateBridgeProxyLockedBalance(context: ActionContext<any, any>): Promise<void> {
Expand Down
17 changes: 17 additions & 0 deletions src/store/bridge/getters.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Operation } from '@sora-substrate/util';
import { BridgeNetworkType } from '@sora-substrate/util/build/bridgeProxy/consts';
import { EthAssetKind } from '@sora-substrate/util/build/bridgeProxy/eth/consts';
import { SubAssetKind } from '@sora-substrate/util/build/bridgeProxy/sub/consts';
import { defineGetters } from 'direct-vuex';

import { ZeroStringValue } from '@/consts';
Expand Down Expand Up @@ -77,6 +79,21 @@ const getters = defineGetters<BridgeState>()({
return !!asset?.externalAddress;
},

isSidechainAsset(...args): boolean {
const { getters, rootState } = bridgeGetterContext(args);
const { asset, isSubBridge } = getters;
const { registeredAssets } = rootState.assets;

if (!asset) return false;
if (!(asset.address in registeredAssets)) return false;

const registered = registeredAssets[asset.address];
const kind = registered.kind;
const sidechainKind = isSubBridge ? SubAssetKind.Sidechain : EthAssetKind.Sidechain;

return kind === sidechainKind;
},

autoselectedAssetAddress(...args): Nullable<string> {
const { rootState } = bridgeGetterContext(args);
const assetIds = Object.keys(rootState.assets.registeredAssets);
Expand Down
3 changes: 2 additions & 1 deletion src/utils/bridge/eth/classes/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ const getReceiptData = async (externalHash: string) => {
};

const getEvmBlockNumber = (ethereumTx: ethers.TransactionResponse | null) => {
return ethereumTx?.blockNumber;
const blockNumber = ethereumTx?.blockNumber; // could be a string
return blockNumber ? +blockNumber : null;
};

const getEvmBlockId = (ethereumTx: ethers.TransactionResponse | null) => {
Expand Down
4 changes: 2 additions & 2 deletions src/utils/bridge/eth/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ const getEthBridgeIncomingGasLimit = (assetEvmAddress: string): bigint => {

export async function getEthNetworkFee(
asset: RegisteredAccountAsset,
assetKind: EthAssetKind,
assetKind: string,
getContractAddress: (symbol: KnownEthBridgeAsset) => Nullable<string>,
value: string,
isOutgoing: boolean,
Expand All @@ -256,7 +256,7 @@ export async function getEthNetworkFee(
let gasLimitTotal!: bigint;

if (isOutgoing) {
gasLimitTotal = getEthBridgeOutgoingGasLimit(asset.externalAddress, assetKind);
gasLimitTotal = getEthBridgeOutgoingGasLimit(asset.externalAddress, assetKind as EthAssetKind);
} else {
const bridgeContractAddress = getContractAddress(KnownEthBridgeAsset.Other) as string;
const allowance = await ethersUtil.getAllowance(evmAccount, bridgeContractAddress, asset.externalAddress);
Expand Down
48 changes: 33 additions & 15 deletions src/views/BridgeTransactionsHistory.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</generic-page-header>
<s-form class="history-form" :show-message="false">
<search-input
v-if="history.length"
v-if="historyList.length"
v-model="query"
:placeholder="t('bridgeHistory.filterPlaceholder')"
autofocus
Expand Down Expand Up @@ -87,6 +87,20 @@ import { state } from '@/store/decorators';

import type { IBridgeTransaction } from '@sora-substrate/util';

const SearchAttrs = [
'assetAddress',
'symbol',
'hash',
'blockId',
'txId',
'externalBlockId',
'externalHash',
'parachainBlockId',
'parachainHash',
'relaychainBlockId',
'relaychainHash',
];

@Component({
components: {
GenericPageHeader: lazyComponent(Components.GenericPageHeader),
Expand Down Expand Up @@ -154,25 +168,29 @@ export default class BridgeTransactionsHistory extends Mixins(
}

getFilteredHistory(history: Array<IBridgeTransaction>): Array<IBridgeTransaction> {
if (this.query) {
const query = this.query.toLowerCase().trim();
return history.filter(
(item) =>
`${item.assetAddress}`.toLowerCase().includes(query) ||
`${this.registeredAssets[item.assetAddress as string]?.address}`.toLowerCase().includes(query) ||
`${item.symbol}`.toLowerCase().includes(query)
);
}
if (!this.query) return history;

const query = this.query.toLowerCase().trim();

return history;
return history.filter((item) => {
const bridgeRegisteredAsset = this.registeredAssets[item.assetAddress as string];
const criterias = [bridgeRegisteredAsset?.address];

SearchAttrs.forEach((attr) => {
if (attr in item) criterias.push(item[attr]);
});

return criterias.some((criteria) => String(criteria).toLowerCase().includes(query));
});
}

formatAmount(historyItem: IBridgeTransaction, received = false): string {
const amount = received ? historyItem.amount2 ?? historyItem.amount : historyItem.amount;
formatAmount(item: IBridgeTransaction, received = false): string {
const amount = received ? item.amount2 ?? item.amount : item.amount;

if (!historyItem.assetAddress || !amount) return '';
if (!item.assetAddress || !amount) return '';

const decimals = this.registeredAssets?.[historyItem.assetAddress]?.decimals;
const bridgeRegisteredAsset = this.registeredAssets[item.assetAddress];
const decimals = bridgeRegisteredAsset?.decimals;

return this.formatStringValue(amount, decimals);
}
Expand Down