From 811f6ae3def20b06c4e1dbf905180420907e3232 Mon Sep 17 00:00:00 2001 From: mmaurello <93129175+mmaurello@users.noreply.github.com> Date: Mon, 21 Nov 2022 11:24:16 +0100 Subject: [PATCH] Bit.Country Pioneer integration with Moonbase (#39) * initial pioneer configuration * WIP neer config and balance interface change * adapt neer config to interface * add initial bit configuration * fix and remove unnecessary test * small adjustments and remove obsolete snapshots * add enum constant * add enum constant when missing * add tokens function for each type to avoid clustering configs * fix tests and add new * Update packages/config/src/balance/balance.ts Co-authored-by: Elmar Kenigs * improve typing on AssetSymbols * implement the functionality to transfer multiple assets in Withdraw with transferMultiCurrencies from the precompiles * update snapshot * move precompile function call to Contract handler * consideration of min amount of auxiliar that pays for fees * pass origin account to sdk and do balance calculations inside * Update packages/config/src/config/moonbase/assets/bit.ts Co-authored-by: Elmar Kenigs * return 2 different mins from withdraw and make origin account optional * return origin balance and not calculations for enough balance * update simple example * change origin account param to have no breaking changes * go back to returning min in withdraw to avoid having breaking changes * remove originAccount param * update example Co-authored-by: Elmar Kenigs --- .../__snapshots__/balance.test.ts.snap | 30 +++++++- .../config/src/balance/balance.constants.ts | 9 +++ .../config/src/balance/balance.interfaces.ts | 27 ++++--- packages/config/src/balance/balance.test.ts | 27 +++++-- packages/config/src/balance/balance.ts | 48 ++++++------ .../config/src/config/moonbase/assets/bit.ts | 66 ++++++++++++++++ .../config/src/config/moonbase/assets/dev.ts | 18 +++++ .../config/src/config/moonbase/assets/neer.ts | 40 ++++++++++ .../src/config/moonbase/moonbase.assets.ts | 12 +++ .../src/config/moonbase/moonbase.chains.ts | 9 +++ .../config/src/config/moonbase/moonbase.ts | 4 + .../config/src/config/moonbeam/assets/ausd.ts | 4 +- .../config/src/config/moonbeam/assets/glmr.ts | 8 +- .../config/src/config/moonbeam/assets/ibtc.ts | 8 +- .../config/src/config/moonbeam/assets/intr.ts | 4 +- .../src/config/moonriver/assets/ausd.ts | 6 +- .../src/config/moonriver/assets/kbtc.ts | 8 +- .../src/config/moonriver/assets/kint.ts | 4 +- .../src/config/moonriver/assets/movr.ts | 8 +- packages/config/src/constants/assets.ts | 2 + packages/config/src/constants/chains.ts | 1 + .../config/src/deposit/deposit.interfaces.ts | 7 +- .../extrinsic/xTokens/xTokens.constants.ts | 9 ++- .../extrinsic/xTokens/xTokens.interfaces.ts | 11 ++- .../src/extrinsic/xTokens/xTokens.test.ts | 2 +- packages/config/src/interfaces.ts | 6 ++ .../__snapshots__/withdraw.test.ts.snap | 1 + .../src/withdraw/withdraw.interfaces.ts | 12 ++- packages/config/src/withdraw/withdraw.ts | 2 + .../src/contracts/XTokensContract/XTokens.sol | 56 ++++++++++++++ .../contracts/XTokensContract/XTokens.sol.sol | 38 --------- .../contracts/XTokensContract/XTokensABI.json | 28 +++---- .../XTokensContract/XTokensContract.ts | 12 +++ packages/sdk/src/sdk/sdk.interfaces.ts | 10 ++- packages/sdk/src/sdk/sdk.ts | 2 + packages/sdk/src/sdk/sdk.withdraw.ts | 77 +++++++++++++++---- 36 files changed, 471 insertions(+), 145 deletions(-) create mode 100644 packages/config/src/config/moonbase/assets/bit.ts create mode 100644 packages/config/src/config/moonbase/assets/neer.ts create mode 100644 packages/sdk/src/contracts/XTokensContract/XTokens.sol delete mode 100644 packages/sdk/src/contracts/XTokensContract/XTokens.sol.sol diff --git a/packages/config/src/balance/__snapshots__/balance.test.ts.snap b/packages/config/src/balance/__snapshots__/balance.test.ts.snap index 3815d735..45a51d75 100644 --- a/packages/config/src/balance/__snapshots__/balance.test.ts.snap +++ b/packages/config/src/balance/__snapshots__/balance.test.ts.snap @@ -75,11 +75,39 @@ exports[`balance tokens should be correct balance config 1`] = ` } `; +exports[`balance tokens should be correct balance config foreignAsset 1`] = ` +{ + "calc": [Function], + "function": "accounts", + "getParams": [Function], + "pallet": "tokens", + "path": [], +} +`; + exports[`balance tokens should be correct params with ForeignAsset 1`] = ` [ "", { - "ForeignAsset": 5, + "ForeignAsset": 0, + }, +] +`; + +exports[`balance tokens should be correct params with FungibleToken 1`] = ` +[ + "", + { + "FungibleToken": 0, + }, +] +`; + +exports[`balance tokens should be correct params with MiningResource 1`] = ` +[ + "", + { + "MiningResource": 0, }, ] `; diff --git a/packages/config/src/balance/balance.constants.ts b/packages/config/src/balance/balance.constants.ts index eb2f7363..e53c9e39 100644 --- a/packages/config/src/balance/balance.constants.ts +++ b/packages/config/src/balance/balance.constants.ts @@ -13,3 +13,12 @@ export enum BalanceFunction { AssetMetadatas = 'assetMetadatas', CurrencyMetadatas = 'currencyMetadatas', } + +export enum BalanceCurrencyTypes { + Token = 'Token', + Token2 = 'Token2', + ForeignAsset = 'ForeignAsset', + NativeToken = 'NativeToken', + MiningResource = 'MiningResource', + FungibleToken = 'FungibleToken', +} diff --git a/packages/config/src/balance/balance.interfaces.ts b/packages/config/src/balance/balance.interfaces.ts index 02594ad0..68227206 100644 --- a/packages/config/src/balance/balance.interfaces.ts +++ b/packages/config/src/balance/balance.interfaces.ts @@ -2,7 +2,11 @@ import { u128 } from '@polkadot/types'; import { PalletBalancesAccountData } from '@polkadot/types/lookup'; import { AssetSymbol } from '../constants'; import { AssetId } from '../interfaces'; -import { BalanceFunction, BalancePallet } from './balance.constants'; +import { + BalanceCurrencyTypes, + BalanceFunction, + BalancePallet, +} from './balance.constants'; export type BalanceConfig = | SystemBalanceConfig @@ -46,19 +50,20 @@ export interface TokensBalanceConfig< pallet: BalancePallet.Tokens; function: BalanceFunction.Accounts; path: []; - getParams: (account: string) => [ - string, - ( - | { - Token: Symbols | 'MOVR' | 'KUSD'; - } - | { ForeignAsset: AssetId } - | { Token2: AssetId } - ), - ]; + getParams: (account: string) => [string, TokensBalanceParamAsset]; calc: (data: TokensPalletAccountData) => bigint; } +export type TokensBalanceParamAsset = + + | { + [BalanceCurrencyTypes.Token]: Symbols | AssetSymbol.KUSD; + } + | { [BalanceCurrencyTypes.ForeignAsset]: AssetId } + | { [BalanceCurrencyTypes.MiningResource]: AssetId } + | { [BalanceCurrencyTypes.FungibleToken]: AssetId } + | { [BalanceCurrencyTypes.Token2]: AssetId }; + export type MinBalanceConfig = | MinBalanceAssetsConfig | MinBalanceAssetRegistryConfig; diff --git a/packages/config/src/balance/balance.test.ts b/packages/config/src/balance/balance.test.ts index e03d76b2..87019750 100644 --- a/packages/config/src/balance/balance.test.ts +++ b/packages/config/src/balance/balance.test.ts @@ -1,3 +1,4 @@ +import { AssetSymbol } from '../constants'; import { createBalanceBuilder } from './balance'; describe('balance', () => { @@ -39,7 +40,7 @@ describe('balance', () => { }); describe('tokens', () => { - const cfg = balance.tokens('MOVR'); + const cfg = balance.tokens().token(AssetSymbol.MOVR); it('should be correct balance config', () => { expect(cfg).toMatchSnapshot(); @@ -49,16 +50,32 @@ describe('balance', () => { expect(cfg.getParams(account)).toMatchSnapshot(); }); - it('should be correct params with ForeignAsset', () => { - const cfg2 = balance.tokens(5); + const cfg2 = balance.tokens().foreignAsset(0); + + it('should be correct balance config foreignAsset', () => { + expect(cfg2).toMatchSnapshot(); + }); + it('should be correct params with ForeignAsset', () => { expect(cfg2.getParams(account)).toMatchSnapshot(); }); + const cfg3 = balance.tokens().miningResource(0); + + it('should be correct params with MiningResource', () => { + expect(cfg3.getParams(account)).toMatchSnapshot(); + }); + + const cfg4 = balance.tokens().fungibleToken(0); + + it('should be correct params with FungibleToken', () => { + expect(cfg4.getParams(account)).toMatchSnapshot(); + }); + it('should be correct params with Token2', () => { - const cfg2 = balance.tokens2(1); + const cfg5 = balance.tokens().token2(1); - expect(cfg2.getParams(account)).toMatchSnapshot(); + expect(cfg5.getParams(account)).toMatchSnapshot(); }); }); }); diff --git a/packages/config/src/balance/balance.ts b/packages/config/src/balance/balance.ts index 182884a3..a3aefb7d 100644 --- a/packages/config/src/balance/balance.ts +++ b/packages/config/src/balance/balance.ts @@ -4,7 +4,11 @@ import { u128 } from '@polkadot/types'; import { PalletBalancesAccountData } from '@polkadot/types/lookup'; import { AssetSymbol } from '../constants'; import { AssetId } from '../interfaces'; -import { BalanceFunction, BalancePallet } from './balance.constants'; +import { + BalanceCurrencyTypes, + BalanceFunction, + BalancePallet, +} from './balance.constants'; import { AssetsBalanceConfig, MinBalanceAssetRegistryConfig, @@ -12,6 +16,7 @@ import { OrmlTokensBalanceConfig, SystemBalanceConfig, TokensBalanceConfig, + TokensBalanceParamAsset, TokensPalletAccountData, } from './balance.interfaces'; @@ -26,9 +31,7 @@ export function createBalanceBuilder< minCurrencyMetadata, ormlTokens, system, - tokens: (asset: number | bigint | Symbols | 'MOVR' | 'KUSD' | 'AUSD') => - tokens(asset), - tokens2: (asset: AssetId) => tokens2(asset), + tokens: () => tokens(), }; } @@ -91,35 +94,30 @@ function system(): SystemBalanceConfig { }; } -function calcTokensBalance({ free, frozen }: TokensPalletAccountData): bigint { - return BigInt(free.sub(frozen).toString()); -} - -function tokens( - asset: number | bigint | Symbols | 'MOVR' | 'KUSD' | 'AUSD', -): TokensBalanceConfig { +function tokens() { return { - pallet: BalancePallet.Tokens, - function: BalanceFunction.Accounts, - path: [], - getParams: (account: string) => [ - account, - Number.isInteger(asset) - ? { ForeignAsset: asset as number } - : { Token: asset as Symbols }, - ], - calc: calcTokensBalance, + foreignAsset: (asset: AssetId | Symbols) => + tokensBase({ [BalanceCurrencyTypes.ForeignAsset]: asset }), + fungibleToken: (asset: AssetId) => + tokensBase({ [BalanceCurrencyTypes.FungibleToken]: asset }), + miningResource: (asset: AssetId) => + tokensBase({ [BalanceCurrencyTypes.MiningResource]: asset }), + token: (asset: Symbols | AssetSymbol.KUSD) => + tokensBase({ [BalanceCurrencyTypes.Token]: asset }), + token2: (asset: AssetId) => + tokensBase({ [BalanceCurrencyTypes.Token2]: asset }), }; } -function tokens2( - asset: AssetId, +function tokensBase( + asset: TokensBalanceParamAsset, ): TokensBalanceConfig { return { pallet: BalancePallet.Tokens, function: BalanceFunction.Accounts, path: [], - getParams: (account: string) => [account, { Token2: asset }], - calc: calcTokensBalance, + getParams: (account: string) => [account, asset], + calc: ({ free, frozen }: TokensPalletAccountData) => + BigInt(free.sub(frozen).toString()), }; } diff --git a/packages/config/src/config/moonbase/assets/bit.ts b/packages/config/src/config/moonbase/assets/bit.ts new file mode 100644 index 00000000..9f8d6816 --- /dev/null +++ b/packages/config/src/config/moonbase/assets/bit.ts @@ -0,0 +1,66 @@ +import { AssetSymbol, ChainKey } from '../../../constants'; +import { + XTokensExtrinsicCurrencyTypes, + XTokensExtrinsicSuccessEvent, +} from '../../../extrinsic'; +import { WithdrawConfig } from '../../../withdraw'; +import { + assets, + balance, + chains, + extrinsic, + withdraw, +} from '../moonbase.common'; +import { MoonbaseXcmConfig } from '../moonbase.interfaces'; +import { NEER } from './neer'; + +const asset = assets[AssetSymbol.BIT]; +const feeAsset = assets[AssetSymbol.NEER]; +const origin = chains[ChainKey.BitCountryPioneer]; +const neerWithdrawConfig = NEER.withdraw[ + origin.key +] as WithdrawConfig; + +export const BIT: MoonbaseXcmConfig = { + asset, + origin, + deposit: { + [origin.key]: { + source: origin, + balance: balance.tokens().miningResource(0), + sourceFeeBalance: balance.system(), + xcmFeeAsset: { + asset: feeAsset, + balance: balance.system(), + }, + extrinsic: extrinsic + .xTokens() + .transferMultiCurrencies() + .successEvent(XTokensExtrinsicSuccessEvent.TransferredMultiAssets) + .origin(origin) + .assets( + { + [XTokensExtrinsicCurrencyTypes.MiningResource]: 0, + }, + { + [XTokensExtrinsicCurrencyTypes.NativeToken]: 0, + }, + ), + }, + }, + withdraw: { + [origin.key]: withdraw.xTokens({ + balance: balance.tokens().miningResource(0), + destination: origin, + feePerWeight: neerWithdrawConfig.feePerWeight, + weight: neerWithdrawConfig.weight, + xcmFeeAsset: { + asset: feeAsset, + balance: { + destination: balance.system(), + origin: balance.assets(feeAsset.id), + }, + }, + }), + }, +}; diff --git a/packages/config/src/config/moonbase/assets/dev.ts b/packages/config/src/config/moonbase/assets/dev.ts index db92d398..b35b855e 100644 --- a/packages/config/src/config/moonbase/assets/dev.ts +++ b/packages/config/src/config/moonbase/assets/dev.ts @@ -16,8 +16,10 @@ import { MoonbaseXcmConfig } from '../moonbase.interfaces'; const asset = assets[AssetSymbol.DEV]; const clover = chains[ChainKey.CloverAlphanet]; +const pioneer = chains[ChainKey.BitCountryPioneer]; const cloverDevId = getMoonAssetId(clover); +const pioneerDevId = getMoonAssetId(pioneer); export const DEV: MoonbaseXcmConfig = { asset, @@ -36,6 +38,17 @@ export const DEV: MoonbaseXcmConfig = { [XTokensExtrinsicCurrencyTypes.OtherReserve]: cloverDevId, }), }, + [pioneer.key]: { + source: pioneer, + balance: balance.tokens().fungibleToken(pioneerDevId), + sourceFeeBalance: balance.system(), + extrinsic: extrinsic + .xTokens() + .transfer() + .successEvent(XTokensExtrinsicSuccessEvent.TransferredMultiAssets) + .origin(pioneer) + .asset({ [XTokensExtrinsicCurrencyTypes.FungibleToken]: pioneerDevId }), + }, }, withdraw: { [clover.key]: withdraw.xTokens({ @@ -43,5 +56,10 @@ export const DEV: MoonbaseXcmConfig = { destination: clover, feePerWeight: 50_000, }), + [pioneer.key]: withdraw.xTokens({ + balance: balance.tokens().fungibleToken(pioneerDevId), + destination: pioneer, + feePerWeight: 50_000, + }), }, }; diff --git a/packages/config/src/config/moonbase/assets/neer.ts b/packages/config/src/config/moonbase/assets/neer.ts new file mode 100644 index 00000000..3d43075f --- /dev/null +++ b/packages/config/src/config/moonbase/assets/neer.ts @@ -0,0 +1,40 @@ +import { AssetSymbol, ChainKey } from '../../../constants'; +import { + XTokensExtrinsicCurrencyTypes, + XTokensExtrinsicSuccessEvent, +} from '../../../extrinsic'; +import { + assets, + balance, + chains, + extrinsic, + withdraw, +} from '../moonbase.common'; +import { MoonbaseXcmConfig } from '../moonbase.interfaces'; + +const asset = assets[AssetSymbol.NEER]; +const origin = chains[ChainKey.BitCountryPioneer]; + +export const NEER: MoonbaseXcmConfig = { + asset, + origin, + deposit: { + [origin.key]: { + source: origin, + balance: balance.system(), + extrinsic: extrinsic + .xTokens() + .transfer() + .successEvent(XTokensExtrinsicSuccessEvent.TransferredMultiAssets) + .origin(origin) + .asset({ [XTokensExtrinsicCurrencyTypes.NativeToken]: 0 }), + }, + }, + withdraw: { + [origin.key]: withdraw.xTokens({ + balance: balance.system(), + destination: origin, + feePerWeight: 8_000_000, + }), + }, +}; diff --git a/packages/config/src/config/moonbase/moonbase.assets.ts b/packages/config/src/config/moonbase/moonbase.assets.ts index 9d872090..582e8579 100644 --- a/packages/config/src/config/moonbase/moonbase.assets.ts +++ b/packages/config/src/config/moonbase/moonbase.assets.ts @@ -3,16 +3,23 @@ import { AssetsMap } from '../config.interfaces'; import { MoonbaseAssets } from './moonbase.interfaces'; export const MOONBASE_ASSETS = [ + AssetSymbol.BIT, AssetSymbol.CLV, AssetSymbol.CRU, AssetSymbol.DEV, AssetSymbol.LIT, + AssetSymbol.NEER, AssetSymbol.TT1, AssetSymbol.UNIT, AssetSymbol.XRT, ]; export const MOONBASE_ASSETS_MAP: AssetsMap = { + [AssetSymbol.BIT]: { + id: '306639095083798603270835754515874921389', + erc20Id: '0xffffffffe6b08aa1fbbaa02f004d3e5aa27f3bad', + originSymbol: AssetSymbol.BIT, + }, [AssetSymbol.CLV]: { id: '281434042901349570144900941495462927562', erc20Id: '0xffffffffd3ba399d7d9d684d94b22767a5fa1cca', @@ -34,6 +41,11 @@ export const MOONBASE_ASSETS_MAP: AssetsMap = { erc20Id: '0xffffffff31103d490325bb0a8e40ef62e2f614c0', originSymbol: AssetSymbol.LIT, }, + [AssetSymbol.NEER]: { + id: '52280927600883288560727505734200597597', + erc20Id: '0xffffffff2754f0bdf7eb215503c69204ccd61c5d', + originSymbol: AssetSymbol.NEER, + }, [AssetSymbol.UNIT]: { id: '42259045809535163221576417993425387648', erc20Id: '0xffffffff1fcacbd218edc0eba20fc2308c778080', diff --git a/packages/config/src/config/moonbase/moonbase.chains.ts b/packages/config/src/config/moonbase/moonbase.chains.ts index 6cab3611..6bd2d42b 100644 --- a/packages/config/src/config/moonbase/moonbase.chains.ts +++ b/packages/config/src/config/moonbase/moonbase.chains.ts @@ -7,6 +7,7 @@ export const MOONBASE_CHAINS = [ ChainKey.CloverAlphanet, ChainKey.CrustShadowAlphanet, ChainKey.LitentryAlphanet, + ChainKey.BitCountryPioneer, ChainKey.MoonbaseBeta, ChainKey.RobonomicsAlphanet, ChainKey.StatemineAlphanet, @@ -20,6 +21,14 @@ export const MOONBASE_CHAINS_MAP: ChainsMap = { weight: 1_000_000_000, parachainId: 0, }, + [ChainKey.BitCountryPioneer]: { + key: ChainKey.BitCountryPioneer, + name: 'Bit.Country Pioneer', + ws: 'wss://moonbase-rpc.bit.country', + weight: 1_000_000_000, + parachainId: 2096, + moonAssetId: 0, + }, [ChainKey.CloverAlphanet]: { key: ChainKey.CloverAlphanet, name: 'Clover Alphanet', diff --git a/packages/config/src/config/moonbase/moonbase.ts b/packages/config/src/config/moonbase/moonbase.ts index 3a25f739..973474b9 100644 --- a/packages/config/src/config/moonbase/moonbase.ts +++ b/packages/config/src/config/moonbase/moonbase.ts @@ -1,19 +1,23 @@ import { AssetSymbol } from '../../constants'; import { MoonbaseXcmConfigs } from './moonbase.interfaces'; +import { BIT } from './assets/bit'; import { CLV } from './assets/clv'; import { CRU } from './assets/cru'; import { DEV } from './assets/dev'; import { LIT } from './assets/lit'; +import { NEER } from './assets/neer'; import { TT1 } from './assets/tt1'; import { UNIT } from './assets/unit'; import { XRT } from './assets/xrt'; export const MOONBASE_CONFIGS: MoonbaseXcmConfigs = { + [AssetSymbol.BIT]: BIT, [AssetSymbol.CLV]: CLV, [AssetSymbol.CRU]: CRU, [AssetSymbol.DEV]: DEV, [AssetSymbol.LIT]: LIT, + [AssetSymbol.NEER]: NEER, [AssetSymbol.TT1]: TT1, [AssetSymbol.UNIT]: UNIT, [AssetSymbol.XRT]: XRT, diff --git a/packages/config/src/config/moonbeam/assets/ausd.ts b/packages/config/src/config/moonbeam/assets/ausd.ts index 1dab17ff..956e3a56 100644 --- a/packages/config/src/config/moonbeam/assets/ausd.ts +++ b/packages/config/src/config/moonbeam/assets/ausd.ts @@ -21,7 +21,7 @@ export const AUSD: MoonbeamXcmConfig = { deposit: { [origin.key]: { source: origin, - balance: balance.tokens(asset.originSymbol), + balance: balance.tokens().token(asset.originSymbol), sourceFeeBalance: balance.system(), extrinsic: extrinsic .xTokens() @@ -35,7 +35,7 @@ export const AUSD: MoonbeamXcmConfig = { }, withdraw: { [origin.key]: withdraw.xTokens({ - balance: balance.tokens(asset.originSymbol), + balance: balance.tokens().token(asset.originSymbol), destination: origin, feePerWeight: 64, }), diff --git a/packages/config/src/config/moonbeam/assets/glmr.ts b/packages/config/src/config/moonbeam/assets/glmr.ts index 0c605ec8..ecf97369 100644 --- a/packages/config/src/config/moonbeam/assets/glmr.ts +++ b/packages/config/src/config/moonbeam/assets/glmr.ts @@ -35,7 +35,7 @@ export const GLMR: MoonbeamXcmConfig = { deposit: { [acala.key]: { source: acala, - balance: balance.tokens(acalaGlmrId), + balance: balance.tokens().foreignAsset(acalaGlmrId), sourceFeeBalance: balance.system(), extrinsic: extrinsic .xTokens() @@ -60,7 +60,7 @@ export const GLMR: MoonbeamXcmConfig = { }, [bifrost.key]: { source: bifrost, - balance: balance.tokens2(bifrostGlmrId), + balance: balance.tokens().token2(bifrostGlmrId), sourceFeeBalance: balance.system(), extrinsic: extrinsic .xTokens() @@ -96,7 +96,7 @@ export const GLMR: MoonbeamXcmConfig = { }, withdraw: { [acala.key]: withdraw.xTokens({ - balance: balance.tokens(acalaGlmrId), + balance: balance.tokens().foreignAsset(acalaGlmrId), destination: acala, feePerWeight: 8_000_000, sourceMinBalance: balance.minAssetRegistryPallet(acalaGlmrId), @@ -107,7 +107,7 @@ export const GLMR: MoonbeamXcmConfig = { feePerWeight: 50_000, }), [bifrost.key]: withdraw.xTokens({ - balance: balance.tokens2(bifrostGlmrId), + balance: balance.tokens().token2(bifrostGlmrId), destination: bifrost, feePerWeight: 0.8, sourceMinBalance: balance.minCurrencyMetadata(bifrostGlmrId), diff --git a/packages/config/src/config/moonbeam/assets/ibtc.ts b/packages/config/src/config/moonbeam/assets/ibtc.ts index 155a9cc4..3762ca40 100644 --- a/packages/config/src/config/moonbeam/assets/ibtc.ts +++ b/packages/config/src/config/moonbeam/assets/ibtc.ts @@ -22,11 +22,11 @@ export const IBTC: MoonbeamXcmConfig = { deposit: { [origin.key]: { source: origin, - balance: balance.tokens(asset.originSymbol), - sourceFeeBalance: balance.tokens(feeAsset.originSymbol), + balance: balance.tokens().token(asset.originSymbol), + sourceFeeBalance: balance.tokens().token(feeAsset.originSymbol), xcmFeeAsset: { asset: feeAsset, - balance: balance.tokens(feeAsset.originSymbol), + balance: balance.tokens().token(feeAsset.originSymbol), }, extrinsic: extrinsic .xTokens() @@ -45,7 +45,7 @@ export const IBTC: MoonbeamXcmConfig = { }, withdraw: { [origin.key]: withdraw.xTokens({ - balance: balance.tokens(asset.originSymbol), + balance: balance.tokens().token(asset.originSymbol), destination: origin, feePerWeight: 0.00000619, }), diff --git a/packages/config/src/config/moonbeam/assets/intr.ts b/packages/config/src/config/moonbeam/assets/intr.ts index bdab8cbb..7641aca4 100644 --- a/packages/config/src/config/moonbeam/assets/intr.ts +++ b/packages/config/src/config/moonbeam/assets/intr.ts @@ -21,7 +21,7 @@ export const INTR: MoonbeamXcmConfig = { deposit: { [origin.key]: { source: origin, - balance: balance.tokens(asset.originSymbol), + balance: balance.tokens().token(asset.originSymbol), extrinsic: extrinsic .xTokens() .transfer() @@ -32,7 +32,7 @@ export const INTR: MoonbeamXcmConfig = { }, withdraw: { [origin.key]: withdraw.xTokens({ - balance: balance.tokens(asset.originSymbol), + balance: balance.tokens().token(asset.originSymbol), destination: origin, feePerWeight: 1.87, }), diff --git a/packages/config/src/config/moonriver/assets/ausd.ts b/packages/config/src/config/moonriver/assets/ausd.ts index 310b42cd..0ef735b5 100644 --- a/packages/config/src/config/moonriver/assets/ausd.ts +++ b/packages/config/src/config/moonriver/assets/ausd.ts @@ -21,7 +21,7 @@ export const AUSD: MoonriverXcmConfig = { deposit: { [origin.key]: { source: origin, - balance: balance.tokens('KUSD'), + balance: balance.tokens().token(AssetSymbol.KUSD), sourceFeeBalance: balance.system(), extrinsic: extrinsic .xTokens() @@ -29,13 +29,13 @@ export const AUSD: MoonriverXcmConfig = { .successEvent(XTokensExtrinsicSuccessEvent.TransferredMultiAssets) .origin(origin) .asset({ - [XTokensExtrinsicCurrencyTypes.Token]: 'KUSD', + [XTokensExtrinsicCurrencyTypes.Token]: AssetSymbol.KUSD, }), }, }, withdraw: { [origin.key]: withdraw.xTokens({ - balance: balance.tokens('KUSD'), + balance: balance.tokens().token(AssetSymbol.KUSD), destination: origin, feePerWeight: 64, }), diff --git a/packages/config/src/config/moonriver/assets/kbtc.ts b/packages/config/src/config/moonriver/assets/kbtc.ts index 2a26dc14..31e7da9e 100644 --- a/packages/config/src/config/moonriver/assets/kbtc.ts +++ b/packages/config/src/config/moonriver/assets/kbtc.ts @@ -22,11 +22,11 @@ export const KBTC: MoonriverXcmConfig = { deposit: { [origin.key]: { source: origin, - balance: balance.tokens(asset.originSymbol), - sourceFeeBalance: balance.tokens(feeAsset.originSymbol), + balance: balance.tokens().token(asset.originSymbol), + sourceFeeBalance: balance.tokens().token(feeAsset.originSymbol), xcmFeeAsset: { asset: feeAsset, - balsance: balance.tokens(feeAsset.originSymbol), + balance: balance.tokens().token(feeAsset.originSymbol), }, extrinsic: extrinsic .xTokens() @@ -45,7 +45,7 @@ export const KBTC: MoonriverXcmConfig = { }, withdraw: { [origin.key]: withdraw.xTokens({ - balance: balance.tokens(asset.originSymbol), + balance: balance.tokens().token(asset.originSymbol), destination: origin, feePerWeight: 0.000000107, }), diff --git a/packages/config/src/config/moonriver/assets/kint.ts b/packages/config/src/config/moonriver/assets/kint.ts index 59ab143e..9a550def 100644 --- a/packages/config/src/config/moonriver/assets/kint.ts +++ b/packages/config/src/config/moonriver/assets/kint.ts @@ -21,7 +21,7 @@ export const KINT: MoonriverXcmConfig = { deposit: { [origin.key]: { source: origin, - balance: balance.tokens(asset.originSymbol), + balance: balance.tokens().token(asset.originSymbol), extrinsic: extrinsic .xTokens() .transfer() @@ -32,7 +32,7 @@ export const KINT: MoonriverXcmConfig = { }, withdraw: { [origin.key]: withdraw.xTokens({ - balance: balance.tokens(asset.originSymbol), + balance: balance.tokens().token(asset.originSymbol), destination: origin, feePerWeight: 0.21, }), diff --git a/packages/config/src/config/moonriver/assets/movr.ts b/packages/config/src/config/moonriver/assets/movr.ts index a58fb52a..b7e73f84 100644 --- a/packages/config/src/config/moonriver/assets/movr.ts +++ b/packages/config/src/config/moonriver/assets/movr.ts @@ -38,7 +38,7 @@ export const MOVR: MoonriverXcmConfig = { deposit: { [bifrost.key]: { source: bifrost, - balance: balance.tokens('MOVR'), + balance: balance.tokens().token(AssetSymbol.MOVR), sourceFeeBalance: balance.system(), extrinsic: extrinsic .xTokens() @@ -77,7 +77,7 @@ export const MOVR: MoonriverXcmConfig = { }, [karura.key]: { source: karura, - balance: balance.tokens(karuraMovrId), + balance: balance.tokens().foreignAsset(karuraMovrId), sourceFeeBalance: balance.system(), extrinsic: extrinsic .xTokens() @@ -125,7 +125,7 @@ export const MOVR: MoonriverXcmConfig = { }, withdraw: { [bifrost.key]: withdraw.xTokens({ - balance: balance.tokens('MOVR'), + balance: balance.tokens().token(AssetSymbol.MOVR), destination: bifrost, feePerWeight: 213_600, }), @@ -141,7 +141,7 @@ export const MOVR: MoonriverXcmConfig = { feePerWeight: 50_000, }), [karura.key]: withdraw.xTokens({ - balance: balance.tokens(karuraMovrId), + balance: balance.tokens().foreignAsset(karuraMovrId), destination: karura, feePerWeight: 50_000, sourceMinBalance: balance.minAssetRegistryPallet(karuraMovrId), diff --git a/packages/config/src/constants/assets.ts b/packages/config/src/constants/assets.ts index 28c053dd..bc6969f5 100644 --- a/packages/config/src/constants/assets.ts +++ b/packages/config/src/constants/assets.ts @@ -2,6 +2,7 @@ export enum AssetSymbol { ACA = 'ACA', ASTR = 'ASTR', AUSD = 'AUSD', + BIT = 'BIT', BNC = 'BNC', CFG = 'CFG', CLV = 'CLV', @@ -23,6 +24,7 @@ export enum AssetSymbol { KUSD = 'KUSD', LIT = 'LIT', MOVR = 'MOVR', + NEER = 'NEER', PARA = 'PARA', PHA = 'PHA', RING = 'RING', diff --git a/packages/config/src/constants/chains.ts b/packages/config/src/constants/chains.ts index fff809b6..e2e7a4dc 100644 --- a/packages/config/src/constants/chains.ts +++ b/packages/config/src/constants/chains.ts @@ -46,6 +46,7 @@ export enum ChainKey { AlphanetRelay = 'AlphanetRelay', Astar = 'Astar', Bifrost = 'Bifrost', + BitCountryPioneer = 'BitCountryPioneer', BifrostPolkadot = 'BifrostPolkadot', Calamari = 'Calamari', CloverAlphanet = 'CloverAlphanet', diff --git a/packages/config/src/deposit/deposit.interfaces.ts b/packages/config/src/deposit/deposit.interfaces.ts index c5f4105c..012d58cc 100644 --- a/packages/config/src/deposit/deposit.interfaces.ts +++ b/packages/config/src/deposit/deposit.interfaces.ts @@ -1,7 +1,7 @@ import { BalanceConfig, MinBalanceConfig } from '../balance'; import { AssetSymbol, ChainKey } from '../constants'; import { ExtrinsicConfig } from '../extrinsic'; -import { Asset, Chain } from '../interfaces'; +import { Chain, XcmFeeAsset } from '../interfaces'; export interface DepositConfig< Symbols extends AssetSymbol = AssetSymbol, @@ -34,8 +34,5 @@ export interface DepositConfig< * Optional - Asset to pay for the XCM fee in Moon*. Needed if the asset being * sent is not accepted as XCM fee payment method. */ - xcmFeeAsset?: { - balance: BalanceConfig; - asset: Asset; - }; + xcmFeeAsset?: XcmFeeAsset; } diff --git a/packages/config/src/extrinsic/xTokens/xTokens.constants.ts b/packages/config/src/extrinsic/xTokens/xTokens.constants.ts index 77963da4..f4ea89ae 100644 --- a/packages/config/src/extrinsic/xTokens/xTokens.constants.ts +++ b/packages/config/src/extrinsic/xTokens/xTokens.constants.ts @@ -11,10 +11,13 @@ export enum XTokensExtrinsicSuccessEvent { } export enum XTokensExtrinsicCurrencyTypes { - Token = 'Token', - Token2 = 'Token2', - Native = 'Native', ForeignAsset = 'ForeignAsset', + FungibleToken = 'FungibleToken', MantaCurrency = 'MantaCurrency', + MiningResource = 'MiningResource', + Native = 'Native', + NativeToken = 'NativeToken', OtherReserve = 'OtherReserve', + Token = 'Token', + Token2 = 'Token2', } diff --git a/packages/config/src/extrinsic/xTokens/xTokens.interfaces.ts b/packages/config/src/extrinsic/xTokens/xTokens.interfaces.ts index cf5be154..2f75c86d 100644 --- a/packages/config/src/extrinsic/xTokens/xTokens.interfaces.ts +++ b/packages/config/src/extrinsic/xTokens/xTokens.interfaces.ts @@ -196,7 +196,7 @@ export type XTokensTransferExtrinsicParamsAsset< Symbols extends AssetSymbol = AssetSymbol, > = | { - [XTokensExtrinsicCurrencyTypes.Token]: Symbols | 'KUSD' | 'MOVR'; + [XTokensExtrinsicCurrencyTypes.Token]: Symbols | AssetSymbol.KUSD; } | { [XTokensExtrinsicCurrencyTypes.Token2]: AssetId; @@ -204,9 +204,18 @@ export type XTokensTransferExtrinsicParamsAsset< | { [XTokensExtrinsicCurrencyTypes.Native]: Symbols; } + | { + [XTokensExtrinsicCurrencyTypes.NativeToken]: AssetId; + } + | { + [XTokensExtrinsicCurrencyTypes.MiningResource]: AssetId; + } | { [XTokensExtrinsicCurrencyTypes.ForeignAsset]: AssetId; } + | { + [XTokensExtrinsicCurrencyTypes.FungibleToken]: AssetId; + } | { [XTokensExtrinsicCurrencyTypes.MantaCurrency]: AssetId; } diff --git a/packages/config/src/extrinsic/xTokens/xTokens.test.ts b/packages/config/src/extrinsic/xTokens/xTokens.test.ts index 549094ce..f49a9b54 100644 --- a/packages/config/src/extrinsic/xTokens/xTokens.test.ts +++ b/packages/config/src/extrinsic/xTokens/xTokens.test.ts @@ -37,7 +37,7 @@ describe('xTokens', () => { .transfer() .successEvent(XTokensExtrinsicSuccessEvent.Transferred) .origin(origin) - .asset({ Token: 'MOVR' }); + .asset({ Token: AssetSymbol.MOVR }); it('should be correct config', () => { expect(cfg).toMatchSnapshot(); diff --git a/packages/config/src/interfaces.ts b/packages/config/src/interfaces.ts index 318af341..ec70352f 100644 --- a/packages/config/src/interfaces.ts +++ b/packages/config/src/interfaces.ts @@ -1,3 +1,4 @@ +import { BalanceConfig } from './balance'; import { AssetSymbol, ChainKey, MoonChainKey } from './constants'; export type AssetId = number | bigint | string; @@ -49,3 +50,8 @@ export interface Chain */ unitsPerSecond?: bigint; } + +export interface XcmFeeAsset { + balance: BalanceConfig; + asset: Asset; +} diff --git a/packages/config/src/withdraw/__snapshots__/withdraw.test.ts.snap b/packages/config/src/withdraw/__snapshots__/withdraw.test.ts.snap index 7b03c1e7..70e46c81 100644 --- a/packages/config/src/withdraw/__snapshots__/withdraw.test.ts.snap +++ b/packages/config/src/withdraw/__snapshots__/withdraw.test.ts.snap @@ -10,6 +10,7 @@ exports[`withdraw xTokens should be correct withdraw config 1`] = ` "getParams": [Function], "sourceMinBalance": undefined, "weight": 4000000000, + "xcmFeeAsset": undefined, } `; diff --git a/packages/config/src/withdraw/withdraw.interfaces.ts b/packages/config/src/withdraw/withdraw.interfaces.ts index 87fee461..6b3919b7 100644 --- a/packages/config/src/withdraw/withdraw.interfaces.ts +++ b/packages/config/src/withdraw/withdraw.interfaces.ts @@ -1,6 +1,6 @@ import { BalanceConfig, MinBalanceConfig } from '../balance'; import { AssetSymbol, ChainKey } from '../constants'; -import { Chain } from '../interfaces'; +import { Asset, Chain } from '../interfaces'; export type WithdrawConfig = WithdrawXTokensConfig; @@ -13,6 +13,7 @@ export interface WithdrawXTokensConfig< destination: Chain; feePerWeight: number; sourceMinBalance?: MinBalanceConfig; + xcmFeeAsset?: WithdrawXcmFeeAsset; weight: number; getParams: (account: string) => WithdrawXTokensParams; } @@ -59,4 +60,13 @@ export interface WithdrawXTokensOptions< feePerWeight: number; sourceMinBalance?: MinBalanceConfig; weight?: number; + xcmFeeAsset?: WithdrawXcmFeeAsset; +} + +interface WithdrawXcmFeeAsset { + asset: Asset; + balance: { + origin: BalanceConfig; + destination: BalanceConfig; + }; } diff --git a/packages/config/src/withdraw/withdraw.ts b/packages/config/src/withdraw/withdraw.ts index a40ffba1..dea19109 100644 --- a/packages/config/src/withdraw/withdraw.ts +++ b/packages/config/src/withdraw/withdraw.ts @@ -21,6 +21,7 @@ function xTokens({ destination, feePerWeight, sourceMinBalance, + xcmFeeAsset, weight = 4_000_000_000, }: WithdrawXTokensOptions): WithdrawXTokensConfig { return { @@ -28,6 +29,7 @@ function xTokens({ destination, feePerWeight, sourceMinBalance, + xcmFeeAsset, weight, getParams: (account: string) => { const { parachainId } = destination; diff --git a/packages/sdk/src/contracts/XTokensContract/XTokens.sol b/packages/sdk/src/contracts/XTokensContract/XTokens.sol new file mode 100644 index 00000000..594db4a3 --- /dev/null +++ b/packages/sdk/src/contracts/XTokensContract/XTokens.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.3; + +/// @dev The Xtokens contract's address. +address constant XTOKENS_ADDRESS = 0x0000000000000000000000000000000000000804; + +/// @dev The Xtokens contract's instance. +Xtokens constant XTOKENS_CONTRACT = Xtokens(XTOKENS_ADDRESS); + +/// @author The Moonbeam Team +/// @title Xtokens Interface +/// @dev The interface through which solidity contracts will interact with xtokens pallet +/// @custom:address 0x0000000000000000000000000000000000000804 +interface Xtokens { + // A multilocation is defined by its number of parents and the encoded junctions (interior) + struct Multilocation { + uint8 parents; + bytes[] interior; + } + + // A Currency is defined by address and the amount to be transferred + struct Currency { + address currencyAddress; + uint256 amount; + } + + /// Transfer a token through XCM based on its currencyId + /// + /// @dev The token transfer burns/transfers the corresponding amount before sending + /// @param currencyAddress The ERC20 address of the currency we want to transfer + /// @param amount The amount of tokens we want to transfer + /// @param destination The Multilocation to which we want to send the tokens + /// @param destination The weight we want to buy in the destination chain + /// @custom:selector b9f813ff + function transfer( + address currencyAddress, + uint256 amount, + Multilocation memory destination, + uint64 weight + ) external; + + /// Transfer several tokens at once through XCM based on its address specifying fee + /// + /// @dev The token transfer burns/transfers the corresponding amount before sending + /// @param currencies The currencies we want to transfer, defined by their address and amount. + /// @param feeItem Which of the currencies to be used as fee + /// @param destination The Multilocation to which we want to send the tokens + /// @param weight The weight we want to buy in the destination chain + /// @custom:selector ab946323 + function transferMultiCurrencies( + Currency[] memory currencies, + uint32 feeItem, + Multilocation memory destination, + uint64 weight + ) external; +} diff --git a/packages/sdk/src/contracts/XTokensContract/XTokens.sol.sol b/packages/sdk/src/contracts/XTokensContract/XTokens.sol.sol deleted file mode 100644 index fa96ce6e..00000000 --- a/packages/sdk/src/contracts/XTokensContract/XTokens.sol.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity >=0.8.0; - -/** - * @title Xtokens Interface - * - * The interface through which solidity contracts will interact with xtokens pallet - * - */ -interface Xtokens { - // A multilocation is defined by its number of parents and the encoded junctions (interior) - struct Multilocation { - uint8 parents; - bytes [] interior; - } - - /** Transfer a token through XCM based on its currency address (erc20 address) - * Selector b9f813ff - * - * @dev The token transfer burns/transfers the corresponding amount before sending - * @param currency_address The ERC20 address of the currency we want to transfer - * @param amount The amount of tokens we want to transfer - * @param destination The Multilocation to which we want to send the tokens - * @param weight The weight we want to buy in the destination chain - */ - function transfer(address currency_address, uint256 amount, Multilocation memory destination, uint64 weight) external; - - /** Transfer a token through XCM based on its multiLocation - * Selector b38c60fa - * - * @dev The token transfer burns/transfers the corresponding amount before sending - * @param asset The asset we want to transfer, defined by its multilocation. Currently only Concrete Fungible assets - * @param amount The amount of tokens we want to transfer - * @param destination The Multilocation to which we want to send the tokens - * @param weight The weight we want to buy in the destination chain - */ - function transfer_multiasset(Multilocation memory asset, uint256 amount, Multilocation memory destination, uint64 weight) external; -} \ No newline at end of file diff --git a/packages/sdk/src/contracts/XTokensContract/XTokensABI.json b/packages/sdk/src/contracts/XTokensContract/XTokensABI.json index 190b338c..fbad370f 100644 --- a/packages/sdk/src/contracts/XTokensContract/XTokensABI.json +++ b/packages/sdk/src/contracts/XTokensContract/XTokensABI.json @@ -3,7 +3,7 @@ "inputs": [ { "internalType": "address", - "name": "currency_address", + "name": "currencyAddress", "type": "address" }, { @@ -44,24 +44,24 @@ { "components": [ { - "internalType": "uint8", - "name": "parents", - "type": "uint8" + "internalType": "address", + "name": "currencyAddress", + "type": "address" }, { - "internalType": "bytes[]", - "name": "interior", - "type": "bytes[]" + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "internalType": "struct Xtokens.Multilocation", - "name": "asset", - "type": "tuple" + "internalType": "struct Xtokens.Currency[]", + "name": "currencies", + "type": "tuple[]" }, { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "internalType": "uint32", + "name": "feeItem", + "type": "uint32" }, { "components": [ @@ -86,7 +86,7 @@ "type": "uint64" } ], - "name": "transfer_multiasset", + "name": "transferMultiCurrencies", "outputs": [], "stateMutability": "nonpayable", "type": "function" diff --git a/packages/sdk/src/contracts/XTokensContract/XTokensContract.ts b/packages/sdk/src/contracts/XTokensContract/XTokensContract.ts index 89b1406e..124be3d9 100644 --- a/packages/sdk/src/contracts/XTokensContract/XTokensContract.ts +++ b/packages/sdk/src/contracts/XTokensContract/XTokensContract.ts @@ -25,7 +25,19 @@ export class XTokensContract { amount: bigint, asset: Asset, config: WithdrawXTokensConfig, + minAmount: bigint, ): Promise { + if (config.xcmFeeAsset) { + return this.#contract.transferMultiCurrencies( + [ + [config.xcmFeeAsset.asset.erc20Id, minAmount], + [asset.erc20Id, amount], + ], + 0, + config.getParams(account), + config.weight, + ); + } return this.#contract.transfer( asset.erc20Id, amount, diff --git a/packages/sdk/src/sdk/sdk.interfaces.ts b/packages/sdk/src/sdk/sdk.interfaces.ts index 5f8ab921..40edd746 100644 --- a/packages/sdk/src/sdk/sdk.interfaces.ts +++ b/packages/sdk/src/sdk/sdk.interfaces.ts @@ -86,7 +86,7 @@ export interface DepositGetParams { export interface XcmSdkWithdrawTo { get: ( - account: string, + destinationAccount: string, params?: WithdrawGetParams, ) => Promise>; } @@ -123,8 +123,10 @@ export interface WithdrawTransferData< destinationFee: bigint; existentialDeposit: bigint; min: bigint; + minXcmFeeAsset: XcmFeeWithDecimals; native: AssetWithDecimals; origin: MoonChain | Chain; + originXcmFeeAssetBalance?: bigint; getFee: (amount: bigint) => Promise; send: (amount: bigint, cb?: ExtrinsicEventsCallback) => Promise; } @@ -134,6 +136,12 @@ export interface AssetWithDecimals decimals: number; } +export interface XcmFeeWithDecimals { + amount: bigint; + decimals: number; + symbol: Symbols; +} + export interface Balance { balance: bigint; decimals: number; diff --git a/packages/sdk/src/sdk/sdk.ts b/packages/sdk/src/sdk/sdk.ts index 79bf6bae..5f166d34 100644 --- a/packages/sdk/src/sdk/sdk.ts +++ b/packages/sdk/src/sdk/sdk.ts @@ -142,6 +142,7 @@ function initByChain( if (!signer) { throw new Error('Ethers signer is not provided to XCM-SDK'); } + const originAccount = await signer.getAddress(); const contract = new XTokensContract(signer); const [polkadot, destinationPolkadot] = @@ -156,6 +157,7 @@ function initByChain( asset, config, contract, + originAccount, destinationAccount, destinationPolkadot, ethersSigner: signer, diff --git a/packages/sdk/src/sdk/sdk.withdraw.ts b/packages/sdk/src/sdk/sdk.withdraw.ts index d2f4e8f9..0265b8a4 100644 --- a/packages/sdk/src/sdk/sdk.withdraw.ts +++ b/packages/sdk/src/sdk/sdk.withdraw.ts @@ -23,6 +23,7 @@ export interface GetWithdrawDataParams< asset: Asset; config: WithdrawConfig; contract: XTokensContract; + originAccount: string; destinationAccount: string; destinationPolkadot: PolkadotService; ethersSigner: EthersSigner; @@ -39,6 +40,7 @@ export async function getWithdrawData< asset, config, contract, + originAccount, destinationAccount, destinationPolkadot, ethersSigner, @@ -50,22 +52,62 @@ export async function getWithdrawData< WithdrawTransferData > { const meta = destinationPolkadot.getMetadata(); - const [decimals, destinationBalance, existentialDeposit, assetMinBalance] = - await Promise.all([ - asset.isNative ? moonChain.decimals : polkadot.getAssetDecimals(asset), - destinationPolkadot.getGenericBalance(destinationAccount, config.balance), - asset.isNative ? 0n : destinationPolkadot.getExistentialDeposit(), - config.sourceMinBalance - ? destinationPolkadot.getAssetMinBalance(config.sourceMinBalance) - : 0n, - ]); + const xcmFeeAsset = config.xcmFeeAsset?.asset ?? asset; + const [ + decimals, + // destinationBalance, + originXcmFeeAssetBalance, + destinationBalance, + destinationXcmFeeAssetBalance, + existentialDeposit, + assetMinBalance, + xcmFeeDecimals, + ] = await Promise.all([ + // decimals + asset.isNative ? moonChain.decimals : polkadot.getAssetDecimals(asset), + // originXcmFeeAssetBalance + config.xcmFeeAsset + ? await polkadot.getGenericBalance( + originAccount, + config.xcmFeeAsset?.balance.origin, + ) + : undefined, + // destinationBalance + destinationPolkadot.getGenericBalance(destinationAccount, config.balance), + // destinationXcmFeeAssetBalance + config.xcmFeeAsset + ? destinationPolkadot.getGenericBalance( + destinationAccount, + config.xcmFeeAsset.balance.destination, + ) + : undefined, + // existentialDeposit + asset.isNative ? 0n : destinationPolkadot.getExistentialDeposit(), + // assetMinBalance + config.sourceMinBalance + ? destinationPolkadot.getAssetMinBalance(config.sourceMinBalance) + : 0n, + // xcmFeeDecimals + polkadot.getAssetDecimals(xcmFeeAsset), + ]); const destinationFee = getFee(assetMinBalance, config); - const min = getMin( - assetMinBalance || existentialDeposit, - destinationBalance, - destinationFee, - ); + const min = config.xcmFeeAsset + ? 0n + : getMin( + assetMinBalance || existentialDeposit, + destinationBalance, + destinationFee, + ); + + const minXcmFeeAsset = + config.xcmFeeAsset && destinationXcmFeeAssetBalance !== undefined + ? getMin( + assetMinBalance || existentialDeposit, + destinationXcmFeeAssetBalance, + destinationFee, + ) + : 0n; return { asset: { ...asset, decimals }, @@ -74,8 +116,14 @@ export async function getWithdrawData< destinationFee, existentialDeposit, min, + minXcmFeeAsset: { + amount: minXcmFeeAsset, + decimals: xcmFeeDecimals, + symbol: xcmFeeAsset.originSymbol, + }, native: { ...nativeAsset, decimals: meta.decimals }, origin, + originXcmFeeAssetBalance, getFee: async (amount) => contract.getTransferFees(destinationAccount, amount, asset, config), send: async (amount: bigint, cb?: ExtrinsicEventsCallback) => { @@ -84,6 +132,7 @@ export async function getWithdrawData< amount, asset, config, + minXcmFeeAsset, ); if (cb) {