From 8bae1d5e6db4551f69aa188d1cf1a49556c24fda Mon Sep 17 00:00:00 2001 From: impelcrypto <92044428+impelcrypto@users.noreply.github.com> Date: Thu, 2 Nov 2023 16:53:53 +0800 Subject: [PATCH] fix: use xTokens pallet on astar (#1004) * fix: use xtokens pallet on astar * fix: dest balance * fix: renamed statemint to AssetHub --- src/assets/img/chain/asset-hub.svg | 22 ++++ src/hooks/xcm/useXcmBridge.ts | 28 ++++- src/modules/xcm/index.ts | 20 ++-- src/modules/xcm/tokens/index.ts | 4 +- .../config/xcm/XcmRepositoryConfiguration.ts | 4 +- src/v2/models/XcmModels.ts | 8 +- .../implementations/XcmRepository.ts | 79 -------------- .../implementations/xcm/AstarXcmRepository.ts | 102 ------------------ .../xcm/StatemintXcmRepository.ts | 2 +- 9 files changed, 64 insertions(+), 205 deletions(-) create mode 100644 src/assets/img/chain/asset-hub.svg diff --git a/src/assets/img/chain/asset-hub.svg b/src/assets/img/chain/asset-hub.svg new file mode 100644 index 000000000..322c339af --- /dev/null +++ b/src/assets/img/chain/asset-hub.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + diff --git a/src/hooks/xcm/useXcmBridge.ts b/src/hooks/xcm/useXcmBridge.ts index 1c4fbc01a..39048ebe2 100644 --- a/src/hooks/xcm/useXcmBridge.ts +++ b/src/hooks/xcm/useXcmBridge.ts @@ -5,6 +5,7 @@ import { capitalize, isValidAddressPolkadotAddress, isValidEvmAddress, + wait, } from '@astar-network/astar-sdk-core'; import { ApiPromise } from '@polkadot/api'; import { ethers } from 'ethers'; @@ -35,6 +36,8 @@ import { Ref, computed, ref, watch, watchEffect } from 'vue'; import { useI18n } from 'vue-i18n'; import { evmToAddress } from '@polkadot/util-crypto'; +import { LOCAL_STORAGE } from 'src/config/localStorage'; +import { castChainName, castXcmEndpoint } from 'src/modules/xcm'; import { Path } from 'src/router'; import { container } from 'src/v2/common'; import { AstarToken } from 'src/v2/config/xcm/XcmRepositoryConfiguration'; @@ -47,8 +50,6 @@ import { } from 'src/v2/services'; import { Symbols } from 'src/v2/symbols'; import { useRouter } from 'vue-router'; -import { castChainName, castXcmEndpoint } from 'src/modules/xcm'; -import { LOCAL_STORAGE } from 'src/config/localStorage'; const { Acala, Astar, Karura, Polkadot, Shiden } = xcmChainObj; @@ -610,16 +611,33 @@ export function useXcmBridge(selectedToken: Ref) { await setOriginChainNativeBal(); }); + // Memo: to avoid using previous endpoint to fetch destChainBalance and it causes a bug (ex: acala -> statemint) + const balMonitorDelay = 500; + watch( [isLoadingApi, currentAccount, selectedToken, srcChain, originChainApiEndpoint], async () => { + // Memo: to display the balance with the same timing as destination balance + await wait(balMonitorDelay); await monitorFromChainBalance(); } ); - watchEffect(async () => { - await monitorDestChainBalance(inputtedAddress.value); - }); + watch( + [ + isLoadingApi, + currentAccount, + selectedToken, + destChain, + originChainApiEndpoint, + inputtedAddress, + ], + async () => { + await wait(balMonitorDelay); + await monitorDestChainBalance(inputtedAddress.value); + }, + { immediate: true } + ); return { amount, diff --git a/src/modules/xcm/index.ts b/src/modules/xcm/index.ts index 73dda41fe..43e157838 100644 --- a/src/modules/xcm/index.ts +++ b/src/modules/xcm/index.ts @@ -142,11 +142,11 @@ export let xcmChainObj: XcmChainObj = { subscan: 'https://shiden.subscan.io', isAstarNativeToken: false, }, - [Chain.STATEMINE]: { - name: Chain.STATEMINE, + [Chain.ASSET_HUB_KUSAMA]: { + name: Chain.ASSET_HUB_KUSAMA, relayChain: Chain.KUSAMA, - img: require('/src/assets/img/chain/statemine.svg'), - parachainId: parachainIds.STATEMINE, + img: require('/src/assets/img/chain/asset-hub.svg'), + parachainId: parachainIds.ASSET_HUB_KUSAMA, endpoints: [ 'wss://kusama-asset-hub-rpc.polkadot.io', 'wss://statemine-rpc.dwellir.com', @@ -154,7 +154,7 @@ export let xcmChainObj: XcmChainObj = { 'wss://statemine.api.onfinality.io/public-ws', 'wss://statemine.public.curie.radiumblock.co/ws', ], - subscan: 'https://statemine.subscan.io', + subscan: 'https://assethub-kusama.subscan.io', isAstarNativeToken: false, }, [Chain.KARURA]: { @@ -220,18 +220,18 @@ export let xcmChainObj: XcmChainObj = { subscan: 'https://moonbeam.subscan.io', isAstarNativeToken: true, }, - [Chain.STATEMINT]: { - name: Chain.STATEMINT, + [Chain.ASSET_HUB]: { + name: Chain.ASSET_HUB, relayChain: Chain.POLKADOT, - img: require('/src/assets/img/chain/statemine.svg'), - parachainId: parachainIds.STATEMINT, + img: require('/src/assets/img/chain/asset-hub.svg'), + parachainId: parachainIds.ASSET_HUB, endpoints: [ 'wss://statemint-rpc.dwellir.com', 'wss://polkadot-asset-hub-rpc.polkadot.io', 'wss://statemint.api.onfinality.io/public-ws', 'wss://statemint.public.curie.radiumblock.co/ws', ], - subscan: 'https://statemint.subscan.io', + subscan: 'https://assethub-polkadot.subscan.io', isAstarNativeToken: false, }, [Chain.KINTSUGI]: { diff --git a/src/modules/xcm/tokens/index.ts b/src/modules/xcm/tokens/index.ts index 104fbe97d..5398cd73c 100644 --- a/src/modules/xcm/tokens/index.ts +++ b/src/modules/xcm/tokens/index.ts @@ -70,7 +70,7 @@ export const xcmToken = { originAssetId: '1984', logo: require('/src/assets/img/token/usdt.png'), isXcmCompatible: true, - originChain: Chain.STATEMINT, + originChain: Chain.ASSET_HUB, minBridgeAmount: '1.5', }, { @@ -203,7 +203,7 @@ export const xcmToken = { originAssetId: '1984', logo: require('/src/assets/img/token/usdt.png'), isXcmCompatible: true, - originChain: Chain.STATEMINE, + originChain: Chain.ASSET_HUB_KUSAMA, minBridgeAmount: '0.1', }, { diff --git a/src/v2/config/xcm/XcmRepositoryConfiguration.ts b/src/v2/config/xcm/XcmRepositoryConfiguration.ts index 48eff8b66..ce634d71c 100644 --- a/src/v2/config/xcm/XcmRepositoryConfiguration.ts +++ b/src/v2/config/xcm/XcmRepositoryConfiguration.ts @@ -19,8 +19,8 @@ export const XcmRepositoryConfiguration: TypeMapping = { [Chain.SHIDEN]: AstarXcmRepository, [Chain.ACALA]: AcalaXcmRepository, [Chain.KARURA]: AcalaXcmRepository, - [Chain.STATEMINE]: StatemintXcmRepository, - [Chain.STATEMINT]: StatemintXcmRepository, + [Chain.ASSET_HUB_KUSAMA]: StatemintXcmRepository, + [Chain.ASSET_HUB]: StatemintXcmRepository, [Chain.MOONBEAM]: MoonbeamXcmRepository, [Chain.MOONRIVER]: MoonbeamXcmRepository, [Chain.POLKADOT]: PolkadotXcmRepository, diff --git a/src/v2/models/XcmModels.ts b/src/v2/models/XcmModels.ts index 73fe1c214..cdb8e0929 100644 --- a/src/v2/models/XcmModels.ts +++ b/src/v2/models/XcmModels.ts @@ -10,8 +10,8 @@ export enum Chain { ACALA = 'Acala', MOONRIVER = 'Moonriver', MOONBEAM = 'Moonbeam', - STATEMINE = 'Statemine', - STATEMINT = 'Statemint', + ASSET_HUB = 'Asset-hub', + ASSET_HUB_KUSAMA = 'Asset-hub-kusama', KINTSUGI = 'Kintsugi', INTERLAY = 'Interlay', CRUST_SHADOW = 'Crust-shadow', @@ -30,8 +30,8 @@ export enum parachainIds { ACALA = 2000, MOONRIVER = 2023, MOONBEAM = 2004, - STATEMINE = 1000, - STATEMINT = 1000, + ASSET_HUB = 1000, + ASSET_HUB_KUSAMA = 1000, KINTSUGI = 2092, INTERLAY = 2032, CRUST_SHADOW = 2012, diff --git a/src/v2/repositories/implementations/XcmRepository.ts b/src/v2/repositories/implementations/XcmRepository.ts index 92baea457..a376dd181 100644 --- a/src/v2/repositories/implementations/XcmRepository.ts +++ b/src/v2/repositories/implementations/XcmRepository.ts @@ -185,18 +185,6 @@ export class XcmRepository implements IXcmRepository { recipientAddress: string, amount: BN, endpoint: string - ): Promise { - const isAstar = from.name === 'Astar'; - return isAstar - ? await this.getPolkadotXcmToOriginChainCall(from, recipientAddress, amount, endpoint) - : await this.getXtokensToOriginChainCall(from, recipientAddress, amount, endpoint); - } - - private async getXtokensToOriginChainCall( - from: XcmChain, - recipientAddress: string, - amount: BN, - endpoint: string ): Promise { const recipientAccountId = getPubkeyFromSS58Addr(recipientAddress); @@ -244,73 +232,6 @@ export class XcmRepository implements IXcmRepository { ); } - // Memo: Remove this method after implementing Xtokens on Astar - private async getPolkadotXcmToOriginChainCall( - from: XcmChain, - recipientAddress: string, - amount: BN, - endpoint: string - ): Promise { - const recipientAccountId = getPubkeyFromSS58Addr(recipientAddress); - const version = 'V3'; - const destination = { - [version]: { - interior: 'Here', - parents: new BN(1), - }, - }; - - const id = decodeAddress(recipientAccountId); - const AccountId32 = { - id, - }; - - const beneficiary = { - [version]: { - interior: { - X1: { - AccountId32, - }, - }, - parents: new BN(0), - }, - }; - - const asset = { - Concrete: { - interior: 'Here', - parents: new BN(1), - }, - }; - - const assets = { - [version]: [ - { - fun: { - Fungible: new BN(amount), - }, - id: asset, - }, - ], - }; - - const weightLimit = { - Unlimited: null, - }; - - return await this.buildTxCall( - from, - endpoint, - 'polkadotXcm', - 'limitedReserveWithdrawAssets', - destination, - beneficiary, - assets, - new BN(0), - weightLimit - ); - } - public getTransferCall( from: XcmChain, to: XcmChain, diff --git a/src/v2/repositories/implementations/xcm/AstarXcmRepository.ts b/src/v2/repositories/implementations/xcm/AstarXcmRepository.ts index bd3e85e0e..e52a67120 100644 --- a/src/v2/repositories/implementations/xcm/AstarXcmRepository.ts +++ b/src/v2/repositories/implementations/xcm/AstarXcmRepository.ts @@ -34,20 +34,7 @@ export class AstarXcmRepository extends XcmRepository { if (!to.parachainId) { throw `Parachain id for ${to.name} is not defined`; } - const isAstar = from.name === 'Astar'; - return isAstar - ? await this.getPolkadotXcmCall(from, to, recipientAddress, token, amount, endpoint) - : await this.getXtokensCall(from, to, recipientAddress, token, amount, endpoint); - } - private async getXtokensCall( - from: XcmChain, - to: XcmChain, - recipientAddress: string, - token: Asset, - amount: BN, - endpoint: string - ): Promise { const recipientAccountId = getPubkeyFromSS58Addr(recipientAddress); const isWithdrawAssets = token.id !== this.astarNativeTokenId; @@ -115,93 +102,4 @@ export class AstarXcmRepository extends XcmRepository { weightLimit ); } - - // Memo: Remove this method after implementing Xtokens on Astar - private async getPolkadotXcmCall( - from: XcmChain, - to: XcmChain, - recipientAddress: string, - token: Asset, - amount: BN, - endpoint: string - ): Promise { - const recipientAccountId = getPubkeyFromSS58Addr(recipientAddress); - const version = 'V3'; - const isWithdrawAssets = token.id !== this.astarNativeTokenId; - const functionName = isWithdrawAssets - ? 'limitedReserveWithdrawAssets' - : 'limitedReserveTransferAssets'; - - const destination = { - [version]: { - interior: { - X1: { - Parachain: new BN(to.parachainId), - }, - }, - parents: new BN(1), - }, - }; - - const isAccountId20 = ethWalletChains.includes(to.name); - - const X1_V3 = isAccountId20 - ? { - AccountKey20: { - key: recipientAccountId, - }, - } - : { - AccountId32: { - id: decodeAddress(recipientAccountId), - }, - }; - - const beneficiary = { - [version]: { - interior: { - X1: X1_V3, - }, - parents: new BN(0), - }, - }; - - const asset = isWithdrawAssets - ? { - Concrete: await this.fetchAssetConfig(from, token, endpoint), - } - : { - Concrete: { - interior: 'Here', - parents: new BN(0), - }, - }; - - const assets = { - [version]: [ - { - fun: { - Fungible: new BN(amount), - }, - id: asset, - }, - ], - }; - - const weightLimit = { - Unlimited: null, - }; - - return await this.buildTxCall( - from, - endpoint, - 'polkadotXcm', - functionName, - destination, - beneficiary, - assets, - new BN(0), - weightLimit - ); - } } diff --git a/src/v2/repositories/implementations/xcm/StatemintXcmRepository.ts b/src/v2/repositories/implementations/xcm/StatemintXcmRepository.ts index 3d87513b0..6b7016d25 100644 --- a/src/v2/repositories/implementations/xcm/StatemintXcmRepository.ts +++ b/src/v2/repositories/implementations/xcm/StatemintXcmRepository.ts @@ -114,7 +114,7 @@ export class StatemintXcmRepository extends XcmRepository { // Memo: avoid getting a UI error when the `token` is `ASTR` while the `monitorDestChainBalance` function(watch) in useXcmBridge.ts // Reproduce the UI error: assets page -> transfer ASTR -> XCM -> flip the chains -> To: Statemint // Todo: The error is because Statemint doesn't have 'ASTR', we can refactor here later - const statemintChains = [Chain.STATEMINT, Chain.STATEMINE]; + const statemintChains = [Chain.ASSET_HUB, Chain.ASSET_HUB_KUSAMA]; if (!statemintChains.includes(token.originChain as Chain)) { return '0'; }