diff --git a/package.json b/package.json
index c4a94cd06..d7f115660 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "polkaswap-exchange-web",
- "version": "1.21.1",
+ "version": "1.22.0",
"repository": {
"type": "git",
"url": "https://github.com/sora-xor/polkaswap-exchange-web.git"
@@ -24,7 +24,7 @@
},
"dependencies": {
"@metamask/detect-provider": "^2.0.0",
- "@soramitsu/soraneo-wallet-web": "1.21.12",
+ "@soramitsu/soraneo-wallet-web": "1.22.2",
"@walletconnect/web3-provider": "^1.8.0",
"core-js": "^3.26.0",
"country-code-emoji": "^2.3.0",
diff --git a/src/components/App/Settings/Language/SelectLanguageDialog.vue b/src/components/App/Settings/Language/SelectLanguageDialog.vue
index 476d61e7f..57d7e59d3 100644
--- a/src/components/App/Settings/Language/SelectLanguageDialog.vue
+++ b/src/components/App/Settings/Language/SelectLanguageDialog.vue
@@ -10,7 +10,7 @@
size="medium"
class="select-language-list__item s-flex"
>
-
+
{{ lang.value }}
@@ -26,7 +26,7 @@
+
+
diff --git a/src/components/pages/Bridge/SelectAccount.vue b/src/components/pages/Bridge/SelectAccount.vue
index 50e2443be..d37e90536 100644
--- a/src/components/pages/Bridge/SelectAccount.vue
+++ b/src/components/pages/Bridge/SelectAccount.vue
@@ -20,7 +20,7 @@ import { api, mixins, components } from '@soramitsu/soraneo-wallet-web';
import { Component, Mixins, Watch } from 'vue-property-decorator';
import TranslationMixin from '@/components/mixins/TranslationMixin';
-import { action, state, mutation } from '@/store/decorators';
+import { state, mutation } from '@/store/decorators';
@Component({
components: {
@@ -32,7 +32,7 @@ export default class BridgeSelectAccount extends Mixins(mixins.LoadingMixin, Tra
@state.web3.subAddress private subAddress!: string;
@state.web3.selectAccountDialogVisibility private selectAccountDialogVisibility!: boolean;
@mutation.web3.setSelectAccountDialogVisibility private setSelectAccountDialogVisibility!: (flag: boolean) => void;
- @action.web3.connectSubAccount private connectSubAccount!: (address: string) => Promise
;
+ @mutation.web3.setSubAddress private setSubAddress!: (address: string) => Promise;
address = '';
@@ -50,11 +50,17 @@ export default class BridgeSelectAccount extends Mixins(mixins.LoadingMixin, Tra
}
get validAddress(): boolean {
- return !!this.address && api.validateAddress(this.address);
+ if (!(this.address && api.validateAddress(this.address))) return false;
+ try {
+ api.formatAddress(this.address);
+ return true; // if it can be formatted -> it's correct
+ } catch {
+ return false; // EVM account address
+ }
}
handleSelectAddress(): void {
- this.connectSubAccount(this.address);
+ this.setSubAddress(this.address);
this.visibility = false;
}
}
diff --git a/src/components/pages/Bridge/SelectAsset.vue b/src/components/pages/Bridge/SelectAsset.vue
index 29e781aab..7d2baf83a 100644
--- a/src/components/pages/Bridge/SelectAsset.vue
+++ b/src/components/pages/Bridge/SelectAsset.vue
@@ -65,8 +65,10 @@ export default class BridgeSelectAsset extends Mixins(TranslationMixin, SelectAs
get assetsList(): Array {
const assetsAddresses = Object.keys(this.registeredAssets);
const excludeAddress = this.asset?.address;
+ const list = this.getAssetsWithBalances(assetsAddresses, excludeAddress);
+ const orderedList = [...list].sort(this.sortByBalance);
- return this.getAssetsWithBalances(assetsAddresses, excludeAddress).sort(this.sortByBalance);
+ return orderedList;
}
get filteredAssets(): Array {
diff --git a/src/components/pages/Bridge/SelectNetwork.vue b/src/components/pages/Bridge/SelectNetwork.vue
index 96b3548ab..ec1214899 100644
--- a/src/components/pages/Bridge/SelectNetwork.vue
+++ b/src/components/pages/Bridge/SelectNetwork.vue
@@ -25,6 +25,7 @@ import NetworkFormatterMixin from '@/components/mixins/NetworkFormatterMixin';
import { action, mutation, state } from '@/store/decorators';
import type { AvailableNetwork } from '@/store/web3/types';
+import type { SubNetwork } from '@sora-substrate/util/build/bridgeProxy/sub/consts';
import type { BridgeNetworkId } from '@sora-substrate/util/build/bridgeProxy/types';
type NetworkItem = {
@@ -47,10 +48,12 @@ export default class BridgeSelectNetwork extends Mixins(NetworkFormatterMixin) {
@state.web3.networkSelected private networkSelected!: Nullable;
@state.web3.selectNetworkDialogVisibility private selectNetworkDialogVisibility!: boolean;
- @mutation.web3.setNetworkType private setNetworkType!: (networkType: BridgeNetworkType) => void;
@mutation.web3.setSelectNetworkDialogVisibility private setSelectNetworkDialogVisibility!: (flag: boolean) => void;
- @action.web3.selectExternalNetwork selectExternalNetwork!: (networkId: BridgeNetworkId) => void;
+ @action.web3.selectExternalNetwork selectExternalNetwork!: (network: {
+ id: BridgeNetworkId;
+ type: BridgeNetworkType;
+ }) => void;
get visibility(): boolean {
return this.selectNetworkDialogVisibility;
@@ -66,7 +69,7 @@ export default class BridgeSelectNetwork extends Mixins(NetworkFormatterMixin) {
const networks = Object.values(record) as AvailableNetwork[];
return networks.reduce((buffer, { available, disabled, data: { id, name } }) => {
- const networkName = type === BridgeNetworkType.EvmLegacy ? `${name} (${this.t('hashiBridgeText')})` : name;
+ const networkName = type === BridgeNetworkType.Eth ? `${name} (${this.t('hashiBridgeText')})` : name;
if (available) {
buffer.push({
@@ -92,10 +95,12 @@ export default class BridgeSelectNetwork extends Mixins(NetworkFormatterMixin) {
set selectedNetworkTuple(value: string) {
const [networkType, networkSelected] = value.split(DELIMETER);
- const networkFormatted =
- networkType === BridgeNetworkType.Sub ? (networkSelected as BridgeNetworkId) : Number(networkSelected);
- this.setNetworkType(networkType as BridgeNetworkType);
- this.selectExternalNetwork(networkFormatted);
+
+ const type = networkType as BridgeNetworkType;
+ const id = type === BridgeNetworkType.Sub ? (networkSelected as SubNetwork) : Number(networkSelected);
+
+ this.selectExternalNetwork({ id, type });
+ this.visibility = false;
}
}
diff --git a/src/components/pages/Bridge/TransactionDetails.vue b/src/components/pages/Bridge/TransactionDetails.vue
index 8de39204a..500e208a5 100644
--- a/src/components/pages/Bridge/TransactionDetails.vue
+++ b/src/components/pages/Bridge/TransactionDetails.vue
@@ -17,9 +17,18 @@
is-formatted
>
- ~
+ {{ ApproximateSign }}
+
@@ -29,7 +38,7 @@ import { components, mixins } from '@soramitsu/soraneo-wallet-web';
import { Component, Mixins, Prop } from 'vue-property-decorator';
import TranslationMixin from '@/components/mixins/TranslationMixin';
-import { Components, ZeroStringValue } from '@/consts';
+import { Components, ZeroStringValue, ApproximateSign } from '@/consts';
import { lazyComponent } from '@/router';
import type { CodecString } from '@sora-substrate/util';
@@ -43,12 +52,19 @@ import type { RegisteredAccountAsset } from '@sora-substrate/util/build/assets/t
})
export default class BridgeTransactionDetails extends Mixins(mixins.FormattedAmountMixin, TranslationMixin) {
readonly XOR = XOR;
+ readonly ApproximateSign = ApproximateSign;
+ @Prop({ default: () => null, type: Object }) readonly asset!: Nullable;
@Prop({ default: () => null, type: Object }) readonly nativeToken!: Nullable;
+ @Prop({ default: ZeroStringValue, type: String }) readonly externalTransferFee!: CodecString;
@Prop({ default: ZeroStringValue, type: String }) readonly externalNetworkFee!: CodecString;
@Prop({ default: ZeroStringValue, type: String }) readonly soraNetworkFee!: CodecString;
@Prop({ default: '', type: String }) readonly networkName!: string;
+ get assetSymbol(): string {
+ return this.asset?.symbol ?? '';
+ }
+
get nativeTokenSymbol(): string {
return this.nativeToken?.symbol ?? '';
}
@@ -60,5 +76,9 @@ export default class BridgeTransactionDetails extends Mixins(mixins.FormattedAmo
get isExternalFeeNotZero(): boolean {
return this.externalNetworkFee !== ZeroStringValue;
}
+
+ get isExternalTransferFeeNotZero(): boolean {
+ return this.externalTransferFee !== ZeroStringValue;
+ }
}
diff --git a/src/components/pages/Moonpay/BridgeInitMixin.ts b/src/components/pages/Moonpay/BridgeInitMixin.ts
index e696c31cd..0e40dd99a 100644
--- a/src/components/pages/Moonpay/BridgeInitMixin.ts
+++ b/src/components/pages/Moonpay/BridgeInitMixin.ts
@@ -13,9 +13,11 @@ import ethersUtil from '@/utils/ethers-util';
import type { MoonpayTransaction } from '@/utils/moonpay';
import { MoonpayEVMTransferAssetData, MoonpayApi } from '@/utils/moonpay';
-import type { CodecString, BridgeHistory } from '@sora-substrate/util';
+import type { CodecString } from '@sora-substrate/util';
import type { Asset, AccountBalance } from '@sora-substrate/util/build/assets/types';
+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';
import type { WALLET_CONSTS } from '@soramitsu/soraneo-wallet-web';
const createError = (text: string, notification: MoonpayNotifications) => {
@@ -27,7 +29,7 @@ const createError = (text: string, notification: MoonpayNotifications) => {
@Component
export default class MoonpayBridgeInitMixin extends Mixins(BridgeHistoryMixin, WalletConnectMixin) {
@state.moonpay.api moonpayApi!: MoonpayApi;
- @state.moonpay.bridgeTransactionData bridgeTransactionData!: Nullable;
+ @state.moonpay.bridgeTransactionData bridgeTransactionData!: Nullable;
@state.web3.ethBridgeEvmNetwork ethBridgeEvmNetwork!: EvmNetwork;
@state.wallet.settings.soraNetwork soraNetwork!: Nullable;
@state.assets.registeredAssets private registeredAssets!: Record;
@@ -40,12 +42,20 @@ export default class MoonpayBridgeInitMixin extends Mixins(BridgeHistoryMixin, W
@mutation.moonpay.setNotificationKey setNotificationKey!: (key: string) => void;
@mutation.moonpay.setBridgeTxData setBridgeTxData!: (options?: BridgeTxData) => void;
+ @action.web3.selectExternalNetwork selectExternalNetwork!: (network: {
+ id: BridgeNetworkId;
+ type: BridgeNetworkType;
+ }) => Promise;
+
@action.moonpay.getTransactionTranserData private getTransactionTranserData!: (
hash: string
) => Promise>;
async prepareEvmNetwork(): Promise {
- await this.selectExternalNetwork(this.ethBridgeEvmNetwork); // WalletConnectMixin
+ await this.selectExternalNetwork({
+ id: this.ethBridgeEvmNetwork,
+ type: BridgeNetworkType.Eth,
+ }); // WalletConnectMixin
}
initMoonpayApi(): void {
@@ -64,7 +74,7 @@ export default class MoonpayBridgeInitMixin extends Mixins(BridgeHistoryMixin, W
}
}
- async getBridgeMoonpayTransaction(): Promise {
+ async getBridgeMoonpayTransaction(): Promise {
if (!this.bridgeTransactionData) {
throw new Error('bridgeTransactionData is empty');
}
@@ -76,18 +86,18 @@ export default class MoonpayBridgeInitMixin extends Mixins(BridgeHistoryMixin, W
if (!tx) {
const historyItem = await this.generateHistoryItem(this.bridgeTransactionData);
- return historyItem as BridgeHistory;
+ return historyItem as EthHistory;
}
return tx;
}
- getBridgeHistoryItemByMoonpayId(moonpayId: string): Nullable {
+ getBridgeHistoryItemByMoonpayId(moonpayId: string): Nullable {
const externalHash = this.moonpayApi.accountRecords?.[moonpayId];
if (!externalHash) return null;
- return Object.values(this.history).find((item) => item.externalHash === externalHash) as Nullable;
+ return Object.values(this.history).find((item) => item.externalHash === externalHash) as Nullable;
}
async startBridgeForMoonpayTransaction(): Promise {
@@ -100,7 +110,7 @@ export default class MoonpayBridgeInitMixin extends Mixins(BridgeHistoryMixin, W
* @param transaction moonpay transaction data
* @returns string - bridge history item id
*/
- async prepareBridgeHistoryItemData(transaction: MoonpayTransaction): Promise {
+ async prepareBridgeHistoryItemData(transaction: MoonpayTransaction): Promise {
return await this.withLoading(async () => {
// this is not really good, but we should change evm network before fetching transaction data
await this.prepareEvmNetwork();
@@ -173,7 +183,7 @@ export default class MoonpayBridgeInitMixin extends Mixins(BridgeHistoryMixin, W
soraNetworkFee: this.networkFees[Operation.EthBridgeIncoming],
externalNetworkFee: evmNetworkFee,
externalNetwork: this.ethBridgeEvmNetwork,
- externalNetworkType: BridgeNetworkType.EvmLegacy,
+ externalNetworkType: BridgeNetworkType.Eth,
to: ethTransferData.to,
payload: {
moonpayId: transaction.id,
diff --git a/src/components/pages/Moonpay/MoonpayHistory.vue b/src/components/pages/Moonpay/MoonpayHistory.vue
index d0dbbdfeb..fd4d4b662 100644
--- a/src/components/pages/Moonpay/MoonpayHistory.vue
+++ b/src/components/pages/Moonpay/MoonpayHistory.vue
@@ -84,7 +84,7 @@ import ethersUtil from '../../../utils/ethers-util';
import { MoonpayTransactionStatus } from '../../../utils/moonpay';
import type { MoonpayTransaction, MoonpayCurrency, MoonpayCurrenciesById } from '../../../utils/moonpay';
-import type { BridgeHistory } from '@sora-substrate/util';
+import type { EthHistory } from '@sora-substrate/util/build/bridgeProxy/eth/types';
import type Theme from '@soramitsu/soramitsu-js-ui/lib/types/Theme';
const HistoryView = 'history';
@@ -135,7 +135,7 @@ export default class MoonpayHistory extends Mixins(mixins.PaginationSearchMixin,
}
},
onNetworkChange: (networkHex: string) => {
- this.connectExternalNetwork(networkHex);
+ this.updateProvidedEvmNetwork(networkHex);
},
onDisconnect: () => {
this.resetProvidedEvmNetwork();
@@ -209,7 +209,7 @@ export default class MoonpayHistory extends Mixins(mixins.PaginationSearchMixin,
return `${this.selectedItem.returnUrl}?${query}`;
}
- get bridgeTxToSora(): Nullable {
+ get bridgeTxToSora(): Nullable {
if (!this.selectedItem.id) return undefined;
return this.getBridgeHistoryItemByMoonpayId(this.selectedItem.id);
@@ -291,7 +291,7 @@ export default class MoonpayHistory extends Mixins(mixins.PaginationSearchMixin,
if (!this.selectedItem.id) return;
if (!this.isValidNetwork) {
- this.updateNetworkProvided();
+ this.changeEvmNetworkProvided();
} else if (this.bridgeTxToSora?.id) {
await this.prepareEvmNetwork(); // MoonpayBridgeInitMixin
await this.showHistory(this.bridgeTxToSora.id); // MoonpayBridgeInitMixin
diff --git a/src/components/pages/Stats/SupplyChart.vue b/src/components/pages/Stats/SupplyChart.vue
index 27b1edf6e..985e488e8 100644
--- a/src/components/pages/Stats/SupplyChart.vue
+++ b/src/components/pages/Stats/SupplyChart.vue
@@ -12,16 +12,16 @@
-
+
@@ -119,7 +120,8 @@ const parse = (node: AssetSnapshotEntity): ChartData => {
PriceChange: lazyComponent(Components.PriceChange),
StatsCard: lazyComponent(Components.StatsCard),
StatsFilter: lazyComponent(Components.StatsFilter),
- TokenSelectDropdown: lazyComponent(Components.TokenSelectDropdown),
+ TokenSelectButton: lazyComponent(Components.TokenSelectButton),
+ SelectToken: lazyComponent(Components.SelectToken),
FormattedAmount: components.FormattedAmount,
},
})
@@ -131,11 +133,24 @@ export default class StatsSupplyChart extends Mixins(mixins.LoadingMixin, ChartS
filter: SnapshotFilter = ASSET_SUPPLY_LINE_FILTERS[0];
token = XOR;
+ showSelectTokenDialog = false;
data: readonly ChartData[] = [];
isFetchingError = false;
+ get areActionsDisabled(): boolean {
+ return this.parentLoading || this.loading;
+ }
+
+ get selectTokenIcon(): Nullable {
+ return !this.areActionsDisabled ? 'chevron-down-rounded-16' : undefined;
+ }
+
+ get tokenTabIndex(): number {
+ return !this.areActionsDisabled ? 0 : -1;
+ }
+
get firstValue(): FPNumber {
return new FPNumber(first(this.data)?.value ?? 0);
}
@@ -275,6 +290,10 @@ export default class StatsSupplyChart extends Mixins(mixins.LoadingMixin, ChartS
};
}
+ handleSelectToken(): void {
+ this.showSelectTokenDialog = true;
+ }
+
changeFilter(filter: SnapshotFilter): void {
this.filter = filter;
this.updateData();
diff --git a/src/components/shared/Dialog/ConfirmBridgeTransaction.vue b/src/components/shared/Dialog/ConfirmBridgeTransaction.vue
index f49064bbf..4c0b0af45 100644
--- a/src/components/shared/Dialog/ConfirmBridgeTransaction.vue
+++ b/src/components/shared/Dialog/ConfirmBridgeTransaction.vue
@@ -25,7 +25,9 @@
null, type: Object }) readonly asset!: Nullable;
@Prop({ default: () => null, type: Object }) readonly nativeToken!: Nullable;
+ @Prop({ default: ZeroStringValue, type: String }) readonly externalTransferFee!: CodecString;
@Prop({ default: ZeroStringValue, type: String }) readonly externalNetworkFee!: CodecString;
@Prop({ default: ZeroStringValue, type: String }) readonly soraNetworkFee!: CodecString;
@Prop({ default: true, type: Boolean }) readonly isSoraToEvm!: boolean;
diff --git a/src/components/shared/Input/TokenSelectDropdown.vue b/src/components/shared/Input/TokenSelectDropdown.vue
deleted file mode 100644
index 9dc8e9680..000000000
--- a/src/components/shared/Input/TokenSelectDropdown.vue
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
- {{ item.symbol }}
-
-
-
-
-
-
-
-
diff --git a/src/components/shared/SelectAsset/SelectToken.vue b/src/components/shared/SelectAsset/SelectToken.vue
index 5fe13a5c0..d37e92b86 100644
--- a/src/components/shared/SelectAsset/SelectToken.vue
+++ b/src/components/shared/SelectAsset/SelectToken.vue
@@ -155,8 +155,10 @@ export default class SelectToken extends Mixins(TranslationMixin, SelectAssetMix
const assetsAddresses = whiteList.map((asset) => asset.address);
const excludeAddress = this.asset?.address;
+ const list = this.getAssetsWithBalances(assetsAddresses, excludeAddress);
+ const orderedList = [...list].sort(this.sortByBalance);
- return this.getAssetsWithBalances(assetsAddresses, excludeAddress).sort(this.sortByBalance);
+ return orderedList;
}
get filteredWhitelistTokens(): Array {
diff --git a/src/consts/index.ts b/src/consts/index.ts
index a083e9566..e121656ff 100644
--- a/src/consts/index.ts
+++ b/src/consts/index.ts
@@ -90,6 +90,8 @@ export const ObjectInit = () => null;
export const ZeroStringValue = '0';
+export const ApproximateSign = '~';
+
export const MetamaskCancellationCode = 4001;
export const DefaultSlippageTolerance = '0.5';
@@ -188,6 +190,7 @@ export enum Components {
BridgeSelectNetwork = 'pages/Bridge/SelectNetwork',
BridgeSelectAccount = 'pages/Bridge/SelectAccount',
BridgeLinksDropdown = 'pages/Bridge/LinksDropdown',
+ BridgeLimitCard = 'pages/Bridge/LimitCard',
// Moonpay Page
Moonpay = 'pages/Moonpay/Moonpay',
MoonpayNotification = 'pages/Moonpay/Notification',
@@ -229,7 +232,6 @@ export enum Components {
// Shared Input
TokenInput = 'shared/Input/TokenInput',
TokenSelectButton = 'shared/Input/TokenSelectButton',
- TokenSelectDropdown = 'shared/Input/TokenSelectDropdown',
// Shared Dialogs
ConfirmBridgeTransactionDialog = 'shared/Dialog/ConfirmBridgeTransaction',
NetworkFeeWarningDialog = 'shared/Dialog/NetworkFeeWarning',
diff --git a/src/consts/sub.ts b/src/consts/sub.ts
index ef0321d5c..f1c3e1e3d 100644
--- a/src/consts/sub.ts
+++ b/src/consts/sub.ts
@@ -74,4 +74,10 @@ export const SUB_TRANSFER_FEES: SubNetworksFees = {
[BridgeTxDirection.Incoming]: '0',
},
},
+ [SubNetwork.Kusama]: {
+ KSM: {
+ [BridgeTxDirection.Outgoing]: '10124190', // [TODO] check in real transfer
+ [BridgeTxDirection.Incoming]: '0',
+ },
+ },
};
diff --git a/src/lang/cs.json b/src/lang/cs.json
index 4fc69664b..c30fb7bd0 100644
--- a/src/lang/cs.json
+++ b/src/lang/cs.json
@@ -545,7 +545,9 @@
"copy": "Zkopírujte síťovou adresu",
"soraAddress": "{Sora} adresa",
"ethereumAddress": "{Ethereum} adresa",
- "limitMessage": "V současné době existuje {type} {amount} {symbol} pro přemostění, aby byla zajištěna stabilita a bezpečnost sítě {Sora}. Děkujeme za pochopení."
+ "limitMessage": "V současné době existuje {type} {amount} {symbol} pro přemostění, aby byla zajištěna stabilita a bezpečnost sítě {Sora}. Děkujeme za pochopení.",
+ "externalTransferFee": "{network} poplatek {XCM}",
+ "externalTransferFeeTooltip": "Když odešlete překlenovací transakci do sítě {network} , z částky, kterou převádíte, se strhne menší poplatek"
},
"selectRegisteredAsset": {
"title": "Vyberte token",
diff --git a/src/lang/de.json b/src/lang/de.json
index c1af17242..2454e2aa2 100644
--- a/src/lang/de.json
+++ b/src/lang/de.json
@@ -545,7 +545,9 @@
"copy": "Netzwerkadresse kopieren",
"soraAddress": "{Sora} Adresse",
"ethereumAddress": "{Ethereum} Adresse",
- "limitMessage": "Derzeit gibt es ein {type} {amount} {symbol} für Bridging, um die Stabilität und Sicherheit des {Sora}-Netzwerks zu gewährleisten. Vielen Dank für Ihr Verständnis."
+ "limitMessage": "Derzeit gibt es ein {type} {amount} {symbol} für Bridging, um die Stabilität und Sicherheit des {Sora}-Netzwerks zu gewährleisten. Vielen Dank für Ihr Verständnis.",
+ "externalTransferFee": "{network} {XCM} -Gebühr",
+ "externalTransferFeeTooltip": "Wenn Sie eine Bridge-Transaktion an das Netzwerk {network} senden, wird eine geringe Gebühr von dem Betrag erhoben, den Sie überweisen"
},
"selectRegisteredAsset": {
"title": "Wähle ein Token",
diff --git a/src/lang/en.json b/src/lang/en.json
index 318ca66fc..86d733f63 100644
--- a/src/lang/en.json
+++ b/src/lang/en.json
@@ -545,7 +545,9 @@
"copy": "Copy network address",
"soraAddress": "{Sora} address",
"ethereumAddress": "{Ethereum} address",
- "limitMessage": "Currently, there's a {type} {amount} {symbol} for bridging to ensure the stability and security of the {Sora} Network. We appreciate your understanding."
+ "limitMessage": "Currently, there's a {type} {amount} {symbol} for bridging to ensure the stability and security of the {Sora} Network. We appreciate your understanding.",
+ "externalTransferFee": "{network} {XCM} fee",
+ "externalTransferFeeTooltip": "When you send a bridge transaction to the {network} network, a minor fee is taken from the amount you are transferring"
},
"selectRegisteredAsset": {
"title": "Select a token",
diff --git a/src/lang/es.json b/src/lang/es.json
index 1c77b7886..f8f64d029 100644
--- a/src/lang/es.json
+++ b/src/lang/es.json
@@ -545,7 +545,9 @@
"copy": "Copiar dirección de red",
"soraAddress": "Dirección de {Sora}",
"ethereumAddress": "dirección {Ethereum}",
- "limitMessage": "Actualmente, existe un {type} {amount} {symbol} para establecer puentes para garantizar la estabilidad y seguridad de la red {Sora} . apreciamos su comprensión."
+ "limitMessage": "Actualmente, existe un {type} {amount} {symbol} para establecer puentes para garantizar la estabilidad y seguridad de la red {Sora} . apreciamos su comprensión.",
+ "externalTransferFee": "tarifa de {network} {XCM}",
+ "externalTransferFeeTooltip": "Cuando envía una transacción puente a la red {network} , se deduce una tarifa menor del monto que está transfiriendo"
},
"selectRegisteredAsset": {
"title": "Seleccione un Token",
diff --git a/src/lang/fr.json b/src/lang/fr.json
index bf47f81e5..7be0fea00 100644
--- a/src/lang/fr.json
+++ b/src/lang/fr.json
@@ -545,7 +545,9 @@
"copy": "Copier l'adresse réseau",
"soraAddress": "{Sora} adresse",
"ethereumAddress": "{Ethereum} adresse",
- "limitMessage": "Actuellement, il existe un {type} {amount} {symbol} pour le pontage afin de garantir la stabilité et la sécurité du réseau {Sora}. Nous apprécions votre compréhension."
+ "limitMessage": "Actuellement, il existe un {type} {amount} {symbol} pour le pontage afin de garantir la stabilité et la sécurité du réseau {Sora}. Nous apprécions votre compréhension.",
+ "externalTransferFee": "Frais {network} {XCM}",
+ "externalTransferFeeTooltip": "Lorsque vous envoyez une transaction relais vers le réseau {network} , des frais mineurs sont prélevés sur le montant que vous transférez"
},
"selectRegisteredAsset": {
"title": "Sélectionnez un jeton",
diff --git a/src/lang/hr.json b/src/lang/hr.json
index 8bbe88bbd..9c11328a8 100644
--- a/src/lang/hr.json
+++ b/src/lang/hr.json
@@ -545,7 +545,9 @@
"copy": "Kopiraj mrežnu adresu",
"soraAddress": "{Sora} adresa",
"ethereumAddress": "{Ethereum} adresa",
- "limitMessage": "Trenutno postoji {type} {amount} {symbol} za premošćivanje kako bi se osigurala stabilnost i sigurnost {Sora} mreže. Cijenimo vaše razumijevanje."
+ "limitMessage": "Trenutno postoji {type} {amount} {symbol} za premošćivanje kako bi se osigurala stabilnost i sigurnost {Sora} mreže. Cijenimo vaše razumijevanje.",
+ "externalTransferFee": "{network} {XCM} naknada",
+ "externalTransferFeeTooltip": "Kada pošaljete premosnu transakciju na mrežu {network} , od iznosa koji prenosite uzima se manja naknada"
},
"selectRegisteredAsset": {
"title": "Odaberite token",
diff --git a/src/lang/hu.json b/src/lang/hu.json
index 7b76f6d38..16db88753 100644
--- a/src/lang/hu.json
+++ b/src/lang/hu.json
@@ -545,7 +545,9 @@
"copy": "Hálózati cím másolása",
"soraAddress": "{Sora} cím",
"ethereumAddress": "{Ethereum} cím",
- "limitMessage": "Jelenleg létezik egy {type} {amount} {symbol} áthidalás, amely biztosítja a {Sora} hálózat stabilitását és biztonságát. Köszönjük megértését."
+ "limitMessage": "Jelenleg létezik egy {type} {amount} {symbol} áthidalás, amely biztosítja a {Sora} hálózat stabilitását és biztonságát. Köszönjük megértését.",
+ "externalTransferFee": "{network} {XCM} díj",
+ "externalTransferFeeTooltip": "Ha hídtranzakciót küld a {network} hálózatra, az átutalt összegből egy kisebb díjat számítanak fel"
},
"selectRegisteredAsset": {
"title": "Token kiválasztása",
diff --git a/src/lang/hy.json b/src/lang/hy.json
index 4f8341ead..b15adcd4f 100644
--- a/src/lang/hy.json
+++ b/src/lang/hy.json
@@ -545,7 +545,9 @@
"copy": "Պատճենել ցանցի հասցեն",
"soraAddress": "{Sora} հասցե",
"ethereumAddress": "{Ethereum} հասցե",
- "limitMessage": "Ներկայումս {Sora} ցանցի կայունությունն ու անվտանգությունն ապահովելու համար կամրջելու համար կա {type} {amount} {symbol} : Մենք գնահատում ենք ձեր ըմբռնումը:"
+ "limitMessage": "Ներկայումս {Sora} ցանցի կայունությունն ու անվտանգությունն ապահովելու համար կամրջելու համար կա {type} {amount} {symbol} : Մենք գնահատում ենք ձեր ըմբռնումը:",
+ "externalTransferFee": "{network} {XCM} վճար",
+ "externalTransferFeeTooltip": "Երբ դուք կամուրջ գործարք եք ուղարկում {network} ցանցին, ձեր փոխանցվող գումարից փոքր վճար է վերցվում"
},
"selectRegisteredAsset": {
"title": "Ընտրեք տոկեն",
diff --git a/src/lang/id.json b/src/lang/id.json
index 5511e3948..ab1a53813 100644
--- a/src/lang/id.json
+++ b/src/lang/id.json
@@ -545,7 +545,9 @@
"copy": "Salin alamat jaringan",
"soraAddress": "{Sora} alamat",
"ethereumAddress": "{Ethereum} alamat",
- "limitMessage": "Saat ini, ada {type} {amount} {symbol} untuk menjembatani guna memastikan stabilitas dan keamanan Jaringan {Sora} . Kami menghargai pengertian Anda."
+ "limitMessage": "Saat ini, ada {type} {amount} {symbol} untuk menjembatani guna memastikan stabilitas dan keamanan Jaringan {Sora} . Kami menghargai pengertian Anda.",
+ "externalTransferFee": "biaya {network} {XCM}",
+ "externalTransferFeeTooltip": "Saat Anda mengirim transaksi jembatan ke jaringan {network} , sedikit biaya akan diambil dari jumlah yang Anda transfer"
},
"selectRegisteredAsset": {
"title": "Pilih token",
diff --git a/src/lang/it.json b/src/lang/it.json
index 74b499b35..ba8981cd3 100644
--- a/src/lang/it.json
+++ b/src/lang/it.json
@@ -545,7 +545,9 @@
"copy": "Copia l'indirizzo di rete",
"soraAddress": "{Sora} indirizzo",
"ethereumAddress": "{Ethereum} indirizzo",
- "limitMessage": "Attualmente, esiste un {type} {amount} {symbol} per il bridging per garantire la stabilità e la sicurezza della rete {Sora} . Apprezziamo la tua comprensione."
+ "limitMessage": "Attualmente, esiste un {type} {amount} {symbol} per il bridging per garantire la stabilità e la sicurezza della rete {Sora} . Apprezziamo la tua comprensione.",
+ "externalTransferFee": "Tariffa {network} {XCM}",
+ "externalTransferFeeTooltip": "Quando invii una transazione bridge alla rete {network} , viene trattenuta una commissione minore dall'importo che stai trasferendo"
},
"selectRegisteredAsset": {
"title": "Seleziona un token",
diff --git a/src/lang/messages.ts b/src/lang/messages.ts
index 5127c869e..1d709fcb0 100644
--- a/src/lang/messages.ts
+++ b/src/lang/messages.ts
@@ -395,6 +395,9 @@ export default {
connectWallets: 'Connect wallets to view respective transaction history.',
soraNetworkFee: '{Sora} Network Fee',
ethereumNetworkFee: '{Ethereum} Network Fee',
+ externalTransferFee: '{network} {XCM} fee',
+ externalTransferFeeTooltip:
+ 'When you send a bridge transaction to the {network} network, a minor fee is taken from the amount you are trasferring',
tooltipValue: '@:comingSoonText',
total: 'Total',
viewHistory: 'View transactions history',
@@ -406,6 +409,8 @@ export default {
copy: 'Copy network address',
soraAddress: '{Sora} address',
ethereumAddress: '{Ethereum} address',
+ limitMessage:
+ "Currently, there's a {type} {amount} {symbol} for bridging to ensure the stability and security of the {Sora} Network. We appreciate your understanding.",
},
selectRegisteredAsset: {
title: 'Select a token',
@@ -858,4 +863,7 @@ export default {
btnGoToSettings: 'Go to settings',
btnAllow: 'Allow access',
},
+ minAmountText: 'min. amount',
+ maxAmountText: 'max. amount',
+ exceededAmountText: '{amount} exceeded',
};
diff --git a/src/lang/nl.json b/src/lang/nl.json
index 772292e37..a2aef3bbd 100644
--- a/src/lang/nl.json
+++ b/src/lang/nl.json
@@ -545,7 +545,9 @@
"copy": "Netwerkadres kopiëren",
"soraAddress": "{Sora} adres",
"ethereumAddress": "{Ethereum} adres",
- "limitMessage": "Momenteel is er een {type} {amount} {symbol} voor overbrugging om de stabiliteit en veiligheid van het {Sora}-netwerk te garanderen. We waarderen je begrip."
+ "limitMessage": "Momenteel is er een {type} {amount} {symbol} voor overbrugging om de stabiliteit en veiligheid van het {Sora}-netwerk te garanderen. We waarderen je begrip.",
+ "externalTransferFee": "{network} {XCM} kosten",
+ "externalTransferFeeTooltip": "Wanneer u een overbruggingstransactie naar het {network} -netwerk verzendt, wordt er een kleine vergoeding in rekening gebracht op het bedrag dat u overdraagt"
},
"selectRegisteredAsset": {
"title": "Kies een token",
diff --git a/src/lang/no.json b/src/lang/no.json
index a72ae903a..4666b15e4 100644
--- a/src/lang/no.json
+++ b/src/lang/no.json
@@ -545,7 +545,9 @@
"copy": "Kopier nettverksadressen",
"soraAddress": "{Sora} adresse",
"ethereumAddress": "{Ethereum} adresse",
- "limitMessage": "For øyeblikket er det en {type} {amount} {symbol} for brobygging for å sikre stabiliteten og sikkerheten til {Sora} -nettverket. Vi setter pris på din forståelse."
+ "limitMessage": "For øyeblikket er det en {type} {amount} {symbol} for brobygging for å sikre stabiliteten og sikkerheten til {Sora} -nettverket. Vi setter pris på din forståelse.",
+ "externalTransferFee": "{network} {XCM} gebyr",
+ "externalTransferFeeTooltip": "Når du sender en brotransaksjon til {network} -nettverket, tas et mindre gebyr fra beløpet du overfører"
},
"selectRegisteredAsset": {
"title": "Velg token",
diff --git a/src/lang/pl.json b/src/lang/pl.json
index dc957e1bd..0e39cb773 100644
--- a/src/lang/pl.json
+++ b/src/lang/pl.json
@@ -545,7 +545,9 @@
"copy": "Skopiuj adres sieciowy",
"soraAddress": "{Sora} adres",
"ethereumAddress": "{Ethereum} adres",
- "limitMessage": "Obecnie istnieje {type} {amount} {symbol} do mostkowania, aby zapewnić stabilność i bezpieczeństwo sieci {Sora} . Doceniamy twoje zrozumienie."
+ "limitMessage": "Obecnie istnieje {type} {amount} {symbol} do mostkowania, aby zapewnić stabilność i bezpieczeństwo sieci {Sora} . Doceniamy twoje zrozumienie.",
+ "externalTransferFee": "Opłata {network} {XCM}",
+ "externalTransferFeeTooltip": "Kiedy wysyłasz transakcję pomostową do sieci {network} , od kwoty przelewu pobierana jest niewielka opłata"
},
"selectRegisteredAsset": {
"title": "Wybierz token",
diff --git a/src/lang/ru.json b/src/lang/ru.json
index c4ff16173..52a3b4d15 100644
--- a/src/lang/ru.json
+++ b/src/lang/ru.json
@@ -545,7 +545,9 @@
"copy": "Скопировать адрес сети",
"soraAddress": "{Sora} адрес",
"ethereumAddress": "{Ethereum} адрес",
- "limitMessage": "В настоящее время существует {type} {amount} {symbol} для моста, обеспечивающая стабильность и безопасность сети {Sora}. Мы ценим ваше понимание."
+ "limitMessage": "В настоящее время существует {type} {amount} {symbol} для моста, обеспечивающая стабильность и безопасность сети {Sora}. Мы ценим ваше понимание.",
+ "externalTransferFee": "{network} комиссия {XCM}",
+ "externalTransferFeeTooltip": "Когда вы отправляете транзакцию моста в сеть {network}, из суммы перевода взимается небольшая комиссия."
},
"selectRegisteredAsset": {
"title": "Выбрать токен",
diff --git a/src/lang/sk.json b/src/lang/sk.json
index aa646f7bd..bbe108b56 100644
--- a/src/lang/sk.json
+++ b/src/lang/sk.json
@@ -545,7 +545,9 @@
"copy": "Skopírujte sieťovú adresu",
"soraAddress": "{Sora} adresa",
"ethereumAddress": "{Ethereum} adresa",
- "limitMessage": "V súčasnosti existuje {type} {amount} {symbol} na premostenie na zaistenie stability a bezpečnosti siete {Sora}. Ďakujeme za pochopenie."
+ "limitMessage": "V súčasnosti existuje {type} {amount} {symbol} na premostenie na zaistenie stability a bezpečnosti siete {Sora}. Ďakujeme za pochopenie.",
+ "externalTransferFee": "{network} poplatok {XCM}",
+ "externalTransferFeeTooltip": "Keď odošlete preklenovaciu transakciu do siete {network} , zo sumy, ktorú prenášate, sa účtuje malý poplatok"
},
"selectRegisteredAsset": {
"title": "Vybrať token",
diff --git a/src/lang/sr.json b/src/lang/sr.json
index 2d920aefe..42924cc2f 100644
--- a/src/lang/sr.json
+++ b/src/lang/sr.json
@@ -545,7 +545,9 @@
"copy": "Копирајте мрежну адресу",
"soraAddress": "{Sora} adresa",
"ethereumAddress": "{Ethereum} adresa",
- "limitMessage": "Тренутно постоји {type} {amount} {symbol} за премошћавање да би се обезбедила стабилност и безбедност мреже {Sora} . Ценимо ваше разумевање."
+ "limitMessage": "Тренутно постоји {type} {amount} {symbol} за премошћавање да би се обезбедила стабилност и безбедност мреже {Sora} . Ценимо ваше разумевање.",
+ "externalTransferFee": "{network} {XCM} накнада",
+ "externalTransferFeeTooltip": "Када пошаљете бридге трансакцију на мрежу {network} , од износа који преносите узима се мања накнада"
},
"selectRegisteredAsset": {
"title": "Изаберите токен",
diff --git a/src/lang/sv.json b/src/lang/sv.json
index dfbc8b891..4d731d32e 100644
--- a/src/lang/sv.json
+++ b/src/lang/sv.json
@@ -545,7 +545,9 @@
"copy": "Kopiera nätverksadress",
"soraAddress": "{Sora} adress",
"ethereumAddress": "{Ethereum} adress",
- "limitMessage": "För närvarande finns det en {type} {amount} {symbol} för överbryggning för att säkerställa stabiliteten och säkerheten i {Sora} -nätverket. Vi uppskattar din förståelse."
+ "limitMessage": "För närvarande finns det en {type} {amount} {symbol} för överbryggning för att säkerställa stabiliteten och säkerheten i {Sora} -nätverket. Vi uppskattar din förståelse.",
+ "externalTransferFee": "{network} {XCM} avgift",
+ "externalTransferFeeTooltip": "När du skickar en bryggtransaktion till {network} -nätverket tas en mindre avgift från beloppet du överför"
},
"selectRegisteredAsset": {
"title": "Välj en token",
diff --git a/src/lang/vi.json b/src/lang/vi.json
index 76d8f225d..03f8497c0 100644
--- a/src/lang/vi.json
+++ b/src/lang/vi.json
@@ -545,7 +545,9 @@
"copy": "Sao chép địa chỉ mạng",
"soraAddress": "địa chỉ {Sora}",
"ethereumAddress": "địa chỉ {Ethereum}",
- "limitMessage": "Hiện tại, có một {type} {amount} {symbol} để kết nối nhằm đảm bảo tính ổn định và bảo mật của Mạng {Sora} . Chúng tôi đánh giá cao sự hiểu biết của bạn."
+ "limitMessage": "Hiện tại, có một {type} {amount} {symbol} để kết nối nhằm đảm bảo tính ổn định và bảo mật của Mạng {Sora} . Chúng tôi đánh giá cao sự hiểu biết của bạn.",
+ "externalTransferFee": "Phí {network} {XCM}",
+ "externalTransferFeeTooltip": "Khi bạn gửi giao dịch bắc cầu tới mạng {network} , số tiền bạn chuyển sẽ bị tính một khoản phí nhỏ"
},
"selectRegisteredAsset": {
"title": "Chọn token",
diff --git a/src/lang/yo.json b/src/lang/yo.json
index 8d1575299..8fbb054de 100644
--- a/src/lang/yo.json
+++ b/src/lang/yo.json
@@ -545,7 +545,9 @@
"copy": "Daakọ adirẹsi nẹtiwọki",
"soraAddress": "{Sora} adirẹsi",
"ethereumAddress": "{Ethereum} adirẹsi",
- "limitMessage": "Lọwọlọwọ, {type} {amount} {symbol} wa fun sisọpọ lati rii daju iduroṣinṣin ati aabo ti Nẹtiwọọki {Sora} . A dupe oye rẹ."
+ "limitMessage": "Lọwọlọwọ, {type} {amount} {symbol} wa fun sisọpọ lati rii daju iduroṣinṣin ati aabo ti Nẹtiwọọki {Sora} . A dupe oye rẹ.",
+ "externalTransferFee": "{network} {XCM} ọya",
+ "externalTransferFeeTooltip": "Nigbati o ba fi iṣowo afara ranṣẹ si netiwọki {network} , owo kekere kan yoo gba lati iye ti o n gbe"
},
"selectRegisteredAsset": {
"title": "Yan Tokini kan",
diff --git a/src/lang/zh_CN.json b/src/lang/zh_CN.json
index f895c757a..0feb699fd 100644
--- a/src/lang/zh_CN.json
+++ b/src/lang/zh_CN.json
@@ -545,7 +545,9 @@
"copy": "复制网络地址",
"soraAddress": "{Sora} 地址",
"ethereumAddress": "{Ethereum} 地址",
- "limitMessage": "目前,有一个{type} {amount} {symbol}用于桥接,以确保 {Sora} 网络的稳定性和安全性。我们感谢您的理解。"
+ "limitMessage": "目前,有一个{type} {amount} {symbol}用于桥接,以确保 {Sora} 网络的稳定性和安全性。我们感谢您的理解。",
+ "externalTransferFee": "{network} {XCM}费用",
+ "externalTransferFeeTooltip": "当您向{network}网络发送桥接交易时,将从您传输的金额中收取少量费用"
},
"selectRegisteredAsset": {
"title": "选择一个代币",
diff --git a/src/modules/demeterFarming/components/CalculatorDialog.vue b/src/modules/demeterFarming/components/CalculatorDialog.vue
index 2b1512017..76672a3b8 100644
--- a/src/modules/demeterFarming/components/CalculatorDialog.vue
+++ b/src/modules/demeterFarming/components/CalculatorDialog.vue
@@ -160,7 +160,7 @@ export default class CalculatorDialog extends Mixins(PoolCardMixin, mixins.Dialo
}
get calculatedRewardsFormatted(): string {
- return '~' + this.calculatedRewards.toLocaleString();
+ return this.calculatedRewards.toLocaleString();
}
get calculatedRewardsFiat(): Nullable {
diff --git a/src/router/index.ts b/src/router/index.ts
index d05c20a78..43cf17e84 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -270,7 +270,7 @@ router.beforeEach((to, from, next) => {
}
}
if (to.matched.some((record) => record.meta.requiresAuth)) {
- if (BridgeChildPages.includes(current) && isLoggedIn && !store.getters.web3.externalAccount) {
+ if (BridgeChildPages.includes(current) && isLoggedIn && !store.getters.bridge.externalAccount) {
setRoute(PageNames.Bridge);
return;
}
diff --git a/src/store/assets/actions.ts b/src/store/assets/actions.ts
index 3199ac301..0e48d8523 100644
--- a/src/store/assets/actions.ts
+++ b/src/store/assets/actions.ts
@@ -80,7 +80,7 @@ async function getRegisteredAssets(context: ActionContext): Promise => {
+ const accountBalance = await getAssetBalance(api.api, accountAddress, asset.address, asset.decimals);
+ return accountBalance.transferable;
+};
+
+const getExternalBalance = async (
+ accountAddress: string,
+ asset: RegisteredAccountAsset,
+ isSub: boolean
+): Promise => {
+ return isSub
+ ? await subBridgeConnector.networkAdapter.getTokenBalance(accountAddress, asset?.externalAddress)
+ : await ethersUtil.getAccountAssetBalance(accountAddress, asset?.externalAddress);
+};
+
+const getAccountBridgeBalance = async (
+ accountAddress: string,
+ asset: Nullable,
+ isSora: boolean,
+ isSub: boolean
+): Promise => {
+ if (!(asset?.address && accountAddress)) return ZeroStringValue;
+
+ try {
+ return isSora
+ ? await getSoraBalance(accountAddress, asset)
+ : await getExternalBalance(accountAddress, asset, isSub);
+ } catch {
+ return ZeroStringValue;
+ }
+};
+
function getBridgeApi(context: ActionContext) {
const { getters } = bridgeActionContext(context);
@@ -47,43 +86,6 @@ function checkEvmNetwork(context: ActionContext): void {
}
}
-async function evmTxDataToHistory(
- assetDataByAddress: (address: string) => Nullable,
- tx: BridgeTransactionData
-): Promise {
- const id = tx.soraHash;
- const asset = assetDataByAddress(tx.soraAssetAddress);
- const transactionState = tx.status;
- const isOutgoing = tx.direction === BridgeTxDirection.Outgoing;
- const blockHeight = isOutgoing ? tx.startBlock : tx.endBlock;
- const externalBlockHeight = isOutgoing ? tx.endBlock : tx.startBlock;
- const blockId = await api.system.getBlockHash(blockHeight);
- const startTime = await api.system.getBlockTimestamp(blockId);
-
- return {
- id,
- txId: id,
- blockId,
- blockHeight,
- type: isOutgoing ? Operation.EvmOutgoing : Operation.EvmIncoming,
- hash: tx.soraHash,
- transactionState,
- externalBlockHeight,
- externalNetwork: tx.externalNetwork as EvmNetwork,
- externalNetworkType: BridgeNetworkType.Evm,
- // for now we don't know it
- externalHash: '',
- amount: FPNumber.fromCodecValue(tx.amount, asset?.decimals).toString(),
- assetAddress: asset?.address,
- symbol: asset?.symbol,
- from: tx.soraAccount,
- to: tx.externalAccount,
- // for now we only know sora block, assume what this is start & end times
- startTime: startTime,
- endTime: startTime,
- };
-}
-
function bridgeDataToHistoryItem(
context: ActionContext,
{ date = Date.now(), payload = {}, ...params } = {}
@@ -93,7 +95,7 @@ function bridgeDataToHistoryItem(
const transactionState = isEthBridge ? WALLET_CONSTS.ETH_BRIDGE_STATES.INITIAL : BridgeTxStatus.Pending;
const externalNetwork = rootState.web3.networkSelected as BridgeNetworkId as any;
const externalNetworkType = isEthBridge
- ? BridgeNetworkType.EvmLegacy
+ ? BridgeNetworkType.Eth
: isEvmBridge
? BridgeNetworkType.Evm
: BridgeNetworkType.Sub;
@@ -106,46 +108,46 @@ function bridgeDataToHistoryItem(
assetAddress: (params as any).assetAddress ?? getters.asset?.address,
startTime: date,
endTime: date,
- status: '',
- hash: '',
transactionState,
- soraNetworkFee: (params as any).soraNetworkFee ?? getters.soraNetworkFee,
+ soraNetworkFee: (params as any).soraNetworkFee ?? state.soraNetworkFee,
externalNetworkFee: (params as any).externalNetworkFee,
externalNetwork,
externalNetworkType,
- to: (params as any).to ?? rootGetters.web3.externalAccount,
+ to: (params as any).to ?? getters.externalAccountFormatted,
payload,
};
}
async function getEvmNetworkFee(context: ActionContext): Promise {
- const { commit, state, rootState } = bridgeActionContext(context);
+ const { commit, getters, state, rootState } = bridgeActionContext(context);
let fee = ZeroStringValue;
- const address = state.assetAddress;
- const registeredAsset = address ? rootState.assets.registeredAssets[address] : null;
+ if (getters.asset && getters.isRegisteredAsset) {
+ const bridgeRegisteredAsset = rootState.assets.registeredAssets[getters.asset.address];
- if (registeredAsset) {
- fee = await ethersUtil.getEvmNetworkFee(registeredAsset.address, registeredAsset.kind, state.isSoraToEvm);
+ fee = await ethersUtil.getEvmNetworkFee(
+ bridgeRegisteredAsset.address,
+ bridgeRegisteredAsset.kind,
+ state.isSoraToEvm
+ );
}
commit.setExternalNetworkFee(fee);
}
async function getSubNetworkFee(context: ActionContext): Promise {
- const { commit } = bridgeActionContext(context);
-
+ const { commit, getters } = bridgeActionContext(context);
let fee = ZeroStringValue;
- if (subConnector.networkAdapter) {
- fee = await subConnector.networkAdapter.getNetworkFee();
+ if (getters.asset && getters.isRegisteredAsset) {
+ fee = await subBridgeConnector.networkAdapter.getNetworkFee(getters.asset);
}
commit.setExternalNetworkFee(fee);
}
-async function getExternalNetworkFee(context: ActionContext): Promise {
+async function updateExternalNetworkFee(context: ActionContext): Promise {
const { getters } = bridgeActionContext(context);
if (getters.isSubBridge) {
@@ -155,39 +157,26 @@ async function getExternalNetworkFee(context: ActionContext): Promise<
}
}
+async function updateExternalLockedBalance(context: ActionContext): Promise {
+ const { getters } = bridgeActionContext(context);
+
+ if (getters.isEthBridge) {
+ await updateEthLockedBalance(context);
+ } else {
+ await updateBridgeProxyLockedBalance(context);
+ }
+}
+
async function updateEvmBalances(context: ActionContext): Promise {
const { commit, getters, state } = bridgeActionContext(context);
- const { sender, recipient, asset } = getters;
+ const { sender, recipient, asset, nativeToken } = getters;
const { isSoraToEvm } = state;
-
const spender = isSoraToEvm ? recipient : sender;
- const getSenderBalance = async () => {
- if (!(asset?.address && sender)) return ZeroStringValue;
-
- return isSoraToEvm
- ? (await getAssetBalance(api.api, sender, asset.address, asset.decimals)).transferable
- : await ethersUtil.getAccountAssetBalance(sender, asset?.externalAddress);
- };
-
- const getRecipientBalance = async () => {
- if (!(asset?.address && recipient)) return ZeroStringValue;
-
- return isSoraToEvm
- ? await ethersUtil.getAccountAssetBalance(recipient, asset?.externalAddress)
- : (await getAssetBalance(api.api, recipient, asset.address, asset.decimals)).transferable;
- };
-
- const getSpenderBalance = async () => {
- if (!(asset?.address && spender)) return ZeroStringValue;
-
- return await ethersUtil.getAccountBalance(spender);
- };
-
const [senderBalance, recipientBalance, nativeBalance] = await Promise.all([
- getSenderBalance(),
- getRecipientBalance(),
- getSpenderBalance(),
+ getAccountBridgeBalance(sender, asset, isSoraToEvm, false),
+ getAccountBridgeBalance(recipient, asset, !isSoraToEvm, false),
+ getAccountBridgeBalance(spender, nativeToken, false, false),
]);
commit.setAssetSenderBalance(senderBalance);
@@ -197,35 +186,14 @@ async function updateEvmBalances(context: ActionContext): Promise): Promise {
const { commit, getters, state } = bridgeActionContext(context);
- const { sender, recipient, asset } = getters;
+ const { sender, recipient, asset, nativeToken } = getters;
const { isSoraToEvm } = state;
-
- const getSenderBalance = async () => {
- if (!(asset?.address && sender)) return ZeroStringValue;
-
- return isSoraToEvm
- ? (await getAssetBalance(api.api, sender, asset.address, asset.decimals)).transferable
- : await subConnector.networkAdapter.getTokenBalance(sender, asset?.externalAddress);
- };
-
- const getRecipientBalance = async () => {
- if (!(asset?.address && recipient)) return ZeroStringValue;
-
- return isSoraToEvm
- ? await subConnector.networkAdapter.getTokenBalance(recipient, asset?.externalAddress)
- : (await getAssetBalance(api.api, recipient, asset.address, asset.decimals)).transferable;
- };
-
- const getSpenderBalance = async () => {
- if (!(asset?.address && sender)) return ZeroStringValue;
-
- return await subConnector.networkAdapter.getTokenBalance(sender);
- };
+ const spender = sender;
const [senderBalance, recipientBalance, nativeBalance] = await Promise.all([
- getSenderBalance(),
- getRecipientBalance(),
- getSpenderBalance(),
+ getAccountBridgeBalance(sender, asset, isSoraToEvm, true),
+ getAccountBridgeBalance(recipient, asset, !isSoraToEvm, true),
+ getAccountBridgeBalance(spender, nativeToken, false, true),
]);
commit.setAssetSenderBalance(senderBalance);
@@ -247,46 +215,30 @@ async function updateEthHistory(context: ActionContext, clearHistory =
await updateHistoryFn(clearHistory, dispatch.updateInternalHistory);
}
-async function updateEvmHistory(context: ActionContext): Promise {
- const { commit, dispatch, state, rootState, rootGetters } = bridgeActionContext(context);
- const externalNetwork = rootState.web3.networkSelected;
-
- if (!externalNetwork) return;
-
- const accountAddress = rootState.wallet.account.address;
- const transactions = await evmBridgeApi.getUserTransactions(accountAddress, externalNetwork as EvmNetwork);
- const externalHistory = {};
-
- // [TODO]: update later
- for (const txData of transactions) {
- const tx = await evmTxDataToHistory(rootGetters.assets.assetDataByAddress, txData);
-
- if (tx.id) {
- const inProgress = state.inProgressIds[tx.id];
-
- if (!inProgress) {
- externalHistory[tx.id] = tx;
-
- await dispatch.removeHistory({ tx, force: false });
- }
- }
- }
-
- commit.setExternalHistory(externalHistory);
-}
-
async function updateEthLockedBalance(context: ActionContext): Promise {
const { commit, getters, rootGetters, rootState } = bridgeActionContext(context);
- const { address, externalAddress } = getters.asset || {};
+ const { address, decimals, externalAddress } = getters.asset ?? {};
+ const { networkSelected } = rootState.web3;
const bridgeContractAddress = rootGetters.web3.contractAddress(KnownEthBridgeAsset.Other);
- if (address && externalAddress && bridgeContractAddress) {
- const assetKind = rootState.assets.registeredAssets[address]?.kind;
-
- if (assetKind === BridgeRequestAssetKind.Sidechain) {
- const value = await ethersUtil.getAccountAssetBalance(bridgeContractAddress, externalAddress);
- commit.setAssetLockedBalance(value);
- return;
+ if (address && networkSelected && 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;
+ }
}
}
@@ -295,20 +247,21 @@ async function updateEthLockedBalance(context: ActionContext): Promise
async function updateBridgeProxyLockedBalance(context: ActionContext): Promise {
const { commit, getters, rootState } = bridgeActionContext(context);
- const { address } = getters.asset || {};
- const { networkSelected, networkType } = rootState.web3;
+ const { address, decimals } = getters.asset ?? {};
+ const { networkSelected } = rootState.web3;
- if (address && networkSelected && networkType) {
- const bridgeApi = getBridgeApi(context) as typeof evmBridgeApi | typeof subBridgeApi;
- const data = await bridgeApi.getLockedAssets(networkSelected as never, address);
- const balance = data.toString();
+ if (address && networkSelected) {
+ const bridgeApi = getBridgeApi(context);
+ const value = await bridgeApi.getLockedAssets(networkSelected as never, address);
+ const balance = FPNumber.fromCodecValue(value, decimals);
commit.setAssetLockedBalance(balance);
+ return;
}
commit.setAssetLockedBalance();
}
-async function getExternalTransferFee(context: ActionContext): Promise {
+async function updateExternalTransferFee(context: ActionContext): Promise {
const { commit, getters, state, rootState } = bridgeActionContext(context);
let fee = ZeroStringValue;
@@ -324,6 +277,96 @@ async function getExternalTransferFee(context: ActionContext): Promise
commit.setExternalTransferFee(fee);
}
+function calculateMaxLimit(
+ limitAsset: string,
+ referenceAsset: string,
+ usdLimit: CodecString,
+ quote: SwapQuote
+): FPNumber {
+ const outgoingLimitUSD = FPNumber.fromCodecValue(usdLimit);
+
+ if (outgoingLimitUSD.isZero() || limitAsset === referenceAsset) return outgoingLimitUSD;
+
+ try {
+ const {
+ result: { amount },
+ } = quote(limitAsset, referenceAsset, 1, false, [], false);
+
+ const assetPriceUSD = FPNumber.fromCodecValue(amount);
+
+ if (!assetPriceUSD.isFinity() || assetPriceUSD.isZero()) return FPNumber.ZERO;
+
+ return outgoingLimitUSD.div(assetPriceUSD);
+ } catch (error) {
+ console.error(error);
+ return FPNumber.ZERO;
+ }
+}
+
+async function updateExternalBlockNumber(context: ActionContext): Promise {
+ const { getters, commit } = bridgeActionContext(context);
+ try {
+ const blockNumber = getters.isSubBridge
+ ? await subBridgeConnector.networkAdapter.getBlockNumber()
+ : await (await ethersUtil.getEthersInstance()).getBlockNumber();
+
+ commit.setExternalBlockNumber(blockNumber);
+ } catch (error) {
+ console.error(error);
+ commit.setExternalBlockNumber(0);
+ }
+}
+
+async function updateFeesAndLockedFunds(context: ActionContext, withSora = false): Promise {
+ const { commit } = bridgeActionContext(context);
+
+ commit.setFeesAndLockedFundsFetching(true);
+
+ const promises = [
+ updateExternalLockedBalance(context),
+ updateExternalNetworkFee(context),
+ updateExternalTransferFee(context),
+ ];
+
+ if (withSora) {
+ promises.push(updateSoraNetworkFee(context));
+ }
+
+ await Promise.allSettled(promises);
+
+ commit.setFeesAndLockedFundsFetching(false);
+}
+
+async function updateSoraNetworkFee(context: ActionContext): Promise {
+ const { commit, state, getters, rootState } = bridgeActionContext(context);
+ const { asset, operation } = getters;
+ const {
+ web3: { networkSelected },
+ wallet: {
+ settings: { networkFees },
+ },
+ } = rootState;
+
+ let fee = ZeroStringValue;
+
+ if (networkSelected && asset && state.isSoraToEvm) {
+ if (getters.isEthBridge) {
+ fee = networkFees[operation];
+ } else {
+ const bridgeApi = getBridgeApi(context) as typeof subBridgeApi | typeof evmBridgeApi;
+ fee = await bridgeApi.getNetworkFee(asset, networkSelected as never);
+ }
+ }
+
+ commit.setSoraNetworkFee(fee);
+}
+
+async function updateBalancesAndFees(context: ActionContext, withSora = false): Promise {
+ const { dispatch } = bridgeActionContext(context);
+
+ await Promise.allSettled([dispatch.updateExternalBalance(), updateFeesAndLockedFunds(context, withSora)]);
+}
+
const actions = defineActions({
setSendedAmount(context, value?: string) {
const { commit, state, getters } = bridgeActionContext(context);
@@ -361,14 +404,10 @@ const actions = defineActions({
}
},
- async updateBalancesAndFees(context): Promise {
+ async resetBridgeForm(context): Promise {
const { dispatch } = bridgeActionContext(context);
- await Promise.all([
- dispatch.updateExternalBalance(),
- dispatch.updateExternalLockedBalance(),
- dispatch.updateExternalFees(),
- ]);
+ await Promise.allSettled([dispatch.setAssetAddress(), dispatch.setSendedAmount()]);
},
async switchDirection(context): Promise {
@@ -378,7 +417,7 @@ const actions = defineActions({
commit.setAssetSenderBalance();
commit.setAssetRecipientBalance();
- await dispatch.updateBalancesAndFees();
+ await updateBalancesAndFees(context, true);
if (state.focusedField === FocusedField.Received) {
await dispatch.setSendedAmount(state.amountReceived);
@@ -394,23 +433,17 @@ const actions = defineActions({
commit.setAssetSenderBalance();
commit.setAssetRecipientBalance();
- await dispatch.updateBalancesAndFees();
- },
-
- async updateExternalFees(context): Promise {
- const { commit } = bridgeActionContext(context);
-
- commit.setExternalNetworkFeeFetching(true);
-
- await Promise.all([getExternalNetworkFee(context), getExternalTransferFee(context)]);
-
- commit.setExternalNetworkFeeFetching(false);
+ await Promise.allSettled([
+ dispatch.updateOutgoingMaxLimit(),
+ dispatch.updateIncomingMinLimit(),
+ updateBalancesAndFees(context, true),
+ ]);
},
async updateExternalBalance(context): Promise {
const { commit, getters } = bridgeActionContext(context);
- commit.setExternalBalancesFetching(true);
+ commit.setBalancesFetching(true);
if (getters.isSubBridge) {
await updateSubBalances(context);
@@ -418,42 +451,78 @@ const actions = defineActions({
await updateEvmBalances(context);
}
- commit.setExternalBalancesFetching(false);
+ commit.setBalancesFetching(false);
},
- async updateExternalLockedBalance(context): Promise {
+ async updateIncomingMinLimit(context): Promise {
const { commit, getters } = bridgeActionContext(context);
- commit.setAssetLockedBalanceFetching(true);
-
- if (getters.isEthBridge) {
- await updateEthLockedBalance(context);
- } else {
- await updateBridgeProxyLockedBalance(context);
+ let minLimit = FPNumber.ZERO;
+
+ if (getters.isSubBridge && getters.asset && getters.isRegisteredAsset) {
+ try {
+ const value = await subBridgeApi.soraParachainApi.getAssetMinimumAmount(
+ getters.asset.address,
+ subBridgeConnector.parachainAdapter.api
+ );
+ minLimit = FPNumber.fromCodecValue(value, getters.asset.externalDecimals);
+ } catch (error) {
+ console.error(error);
+ }
}
- commit.setAssetLockedBalanceFetching(false);
+ commit.setIncomingMinLimit(minLimit);
},
- async updateExternalBlockNumber(context): Promise {
- const { getters, commit } = bridgeActionContext(context);
+ async updateOutgoingMaxLimit(context): Promise {
+ const { state, commit } = bridgeActionContext(context);
- try {
- const blockNumber = getters.isSubBridge
- ? await subConnector.networkAdapter.getBlockNumber()
- : await (await ethersUtil.getEthersInstance()).getBlockNumber();
+ const limitAsset = state.assetAddress;
- commit.setExternalBlockNumber(blockNumber);
- } catch {
- commit.setExternalBlockNumber(0);
- }
+ commit.resetOutgoingMaxLimitSubscription();
+
+ if (!limitAsset) return;
+
+ const hasOutgoingLimit = await api.bridgeProxy.isAssetTransferLimited(limitAsset);
+
+ if (!hasOutgoingLimit) return;
+
+ const referenceAsset = DAI.address;
+ const sources = [LiquiditySourceTypes.XYKPool, LiquiditySourceTypes.XSTPool];
+ const limitObservable = api.bridgeProxy.getCurrentTransferLimitObservable();
+ const quoteObservable = await api.swap.getSwapQuoteObservable(referenceAsset, limitAsset, sources, DexId.XOR);
+
+ let subscription!: Subscription;
+
+ await new Promise((resolve) => {
+ subscription = combineLatest([limitObservable, quoteObservable]).subscribe(([usdLimit, { quote }]) => {
+ const outgoingMaxLimit = calculateMaxLimit(limitAsset, referenceAsset, usdLimit, quote);
+ commit.setOutgoingMaxLimit(outgoingMaxLimit);
+ resolve();
+ });
+ });
+
+ commit.setOutgoingMaxLimitSubscription(subscription);
+ },
+
+ async subscribeOnBlockUpdates(context): Promise {
+ const { commit } = bridgeActionContext(context);
+
+ commit.resetBlockUpdatesSubscription();
+
+ const subscription = api.system.updated.subscribe(() => {
+ updateExternalBlockNumber(context);
+ updateBalancesAndFees(context);
+ });
+
+ commit.setBlockUpdatesSubscription(subscription);
},
async generateHistoryItem(context, playground): Promise {
const { dispatch } = bridgeActionContext(context);
const historyData = bridgeDataToHistoryItem(context, playground);
const bridgeApi = getBridgeApi(context);
- const historyItem = bridgeApi.generateHistoryItem(historyData as any);
+ const historyItem = bridgeApi.generateHistoryItem(historyData as never);
if (!historyItem) {
throw new Error('[Bridge]: "generateHistoryItem" failed');
@@ -481,18 +550,18 @@ const actions = defineActions({
if (getters.isEthBridge) {
await updateEthHistory(context, clearHistory);
}
- if (getters.isEvmBridge) {
- await updateEvmHistory(context);
- }
if (getters.isSubBridge) {
await updateSubHistory(context, clearHistory);
}
+ if (getters.isEvmBridge) {
+ console.info('Evm history not implemented');
+ }
commit.setHistoryLoading(false);
},
removeHistory(context, { tx, force = false }: { tx: Partial; force: boolean }): void {
- const { commit, dispatch, getters, state, rootState } = bridgeActionContext(context);
+ const { commit, dispatch, state, rootState } = bridgeActionContext(context);
const { id, hash } = tx;
@@ -555,7 +624,7 @@ const actions = defineActions({
async signEthBridgeOutgoingEvm(context, id: string): Promise {
const { rootState, rootGetters } = bridgeActionContext(context);
- const tx = ethBridgeApi.getHistory(id) as Nullable;
+ const tx = ethBridgeApi.getHistory(id) as Nullable;
if (!tx?.hash) throw new Error('TX ID cannot be empty!');
if (!tx.amount) throw new Error('TX amount cannot be empty!');
@@ -582,11 +651,11 @@ const actions = defineActions({
const contractInstance = new ethers.Contract(contractAddress, contract.abi, signer);
const method = isValOrXor
? 'mintTokensByPeers'
- : request.currencyType === BridgeCurrencyType.TokenAddress
+ : request.currencyType === EthCurrencyType.TokenAddress
? 'receiveByEthereumAssetAddress'
: 'receiveBySidechainAssetId';
const methodArgs: Array = [
- isValOrXor || request.currencyType === BridgeCurrencyType.TokenAddress
+ isValOrXor || request.currencyType === EthCurrencyType.TokenAddress
? asset.externalAddress // address tokenAddress OR
: asset.address, // bytes32 assetId
new FPNumber(tx.amount, asset.externalDecimals).toCodecString(), // uint256 amount
diff --git a/src/store/bridge/getters.ts b/src/store/bridge/getters.ts
index 7d04cb598..4bf8c4fab 100644
--- a/src/store/bridge/getters.ts
+++ b/src/store/bridge/getters.ts
@@ -4,6 +4,7 @@ import { defineGetters } from 'direct-vuex';
import { ZeroStringValue } from '@/consts';
import { bridgeGetterContext } from '@/store/bridge';
+import { formatSubAddress } from '@/utils/bridge/sub/utils';
import type { BridgeState } from './types';
import type { IBridgeTransaction, CodecString } from '@sora-substrate/util';
@@ -59,26 +60,56 @@ const getters = defineGetters()({
return !!asset?.externalAddress;
},
+ externalAccount(...args): string {
+ const { getters, rootState } = bridgeGetterContext(args);
+ const { evmAddress, subAddress } = rootState.web3;
+
+ if (getters.isSubBridge) {
+ return subAddress;
+ } else {
+ return evmAddress;
+ }
+ },
+
+ externalAccountFormatted(...args): string {
+ const { getters, state, rootState } = bridgeGetterContext(args);
+ const { subSS58 } = rootState.web3;
+
+ if (getters.isSubBridge && state.isSoraToEvm && getters.externalAccount) {
+ return formatSubAddress(getters.externalAccount, subSS58);
+ } else {
+ return getters.externalAccount;
+ }
+ },
+
sender(...args): string {
const { state, rootState, getters } = bridgeGetterContext(args);
+ const { address: soraAddress } = rootState.wallet.account;
+ const { evmAddress, subSS58 } = rootState.web3;
- if (getters.isSubBridge) return rootState.wallet.account.address;
+ if (getters.isSubBridge) {
+ return !state.isSoraToEvm && soraAddress ? formatSubAddress(soraAddress, subSS58) : soraAddress;
+ }
- return state.isSoraToEvm ? rootState.wallet.account.address : rootState.web3.evmAddress;
+ return state.isSoraToEvm ? soraAddress : evmAddress;
},
recipient(...args): string {
const { state, rootState, getters } = bridgeGetterContext(args);
+ const { address: soraAddress } = rootState.wallet.account;
+ const { evmAddress, subAddress, subSS58 } = rootState.web3;
- if (getters.isSubBridge) return rootState.web3.subAddress;
+ if (getters.isSubBridge) {
+ return state.isSoraToEvm && subAddress ? formatSubAddress(subAddress, subSS58) : subAddress;
+ }
- return state.isSoraToEvm ? rootState.web3.evmAddress : rootState.wallet.account.address;
+ return state.isSoraToEvm ? evmAddress : soraAddress;
},
isEthBridge(...args): boolean {
const { rootState } = bridgeGetterContext(args);
- return rootState.web3.networkType === BridgeNetworkType.EvmLegacy;
+ return rootState.web3.networkType === BridgeNetworkType.Eth;
},
isEvmBridge(...args): boolean {
const { rootState } = bridgeGetterContext(args);
@@ -100,10 +131,6 @@ const getters = defineGetters()({
return state.isSoraToEvm ? Operation.SubstrateOutgoing : Operation.SubstrateIncoming;
}
},
- soraNetworkFee(...args): CodecString {
- const { getters, rootState } = bridgeGetterContext(args);
- return rootState.wallet.settings.networkFees[getters.operation] ?? ZeroStringValue;
- },
externalNetworkFee(...args): CodecString {
const { state, getters } = bridgeGetterContext(args);
diff --git a/src/store/bridge/mutations.ts b/src/store/bridge/mutations.ts
index 7458d9bf7..8ef9f2a9e 100644
--- a/src/store/bridge/mutations.ts
+++ b/src/store/bridge/mutations.ts
@@ -2,7 +2,8 @@ import { defineMutations } from 'direct-vuex';
import omit from 'lodash/fp/omit';
import type { BridgeState, FocusedField } from './types';
-import type { IBridgeTransaction, CodecString } from '@sora-substrate/util';
+import type { FPNumber, IBridgeTransaction, CodecString } from '@sora-substrate/util';
+import type { Subscription } from 'rxjs';
const mutations = defineMutations()({
setSoraToEvm(state, isSoraToEvm: boolean): void {
@@ -21,18 +22,39 @@ const mutations = defineMutations()({
state.assetRecipientBalance = balance;
},
- setAssetLockedBalance(state, balance: Nullable = null): void {
+ setAssetLockedBalance(state, balance: Nullable = null): void {
state.assetLockedBalance = balance;
},
- setAssetLockedBalanceFetching(state, flag: boolean): void {
- state.assetLockedBalanceFetching = flag;
- },
setExternalBalance(state, balance: Nullable = null): void {
state.externalNativeBalance = balance;
},
- setExternalBalancesFetching(state, flag: boolean): void {
- state.externalBalancesFetching = flag;
+
+ setIncomingMinLimit(state, amount: FPNumber): void {
+ state.incomingMinLimit = amount;
+ },
+
+ setOutgoingMaxLimit(state, amount: Nullable): void {
+ state.outgoingMaxLimit = amount;
+ },
+
+ setOutgoingMaxLimitSubscription(state, subscription: Subscription): void {
+ state.outgoingMaxLimitSubscription = subscription;
+ },
+
+ resetOutgoingMaxLimitSubscription(state): void {
+ state.outgoingMaxLimitSubscription?.unsubscribe();
+ state.outgoingMaxLimitSubscription = null;
+ state.outgoingMaxLimit = null;
+ },
+
+ setBlockUpdatesSubscription(state, subscription: Subscription): void {
+ state.blockUpdatesSubscription = subscription;
+ },
+
+ resetBlockUpdatesSubscription(state): void {
+ state.blockUpdatesSubscription?.unsubscribe();
+ state.blockUpdatesSubscription = null;
},
setAmountSend(state, value?: string): void {
@@ -47,8 +69,12 @@ const mutations = defineMutations()({
state.focusedField = field;
},
- setExternalNetworkFeeFetching(state, flag: boolean): void {
- state.externalNetworkFeeFetching = flag;
+ setBalancesFetching(state, flag: boolean): void {
+ state.balancesFetching = flag;
+ },
+
+ setFeesAndLockedFundsFetching(state, flag: boolean): void {
+ state.feesAndLockedFundsFetching = flag;
},
setExternalNetworkFee(state, fee: CodecString): void {
@@ -59,6 +85,10 @@ const mutations = defineMutations()({
state.externalTransferFee = fee;
},
+ setSoraNetworkFee(state, fee: CodecString) {
+ state.soraNetworkFee = fee;
+ },
+
/**
* Set bridge transactions from localstorage (ethBridgeApi or evmBridgeApi)
*/
diff --git a/src/store/bridge/state.ts b/src/store/bridge/state.ts
index f6c0074f4..6bf0fbf09 100644
--- a/src/store/bridge/state.ts
+++ b/src/store/bridge/state.ts
@@ -1,3 +1,5 @@
+import { FPNumber } from '@sora-substrate/util';
+
import { ZeroStringValue } from '@/consts';
import type { BridgeState } from './types';
@@ -9,15 +11,19 @@ function initialState(): BridgeState {
assetSenderBalance: null, // balance for sora
assetRecipientBalance: null, // balance for bridge network
assetLockedBalance: null, // asset balance locked on bridge
- assetLockedBalanceFetching: false,
+ incomingMinLimit: FPNumber.ZERO, // incoming min limit in asset amount
+ outgoingMaxLimit: null, // outgoing max limit in asset amount
+ outgoingMaxLimitSubscription: null,
+ blockUpdatesSubscription: null,
amountSend: '',
amountReceived: '',
focusedField: null,
+ soraNetworkFee: ZeroStringValue,
externalTransferFee: ZeroStringValue, // fee for transfer between networks (xcm message fee for substrate network)
externalNetworkFee: ZeroStringValue, // fee for transaction execution
- externalNetworkFeeFetching: false,
+ balancesFetching: false,
+ feesAndLockedFundsFetching: false,
externalNativeBalance: ZeroStringValue, // balance for external native token (like ETH)
- externalBalancesFetching: false,
externalBlockNumber: 0,
// history sources
historyInternal: {}, // localstorage history
diff --git a/src/store/bridge/types.ts b/src/store/bridge/types.ts
index 2ba335fde..1a6ce8c83 100644
--- a/src/store/bridge/types.ts
+++ b/src/store/bridge/types.ts
@@ -1,4 +1,5 @@
-import type { CodecString, IBridgeTransaction } from '@sora-substrate/util';
+import type { FPNumber, CodecString, IBridgeTransaction } from '@sora-substrate/util';
+import type { Subscription } from 'rxjs';
export enum FocusedField {
Sended = 'Sended',
@@ -10,16 +11,20 @@ export type BridgeState = {
assetAddress: string;
assetSenderBalance: Nullable;
assetRecipientBalance: Nullable;
- assetLockedBalance: Nullable;
- assetLockedBalanceFetching: boolean;
+ assetLockedBalance: Nullable;
+ incomingMinLimit: FPNumber;
+ outgoingMaxLimit: Nullable;
+ outgoingMaxLimitSubscription: Nullable;
+ blockUpdatesSubscription: Nullable;
amountSend: string;
amountReceived: string;
focusedField: Nullable;
+ soraNetworkFee: CodecString;
externalTransferFee: CodecString;
externalNetworkFee: CodecString;
- externalNetworkFeeFetching: boolean;
+ balancesFetching: boolean;
+ feesAndLockedFundsFetching: boolean;
externalNativeBalance: Nullable;
- externalBalancesFetching: boolean;
externalBlockNumber: number;
// history sources (unsynced localstorage & network)
historyInternal: Record;
diff --git a/src/store/moonpay/actions.ts b/src/store/moonpay/actions.ts
index 899c27973..c99b4b9a1 100644
--- a/src/store/moonpay/actions.ts
+++ b/src/store/moonpay/actions.ts
@@ -93,10 +93,8 @@ const actions = defineActions({
if (!decodedInput) throw new Error(`Unable to parse transaction data: "${tx.data}"`);
const address = tx.to ?? ''; // asset address
- const {
- value, // BigNumber
- to = '', // ethereum address
- } = decodedInput.args;
+ const value = decodedInput.args.getValue('value'); // BigNumber
+ const to = decodedInput.args.getValue('to'); // ethereum address
const amount = new FPNumber(value).toString(); // transferred amount
return {
diff --git a/src/store/moonpay/types.ts b/src/store/moonpay/types.ts
index 6c28fa6ac..e1d615ff1 100644
--- a/src/store/moonpay/types.ts
+++ b/src/store/moonpay/types.ts
@@ -1,7 +1,7 @@
import type { MoonpayNotifications } from '@/components/pages/Moonpay/consts';
import type { MoonpayApi, MoonpayCurrency, MoonpayTransaction } from '@/utils/moonpay';
-import type { BridgeHistory } from '@sora-substrate/util';
+import type { EthHistory } from '@sora-substrate/util/build/bridgeProxy/eth/types';
export type MoonpayState = {
api: MoonpayApi;
@@ -12,12 +12,12 @@ export type MoonpayState = {
pollingTimestamp: number;
transactions: Array;
transactionsFetching: boolean;
- bridgeTransactionData: Nullable;
+ bridgeTransactionData: Nullable;
startBridgeButtonVisibility: boolean;
currencies: Array;
};
export type BridgeTxData = Partial<{
- data: Nullable;
+ data: Nullable;
startBridgeButtonVisibility: boolean;
}>;
diff --git a/src/store/web3/actions.ts b/src/store/web3/actions.ts
index e905bed96..483881886 100644
--- a/src/store/web3/actions.ts
+++ b/src/store/web3/actions.ts
@@ -6,83 +6,60 @@ import { ethers } from 'ethers';
import { KnownEthBridgeAsset, SmartContracts, SmartContractType } from '@/consts/evm';
import { web3ActionContext } from '@/store/web3';
-import { subConnector } from '@/utils/bridge/sub/classes/adapter';
+import { SubNetworksConnector, subBridgeConnector } from '@/utils/bridge/sub/classes/adapter';
import ethersUtil from '@/utils/ethers-util';
-import type { Provider } from '@/utils/ethers-util';
import type { SubNetworkApps } from './types';
import type { SubNetwork } from '@sora-substrate/util/build/bridgeProxy/sub/consts';
import type { ActionContext } from 'vuex';
-async function connectEvmNetwork(context: ActionContext, networkHex?: string): Promise {
- const { commit } = web3ActionContext(context);
- const evmNetwork = networkHex ? ethersUtil.hexToNumber(networkHex) : await ethersUtil.getEvmNetworkId();
- commit.setProvidedEvmNetwork(evmNetwork);
-}
-
async function connectSubNetwork(context: ActionContext): Promise {
- const { getters } = web3ActionContext(context);
+ const { getters, commit } = web3ActionContext(context);
const subNetwork = getters.selectedNetwork;
if (!subNetwork) return;
- await subConnector.open(subNetwork.id as SubNetwork);
+ await subBridgeConnector.open(subNetwork.id as SubNetwork);
+
+ const ss58 = subBridgeConnector.networkAdapter.api.registry.chainSS58;
+
+ if (ss58) commit.setSubSS58(ss58);
}
const actions = defineActions({
- async connectEvmAccount(context, provider: Provider): Promise {
+ async updateProvidedEvmNetwork(context, networkHex?: string): Promise {
const { commit } = web3ActionContext(context);
- const address = await ethersUtil.onConnect({ provider });
- commit.setEvmAddress(address);
+ const evmNetwork = networkHex ? ethersUtil.hexToNumber(networkHex) : await ethersUtil.getEvmNetworkId();
+ commit.setProvidedEvmNetwork(evmNetwork);
},
- async connectSubAccount(context, address: string): Promise {
- const { commit, rootDispatch } = web3ActionContext(context);
- commit.setSubAddress(address);
-
- await rootDispatch.bridge.updateExternalBalance();
+ async disconnectExternalNetwork(context): Promise {
+ await subBridgeConnector.stop();
},
- async connectExternalNetwork(context, network?: string): Promise {
- const { dispatch, state, rootDispatch } = web3ActionContext(context);
+ async selectExternalNetwork(context, { id, type }: { id: BridgeNetworkId; type: BridgeNetworkType }): Promise {
+ const { commit, dispatch, rootDispatch } = web3ActionContext(context);
- await dispatch.disconnectExternalNetwork();
+ dispatch.disconnectExternalNetwork();
- if (state.networkType === BridgeNetworkType.Sub) {
- await connectSubNetwork(context);
- } else {
- await connectEvmNetwork(context, network);
- }
+ commit.setNetworkType(type);
+ commit.setSelectedNetwork(id);
- await Promise.all([rootDispatch.assets.updateRegisteredAssets(), rootDispatch.bridge.updateBalancesAndFees()]);
- },
+ rootDispatch.assets.updateRegisteredAssets();
- async disconnectExternalNetwork(context): Promise {
- const { commit } = web3ActionContext(context);
-
- await subConnector.stop();
-
- commit.resetProvidedEvmNetwork();
- },
-
- async selectExternalNetwork(context, network: BridgeNetworkId): Promise {
- const { commit, dispatch } = web3ActionContext(context);
- commit.setSelectedNetwork(network);
- await dispatch.updateNetworkProvided();
+ if (type === BridgeNetworkType.Sub) {
+ await connectSubNetwork(context);
+ }
},
- async updateNetworkProvided(context): Promise {
- const { dispatch, getters, state } = web3ActionContext(context);
+ async changeEvmNetworkProvided(context): Promise {
+ const { getters, state } = web3ActionContext(context);
const { selectedNetwork } = getters;
const { networkType } = state;
- if (!selectedNetwork) return;
-
- if (networkType !== BridgeNetworkType.Sub) {
+ if (selectedNetwork && networkType !== BridgeNetworkType.Sub) {
await ethersUtil.switchOrAddChain(selectedNetwork);
}
-
- await dispatch.connectExternalNetwork();
},
async getSupportedApps(context): Promise {
@@ -95,15 +72,15 @@ const actions = defineActions({
const { commit } = web3ActionContext(context);
// update apps in store
commit.setSubNetworkApps(apps);
- // update endpoints in subConnector
- subConnector.endpoints = apps;
+ // update endpoints in SubNetworksConnector class
+ SubNetworksConnector.endpoints = apps;
},
/**
- * Restore selected by user network & network type (EVMLegacy, EVM, Sub)
+ * Restore selected by user network & network type (Eth, EVM, Sub)
*/
async restoreSelectedNetwork(context): Promise {
- const { commit, state, getters } = web3ActionContext(context);
+ const { dispatch, state, getters } = web3ActionContext(context);
const [type, id] = [ethersUtil.getSelectedBridgeType(), ethersUtil.getSelectedNetwork()];
@@ -111,14 +88,15 @@ const actions = defineActions({
const networkData = getters.availableNetworks[type]?.[id];
if (!!networkData && !networkData.disabled) {
- commit.setNetworkType(type);
- commit.setSelectedNetwork(id);
+ await dispatch.selectExternalNetwork({ id, type });
return;
}
}
- commit.setNetworkType(BridgeNetworkType.EvmLegacy);
- commit.setSelectedNetwork(state.ethBridgeEvmNetwork);
+ await dispatch.selectExternalNetwork({
+ id: state.ethBridgeEvmNetwork,
+ type: BridgeNetworkType.Eth,
+ });
},
async getEvmTokenAddressByAssetId(context, soraAssetId: string): Promise {
diff --git a/src/store/web3/getters.ts b/src/store/web3/getters.ts
index b57d16250..2061ad99b 100644
--- a/src/store/web3/getters.ts
+++ b/src/store/web3/getters.ts
@@ -13,16 +13,6 @@ import type { Web3State, AvailableNetwork } from './types';
import type { BridgeNetworkId } from '@sora-substrate/util/build/bridgeProxy/types';
const getters = defineGetters()({
- externalAccount(...args): string {
- const { state } = web3GetterContext(args);
-
- if (state.networkType === BridgeNetworkType.Sub) {
- return state.subAddress;
- } else {
- return state.evmAddress;
- }
- },
-
availableNetworks(...args): Record>> {
const { state } = web3GetterContext(args);
@@ -75,7 +65,7 @@ const getters = defineGetters()({
}, {});
return {
- [BridgeNetworkType.EvmLegacy]: hashi,
+ [BridgeNetworkType.Eth]: hashi,
[BridgeNetworkType.Evm]: evm,
[BridgeNetworkType.Sub]: sub,
};
diff --git a/src/store/web3/mutations.ts b/src/store/web3/mutations.ts
index 660838a75..30b7113f0 100644
--- a/src/store/web3/mutations.ts
+++ b/src/store/web3/mutations.ts
@@ -22,6 +22,10 @@ const mutations = defineMutations()({
state.subAddress = address;
},
+ setSubSS58(state, prefix: number) {
+ state.subSS58 = prefix;
+ },
+
setEvmNetworksApp(state, networksIds: EvmNetwork[]): void {
state.evmNetworkApps = networksIds;
},
diff --git a/src/store/web3/state.ts b/src/store/web3/state.ts
index febd3e895..7ff579007 100644
--- a/src/store/web3/state.ts
+++ b/src/store/web3/state.ts
@@ -1,15 +1,13 @@
import { BridgeNetworkType } from '@sora-substrate/util/build/bridgeProxy/consts';
import { EvmNetworkId } from '@sora-substrate/util/build/bridgeProxy/evm/consts';
-import { ZeroStringValue } from '@/consts';
-import ethersUtil from '@/utils/ethers-util';
-
import type { Web3State } from './types';
export function initialState(): Web3State {
return {
evmAddress: '', // external evm address
subAddress: '', // external sub address
+ subSS58: 69, // external sub network ss58 prefix (sora by default)
networkType: null, // network type for selected network
networkSelected: null, // network selected by user
@@ -19,7 +17,7 @@ export function initialState(): Web3State {
subNetworkApps: {}, // sub netowrks from app config
supportedApps: {
- [BridgeNetworkType.EvmLegacy]: {},
+ [BridgeNetworkType.Eth]: {},
[BridgeNetworkType.Evm]: {},
[BridgeNetworkType.Sub]: [],
}, // supported apps from chain
diff --git a/src/store/web3/types.ts b/src/store/web3/types.ts
index 1d3681a06..d43f74076 100644
--- a/src/store/web3/types.ts
+++ b/src/store/web3/types.ts
@@ -29,6 +29,7 @@ export type AvailableNetwork = {
export type Web3State = {
evmAddress: string;
subAddress: string;
+ subSS58: number;
networkType: Nullable;
networkSelected: Nullable;
diff --git a/src/utils/bridge/common/utils.ts b/src/utils/bridge/common/utils.ts
index 7351fa98d..3e073f486 100644
--- a/src/utils/bridge/common/utils.ts
+++ b/src/utils/bridge/common/utils.ts
@@ -1,4 +1,4 @@
-import { Operation, isBridgeOperation, isEvmOperation, isSubstrateOperation } from '@sora-substrate/util';
+import { Operation, isEthOperation, isEvmOperation, isSubstrateOperation } from '@sora-substrate/util';
import { api as soraApi } from '@soramitsu/soraneo-wallet-web';
import { ethers } from 'ethers';
@@ -8,7 +8,8 @@ import { isUnsignedTx as isUnsignedSubTx } from '@/utils/bridge/sub/utils';
import ethersUtil from '@/utils/ethers-util';
import type { ApiPromise } from '@polkadot/api';
-import type { IBridgeTransaction, BridgeHistory } from '@sora-substrate/util';
+import type { IBridgeTransaction } from '@sora-substrate/util';
+import type { EthHistory } from '@sora-substrate/util/build/bridgeProxy/eth/types';
import type { EvmHistory } from '@sora-substrate/util/build/bridgeProxy/evm/types';
import type { SubHistory } from '@sora-substrate/util/build/bridgeProxy/sub/types';
@@ -64,39 +65,26 @@ export const getEvmTransactionRecieptByHash = async (
}
};
+export const getBlockEventsByTxIndex = async (blockHash: string, index: number, api: ApiPromise) => {
+ const blockEvents = await soraApi.system.getBlockEvents(blockHash, api);
+ const transactionEvents = blockEvents.filter(
+ ({ phase }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.toNumber() === index
+ );
+
+ return transactionEvents;
+};
+
export const getTransactionEvents = async (blockHash: string, transactionHash: string, api: ApiPromise) => {
const extrinsics = await soraApi.system.getExtrinsicsFromBlock(blockHash, api);
const extrinsicIndex = extrinsics.findIndex((ext) => ext.hash.toString() === transactionHash);
if (extrinsicIndex === -1) throw new Error(`Unable to find extrinsic "${transactionHash}" in block "${blockHash}"`);
- const blockEvents = await soraApi.system.getBlockEvents(blockHash, api);
- const transactionEvents = blockEvents.filter(
- ({ phase }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.toNumber() === extrinsicIndex
- );
+ const transactionEvents = await getBlockEventsByTxIndex(blockHash, extrinsicIndex, api);
return transactionEvents;
};
-export const findEventInBlock = async ({
- api,
- blockId,
- section,
- method,
-}: {
- api: ApiPromise;
- blockId: string;
- section: string;
- method: string;
-}) => {
- const blockEvents = await soraApi.system.getBlockEvents(blockId, api);
- const event = blockEvents.find(({ event }) => event.section === section && event.method === method);
-
- if (!event) throw new Error('Event not found');
-
- return event.event.data;
-};
-
export const isOutgoingTransaction = (transaction: Nullable): boolean => {
if (!transaction?.type) return false;
@@ -106,7 +94,7 @@ export const isOutgoingTransaction = (transaction: Nullable)
export const isUnsignedTx = (transaction: Nullable): boolean => {
if (!transaction?.type) return true;
- if (isBridgeOperation(transaction.type)) return isUnsignedEthTx(transaction as BridgeHistory);
+ if (isEthOperation(transaction.type)) return isUnsignedEthTx(transaction as EthHistory);
if (isEvmOperation(transaction.type)) return isUnsignedEvmTx(transaction as EvmHistory);
if (isSubstrateOperation(transaction.type)) return isUnsignedSubTx(transaction as SubHistory);
diff --git a/src/utils/bridge/eth/api.ts b/src/utils/bridge/eth/api.ts
index ab5dd794d..366271557 100644
--- a/src/utils/bridge/eth/api.ts
+++ b/src/utils/bridge/eth/api.ts
@@ -1,3 +1,3 @@
import { api } from '@soramitsu/soraneo-wallet-web';
-export const ethBridgeApi = api.bridge;
+export const ethBridgeApi = api.bridgeProxy.eth;
diff --git a/src/utils/bridge/eth/classes/history.ts b/src/utils/bridge/eth/classes/history.ts
index 5a534c801..242c570b9 100644
--- a/src/utils/bridge/eth/classes/history.ts
+++ b/src/utils/bridge/eth/classes/history.ts
@@ -1,5 +1,5 @@
-import { BridgeTxStatus, Operation } from '@sora-substrate/util';
-import { BridgeNetworkType } from '@sora-substrate/util/build/bridgeProxy/consts';
+import { Operation } from '@sora-substrate/util';
+import { BridgeNetworkType, BridgeTxStatus } from '@sora-substrate/util/build/bridgeProxy/consts';
import {
api,
historyElementsFilter,
@@ -19,8 +19,9 @@ import { getEvmTransactionRecieptByHash, isOutgoingTransaction } from '@/utils/b
import { ethBridgeApi } from '@/utils/bridge/eth/api';
import ethersUtil from '@/utils/ethers-util';
-import type { BridgeHistory, NetworkFeesObject } from '@sora-substrate/util';
+import type { NetworkFeesObject } from '@sora-substrate/util';
import type { RegisteredAccountAsset } from '@sora-substrate/util/build/assets/types';
+import type { EthHistory } from '@sora-substrate/util/build/bridgeProxy/eth/types';
import type { ActionContext } from 'vuex';
export default class EtherscanHistoryProvider extends EtherscanProvider {
@@ -44,7 +45,7 @@ const BRIDGE_INTERFACE = new ethers.Interface([
const { ETH_BRIDGE_STATES } = WALLET_CONSTS;
-const isLocalHistoryItem = (item: BridgeHistory, txId: string, isOutgoing: boolean, requestHash: string) => {
+const isLocalHistoryItem = (item: EthHistory, txId: string, isOutgoing: boolean, requestHash: string) => {
if (item.txId === txId) return true;
return isOutgoing ? item.hash === requestHash : item.externalHash === requestHash;
@@ -92,7 +93,7 @@ const getTransactionState = (isOutgoing: boolean, soraPartCompleted: boolean, ex
}
};
-const hasFinishedState = (item: Nullable) => {
+const hasFinishedState = (item: Nullable) => {
if (!item) return false;
const isOutgoing = isOutgoingTransaction(item);
@@ -232,12 +233,14 @@ export class EthBridgeHistory {
for (const tx of Object.values(transactions)) {
try {
- const decodedInput = BRIDGE_INTERFACE.parseTransaction(tx);
+ const data = (tx as any).input; // 'data' is named as 'input'
+ const decodedInput = BRIDGE_INTERFACE.parseTransaction({ data });
- if (decodedInput?.args.txHash.toLowerCase() === hash.toLowerCase()) {
+ if (decodedInput?.args.getValue('txHash').toLowerCase() === hash.toLowerCase()) {
return tx;
}
} catch (err) {
+ console.info(err);
continue;
}
}
@@ -294,7 +297,7 @@ export class EthBridgeHistory {
if (!historyElements.length) return;
- const currentHistory = ethBridgeApi.historyList as BridgeHistory[];
+ const currentHistory = ethBridgeApi.historyList as EthHistory[];
const { externalNetwork } = this;
@@ -307,7 +310,7 @@ export class EthBridgeHistory {
const { id: txId, blockHash: blockId, blockHeight, data: historyElementData } = historyElement;
const { requestHash, amount, assetId: assetAddress, sidechainAddress } = historyElementData as HistoryElementData;
- const localHistoryItem = currentHistory.find((item: BridgeHistory) =>
+ const localHistoryItem = currentHistory.find((item: EthHistory) =>
isLocalHistoryItem(item, txId, isOutgoing, requestHash)
);
@@ -354,16 +357,16 @@ export class EthBridgeHistory {
externalBlockId,
externalBlockHeight,
externalNetwork,
- externalNetworkType: BridgeNetworkType.EvmLegacy,
+ externalNetworkType: BridgeNetworkType.Eth,
externalNetworkFee,
to,
};
// update or create local history item
if (localHistoryItem) {
- ethBridgeApi.saveHistory({ ...localHistoryItem, ...historyItemData } as BridgeHistory);
+ ethBridgeApi.saveHistory({ ...localHistoryItem, ...historyItemData } as EthHistory);
} else {
- ethBridgeApi.generateHistoryItem(historyItemData as BridgeHistory);
+ ethBridgeApi.generateHistoryItem(historyItemData as EthHistory);
}
await updateCallback?.();
@@ -395,7 +398,7 @@ export const updateEthBridgeHistory =
bridge: { inProgressIds },
} = rootState;
- const networkData = rootGetters.web3.availableNetworks[BridgeNetworkType.EvmLegacy][ethBridgeEvmNetwork];
+ const networkData = rootGetters.web3.availableNetworks[BridgeNetworkType.Eth][ethBridgeEvmNetwork];
if (!networkData) {
throw new Error(
diff --git a/src/utils/bridge/eth/classes/reducers.ts b/src/utils/bridge/eth/classes/reducers.ts
index dcc9454ec..935a0565c 100644
--- a/src/utils/bridge/eth/classes/reducers.ts
+++ b/src/utils/bridge/eth/classes/reducers.ts
@@ -1,20 +1,20 @@
-import { api, SUBQUERY_TYPES, WALLET_CONSTS } from '@soramitsu/soraneo-wallet-web';
-import { ethers } from 'ethers';
+import { SUBQUERY_TYPES, WALLET_CONSTS } from '@soramitsu/soraneo-wallet-web';
import first from 'lodash/fp/first';
import { BridgeReducer } from '@/utils/bridge/common/classes';
import type { IBridgeReducerOptions, GetBridgeHistoryInstance, SignExternal } from '@/utils/bridge/common/types';
import {
getEvmTransactionRecieptByHash,
- findEventInBlock,
+ getTransactionEvents,
waitForEvmTransactionMined,
} from '@/utils/bridge/common/utils';
import { ethBridgeApi } from '@/utils/bridge/eth/api';
import type { EthBridgeHistory } from '@/utils/bridge/eth/classes/history';
import { getTransaction, waitForApprovedRequest, waitForIncomingRequest } from '@/utils/bridge/eth/utils';
-import type { BridgeHistory, IBridgeTransaction } from '@sora-substrate/util';
+import type { IBridgeTransaction } from '@sora-substrate/util';
import type { RegisteredAccountAsset } from '@sora-substrate/util/build/assets/types';
+import type { EthHistory } from '@sora-substrate/util/build/bridgeProxy/eth/types';
const { ETH_BRIDGE_STATES } = WALLET_CONSTS;
@@ -24,12 +24,12 @@ type EthBridgeReducerOptions = IBridgeReducerOptio
signExternalIncoming: SignExternal;
};
-export class EthBridgeReducer extends BridgeReducer {
+export class EthBridgeReducer extends BridgeReducer {
protected readonly getBridgeHistoryInstance!: GetBridgeHistoryInstance;
protected readonly signExternalOutgoing!: SignExternal;
protected readonly signExternalIncoming!: SignExternal;
- constructor(options: EthBridgeReducerOptions) {
+ constructor(options: EthBridgeReducerOptions) {
super(options);
this.getBridgeHistoryInstance = options.getBridgeHistoryInstance;
@@ -53,7 +53,7 @@ export class EthBridgeReducer extends BridgeReducer {
);
}
- // In BridgeHistory 'blockHeight' will store evm block number
+ // In EthHistory 'blockHeight' will store evm block number
this.updateTransactionParams(id, {
externalNetworkFee: fee,
externalBlockHeight: blockNumber,
@@ -97,7 +97,7 @@ export class EthBridgeReducer extends BridgeReducer {
}
export class EthBridgeOutgoingReducer extends EthBridgeReducer {
- async changeState(transaction: BridgeHistory): Promise {
+ async changeState(transaction: EthHistory): Promise {
if (!transaction.id) throw new Error('[Bridge]: TX ID cannot be empty');
switch (transaction.transactionState) {
@@ -122,7 +122,7 @@ export class EthBridgeOutgoingReducer extends EthBridgeReducer {
if (!tx.txId) {
await this.beforeSign(id);
const asset = this.getAssetByAddress(tx.assetAddress as string) as RegisteredAccountAsset;
- await ethBridgeApi.transferToEth(asset, tx.to as string, tx.amount as string, id);
+ await ethBridgeApi.transfer(asset, tx.to as string, tx.amount as string, id);
}
// signed sora transaction has to be parsed by subquery
@@ -153,18 +153,17 @@ export class EthBridgeOutgoingReducer extends EthBridgeReducer {
await this.waitForTransactionStatus(id);
await this.waitForTransactionBlockId(id);
- const { blockId } = this.getTransaction(id);
+ const { blockId, txId, hash: soraHash } = this.getTransaction(id);
- const eventData = await findEventInBlock({
- api: api.api,
- blockId: blockId as string,
- section: 'ethBridge',
- method: 'RequestRegistered',
- });
+ if (!soraHash) {
+ const transactionEvents = await getTransactionEvents(blockId as string, txId as string, ethBridgeApi.api);
+ const requestEvent = transactionEvents.find((e) =>
+ ethBridgeApi.api.events.ethBridge.RequestRegistered.is(e.event)
+ );
+ const hash = requestEvent.event.data[0].toString();
- const hash = eventData[0].toString();
-
- this.updateTransactionParams(id, { hash });
+ this.updateTransactionParams(id, { hash });
+ }
const tx = this.getTransaction(id);
@@ -205,7 +204,7 @@ export class EthBridgeOutgoingReducer extends EthBridgeReducer {
}
export class EthBridgeIncomingReducer extends EthBridgeReducer {
- async changeState(transaction: BridgeHistory): Promise {
+ async changeState(transaction: EthHistory): Promise {
if (!transaction.id) throw new Error('[Bridge]: TX ID cannot be empty');
switch (transaction.transactionState) {
diff --git a/src/utils/bridge/eth/index.ts b/src/utils/bridge/eth/index.ts
index 20befd17c..7ffa79ca0 100644
--- a/src/utils/bridge/eth/index.ts
+++ b/src/utils/bridge/eth/index.ts
@@ -9,13 +9,13 @@ import { EthBridgeOutgoingReducer, EthBridgeIncomingReducer } from '@/utils/brid
import type { EthBridgeReducer } from '@/utils/bridge/eth/classes/reducers';
import { getTransaction, updateTransaction } from '@/utils/bridge/eth/utils';
-import type { BridgeHistory } from '@sora-substrate/util';
+import type { EthHistory } from '@sora-substrate/util/build/bridgeProxy/eth/types';
-interface EthBridgeConstructorOptions extends IBridgeConstructorOptions {
+interface EthBridgeConstructorOptions extends IBridgeConstructorOptions {
getBridgeHistoryInstance: GetBridgeHistoryInstance;
}
-type EthBridge = Bridge;
+type EthBridge = Bridge;
const { ETH_BRIDGE_STATES } = WALLET_CONSTS;
@@ -41,11 +41,11 @@ const ethBridge: EthBridge = new Bridge({
getTransaction,
updateTransaction,
// ui integration
- showNotification: (tx: BridgeHistory) => store.commit.bridge.setNotificationData(tx as any),
+ showNotification: (tx: EthHistory) => store.commit.bridge.setNotificationData(tx as any),
addTransactionToProgress: (id: string) => store.commit.bridge.addTxIdInProgress(id),
removeTransactionFromProgress: (id: string) => store.commit.bridge.removeTxIdFromProgress(id),
updateHistory: () => store.dispatch.bridge.updateInternalHistory(),
- getActiveTransaction: () => store.getters.bridge.historyItem as BridgeHistory,
+ getActiveTransaction: () => store.getters.bridge.historyItem as EthHistory,
// transaction signing
beforeTransactionSign: () => store.dispatch.wallet.transactions.beforeTransactionSign(),
// custom
diff --git a/src/utils/bridge/eth/utils.ts b/src/utils/bridge/eth/utils.ts
index 0e5b1f40e..9906fd366 100644
--- a/src/utils/bridge/eth/utils.ts
+++ b/src/utils/bridge/eth/utils.ts
@@ -1,11 +1,12 @@
-import { Operation, BridgeTxStatus } from '@sora-substrate/util';
+import { Operation } from '@sora-substrate/util';
+import { BridgeTxStatus } from '@sora-substrate/util/build/bridgeProxy/consts';
import { ethBridgeApi } from '@/utils/bridge/eth/api';
-import type { BridgeHistory, BridgeApprovedRequest } from '@sora-substrate/util';
+import type { EthHistory, EthApprovedRequest } from '@sora-substrate/util/build/bridgeProxy/eth/types';
import type { Subscription } from 'rxjs';
-export const isUnsignedFromPart = (tx: BridgeHistory): boolean => {
+export const isUnsignedFromPart = (tx: EthHistory): boolean => {
if (tx.type === Operation.EthBridgeOutgoing) {
return !tx.blockId && !tx.txId;
} else if (tx.type === Operation.EthBridgeIncoming) {
@@ -15,7 +16,7 @@ export const isUnsignedFromPart = (tx: BridgeHistory): boolean => {
}
};
-export const isUnsignedToPart = (tx: BridgeHistory): boolean => {
+export const isUnsignedToPart = (tx: EthHistory): boolean => {
if (tx.type === Operation.EthBridgeOutgoing) {
return !tx.externalHash;
} else if (tx.type === Operation.EthBridgeIncoming) {
@@ -25,12 +26,12 @@ export const isUnsignedToPart = (tx: BridgeHistory): boolean => {
}
};
-export const isUnsignedTx = (tx: BridgeHistory): boolean => {
+export const isUnsignedTx = (tx: EthHistory): boolean => {
return isUnsignedFromPart(tx);
};
-export const getTransaction = (id: string): BridgeHistory => {
- const tx = ethBridgeApi.getHistory(id) as BridgeHistory;
+export const getTransaction = (id: string): EthHistory => {
+ const tx = ethBridgeApi.getHistory(id) as EthHistory;
if (!tx) throw new Error(`[Bridge]: Transaction is not exists: ${id}`);
@@ -42,7 +43,7 @@ export const updateTransaction = async (id: string, params = {}) => {
ethBridgeApi.saveHistory({ ...tx, ...params });
};
-export const waitForApprovedRequest = async (tx: BridgeHistory): Promise => {
+export const waitForApprovedRequest = async (tx: EthHistory): Promise => {
if (!tx.hash) throw new Error(`[Bridge]: Tx hash cannot be empty`);
if (!Number.isFinite(tx.externalNetwork))
throw new Error(`[Bridge]: Tx externalNetwork should be a number, ${tx.externalNetwork} received`);
@@ -54,6 +55,7 @@ export const waitForApprovedRequest = async (tx: BridgeHistory): Promise => {
+export const waitForIncomingRequest = async (tx: EthHistory): Promise<{ hash: string; blockId: string }> => {
if (!tx.externalHash) throw new Error('[Bridge]: externalHash cannot be empty!');
if (!Number.isFinite(tx.externalNetwork))
throw new Error(`[Bridge]: Tx externalNetwork should be a number, ${tx.externalNetwork} received`);
@@ -81,6 +83,7 @@ export const waitForIncomingRequest = async (tx: BridgeHistory): Promise<{ hash:
switch (request.status) {
case BridgeTxStatus.Failed:
case BridgeTxStatus.Frozen:
+ case BridgeTxStatus.Broken:
reject(new Error('[Bridge]: Transaction was failed or canceled'));
break;
case BridgeTxStatus.Done:
diff --git a/src/utils/bridge/evm/classes/reducers.ts b/src/utils/bridge/evm/classes/reducers.ts
index fbffa42bc..3c91e6b5f 100644
--- a/src/utils/bridge/evm/classes/reducers.ts
+++ b/src/utils/bridge/evm/classes/reducers.ts
@@ -2,7 +2,7 @@ import { BridgeTxStatus } from '@sora-substrate/util/build/bridgeProxy/consts';
import { BridgeReducer } from '@/utils/bridge/common/classes';
import type { RemoveTransactionByHash, IBridgeReducerOptions } from '@/utils/bridge/common/types';
-import { findEventInBlock } from '@/utils/bridge/common/utils';
+import { getTransactionEvents } from '@/utils/bridge/common/utils';
import { evmBridgeApi } from '@/utils/bridge/evm/api';
import type { RegisteredAccountAsset } from '@sora-substrate/util/build/assets/types';
@@ -97,14 +97,13 @@ export class EvmBridgeOutgoingReducer extends EvmBridgeReducer {
if (tx.hash) return tx.hash;
- const eventData = await findEventInBlock({
- api: evmBridgeApi.api,
- blockId: tx.blockId as string,
- section: 'bridgeProxy',
- method: 'RequestStatusUpdate',
- });
-
- const hash = eventData[0].toString();
+ const blockHash = tx.blockId as string;
+ const transactionHash = tx.txId as string;
+ const transactionEvents = await getTransactionEvents(blockHash, transactionHash, evmBridgeApi.api);
+ const requestEvent = transactionEvents.find((e) =>
+ evmBridgeApi.api.events.bridgeProxy.RequestStatusUpdate.is(e.event)
+ );
+ const hash = requestEvent.event.data[0].toString();
this.updateTransactionParams(id, { hash });
diff --git a/src/utils/bridge/sub/classes/adapter.ts b/src/utils/bridge/sub/classes/adapter.ts
index 21f8cebcc..19b423720 100644
--- a/src/utils/bridge/sub/classes/adapter.ts
+++ b/src/utils/bridge/sub/classes/adapter.ts
@@ -34,7 +34,7 @@ export class SubAdapter {
}
get connected(): boolean {
- return this.connection.opened;
+ return !!this.api?.isConnected;
}
public setEndpoint(endpoint: string): void {
@@ -44,6 +44,7 @@ export class SubAdapter {
public async connect(): Promise {
if (!this.connected && this.endpoint) {
await this.connection.open(this.endpoint);
+ await this.api.isReady;
}
}
@@ -53,8 +54,12 @@ export class SubAdapter {
}
}
+ public getSoraParachainNetwork(): SubNetwork {
+ return subBridgeApi.getSoraParachain(this.subNetwork);
+ }
+
public getSoraParachainId(): number | undefined {
- const soraParachain = subBridgeApi.getSoraParachain(this.subNetwork);
+ const soraParachain = this.getSoraParachainNetwork();
const soraParachainId = subBridgeApi.parachainIds[soraParachain];
return soraParachainId;
@@ -63,6 +68,8 @@ export class SubAdapter {
public async getBlockNumber(): Promise {
if (!this.connected) return 0;
+ await this.api.isReady;
+
const result = await this.api.query.system.number();
return result.toNumber();
@@ -71,6 +78,8 @@ export class SubAdapter {
protected async getAccountBalance(accountAddress: string): Promise {
if (!(this.connected && accountAddress)) return ZeroStringValue;
+ await this.api.isReady;
+
const accountInfo = await this.api.query.system.account(accountAddress);
const accountBalance = formatBalance(accountInfo.data);
const balance = accountBalance.transferable;
@@ -100,9 +109,13 @@ export class SubAdapter {
}
/* [Substrate 5] Runtime call transactionPaymentApi */
- public async getNetworkFee(): Promise {
+ public async getNetworkFee(asset: RegisteredAsset): Promise {
+ if (!this.connected) return ZeroStringValue;
+
+ await this.api.isReady;
+
const decimals = this.api.registry.chainDecimals[0];
- const tx = this.getTransferExtrinsic({} as RegisteredAsset, '', ZeroStringValue);
+ const tx = this.getTransferExtrinsic(asset, '', ZeroStringValue);
const res = await tx.paymentInfo('');
return new FPNumber(res.partialFee, decimals).toCodecString();
@@ -162,9 +175,9 @@ class KusamaAdapter extends SubAdapter {
}
/* Throws error until Substrate 5 migration */
- public async getNetworkFee(): Promise {
+ public async getNetworkFee(asset: RegisteredAsset): Promise {
try {
- return await super.getNetworkFee();
+ return await super.getNetworkFee(asset);
} catch {
// Hardcoded value for Kusama - 0.0007 KSM
return '700000000';
@@ -189,7 +202,15 @@ class KusamaAdapter extends SubAdapter {
}
}
-class SubConnector {
+export class SubNetworksConnector {
+ public network!: SubNetwork;
+ public parachainNetwork!: SubNetwork;
+ public networkAdapter!: SubAdapter;
+ public parachainAdapter!: SubAdapter;
+ public parachainId!: number;
+
+ public static endpoints: SubNetworkApps = {};
+
public readonly adapters = {
[SubNetwork.Rococo]: () => new KusamaAdapter(SubNetwork.Rococo),
[SubNetwork.Kusama]: () => new KusamaAdapter(SubNetwork.Kusama),
@@ -197,19 +218,14 @@ class SubConnector {
[SubNetwork.KusamaSora]: () => new SubAdapter(SubNetwork.KusamaSora),
};
- public endpoints: SubNetworkApps = {};
-
- /** Adapter for Substrate network. Used for network selected in app */
- public networkAdapter!: SubAdapter;
-
public getAdapterForNetwork(network: SubNetwork): SubAdapter {
if (!(network in this.adapters)) {
throw new Error(`[${this.constructor.name}] Adapter for "${network}" network not implemented`);
}
- if (!(network in this.endpoints)) {
+ if (!(network in SubNetworksConnector.endpoints)) {
throw new Error(`[${this.constructor.name}] Endpoint for "${network}" network is not defined`);
}
- const endpoint = this.endpoints[network];
+ const endpoint = SubNetworksConnector.endpoints[network];
const adapter = this.adapters[network]();
adapter.setEndpoint(endpoint);
@@ -217,24 +233,39 @@ class SubConnector {
return adapter;
}
+ public async init(network: SubNetwork): Promise {
+ this.network = network;
+ this.networkAdapter = this.getAdapterForNetwork(this.network);
+ this.parachainNetwork = this.networkAdapter.getSoraParachainNetwork();
+ this.parachainAdapter = this.getAdapterForNetwork(this.parachainNetwork);
+ this.parachainId = this.parachainAdapter.getSoraParachainId() as number;
+ }
+
/**
- * Open main connection with Substrate network
+ * Open main connection with Substrate network & Sora parachain
*/
public async open(network: SubNetwork): Promise {
- // stop current adapter connection
+ // stop current connections
await this.stop();
// set adapter for network arg
- this.networkAdapter = this.getAdapterForNetwork(network);
- // open adapter connection
- await this.networkAdapter.connect();
+ await this.init(network);
+ // open adapters connections
+ await this.start();
+ }
+
+ /**
+ * Connect to Substrate network & Sora parachain
+ */
+ public async start(): Promise {
+ await Promise.all([this.networkAdapter.connect(), this.parachainAdapter.connect()]);
}
/**
- * Close main connection to selected Substrate network
+ * Close connections to Substrate network & Sora parachain
*/
public async stop(): Promise {
- await this.networkAdapter?.stop();
+ await Promise.all([this.networkAdapter?.stop(), this.parachainAdapter?.stop()]);
}
}
-export const subConnector = new SubConnector();
+export const subBridgeConnector = new SubNetworksConnector();
diff --git a/src/utils/bridge/sub/classes/history.ts b/src/utils/bridge/sub/classes/history.ts
index 8a0f7f959..739606d3d 100644
--- a/src/utils/bridge/sub/classes/history.ts
+++ b/src/utils/bridge/sub/classes/history.ts
@@ -4,15 +4,10 @@ import { api } from '@soramitsu/soraneo-wallet-web';
import { ZeroStringValue } from '@/consts';
import { rootActionContext } from '@/store';
-import { findEventInBlock } from '@/utils/bridge/common/utils';
+import { getBlockEventsByTxIndex } from '@/utils/bridge/common/utils';
import { subBridgeApi } from '@/utils/bridge/sub/api';
-import { subConnector } from '@/utils/bridge/sub/classes/adapter';
-import type { SubAdapter } from '@/utils/bridge/sub/classes/adapter';
-import {
- getRelayChainBlockNumber,
- getMessageAcceptedNonces,
- isMessageDispatchedNonces,
-} from '@/utils/bridge/sub/utils';
+import { SubNetworksConnector } from '@/utils/bridge/sub/classes/adapter';
+import { getMessageAcceptedNonces, isMessageDispatchedNonces, formatSubAddress } from '@/utils/bridge/sub/utils';
import type { ApiPromise } from '@polkadot/api';
import type { NetworkFeesObject } from '@sora-substrate/util';
@@ -56,35 +51,17 @@ const findTxInBlock = async (blockHash: string, soraHash: string) => {
return { hash: txHash, events: txEvents };
};
-class SubBridgeHistory {
- private externalNetwork!: SubNetwork;
- private parachainNetwork!: SubNetwork;
- private externalNetworkAdapter!: SubAdapter;
- private parachainNetworkAdapter!: SubAdapter;
- private parachainId!: number;
-
- public async init(externalNetwork: SubNetwork): Promise {
- this.externalNetwork = externalNetwork;
- this.parachainNetwork = subBridgeApi.getSoraParachain(this.externalNetwork);
- this.externalNetworkAdapter = subConnector.getAdapterForNetwork(this.externalNetwork);
- this.parachainNetworkAdapter = subConnector.getAdapterForNetwork(this.parachainNetwork);
- this.parachainId = subBridgeApi.parachainIds[this.parachainNetwork] as number;
- }
-
+class SubBridgeHistory extends SubNetworksConnector {
get soraApi(): ApiPromise {
return subBridgeApi.api;
}
get parachainApi(): ApiPromise {
- return this.parachainNetworkAdapter.api;
+ return this.parachainAdapter.api;
}
get externalApi(): ApiPromise {
- return this.externalNetworkAdapter.api;
- }
-
- private async connect() {
- await Promise.all([this.externalNetworkAdapter.connect(), this.parachainNetworkAdapter.connect()]);
+ return this.networkAdapter.api;
}
public async clearHistory(updateCallback?: FnWithoutArgs | AsyncFnWithoutArgs): Promise {
@@ -100,7 +77,7 @@ class SubBridgeHistory {
updateCallback?: FnWithoutArgs | AsyncFnWithoutArgs
): Promise {
try {
- const transactions = await subBridgeApi.getUserTransactions(address, this.externalNetwork);
+ const transactions = await subBridgeApi.getUserTransactions(address, this.network);
if (!transactions.length) return;
@@ -114,7 +91,7 @@ class SubBridgeHistory {
if ((localHistoryItem?.id as string) in inProgressIds) continue;
if (hasFinishedState(localHistoryItem)) continue;
- await this.connect();
+ await this.start();
const historyItemData = await this.txDataToHistory(tx, networkFees, assetDataByAddress);
@@ -130,8 +107,7 @@ class SubBridgeHistory {
await updateCallback?.();
}
} finally {
- this.externalNetworkAdapter.stop();
- this.parachainNetworkAdapter.stop();
+ this.stop();
}
}
@@ -153,7 +129,6 @@ class SubBridgeHistory {
const asset = assetDataByAddress(tx.soraAssetAddress);
const amount = FPNumber.fromCodecValue(tx.amount, asset?.decimals).toString();
const type = getType(isOutgoing);
- const soraNetworkFee = networkFees[type] ?? ZeroStringValue;
const history: SubHistory = {
id,
@@ -162,12 +137,11 @@ class SubBridgeHistory {
hash: id,
transactionState: tx.status,
parachainBlockHeight,
- externalNetwork: this.externalNetwork,
+ externalNetwork: this.network,
externalNetworkType: BridgeNetworkType.Sub,
amount,
assetAddress: asset?.address,
symbol: asset?.symbol,
- soraNetworkFee,
from: tx.soraAccount,
};
@@ -182,7 +156,7 @@ class SubBridgeHistory {
const [{ hash, events }, startTime, relayChainBlockNumber] = await Promise.all([
findTxInBlock(blockId, id),
api.system.getBlockTimestamp(blockId, this.soraApi),
- getRelayChainBlockNumber(parachainBlockId, this.parachainApi),
+ subBridgeApi.soraParachainApi.getRelayChainBlockNumber(parachainBlockId, this.parachainApi),
]);
history.txId = hash;
@@ -223,6 +197,7 @@ class SubBridgeHistory {
asset: Nullable;
events: any[];
}): Promise {
+ const soraFeeEvent = events.find((e) => this.soraApi.events.transactionPayment.TransactionFeePaid.is(e.event));
// sended from sora nonces
const [soraBatchNonce, soraMessageNonce] = getMessageAcceptedNonces(events, this.soraApi);
const parachainEvents = await api.system.getBlockEvents(parachainBlockId, this.parachainApi);
@@ -264,11 +239,12 @@ class SubBridgeHistory {
);
const received = balancesDepositEvent.event.data.amount.toString();
+ history.soraNetworkFee = soraFeeEvent.event.data[1].toString();
history.externalNetworkFee = ZeroStringValue;
history.externalBlockId = blockId;
history.externalBlockHeight = n;
history.amount2 = FPNumber.fromCodecValue(received, asset?.externalDecimals).toString();
- history.to = to;
+ history.to = formatSubAddress(tx.externalAccount, this.externalApi.registry.chainSS58 as number);
break;
} catch {
continue;
@@ -291,7 +267,7 @@ class SubBridgeHistory {
const blockId = await api.system.getBlockHash(n, this.externalApi);
const extrinsics = await api.system.getExtrinsicsFromBlock(blockId, this.externalApi);
- for (const extrinsic of extrinsics) {
+ for (const [extrinsicIndex, extrinsic] of extrinsics.entries()) {
try {
if (!(extrinsic.method.section === 'xcmPallet' && extrinsic.method.method === 'reserveTransferAssets'))
continue;
@@ -300,21 +276,22 @@ class SubBridgeHistory {
const parachainId = (dest as any).asV3.interior.asX1.asParachain.toNumber();
const accountId = (beneficiary as any).asV3.interior.asX1.asAccountId32.id.toString();
const receiver = subBridgeApi.formatAddress(accountId);
+ const from = subBridgeApi.formatAddress(history.from as string);
- if (!(parachainId === this.parachainId && receiver === history.from)) continue;
+ if (!(parachainId === this.parachainId && receiver === from)) continue;
- const feeData = await findEventInBlock({
- api: this.externalApi,
- blockId,
- section: 'transactionPayment',
- method: 'TransactionFeePaid',
- });
+ const signer = extrinsic.signer.toString();
+ const extrinsicEvents = await getBlockEventsByTxIndex(blockId, extrinsicIndex, this.externalApi);
+ const feeEvent = extrinsicEvents.find((e) =>
+ this.externalApi.events.transactionPayment.TransactionFeePaid.is(e.event)
+ );
- history.externalNetworkFee = feeData[1].toString();
+ history.soraNetworkFee = ZeroStringValue;
+ history.externalNetworkFee = feeEvent.event.data[1].toString();
history.externalBlockId = blockId;
history.externalBlockHeight = n;
- history.to = subBridgeApi.formatAddress(extrinsic.signer.toString());
- break;
+ history.to = formatSubAddress(signer, this.externalApi.registry.chainSS58 as number);
+ return;
} catch {
continue;
}
diff --git a/src/utils/bridge/sub/classes/reducers.ts b/src/utils/bridge/sub/classes/reducers.ts
index 5c7bc581c..e0bc6b479 100644
--- a/src/utils/bridge/sub/classes/reducers.ts
+++ b/src/utils/bridge/sub/classes/reducers.ts
@@ -8,37 +8,32 @@ import { ZeroStringValue } from '@/consts';
import { BridgeReducer } from '@/utils/bridge/common/classes';
import { getTransactionEvents } from '@/utils/bridge/common/utils';
import { subBridgeApi } from '@/utils/bridge/sub/api';
-import { subConnector } from '@/utils/bridge/sub/classes/adapter';
-import type { SubAdapter } from '@/utils/bridge/sub/classes/adapter';
+import { SubNetworksConnector } from '@/utils/bridge/sub/classes/adapter';
import { getMessageAcceptedNonces, isMessageDispatchedNonces, isAssetAddedToChannel } from '@/utils/bridge/sub/utils';
-import type { ApiPromise } from '@polkadot/api';
+import type { ApiPromise, ApiRx } from '@polkadot/api';
import type { RegisteredAccountAsset } from '@sora-substrate/util/build/assets/types';
import type { SubHistory } from '@sora-substrate/util/build/bridgeProxy/sub/types';
import type { Subscription } from 'rxjs';
export class SubBridgeReducer extends BridgeReducer {
- protected subNetworkAdapter!: SubAdapter;
- protected soraParachainAdapter!: SubAdapter;
-
protected asset!: RegisteredAccountAsset;
+ protected connector!: SubNetworksConnector;
- createConnections(id: string): void {
+ initConnector(id: string): void {
const { externalNetwork } = this.getTransaction(id);
if (!externalNetwork) throw new Error(`[${this.constructor.name}]: Transaction "externalNetwork" is not defined`);
- const soraParachainNetwork = subBridgeApi.getSoraParachain(externalNetwork);
-
- this.subNetworkAdapter = subConnector.getAdapterForNetwork(externalNetwork);
- this.soraParachainAdapter = subConnector.getAdapterForNetwork(soraParachainNetwork);
+ this.connector = new SubNetworksConnector();
+ this.connector.init(externalNetwork);
}
- async closeConnections(): Promise {
- await Promise.all([this.subNetworkAdapter?.stop(), this.soraParachainAdapter?.stop()]);
+ async closeConnector(): Promise {
+ await this.connector.stop();
}
- async getHashesByBlockNumber(adapter: SubAdapter, blockHeight: number) {
+ async getHashesByBlockNumber(blockHeight: number, apiRx: ApiRx) {
let blockId = '';
if (Number.isFinite(blockHeight)) {
@@ -46,7 +41,7 @@ export class SubBridgeReducer extends BridgeReducer {
try {
await new Promise((resolve) => {
- subscription = api.system.getBlockHashObservable(blockHeight, adapter.apiRx).subscribe((hash) => {
+ subscription = api.system.getBlockHashObservable(blockHeight, apiRx).subscribe((hash) => {
if (hash) {
blockId = hash;
resolve();
@@ -87,7 +82,7 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer {
handler: async (id: string) => {
try {
this.beforeSubmit(id);
- this.createConnections(id);
+ this.initConnector(id);
this.updateTransactionParams(id, { transactionState: BridgeTxStatus.Pending });
await this.checkTxId(id);
@@ -96,7 +91,7 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer {
await this.waitSoraBlockByHash(id);
await this.onComplete(id);
} finally {
- this.closeConnections();
+ this.closeConnector();
}
},
});
@@ -121,11 +116,11 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer {
// transaction not signed
await this.beforeSign(id);
// open connections
- await Promise.all([this.subNetworkAdapter.connect(), this.soraParachainAdapter.connect()]);
+ await this.connector.start();
// sign transaction
- await this.subNetworkAdapter.transfer(asset, tx.to as string, tx.amount as string, id);
+ await this.connector.networkAdapter.transfer(asset, tx.to as string, tx.amount as string, id);
// store sora parachain block number when tx was signed in external network
- const parachainStartBlock = (await this.soraParachainAdapter.api.query.system.number()).toNumber();
+ const parachainStartBlock = (await this.connector.parachainAdapter.api.query.system.number()).toNumber();
// update history to change tx status in ui
this.updateTransactionParams(id, {
payload: {
@@ -148,12 +143,12 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer {
private async updateTxExternalData(id: string): Promise {
const tx = this.getTransaction(id);
- await this.subNetworkAdapter.connect();
+ await this.connector.networkAdapter.connect();
if (!tx.externalBlockHeight) {
const externalBlockHeight = await api.system.getBlockNumber(
tx.externalBlockId as string,
- this.subNetworkAdapter.api
+ this.connector.networkAdapter.api
);
this.updateTransactionParams(id, {
@@ -163,12 +158,14 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer {
const blockHash = tx.externalBlockId as string;
const transactionHash = tx.externalHash as string;
- const transactionEvents = await getTransactionEvents(blockHash, transactionHash, this.subNetworkAdapter.api);
+ const transactionEvents = await getTransactionEvents(blockHash, transactionHash, this.connector.networkAdapter.api);
const feeEvent = transactionEvents.find((e) =>
- this.subNetworkAdapter.api.events.transactionPayment.TransactionFeePaid.is(e.event)
+ this.connector.networkAdapter.api.events.transactionPayment.TransactionFeePaid.is(e.event)
+ );
+ const xcmEvent = transactionEvents.find((e) =>
+ this.connector.networkAdapter.api.events.xcmPallet.Attempted.is(e.event)
);
- const xcmEvent = transactionEvents.find((e) => this.subNetworkAdapter.api.events.xcmPallet.Attempted.is(e.event));
if (feeEvent) {
const externalNetworkFee = feeEvent.event.data[1].toString();
@@ -204,11 +201,11 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer {
let blockNumber!: number;
try {
- await this.soraParachainAdapter.connect();
+ await this.connector.parachainAdapter.connect();
await new Promise((resolve, reject) => {
- const eventsObservable = api.system.getEventsObservable(this.soraParachainAdapter.apiRx);
- const blockNumberObservable = api.system.getBlockNumberObservable(this.soraParachainAdapter.apiRx);
+ const eventsObservable = api.system.getEventsObservable(this.connector.parachainAdapter.apiRx);
+ const blockNumberObservable = api.system.getBlockNumberObservable(this.connector.parachainAdapter.apiRx);
subscription = combineLatest([eventsObservable, blockNumberObservable]).subscribe(
([eventsVec, blockHeight]) => {
@@ -221,13 +218,13 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer {
const events = [...eventsVec.toArray()].reverse();
const downwardMessagesProcessedEvent = events.find((e) =>
- this.soraParachainAdapter.api.events.parachainSystem.DownwardMessagesProcessed.is(e.event)
+ this.connector.parachainAdapter.api.events.parachainSystem.DownwardMessagesProcessed.is(e.event)
);
if (!downwardMessagesProcessedEvent) return;
const assetAddedToChannelEventIndex = events.findIndex((e) =>
- isAssetAddedToChannel(e, this.asset, to, sended, this.soraParachainAdapter.api)
+ isAssetAddedToChannel(e, this.asset, to, sended, this.connector.parachainAdapter.api)
);
if (assetAddedToChannelEventIndex === -1) {
@@ -238,7 +235,7 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer {
blockNumber = blockHeight;
[batchNonce, messageNonce] = getMessageAcceptedNonces(
events.slice(assetAddedToChannelEventIndex),
- this.soraParachainAdapter.api
+ this.connector.parachainAdapter.api
);
resolve();
@@ -252,14 +249,16 @@ export class SubBridgeIncomingReducer extends SubBridgeReducer {
subscription.unsubscribe();
// run non blocking process promise
- this.getHashesByBlockNumber(this.soraParachainAdapter, blockNumber)
+ this.getHashesByBlockNumber(blockNumber, this.connector.parachainAdapter.apiRx)
.then(({ blockHeight, blockId }) =>
this.updateTransactionParams(id, {
parachainBlockHeight: blockHeight, // parachain block number
parachainBlockId: blockId, // parachain block hash
})
)
- .finally(() => this.closeConnections());
+ .finally(() => {
+ this.closeConnector();
+ });
}
const { payload: prevPayload } = this.getTransaction(id);
@@ -359,7 +358,7 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer {
handler: async (id: string) => {
try {
this.beforeSubmit(id);
- this.createConnections(id);
+ this.initConnector(id);
this.updateTransactionParams(id, { transactionState: BridgeTxStatus.Pending });
await this.checkTxId(id);
@@ -370,7 +369,7 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer {
await this.waitForDestinationMessageHash(id);
await this.onComplete(id);
} finally {
- this.closeConnections();
+ this.closeConnector();
}
},
});
@@ -432,11 +431,11 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer {
let blockNumber!: number;
try {
- await this.soraParachainAdapter.connect();
+ await this.connector.parachainAdapter.connect();
await new Promise((resolve, reject) => {
- const eventsObservable = api.system.getEventsObservable(this.soraParachainAdapter.apiRx);
- const blockNumberObservable = api.system.getBlockNumberObservable(this.soraParachainAdapter.apiRx);
+ const eventsObservable = api.system.getEventsObservable(this.connector.parachainAdapter.apiRx);
+ const blockNumberObservable = api.system.getBlockNumberObservable(this.connector.parachainAdapter.apiRx);
subscription = combineLatest([eventsObservable, blockNumberObservable]).subscribe(
([eventsVec, blockHeight]) => {
@@ -447,7 +446,7 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer {
tx.payload.batchNonce,
tx.payload.messageNonce,
e,
- this.soraParachainAdapter.api
+ this.connector.parachainAdapter.api
)
);
@@ -457,7 +456,7 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer {
const parachainSystemEvent = events
.slice(substrateDispatchEventIndex)
- .find((e) => this.soraParachainAdapter.api.events.parachainSystem.UpwardMessageSent.is(e.event));
+ .find((e) => this.connector.parachainAdapter.api.events.parachainSystem.UpwardMessageSent.is(e.event));
if (!parachainSystemEvent) {
throw new Error(`[${this.constructor.name}]: Unable to find "parachainSystem.UpwardMessageSent" event`);
@@ -476,14 +475,16 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer {
subscription.unsubscribe();
// run non blocking proccess promise
- this.getHashesByBlockNumber(this.soraParachainAdapter, blockNumber)
+ this.getHashesByBlockNumber(blockNumber, this.connector.parachainAdapter.apiRx)
.then(({ blockHeight, blockId }) =>
this.updateTransactionParams(id, {
parachainBlockHeight: blockHeight, // parachain block number
parachainBlockId: blockId, // parachain block hash
})
)
- .finally(() => this.soraParachainAdapter.stop());
+ .finally(() => {
+ this.connector.parachainAdapter.stop();
+ });
}
const payload = { ...tx.payload, messageHash };
@@ -502,11 +503,11 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer {
let amount!: string;
try {
- await this.subNetworkAdapter.connect();
+ await this.connector.networkAdapter.connect();
await new Promise((resolve, reject) => {
- const eventsObservable = api.system.getEventsObservable(this.subNetworkAdapter.apiRx);
- const blockNumberObservable = api.system.getBlockNumberObservable(this.subNetworkAdapter.apiRx);
+ const eventsObservable = api.system.getEventsObservable(this.connector.networkAdapter.apiRx);
+ const blockNumberObservable = api.system.getBlockNumberObservable(this.connector.networkAdapter.apiRx);
subscription = combineLatest([eventsObservable, blockNumberObservable]).subscribe(
([eventsVec, blockHeight]) => {
@@ -514,7 +515,7 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer {
const events = [...eventsVec.toArray()].reverse();
const messageQueueProcessedEventIndex = events.findIndex(
(e) =>
- this.subNetworkAdapter.api.events.messageQueue.Processed.is(e.event) &&
+ this.connector.networkAdapter.api.events.messageQueue.Processed.is(e.event) &&
e.event.data[0].toString() === messageHash
);
@@ -527,8 +528,9 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer {
.slice(messageQueueProcessedEventIndex)
.find(
(e) =>
- this.subNetworkAdapter.api.events.balances.Deposit.is(e.event) &&
- subBridgeApi.formatAddress(e.event.data.who.toString()) === tx.to
+ this.connector.networkAdapter.api.events.balances.Deposit.is(e.event) &&
+ subBridgeApi.formatAddress(e.event.data.who.toString()) ===
+ subBridgeApi.formatAddress(tx.to as string)
);
if (!balancesDepositEvent)
@@ -547,14 +549,16 @@ export class SubBridgeOutgoingReducer extends SubBridgeReducer {
subscription.unsubscribe();
// run blocking process promise
- await this.getHashesByBlockNumber(this.subNetworkAdapter, blockNumber)
+ await this.getHashesByBlockNumber(blockNumber, this.connector.networkAdapter.apiRx)
.then(({ blockHeight, blockId }) =>
this.updateTransactionParams(id, {
externalBlockHeight: blockHeight, // parachain block number
externalBlockId: blockId, // parachain block hash
})
)
- .finally(() => this.subNetworkAdapter.stop());
+ .finally(() => {
+ this.connector.networkAdapter.stop();
+ });
}
const received = FPNumber.fromCodecValue(amount, this.asset.externalDecimals);
diff --git a/src/utils/bridge/sub/utils.ts b/src/utils/bridge/sub/utils.ts
index db508d9d9..19ab78010 100644
--- a/src/utils/bridge/sub/utils.ts
+++ b/src/utils/bridge/sub/utils.ts
@@ -1,3 +1,5 @@
+import { decodeAddress, encodeAddress } from '@polkadot/util-crypto';
+
import { subBridgeApi } from '@/utils/bridge/sub/api';
import type { ApiPromise } from '@polkadot/api';
@@ -23,13 +25,6 @@ export const updateTransaction = (id: string, params = {}): void => {
subBridgeApi.saveHistory(data);
};
-export const getRelayChainBlockNumber = async (blockHash: string, api: ApiPromise): Promise => {
- const apiInstanceAtBlock = await api.at(blockHash);
- const blockNumber = await apiInstanceAtBlock.query.parachainSystem.lastRelayChainBlockNumber();
-
- return Number(blockNumber.toString());
-};
-
export const getMessageAcceptedNonces = (events: Array, api: ApiPromise): [number, number] => {
const messageAcceptedEvent = events.find((e) =>
api.events.substrateBridgeOutboundChannel.MessageAccepted.is(e.event)
@@ -78,7 +73,7 @@ export const isAssetAddedToChannel = (
const { amount, assetId, recipient } = e.event.data[0].asTransfer;
// address check
- if (subBridgeApi.formatAddress(recipient.toString()) !== to) return false;
+ if (subBridgeApi.formatAddress(recipient.toString()) !== subBridgeApi.formatAddress(to)) return false;
// asset check
if (assetId.toString() !== asset.address) return false;
// amount check
@@ -87,3 +82,10 @@ export const isAssetAddedToChannel = (
return true;
};
+
+// [TECH] move to js-lib
+export const formatSubAddress = (address: string, ss58: number): string => {
+ const publicKey = decodeAddress(address, false);
+
+ return encodeAddress(publicKey, ss58);
+};
diff --git a/src/utils/ethers-util.ts b/src/utils/ethers-util.ts
index 39481f795..23445ffba 100644
--- a/src/utils/ethers-util.ts
+++ b/src/utils/ethers-util.ts
@@ -1,7 +1,8 @@
import detectEthereumProvider from '@metamask/detect-provider';
import { decodeAddress } from '@polkadot/util-crypto';
-import { FPNumber, BridgeRequestAssetKind } from '@sora-substrate/util';
+import { FPNumber } from '@sora-substrate/util';
import { BridgeNetworkType } from '@sora-substrate/util/build/bridgeProxy/consts';
+import { EthAssetKind } from '@sora-substrate/util/build/bridgeProxy/eth/consts';
import WalletConnectProvider from '@walletconnect/web3-provider';
import { ethers } from 'ethers';
@@ -44,14 +45,14 @@ const gasLimit = {
/**
* It's in gwei.
*/
-const getEthBridgeGasLimit = (assetEvmAddress: string, kind: BridgeRequestAssetKind, isSoraToEvm: boolean) => {
+const getEthBridgeGasLimit = (assetEvmAddress: string, kind: EthAssetKind, isSoraToEvm: boolean) => {
if (isSoraToEvm) {
switch (kind) {
- case BridgeRequestAssetKind.SidechainOwned:
+ case EthAssetKind.SidechainOwned:
return gasLimit.mintTokensByPeers;
- case BridgeRequestAssetKind.Thischain:
+ case EthAssetKind.Thischain:
return gasLimit.receiveBySidechainAssetId;
- case BridgeRequestAssetKind.Sidechain:
+ case EthAssetKind.Sidechain:
return isNativeEvmTokenAddress(assetEvmAddress)
? gasLimit.receiveByEthereumAssetAddress.ETH
: gasLimit.receiveByEthereumAssetAddress.OTHER;
@@ -309,7 +310,7 @@ async function getEvmNetworkFee(
const ethersInstance = await getEthersInstance();
const { maxFeePerGas } = await ethersInstance.getFeeData();
const gasPrice = maxFeePerGas ?? BigInt(0);
- const gasLimit = BigInt(getEthBridgeGasLimit(assetEvmAddress, assetKind as BridgeRequestAssetKind, isSoraToEvm));
+ const gasLimit = BigInt(getEthBridgeGasLimit(assetEvmAddress, assetKind as EthAssetKind, isSoraToEvm));
const fee = calcEvmFee(gasPrice, gasLimit);
return fee;
@@ -339,7 +340,7 @@ async function getEvmTransactionReceipt(hash: string): Promise {
const ethersInstance = await getEthersInstance();
- const block = await ethersInstance.getBlock(number);
+ const block = await ethersInstance.getBlock(Number(number));
return block;
}
diff --git a/src/utils/index.ts b/src/utils/index.ts
index ca79c69c1..6ada87f47 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -66,7 +66,7 @@ export const isMaxButtonAvailable = (
return !FPNumber.eq(fpMaxBalance, fpAmount) && !hasInsufficientXorForFee(xorAsset, fee, isXorOutputSwap);
};
-const getMaxBalance = (
+export const getMaxBalance = (
asset: AssetWithBalance,
fee: CodecString,
{ isExternalBalance = false, isExternalNative = false, isBondedBalance = false } = {}
diff --git a/src/views/Bridge.vue b/src/views/Bridge.vue
index c0ffd2d45..b67c7e3bc 100644
--- a/src/views/Bridge.vue
+++ b/src/views/Bridge.vue
@@ -12,7 +12,7 @@
-
-
@@ -317,13 +332,13 @@ import {
hasInsufficientBalance,
hasInsufficientXorForFee,
hasInsufficientNativeTokenForFee,
- getMaxValue,
+ getMaxBalance,
getAssetBalance,
asZeroValue,
delay,
} from '@/utils';
-import type { IBridgeTransaction } from '@sora-substrate/util';
+import type { IBridgeTransaction, CodecString } from '@sora-substrate/util';
import type { AccountAsset, RegisteredAccountAsset } from '@sora-substrate/util/build/assets/types';
@Component({
@@ -332,6 +347,7 @@ import type { AccountAsset, RegisteredAccountAsset } from '@sora-substrate/util/
BridgeSelectNetwork: lazyComponent(Components.BridgeSelectNetwork),
BridgeSelectAccount: lazyComponent(Components.BridgeSelectAccount),
BridgeTransactionDetails: lazyComponent(Components.BridgeTransactionDetails),
+ BridgeLimitCard: lazyComponent(Components.BridgeLimitCard),
GenericPageHeader: lazyComponent(Components.GenericPageHeader),
ConfirmBridgeTransactionDialog: lazyComponent(Components.ConfirmBridgeTransactionDialog),
NetworkFeeWarningDialog: lazyComponent(Components.NetworkFeeWarningDialog),
@@ -356,13 +372,13 @@ export default class Bridge extends Mixins(
readonly KnownSymbols = KnownSymbols;
readonly FocusedField = FocusedField;
- @state.bridge.externalNetworkFeeFetching private externalNetworkFeeFetching!: boolean;
- @state.bridge.externalBalancesFetching private externalBalancesFetching!: boolean;
- @state.bridge.assetLockedBalanceFetching private assetLockedBalanceFetching!: boolean;
+ @state.bridge.externalTransferFee private externalTransferFee!: CodecString;
+ @state.bridge.balancesFetching private balancesFetching!: boolean;
+ @state.bridge.feesAndLockedFundsFetching private feesAndLockedFundsFetching!: boolean;
+ @state.assets.registeredAssetsFetching private registeredAssetsFetching!: boolean;
@state.bridge.amountSend amountSend!: string;
@state.bridge.amountReceived amountReceived!: string;
@state.bridge.isSoraToEvm isSoraToEvm!: boolean;
- @state.assets.registeredAssetsFetching registeredAssetsFetching!: boolean;
@getter.bridge.isRegisteredAsset isRegisteredAsset!: boolean;
@getter.bridge.operation private operation!: Operation;
@@ -371,6 +387,7 @@ export default class Bridge extends Mixins(
@mutation.bridge.setSoraToEvm private setSoraToEvm!: (value: boolean) => void;
@mutation.bridge.setHistoryId private setHistoryId!: (id?: string) => void;
@mutation.bridge.setFocusedField setFocusedField!: (field: FocusedField) => void;
+ @mutation.web3.setSelectNetworkDialogVisibility private setSelectNetworkDialogVisibility!: (flag: boolean) => void;
@action.bridge.setSendedAmount setSendedAmount!: (value?: string) => void;
@action.bridge.setReceivedAmount setReceivedAmount!: (value?: string) => void;
@@ -400,7 +417,7 @@ export default class Bridge extends Mixins(
return await this.waitOnExternalFeeWarningConfirmation();
}
- get areNetworksConnected(): boolean {
+ get areAccountsConnected(): boolean {
return !!this.sender && !!this.recipient;
}
@@ -442,35 +459,31 @@ export default class Bridge extends Mixins(
if (!(this.asset && this.isRegisteredAsset)) return ZeroStringValue;
const fee = this.isSoraToEvm ? this.soraNetworkFee : this.externalNetworkFee;
- const maxBalance = getMaxValue(this.asset, fee, {
+ const maxBalance = getMaxBalance(this.asset, fee, {
isExternalBalance: !this.isSoraToEvm,
isExternalNative: this.isNativeTokenSelected,
});
- if (this.assetLockedBalance && this.isSoraToEvm) {
- const fpBalance = this.getFPNumber(maxBalance, this.asset.decimals);
- const fpLocked = this.getFPNumberFromCodec(this.assetLockedBalance, this.asset.externalDecimals);
-
- if (FPNumber.gt(fpBalance, fpLocked)) return fpLocked.toString();
+ if (this.isSoraToEvm && this.outgoingMaxAmount) {
+ if (FPNumber.gt(maxBalance, this.outgoingMaxAmount)) return this.outgoingMaxAmount.toString();
}
- return maxBalance;
+ return maxBalance.toString();
}
get isMaxAvailable(): boolean {
- if (!(this.asset && this.isRegisteredAsset && this.areNetworksConnected && !asZeroValue(this.maxValue)))
+ if (!(this.asset && this.isRegisteredAsset && this.areAccountsConnected && !asZeroValue(this.maxValue)))
return false;
return this.maxValue !== this.amountSend;
}
- get isInsufficientLiquidity(): boolean {
- if (!(this.asset && this.assetLockedBalance && this.isSoraToEvm)) return false;
-
- const fpAmount = new FPNumber(this.amountSend, this.asset.decimals);
- const fpLocked = FPNumber.fromCodecValue(this.assetLockedBalance, this.asset.externalDecimals);
+ get isGreaterThanMaxAmount(): boolean {
+ return this.isGreaterThanOutgoingMaxAmount(this.amountSend, this.asset, this.isSoraToEvm, this.isRegisteredAsset);
+ }
- return FPNumber.gt(fpAmount, fpLocked);
+ get isLowerThanMinAmount(): boolean {
+ return this.isLowerThanIncomingMinAmount(this.amountSend, this.asset, this.isSoraToEvm, this.isRegisteredAsset);
}
get isInsufficientXorForFee(): boolean {
@@ -509,28 +522,32 @@ export default class Bridge extends Mixins(
return this.getStringFromCodec(this.externalNetworkFee, this.nativeTokenDecimals);
}
+ get formattedExternalTransferFee(): string {
+ return this.getStringFromCodec(this.externalTransferFee, this.asset?.externalDecimals);
+ }
+
get isConfirmTxDisabled(): boolean {
return (
!this.isAssetSelected ||
!this.isRegisteredAsset ||
- !this.areNetworksConnected ||
+ !this.areAccountsConnected ||
!this.isValidNetwork ||
this.isZeroAmountSend ||
this.isZeroAmountReceived ||
this.isInsufficientXorForFee ||
this.isInsufficientNativeTokenForFee ||
this.isInsufficientBalance ||
- this.isInsufficientLiquidity
+ this.isGreaterThanMaxAmount ||
+ this.isLowerThanMinAmount
);
}
get isConfirmTxLoading(): boolean {
return (
this.isSelectAssetLoading ||
- this.externalNetworkFeeFetching ||
- this.externalBalancesFetching ||
- this.registeredAssetsFetching ||
- this.assetLockedBalanceFetching
+ this.balancesFetching ||
+ this.feesAndLockedFundsFetching ||
+ this.registeredAssetsFetching
);
}
@@ -564,8 +581,11 @@ export default class Bridge extends Mixins(
return FPNumber.gte(fpAfterTransfer, fpFee);
}
- getDecimals(isSora = true): number | undefined {
- return isSora ? this.asset?.decimals : this.asset?.externalDecimals;
+ get amountDecimals(): number {
+ const internal = this.asset?.decimals ?? FPNumber.DEFAULT_PRECISION;
+ const external = this.asset?.externalDecimals ?? FPNumber.DEFAULT_PRECISION;
+
+ return Math.min(internal, external);
}
private getBalance(isSora = true): Nullable {
@@ -576,7 +596,7 @@ export default class Bridge extends Mixins(
if (!balance) {
return null;
}
- const decimals = this.getDecimals(isSora);
+ const decimals = isSora ? this.asset?.decimals : this.asset?.externalDecimals;
return this.getFPNumberFromCodec(balance, decimals);
}
@@ -585,14 +605,16 @@ export default class Bridge extends Mixins(
}
async created(): Promise {
- const { address, amount, isIncoming } = this.$route.params;
- if (address) {
- this.setAssetAddress(address);
- }
- if (isIncoming) {
- this.setSoraToEvm(false);
- }
- this.setSendedAmount(amount);
+ await this.withParentLoading(async () => {
+ const { address, amount, isIncoming } = this.$route.params;
+ this.setSendedAmount(amount);
+ if (isIncoming) {
+ this.setSoraToEvm(false);
+ }
+ if (address) {
+ this.updateAssetAddress(address);
+ }
+ });
}
getBridgeItemTitle(isSoraNetwork = false): string {
@@ -634,10 +656,6 @@ export default class Bridge extends Mixins(
this.showConfirmTransactionDialog = true;
}
- handleViewTransactionsHistory(): void {
- router.push({ name: PageNames.BridgeTransactionsHistory });
- }
-
handleChangeNetwork(): void {
this.setSelectNetworkDialogVisibility(true);
}
@@ -649,8 +667,12 @@ export default class Bridge extends Mixins(
async selectAsset(selectedAsset?: RegisteredAccountAsset): Promise {
if (!selectedAsset) return;
+ await this.updateAssetAddress(selectedAsset.address);
+ }
+
+ private async updateAssetAddress(address: string): Promise {
await this.withSelectAssetLoading(async () => {
- await this.setAssetAddress(selectedAsset.address);
+ await this.setAssetAddress(address);
});
}
@@ -773,5 +795,9 @@ $bridge-input-color: var(--s-color-base-content-tertiary);
line-height: var(--s-line-height-big);
color: var(--s-color-base-content-secondary);
}
+
+ &-limit-card {
+ margin-top: $inner-spacing-medium;
+ }
}
diff --git a/src/views/BridgeContainer.vue b/src/views/BridgeContainer.vue
index 65065713f..6b86e12ec 100644
--- a/src/views/BridgeContainer.vue
+++ b/src/views/BridgeContainer.vue
@@ -1,7 +1,7 @@
diff --git a/src/views/BridgeTransaction.vue b/src/views/BridgeTransaction.vue
index d0665f89e..94a8e1961 100644
--- a/src/views/BridgeTransaction.vue
+++ b/src/views/BridgeTransaction.vue
@@ -21,7 +21,7 @@
:value="formattedAmount"
:asset-symbol="assetSymbol"
>
-
+
-
+
@@ -83,7 +83,7 @@
:fiat-value="txExternalNetworkFeeFiatValue"
>
- ~
+ {{ ApproximateSign }}
@@ -159,11 +159,14 @@
{{
t('insufficientBalanceText', { tokenSymbol: nativeTokenSymbol })
}}
-
- {{ t('swap.insufficientLiquidity') }}
+
+ {{ t('exceededAmountText', { amount: t('maxAmountText') }) }}
+
+
+ {{ t('exceededAmountText', { amount: t('minAmountText') }) }}
{{ t('bridgeTransaction.confirm', { direction: 'metamask' }) }}
- {{ t('retryText') }}
+ {{ t('retryText') }}
@@ -177,7 +180,6 @@