diff --git a/packages/builder/CHANGELOG.md b/packages/builder/CHANGELOG.md index 79cd5891..db2ead6e 100644 --- a/packages/builder/CHANGELOG.md +++ b/packages/builder/CHANGELOG.md @@ -1,5 +1,14 @@ # @moonbeam-network/xcm-builder +## 2.5.2 + +### Patch Changes + +- [#339](https://github.com/moonbeam-foundation/xcm-sdk/pull/339) [`6e543ce`](https://github.com/moonbeam-foundation/xcm-sdk/commit/6e543ce1adb1e81d283e1b1811d0eab6bffaad47) Thanks [@mmaurello](https://github.com/mmaurello)! - Add sovereign account balance checking + +- Updated dependencies [[`6e543ce`](https://github.com/moonbeam-foundation/xcm-sdk/commit/6e543ce1adb1e81d283e1b1811d0eab6bffaad47)]: + - @moonbeam-network/xcm-types@2.5.0 + ## 2.5.1 ### Patch Changes diff --git a/packages/builder/package.json b/packages/builder/package.json index 29846191..14ba345c 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@moonbeam-network/xcm-builder", - "version": "2.5.1", + "version": "2.5.2", "description": "Moonbeam XCM builder", "scripts": { "build": "tsup", diff --git a/packages/builder/src/extrinsic/pallets/polkadotXcm/polkadotXcm.ts b/packages/builder/src/extrinsic/pallets/polkadotXcm/polkadotXcm.ts index f78136cb..cbd6d04e 100644 --- a/packages/builder/src/extrinsic/pallets/polkadotXcm/polkadotXcm.ts +++ b/packages/builder/src/extrinsic/pallets/polkadotXcm/polkadotXcm.ts @@ -185,5 +185,36 @@ export function polkadotXcm() { }), }; }, + trasferAssets: () => { + const func = 'transferAssets'; + + return { + here: (): ExtrinsicConfigBuilder => ({ + build: (params) => + new ExtrinsicConfig({ + module: pallet, + func, + getArgs: (extrinsicFunction) => + getPolkadotXcmExtrinsicArgs({ + ...params, + func: extrinsicFunction, + asset: [ + { + id: { + Concrete: { + parents: 1, + interior: 'Here', + }, + }, + fun: { + Fungible: params.asset.amount, + }, + }, + ], + }), + }), + }), + }; + }, }; } diff --git a/packages/config/CHANGELOG.md b/packages/config/CHANGELOG.md index c1f4c4d4..4151ea66 100644 --- a/packages/config/CHANGELOG.md +++ b/packages/config/CHANGELOG.md @@ -1,5 +1,17 @@ # @moonbeam-network/xcm-config +## 2.7.0 + +### Minor Changes + +- [#339](https://github.com/moonbeam-foundation/xcm-sdk/pull/339) [`6e543ce`](https://github.com/moonbeam-foundation/xcm-sdk/commit/6e543ce1adb1e81d283e1b1811d0eab6bffaad47) Thanks [@mmaurello](https://github.com/mmaurello)! - Add sovereign account balance checking + +### Patch Changes + +- Updated dependencies [[`6e543ce`](https://github.com/moonbeam-foundation/xcm-sdk/commit/6e543ce1adb1e81d283e1b1811d0eab6bffaad47)]: + - @moonbeam-network/xcm-types@2.5.0 + - @moonbeam-network/xcm-builder@2.5.2 + ## 2.6.4 ### Patch Changes diff --git a/packages/config/package.json b/packages/config/package.json index 66a6bc3f..91fb2e22 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@moonbeam-network/xcm-config", - "version": "2.6.4", + "version": "2.7.0", "description": "All necessary configuration to transfer assets from Moonbeam, Moonriver, Moonbase to other parachains and back", "scripts": { "build": "tsup", diff --git a/packages/config/src/chains.ts b/packages/config/src/chains.ts index f3d6950a..78068034 100644 --- a/packages/config/src/chains.ts +++ b/packages/config/src/chains.ts @@ -165,6 +165,7 @@ export const alphanetRelay = new Parachain({ ecosystem: Ecosystem.AlphanetRelay, genesisHash: '0xe1ea3ab1d46ba8f4898b6b4b9c54ffc05282d299f89e84bd0fd08067758c9443', + isRelay: true, isTestChain: true, key: 'alphanet-relay', name: 'Alphanet Relay', @@ -749,6 +750,7 @@ export const kusama = new Parachain({ ecosystem: Ecosystem.Kusama, genesisHash: '0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe', + isRelay: true, key: 'kusama', name: 'Kusama', nativeAsset: ksm, @@ -781,6 +783,7 @@ export const kusamaAssetHub = new Parachain({ decimals: 12, }), ], + checkSovereignAccountBalances: true, ecosystem: Ecosystem.Kusama, genesisHash: '0x48239ef607d7928874027a43a67689209727dfb3d3dc5e5b03a39bdc2eda771a', @@ -1963,6 +1966,7 @@ export const polkadot = new Parachain({ ecosystem: Ecosystem.Polkadot, genesisHash: '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3', + isRelay: true, key: 'polkadot', name: 'Polkadot', nativeAsset: dot, @@ -2030,6 +2034,7 @@ export const polkadotAssetHub = new Parachain({ }, }), ], + checkSovereignAccountBalances: true, ecosystem: Ecosystem.Polkadot, genesisHash: '0x68d56f15f85d3136970ec16946040bc1752654e906147f7e43e9d539d7c3de2f', diff --git a/packages/config/src/xcm-configs/moonbeam.ts b/packages/config/src/xcm-configs/moonbeam.ts index 12c7f2e3..fb01d897 100644 --- a/packages/config/src/xcm-configs/moonbeam.ts +++ b/packages/config/src/xcm-configs/moonbeam.ts @@ -715,6 +715,7 @@ export const moonbeamRoutes = new ChainRoutes({ fee: { amount: 0.2, asset: usdt, + balance: BalanceBuilder().substrate().assets().account(), }, }, contract: ContractBuilder().Xtokens().transferMultiCurrencies(), diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index deeb5acf..8d0e3078 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -1,5 +1,18 @@ # @moonbeam-network/xcm-sdk +## 2.7.0 + +### Minor Changes + +- [#339](https://github.com/moonbeam-foundation/xcm-sdk/pull/339) [`6e543ce`](https://github.com/moonbeam-foundation/xcm-sdk/commit/6e543ce1adb1e81d283e1b1811d0eab6bffaad47) Thanks [@mmaurello](https://github.com/mmaurello)! - Add sovereign account balance checking + +### Patch Changes + +- Updated dependencies [[`6e543ce`](https://github.com/moonbeam-foundation/xcm-sdk/commit/6e543ce1adb1e81d283e1b1811d0eab6bffaad47)]: + - @moonbeam-network/xcm-config@2.7.0 + - @moonbeam-network/xcm-types@2.5.0 + - @moonbeam-network/xcm-builder@2.5.2 + ## 2.6.4 ### Patch Changes diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 427cc122..d227b780 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@moonbeam-network/xcm-sdk", - "version": "2.6.4", + "version": "2.7.0", "description": "The Moonbeam XCM SDK enables developers to easily deposit and withdraw assets to Moonbeam/Moonriver from the relay chain and other parachains in the Polkadot/Kusama ecosystem", "scripts": { "build": "tsup", diff --git a/packages/sdk/src/getTransferData/getDestinationData.ts b/packages/sdk/src/getTransferData/getDestinationData.ts index b45359bd..b65a7952 100644 --- a/packages/sdk/src/getTransferData/getDestinationData.ts +++ b/packages/sdk/src/getTransferData/getDestinationData.ts @@ -1,4 +1,4 @@ -import type { AssetRoute } from '@moonbeam-network/xcm-config'; +import type { AssetRoute, DestinationConfig, SourceConfig } from '@moonbeam-network/xcm-config'; import type { DestinationChainTransferData } from '../sdk.interfaces'; import { getAssetMin, @@ -6,6 +6,10 @@ import { getDestinationFee, getExistentialDeposit, } from './getTransferData.utils'; +import { + getSovereignAccountAddresses, +} from '@moonbeam-network/xcm-utils'; +import { Parachain } from '@moonbeam-network/xcm-types'; export interface GetDestinationDataParams { route: AssetRoute; @@ -44,5 +48,56 @@ export async function getDestinationData({ existentialDeposit, fee, min, + sovereignAccountBalances: await getSovereignAccountBalances({ + source: route.source, + destination: route.destination, + }), + }; + +} + +interface GetSovereignAccountBalancesProps { + source: SourceConfig; + destination: DestinationConfig; +} + +async function getSovereignAccountBalances( { + destination, + source, +}: GetSovereignAccountBalancesProps) { + + if(!Parachain.is(source.chain) || !Parachain.is(destination.chain)) { + return undefined + } + + const sovereignAccountAddresses = getSovereignAccountAddresses( + source.chain.parachainId, + ); + + const destinationFeeAssetBalance = + destination.fee.balance; + + const sovereignAccountAddress = destination.chain.isRelay + ? sovereignAccountAddresses.relay + : sovereignAccountAddresses.generic; + + const sovereignAccountBalance = await getBalance({ + address: sovereignAccountAddress, + asset: destination.chain.getChainAsset(destination.asset), + builder: destination.balance, + chain: destination.chain, + }); + + const sovereignAccountFeeAssetBalance = destinationFeeAssetBalance + ? await getBalance({ + address: sovereignAccountAddress, + asset: destination.chain.getChainAsset(destination.fee.asset), + builder: destinationFeeAssetBalance, + chain: destination.chain, + }) + : undefined; + return { + feeAssetBalance: sovereignAccountFeeAssetBalance?.amount, + transferAssetBalance: sovereignAccountBalance.amount, }; } diff --git a/packages/sdk/src/getTransferData/getSourceData.ts b/packages/sdk/src/getTransferData/getSourceData.ts index 1ad2e258..0458c95d 100644 --- a/packages/sdk/src/getTransferData/getSourceData.ts +++ b/packages/sdk/src/getTransferData/getSourceData.ts @@ -114,6 +114,7 @@ export async function getSourceData({ return { balance, chain: source, + destinationFee, destinationFeeBalance, existentialDeposit, fee, diff --git a/packages/sdk/src/getTransferData/getTransferData.ts b/packages/sdk/src/getTransferData/getTransferData.ts index a8b8d26f..cf45947a 100644 --- a/packages/sdk/src/getTransferData/getTransferData.ts +++ b/packages/sdk/src/getTransferData/getTransferData.ts @@ -11,7 +11,7 @@ import { EvmService } from '../services/evm/EvmService'; import { PolkadotService } from '../services/polkadot'; import { getDestinationData } from './getDestinationData'; import { getSourceData } from './getSourceData'; -import { convertToChainDecimals, getMin } from './getTransferData.utils'; +import { convertToChainDecimals, getMin, validateSovereignAccountBalances} from './getTransferData.utils'; export interface GetTransferDataParams { route: AssetRoute; @@ -49,6 +49,7 @@ export async function getTransferData({ const bigAmount = Big( toBigInt(amount, sourceData.balance.decimals).toString(), ); + const result = bigAmount.minus( sourceData.balance.isSame(destinationFee) ? destinationFee.toBig() @@ -66,9 +67,15 @@ export async function getTransferData({ amount, { evmSigner, polkadotSigner }: Partial, ): Promise { + const source = route.source.chain as AnyParachain; const destination = route.destination.chain as AnyParachain; const bigintAmount = toBigInt(amount, sourceData.balance.decimals); + validateSovereignAccountBalances({ + amount: bigintAmount, + destination, + source, + }); const asset = AssetAmount.fromChainAsset( route.source.chain.getChainAsset(route.source.asset), { amount: bigintAmount }, diff --git a/packages/sdk/src/getTransferData/getTransferData.utils.ts b/packages/sdk/src/getTransferData/getTransferData.utils.ts index f376cfa8..05223500 100644 --- a/packages/sdk/src/getTransferData/getTransferData.utils.ts +++ b/packages/sdk/src/getTransferData/getTransferData.utils.ts @@ -16,12 +16,17 @@ import { type ChainAsset, EvmChain, EvmParachain, + Parachain, } from '@moonbeam-network/xcm-types'; import { convertDecimals, toBigInt } from '@moonbeam-network/xcm-utils'; import Big from 'big.js'; -import type { DestinationChainTransferData } from '../sdk.interfaces'; import { EvmService } from '../services/evm/EvmService'; import { PolkadotService } from '../services/polkadot'; +import { + DestinationChainTransferData, + SourceChainTransferData, +} from '../sdk.interfaces'; + export interface GetBalancesParams { address: string; @@ -29,7 +34,6 @@ export interface GetBalancesParams { builder: BalanceConfigBuilder; chain: AnyChain; } - export async function getBalance({ address, asset, @@ -338,3 +342,36 @@ export async function getContractFee({ ); } } + +interface ValidateSovereignAccountBalancesProps { + amount: bigint; + destination: DestinationChainTransferData; + source: SourceChainTransferData; +} + +export function validateSovereignAccountBalances({ + amount, + source, + destination, +}: ValidateSovereignAccountBalancesProps): void { + if ( + !Parachain.is(destination.chain) || + !destination.chain.checkSovereignAccountBalances || + !destination.sovereignAccountBalances + ) { + return; + } + const { feeAssetBalance, transferAssetBalance } = + destination.sovereignAccountBalances; + + if (amount > transferAssetBalance) { + throw new Error( + `${source.chain.name} Sovereign account in ${destination.chain.name} does not have enough balance for this transaction`, + ); + } + if (feeAssetBalance && source.destinationFee.amount > feeAssetBalance) { + throw new Error( + `${source.chain.name} Sovereign account in ${destination.chain.name} does not have enough balance to pay for fees for this transaction`, + ); + } +} diff --git a/packages/sdk/src/sdk.interfaces.ts b/packages/sdk/src/sdk.interfaces.ts index 2d07bfc7..48f33351 100644 --- a/packages/sdk/src/sdk.interfaces.ts +++ b/packages/sdk/src/sdk.interfaces.ts @@ -20,12 +20,20 @@ export interface TransferData { } export interface SourceChainTransferData extends ChainTransferData { + destinationFee: AssetAmount; destinationFeeBalance: AssetAmount; feeBalance: AssetAmount; max: AssetAmount; } -export interface DestinationChainTransferData extends ChainTransferData {} +export interface SovereignAccountBalance { + feeAssetBalance: bigint | undefined; + transferAssetBalance: bigint; +} + +export interface DestinationChainTransferData extends ChainTransferData { + sovereignAccountBalances?: SovereignAccountBalance; +} export interface ChainTransferData { balance: AssetAmount; diff --git a/packages/sdk/tests/acceptance/__snapshots__/sdk.test.ts.snap b/packages/sdk/tests/acceptance/__snapshots__/sdk.test.ts.snap index b4f35a1c..3e25c978 100644 --- a/packages/sdk/tests/acceptance/__snapshots__/sdk.test.ts.snap +++ b/packages/sdk/tests/acceptance/__snapshots__/sdk.test.ts.snap @@ -473,71 +473,6 @@ exports[`sdk > getParachainBalances > on 'Moonbase Alpha' for address: '0x4E8214 ] `; -exports[`sdk > getParachainBalances > on 'Moonbase Beta' for address: '0x4E82143Af671Cc8201Bc7efCBbCED3A69e8…' > should get expected balances 1`] = ` -[ - _AssetAmount { - "address": undefined, - "amount": 100000000000000000n, - "decimals": 18, - "ids": { - "balanceId": "198801030527939140930753142903035039136", - "id": { - "ForeignAsset": "198801030527939140930753142903035039136", - }, - }, - "key": "ftmwh", - "min": undefined, - "originSymbol": "FTM.wh", - "symbol": undefined, - }, - _AssetAmount { - "address": undefined, - "amount": 0n, - "decimals": 6, - "ids": { - "balanceId": "319794858556516669238969276945382613133", - "id": { - "ForeignAsset": "319794858556516669238969276945382613133", - }, - }, - "key": "usdcwh", - "min": undefined, - "originSymbol": "USDC.Wh", - "symbol": undefined, - }, - _AssetAmount { - "address": undefined, - "amount": 1100000000000000000n, - "decimals": 18, - "ids": { - "balanceId": "85534404031760856987006367174489651085", - "id": { - "ForeignAsset": "85534404031760856987006367174489651085", - }, - }, - "key": "alan", - "min": undefined, - "originSymbol": "ALAN", - "symbol": undefined, - }, - _AssetAmount { - "address": undefined, - "amount": 1100000000000000000n, - "decimals": 18, - "ids": { - "balanceId": "222902676330054289648817870329963141953", - "id": { - "ForeignAsset": "222902676330054289648817870329963141953", - }, - }, - "key": "dev", - "min": undefined, - "originSymbol": "DEV", - "symbol": undefined, - }, -] -`; - exports[`sdk > getParachainBalances > on 'Moonbeam' for address: '0x4E82143Af671Cc8201Bc7efCBbCED3A69e8…' > should get expected balances 1`] = ` [ _AssetAmount { diff --git a/packages/sdk/tests/acceptance/sdk.test.ts b/packages/sdk/tests/acceptance/sdk.test.ts index ed6eeef0..4302b793 100644 --- a/packages/sdk/tests/acceptance/sdk.test.ts +++ b/packages/sdk/tests/acceptance/sdk.test.ts @@ -31,10 +31,10 @@ const config: { chain: AnyParachain; address: string }[] = [ { chain: centrifuge, address: substrateAddress }, { chain: hydrationAlphanet, address: hydrationAddress }, { chain: hydrationAlphanet, address: substrateAddress }, - { - chain: moonbaseBeta, - address: '0x4E82143Af671Cc8201Bc7efCBbCED3A69e84405e', - }, + // { + // chain: moonbaseBeta, + // address: '0x4E82143Af671Cc8201Bc7efCBbCED3A69e84405e', + // }, { chain: moonbaseAlpha, address: moonEvmAddress }, { chain: peaqEvmAlphanet, address: moonEvmAddress }, { chain: peaqAlphanet, address: substrateAddress }, diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index ddcb6d5b..b07f603b 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,11 @@ # @moonbeam-network/xcm-types +## 2.5.0 + +### Minor Changes + +- [#339](https://github.com/moonbeam-foundation/xcm-sdk/pull/339) [`6e543ce`](https://github.com/moonbeam-foundation/xcm-sdk/commit/6e543ce1adb1e81d283e1b1811d0eab6bffaad47) Thanks [@mmaurello](https://github.com/mmaurello)! - Add sovereign account balance checking + ## 2.4.1 ### Patch Changes diff --git a/packages/types/package.json b/packages/types/package.json index c10e0996..0988a403 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@moonbeam-network/xcm-types", - "version": "2.4.1", + "version": "2.5.0", "description": "Moonbeam XCM Types", "scripts": { "build": "tsup", diff --git a/packages/types/src/chain/parachain/Parachain.ts b/packages/types/src/chain/parachain/Parachain.ts index 99f43996..712aa87d 100644 --- a/packages/types/src/chain/parachain/Parachain.ts +++ b/packages/types/src/chain/parachain/Parachain.ts @@ -1,7 +1,9 @@ import { Chain, type ChainConstructorParams } from '../Chain'; export interface ParachainConstructorParams extends ChainConstructorParams { + checkSovereignAccountBalances?: boolean; genesisHash: string; + isRelay?: boolean; parachainId: number; ss58Format: number; usesChainDecimals?: boolean; @@ -10,8 +12,13 @@ export interface ParachainConstructorParams extends ChainConstructorParams { } export class Parachain extends Chain { + + readonly checkSovereignAccountBalances: boolean; + readonly genesisHash: string; + readonly isRelay: boolean; + readonly parachainId: number; readonly ss58Format: number; @@ -27,7 +34,9 @@ export class Parachain extends Chain { } constructor({ + checkSovereignAccountBalances, genesisHash, + isRelay, parachainId, usesChainDecimals, ss58Format, @@ -37,7 +46,9 @@ export class Parachain extends Chain { }: ParachainConstructorParams) { super(others); + this.checkSovereignAccountBalances = !!checkSovereignAccountBalances; this.genesisHash = genesisHash; + this.isRelay = !!isRelay; this.parachainId = parachainId; this.ss58Format = ss58Format; this.usesChainDecimals = !!usesChainDecimals;