diff --git a/.changeset/wild-singers-retire.md b/.changeset/wild-singers-retire.md new file mode 100644 index 00000000..7e6620fd --- /dev/null +++ b/.changeset/wild-singers-retire.md @@ -0,0 +1,7 @@ +--- +'@moonbeam-network/xcm-config': patch +'@moonbeam-network/xcm-types': patch +'@moonbeam-network/xcm-sdk': patch +--- + +USDC wh integration with Moonbeam diff --git a/packages/config/src/chains.ts b/packages/config/src/chains.ts index 4cf8b9dd..dcd1c40c 100644 --- a/packages/config/src/chains.ts +++ b/packages/config/src/chains.ts @@ -454,13 +454,11 @@ export const interlay = new Parachain({ asset: intr, decimals: 10, id: { Token: intr.originSymbol }, - metadataId: 0, }, { asset: ibtc, decimals: 8, id: { Token: ibtc.originSymbol }, - metadataId: 0, }, ], ecosystem: Ecosystem.Polkadot, @@ -549,7 +547,6 @@ export const kintsugi = new Parachain({ asset: kbtc, decimals: 8, id: { Token: kbtc.originSymbol }, - metadataId: 0, }, ], ecosystem: Ecosystem.Kusama, @@ -1400,6 +1397,16 @@ export const uniqueAlpha = new Parachain({ }); export const zeitgeist = new Parachain({ + assetsData: [ + { + asset: usdcwh, + id: { ForeignAsset: 1 }, + }, + { + asset: glmr, + id: { ForeignAsset: 3 }, + }, + ], ecosystem: Ecosystem.Polkadot, genesisHash: '0x1bf2a2ecb4a868de66ea8610f2ce7c8c43706561b6476031315f6640fe38e060', @@ -1407,6 +1414,7 @@ export const zeitgeist = new Parachain({ name: 'Zeitgeist', parachainId: 2092, ss58Format: 73, + usesChainDecimals: true, ws: 'wss://zeitgeist-rpc.dwellir.com', }); diff --git a/packages/config/src/configs/moonbeam.ts b/packages/config/src/configs/moonbeam.ts index 802a6937..e5883d5a 100644 --- a/packages/config/src/configs/moonbeam.ts +++ b/packages/config/src/configs/moonbeam.ts @@ -165,7 +165,18 @@ export const moonbeamConfig = new ChainConfig({ contract: ContractBuilder().Xtokens().transfer(), destination: pendulum, destinationFee: { - amount: 0.0002, // + amount: 0.0002, + asset: glmr, + balance: BalanceBuilder().substrate().system().account(), + }, + }), + new AssetConfig({ + asset: glmr, + balance: BalanceBuilder().substrate().system().account(), + contract: ContractBuilder().Xtokens().transfer(), + destination: zeitgeist, + destinationFee: { + amount: 0.3, asset: glmr, balance: BalanceBuilder().substrate().system().account(), }, @@ -515,6 +526,21 @@ export const moonbeamConfig = new ChainConfig({ balance: BalanceBuilder().substrate().system().account(), }, }), + new AssetConfig({ + asset: usdcwh, + balance: BalanceBuilder().evm().erc20(), + contract: ContractBuilder().Xtokens().transfer(), + destination: zeitgeist, + destinationFee: { + amount: 0.101, + asset: usdcwh, + balance: BalanceBuilder().evm().erc20(), + }, + fee: { + asset: glmr, + balance: BalanceBuilder().substrate().system().account(), + }, + }), new AssetConfig({ asset: usdtwh, balance: BalanceBuilder().evm().erc20(), diff --git a/packages/config/src/configs/zeitgeist.ts b/packages/config/src/configs/zeitgeist.ts index 3c543623..2fbf5d5f 100644 --- a/packages/config/src/configs/zeitgeist.ts +++ b/packages/config/src/configs/zeitgeist.ts @@ -3,7 +3,7 @@ import { ExtrinsicBuilder, FeeBuilder, } from '@moonbeam-network/xcm-builder'; -import { ztg } from '../assets'; +import { glmr, usdcwh, ztg } from '../assets'; import { moonbeam, zeitgeist } from '../chains'; import { AssetConfig } from '../types/AssetConfig'; import { ChainConfig } from '../types/ChainConfig'; @@ -21,6 +21,32 @@ export const zeitgeistConfig = new ChainConfig({ }, extrinsic: ExtrinsicBuilder().xTokens().transfer(), }), + new AssetConfig({ + asset: usdcwh, + balance: BalanceBuilder().substrate().tokens().accounts(), + destination: moonbeam, + destinationFee: { + amount: 0.04, + asset: glmr, + balance: BalanceBuilder().substrate().tokens().accounts(), + }, + extrinsic: ExtrinsicBuilder().xTokens().transferMultiCurrencies(), + fee: { + asset: ztg, + balance: BalanceBuilder().substrate().system().account(), + }, + }), + new AssetConfig({ + asset: glmr, + balance: BalanceBuilder().substrate().tokens().accounts(), + destination: moonbeam, + destinationFee: { + amount: 0.01, + asset: glmr, + balance: BalanceBuilder().substrate().tokens().accounts(), + }, + extrinsic: ExtrinsicBuilder().xTokens().transfer(), + }), ], chain: zeitgeist, }); diff --git a/packages/sdk/src/getTransferData/getDestinationData.ts b/packages/sdk/src/getTransferData/getDestinationData.ts index d6e51256..fbfe0ee3 100644 --- a/packages/sdk/src/getTransferData/getDestinationData.ts +++ b/packages/sdk/src/getTransferData/getDestinationData.ts @@ -29,6 +29,7 @@ export async function getDestinationData({ amount: 0n, decimals: await getDecimals({ address: destinationAddress, + chain, config, evmSigner, polkadot, @@ -37,7 +38,9 @@ export async function getDestinationData({ const balance = await getBalance({ address: destinationAddress, + chain, config, + decimals: zeroAmount.decimals, evmSigner, polkadot, }); @@ -53,7 +56,6 @@ export async function getDestinationData({ polkadot, }); const minAmount = zeroAmount.copyWith({ amount: min }); - return { balance: balanceAmount, chain, diff --git a/packages/sdk/src/getTransferData/getSourceData.ts b/packages/sdk/src/getTransferData/getSourceData.ts index c5b2ff6b..8f26d8c9 100644 --- a/packages/sdk/src/getTransferData/getSourceData.ts +++ b/packages/sdk/src/getTransferData/getSourceData.ts @@ -5,13 +5,18 @@ import { SubstrateQueryConfig, } from '@moonbeam-network/xcm-builder'; import { FeeAssetConfig, TransferConfig } from '@moonbeam-network/xcm-config'; -import { AssetAmount } from '@moonbeam-network/xcm-types'; +import { AnyChain, AssetAmount } from '@moonbeam-network/xcm-types'; import { convertDecimals, toBigInt } from '@moonbeam-network/xcm-utils'; import Big from 'big.js'; import { TransferContractInterface, createContract } from '../contract'; import { PolkadotService } from '../polkadot'; import { EvmSigner, SourceChainTransferData } from '../sdk.interfaces'; -import { getBalance, getDecimals, getMin } from './getTransferData.utils'; +import { + GetBalancesParams, + getBalance, + getDecimals, + getMin, +} from './getTransferData.utils'; export interface GetSourceDataParams { transferConfig: TransferConfig; @@ -39,6 +44,7 @@ export async function getSourceData({ amount: 0n, decimals: await getDecimals({ address: destinationAddress, + chain, config, evmSigner, polkadot, @@ -50,6 +56,7 @@ export async function getSourceData({ decimals: await getDecimals({ address: destinationAddress, asset: config.fee.asset, + chain, config, evmSigner, polkadot, @@ -62,6 +69,7 @@ export async function getSourceData({ decimals: await getDecimals({ address: destinationAddress, asset: config.destinationFee.asset, + chain, config, evmSigner, polkadot, @@ -71,14 +79,18 @@ export async function getSourceData({ const balance = await getBalance({ address: sourceAddress, + chain, config, + decimals: zeroAmount.decimals, evmSigner, polkadot, }); - const feeBalance = await getFeeBalances({ + const feeBalance = await getFeeBalance({ address: sourceAddress, balance, + chain, + decimals: zeroFeeAmount.decimals, feeConfig: config.fee, polkadot, }); @@ -87,9 +99,11 @@ export async function getSourceData({ config.destinationFee.asset, ) ? balance - : await getFeeBalances({ + : await getFeeBalance({ address: sourceAddress, balance, + chain, + decimals: zeroDestinationFeeAmount.decimals, feeConfig: config.destinationFee, polkadot, }); @@ -117,6 +131,7 @@ export async function getSourceData({ }); const fee = await getFee({ balance, + chain, contract, decimals: zeroFeeAmount.decimals, evmSigner, @@ -134,6 +149,7 @@ export async function getSourceData({ amount: destinationFeeBalance, }); const minAmount = zeroAmount.copyWith({ amount: min }); + const maxAmount = getMax({ balanceAmount, existentialDeposit, @@ -153,32 +169,40 @@ export async function getSourceData({ }; } -export interface GetBalancesParams { - address: string; +export interface GetFeeBalanceParams + extends Omit { balance: bigint; feeConfig: FeeAssetConfig | undefined; - polkadot: PolkadotService; } -export async function getFeeBalances({ +export async function getFeeBalance({ address, balance, + chain, + decimals, feeConfig, polkadot, -}: GetBalancesParams) { - return feeConfig - ? polkadot.query( - feeConfig.balance.build({ - address, - asset: polkadot.chain.getBalanceAssetId(feeConfig.asset), - }) as SubstrateQueryConfig, - ) - : balance; +}: GetFeeBalanceParams) { + if (!feeConfig) { + return balance; + } + + const feeBalance = await polkadot.query( + feeConfig.balance.build({ + address, + asset: polkadot.chain.getBalanceAssetId(feeConfig.asset), + }) as SubstrateQueryConfig, + ); + + return chain.usesChainDecimals + ? convertDecimals(feeBalance, polkadot.decimals, decimals) + : feeBalance; } export interface GetFeeParams { balance: bigint; contract?: ContractConfig; + chain: AnyChain; decimals: number; evmSigner?: EvmSigner; extrinsic?: ExtrinsicConfig; @@ -189,6 +213,7 @@ export interface GetFeeParams { export async function getFee({ balance, + chain, contract, decimals, evmSigner, @@ -215,7 +240,11 @@ export async function getFee({ const xcmDeliveryFee = getXcmDeliveryFee(decimals, feeConfig); - return extrinsicFee + xcmDeliveryFee; + const totalFee = extrinsicFee + xcmDeliveryFee; + + return chain.usesChainDecimals + ? convertDecimals(totalFee, polkadot.decimals, decimals) + : totalFee; } throw new Error('Either contract or extrinsic must be provided'); diff --git a/packages/sdk/src/getTransferData/getTransferData.utils.ts b/packages/sdk/src/getTransferData/getTransferData.utils.ts index f0c4b1ac..d6fac4f8 100644 --- a/packages/sdk/src/getTransferData/getTransferData.utils.ts +++ b/packages/sdk/src/getTransferData/getTransferData.utils.ts @@ -1,32 +1,41 @@ import { CallType, SubstrateQueryConfig } from '@moonbeam-network/xcm-builder'; import { AssetConfig } from '@moonbeam-network/xcm-config'; -import { Asset } from '@moonbeam-network/xcm-types'; -import { toBigInt } from '@moonbeam-network/xcm-utils'; +import { AnyChain, Asset } from '@moonbeam-network/xcm-types'; +import { convertDecimals, toBigInt } from '@moonbeam-network/xcm-utils'; import { BalanceContractInterface, createContract } from '../contract'; import { PolkadotService } from '../polkadot'; import { EvmSigner } from '../sdk.interfaces'; -export interface GetFeeBalancesParams { +export interface GetBalancesParams { address: string; + asset?: Asset; + chain: AnyChain; config: AssetConfig; + decimals: number; evmSigner?: EvmSigner; polkadot: PolkadotService; - asset?: Asset; } +export type GetDecimalsParams = Omit; + export async function getBalance({ address, + chain, config, + decimals, evmSigner, polkadot, -}: GetFeeBalancesParams) { +}: GetBalancesParams) { const cfg = config.balance.build({ address, asset: polkadot.chain.getBalanceAssetId(config.asset), }); if (cfg.type === CallType.Substrate) { - return polkadot.query(cfg as SubstrateQueryConfig); + const balance = await polkadot.query(cfg as SubstrateQueryConfig); + return chain.usesChainDecimals + ? convertDecimals(balance, polkadot.decimals, decimals) + : balance; } if (!evmSigner) { @@ -44,7 +53,7 @@ export async function getDecimals({ config, evmSigner, polkadot, -}: GetFeeBalancesParams) { +}: GetDecimalsParams) { const cfg = config.balance.build({ address, asset: polkadot.chain.getBalanceAssetId(asset || config.asset), diff --git a/packages/sdk/src/polkadot/PolkadotService.ts b/packages/sdk/src/polkadot/PolkadotService.ts index ef634242..f45c1420 100644 --- a/packages/sdk/src/polkadot/PolkadotService.ts +++ b/packages/sdk/src/polkadot/PolkadotService.ts @@ -148,9 +148,9 @@ export class PolkadotService { async getAssetDecimals(asset: Asset): Promise { const metaId = this.chain.getMetadataAssetId(asset); return ( + this.chain.getAssetDecimals(asset) || (await this.getAssetDecimalsFromQuery(metaId)) || (await this.getAssetMeta(metaId))?.decimals || - this.chain.getAssetDecimals(asset) || this.decimals ); } diff --git a/packages/types/src/chain/parachain/Parachain.ts b/packages/types/src/chain/parachain/Parachain.ts index 03cb14ae..98e7d7e2 100644 --- a/packages/types/src/chain/parachain/Parachain.ts +++ b/packages/types/src/chain/parachain/Parachain.ts @@ -10,6 +10,7 @@ export interface ParachainConstructorParams genesisHash: string; parachainId: number; ss58Format: number; + usesChainDecimals?: boolean; weight?: number; ws: string; } @@ -23,6 +24,8 @@ export class Parachain extends Chain { readonly ss58Format: number; + readonly usesChainDecimals: boolean; + readonly weight: number | undefined; readonly ws: string; @@ -31,6 +34,7 @@ export class Parachain extends Chain { assetsData, genesisHash, parachainId, + usesChainDecimals, ss58Format, weight, ws, @@ -46,6 +50,7 @@ export class Parachain extends Chain { this.genesisHash = genesisHash; this.parachainId = parachainId; this.ss58Format = ss58Format; + this.usesChainDecimals = !!usesChainDecimals; this.weight = weight; this.ws = ws; }