diff --git a/packages/builder/src/mrl/providers/wormhole/extrinsic/polkadotXcm/polkadotXcm.ts b/packages/builder/src/mrl/providers/wormhole/extrinsic/polkadotXcm/polkadotXcm.ts index a7e7cee7..8f72998c 100644 --- a/packages/builder/src/mrl/providers/wormhole/extrinsic/polkadotXcm/polkadotXcm.ts +++ b/packages/builder/src/mrl/providers/wormhole/extrinsic/polkadotXcm/polkadotXcm.ts @@ -14,8 +14,6 @@ export function polkadotXcm() { build: ({ asset, destination, - destinationAddress, - destinationApi, fee, moonAsset, moonChain, diff --git a/packages/builder/src/mrl/providers/wormhole/wormhole/wormhole.ts b/packages/builder/src/mrl/providers/wormhole/wormhole/wormhole.ts index c574982c..8ff19c30 100644 --- a/packages/builder/src/mrl/providers/wormhole/wormhole/wormhole.ts +++ b/packages/builder/src/mrl/providers/wormhole/wormhole/wormhole.ts @@ -1,4 +1,5 @@ import { EvmChain, EvmParachain } from '@moonbeam-network/xcm-types'; +import { getMultilocationDerivedAddresses } from '@moonbeam-network/xcm-utils'; import { evmToAddress } from '@polkadot/util-crypto/address'; import { Wormhole } from '@wormhole-foundation/sdk-connect'; import { getExtrinsicAccount } from '../../../../extrinsic/ExtrinsicBuilder.utils'; @@ -24,25 +25,38 @@ export function wormhole() { moonChain, source, sourceAddress, - }) => { + }): WormholeConfig => { const isNativeAsset = asset.isSame(source.nativeAsset); const isDestinationMoonChain = destination.isEqual(moonChain); const isDestinationEvmChain = EvmChain.is(destination); - const tokenAddress = isNativeAsset ? 'native' : asset.address; + const tokenAddress = isNativeAsset + ? 'native' + : isDestinationEvmChain + ? moonChain.getChainAsset(asset).address + : asset.address; + + const { address20: computedOriginAccount } = + getMultilocationDerivedAddresses({ + address: sourceAddress, + paraId: moonChain.parachainId, + isParents: true, + }); if (!tokenAddress) { throw new Error(`Asset ${asset.key} has no address`); } const wh = wormholeFactory(source); - const whSource = wh.getChain(source.getWormholeName()); + const whSource = isDestinationEvmChain + ? wh.getChain(moonChain.getWormholeName()) + : wh.getChain(source.getWormholeName()); const whDestination = isDestinationEvmChain ? wh.getChain(destination.getWormholeName()) : wh.getChain(moonChain.getWormholeName()); const whAsset = Wormhole.tokenId(whSource.chain, tokenAddress); const whSourceAddress = Wormhole.chainAddress( whSource.chain, - sourceAddress, + isDestinationEvmChain ? computedOriginAccount : sourceAddress, ); const whDestinationAddress = Wormhole.chainAddress( whDestination.chain, diff --git a/packages/config/src/chains.ts b/packages/config/src/chains.ts index 659a338b..e43dcdf9 100644 --- a/packages/config/src/chains.ts +++ b/packages/config/src/chains.ts @@ -460,11 +460,15 @@ export const fantomTestnet = new EvmChain({ ChainAsset.fromAsset(ftm, { decimals: 18, }), - // TODO should be WGLMR + // TODO should be WGLMR ? ChainAsset.fromAsset(dev, { address: '0x41E3CFDFC255A4bF3C8D3560Bc8D3D9b5080338e', decimals: 18, }), + ChainAsset.fromAsset(agng, { + address: '0xBb4D53C75654D28f69470546414401A2b31b586c', + decimals: 18, + }), ], ecosystem: Ecosystem.AlphanetRelay, explorer: 'https://testnet.ftmscan.com', diff --git a/packages/config/src/mrl-configs/fantomTestnet.ts b/packages/config/src/mrl-configs/fantomTestnet.ts index 4269db98..3b742504 100644 --- a/packages/config/src/mrl-configs/fantomTestnet.ts +++ b/packages/config/src/mrl-configs/fantomTestnet.ts @@ -1,6 +1,11 @@ import { BalanceBuilder, MrlBuilder } from '@moonbeam-network/xcm-builder'; import { dev, ftm, ftmwh } from '../assets'; -import { fantomTestnet, moonbaseAlpha, peaqAlphanet } from '../chains'; +import { + fantomTestnet, + moonbaseAlpha, + moonbaseBeta, + peaqAlphanet, +} from '../chains'; import { ChainRoutes } from '../types/ChainRoutes'; export const fantomTestnetRoutes = new ChainRoutes({ @@ -25,7 +30,38 @@ export const fantomTestnetRoutes = new ChainRoutes({ }, }, mrl: { - isAutomatic: false, // TODO should be isAutomaticPossible + isAutomaticPossible: false, + transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(), + moonChain: { + asset: ftmwh, + fee: { + asset: dev, + amount: 0.1, + balance: BalanceBuilder().substrate().system().account(), + }, + }, + }, + }, + { + source: { + asset: ftm, + balance: BalanceBuilder().evm().native(), + destinationFee: { + asset: ftm, + balance: BalanceBuilder().evm().native(), + }, + }, + destination: { + asset: ftmwh, + chain: moonbaseBeta, + balance: BalanceBuilder().substrate().assets().account(), + fee: { + asset: ftmwh, + amount: 0.06, + }, + }, + mrl: { + isAutomaticPossible: false, transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(), moonChain: { asset: ftmwh, @@ -56,7 +92,7 @@ export const fantomTestnetRoutes = new ChainRoutes({ }, }, mrl: { - isAutomatic: true, + isAutomaticPossible: true, transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(), moonChain: { asset: ftmwh, @@ -87,7 +123,7 @@ export const fantomTestnetRoutes = new ChainRoutes({ }, }, mrl: { - isAutomatic: false, + isAutomaticPossible: true, transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(), moonChain: { asset: dev, diff --git a/packages/config/src/mrl-configs/index.ts b/packages/config/src/mrl-configs/index.ts index 4636267a..fdfb929e 100644 --- a/packages/config/src/mrl-configs/index.ts +++ b/packages/config/src/mrl-configs/index.ts @@ -1,11 +1,13 @@ import type { ChainRoutes } from '../types/ChainRoutes'; import { fantomTestnetRoutes } from './fantomTestnet'; import { moonbaseAlphaRoutes } from './moonbaseAlpha'; +import { moonbaseBetaRoutes } from './moonbaseBeta'; import { peaqAlphanetRoutes } from './peaqAlphanet'; export const mrlRoutesList: ChainRoutes[] = [ fantomTestnetRoutes, moonbaseAlphaRoutes, + moonbaseBetaRoutes, peaqAlphanetRoutes, ]; diff --git a/packages/config/src/mrl-configs/moonbaseAlpha.ts b/packages/config/src/mrl-configs/moonbaseAlpha.ts index ac238499..efca13c9 100644 --- a/packages/config/src/mrl-configs/moonbaseAlpha.ts +++ b/packages/config/src/mrl-configs/moonbaseAlpha.ts @@ -14,6 +14,10 @@ export const moonbaseAlphaRoutes = new ChainRoutes({ asset: ftmwh, balance: BalanceBuilder().evm().erc20(), }, + fee: { + asset: dev, + balance: BalanceBuilder().substrate().system().account(), + }, }, destination: { asset: ftm, @@ -25,7 +29,7 @@ export const moonbaseAlphaRoutes = new ChainRoutes({ }, }, mrl: { - isAutomatic: true, + isAutomaticPossible: true, transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(), moonChain: { asset: ftmwh, @@ -56,7 +60,7 @@ export const moonbaseAlphaRoutes = new ChainRoutes({ }, }, mrl: { - isAutomatic: true, + isAutomaticPossible: true, transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(), moonChain: { asset: dev, diff --git a/packages/config/src/mrl-configs/moonbaseBeta.ts b/packages/config/src/mrl-configs/moonbaseBeta.ts new file mode 100644 index 00000000..c32e5bb4 --- /dev/null +++ b/packages/config/src/mrl-configs/moonbaseBeta.ts @@ -0,0 +1,45 @@ +import { BalanceBuilder, MrlBuilder } from '@moonbeam-network/xcm-builder'; +import { betaDEV, dev, ftm, ftmwh } from '../assets'; +import { fantomTestnet, moonbaseBeta } from '../chains'; +import { ChainRoutes } from '../types/ChainRoutes'; + +export const moonbaseBetaRoutes = new ChainRoutes({ + chain: moonbaseBeta, + routes: [ + { + source: { + asset: ftmwh, + balance: BalanceBuilder().substrate().assets().account(), + destinationFee: { + asset: ftmwh, + balance: BalanceBuilder().substrate().assets().account(), + }, + fee: { + asset: betaDEV, + balance: BalanceBuilder().substrate().system().account(), + }, + }, + destination: { + asset: ftm, + chain: fantomTestnet, + balance: BalanceBuilder().evm().native(), + fee: { + asset: ftm, + amount: 0, + }, + }, + mrl: { + isAutomaticPossible: true, + transfer: MrlBuilder().wormhole().extrinsic().polkadotXcm().send(), + moonChain: { + asset: ftmwh, + fee: { + asset: dev, + amount: 0.1, + balance: BalanceBuilder().substrate().system().account(), + }, + }, + }, + }, + ], +}); diff --git a/packages/config/src/mrl-configs/peaqAlphanet.ts b/packages/config/src/mrl-configs/peaqAlphanet.ts index 4328fd21..4795c67a 100644 --- a/packages/config/src/mrl-configs/peaqAlphanet.ts +++ b/packages/config/src/mrl-configs/peaqAlphanet.ts @@ -29,7 +29,7 @@ export const peaqAlphanetRoutes = new ChainRoutes({ }, }, mrl: { - isAutomatic: true, + isAutomaticPossible: true, transfer: MrlBuilder().wormhole().extrinsic().polkadotXcm().send(), moonChain: { asset: ftmwh, @@ -51,19 +51,19 @@ export const peaqAlphanetRoutes = new ChainRoutes({ }, }, destination: { - asset: ftm, + asset: agng, chain: fantomTestnet, balance: BalanceBuilder().evm().native(), fee: { - asset: ftm, - amount: 0, + asset: agng, + amount: 0.2, }, }, mrl: { - isAutomatic: true, + isAutomaticPossible: true, transfer: MrlBuilder().wormhole().extrinsic().polkadotXcm().send(), moonChain: { - asset: ftmwh, + asset: agng, fee: { asset: dev, amount: 0.1, diff --git a/packages/config/src/types/AssetRoute.ts b/packages/config/src/types/AssetRoute.ts index 31895dc5..e8d4069e 100644 --- a/packages/config/src/types/AssetRoute.ts +++ b/packages/config/src/types/AssetRoute.ts @@ -46,7 +46,7 @@ export interface FeeConfig { } export interface MrlConfig { - isAutomatic: boolean; + isAutomaticPossible: boolean; transfer: MrlConfigBuilder; moonChain: MoonChainConfig; } diff --git a/packages/mrl/src/getTransferData/getMoonChainData.ts b/packages/mrl/src/getTransferData/getMoonChainData.ts index 0bcc37cc..e162057d 100644 --- a/packages/mrl/src/getTransferData/getMoonChainData.ts +++ b/packages/mrl/src/getTransferData/getMoonChainData.ts @@ -38,10 +38,10 @@ export async function getMoonChainData({ const fee = await getDestinationFee({ address: sourceAddress, // TODO not correct - asset: route.mrl.moonChain.fee.asset, + asset: route.source.asset, destination: moonChain, fee: route.mrl.moonChain.fee.amount, - transferAsset: route.source.asset, + feeAsset: route.mrl.moonChain.fee.asset, }); let address = sourceAddress; diff --git a/packages/mrl/src/getTransferData/getSourceData.ts b/packages/mrl/src/getTransferData/getSourceData.ts index e2dc3bfc..d1a8f29b 100644 --- a/packages/mrl/src/getTransferData/getSourceData.ts +++ b/packages/mrl/src/getTransferData/getSourceData.ts @@ -1,11 +1,11 @@ import { ContractConfig, type ExtrinsicConfig, + MrlBuilder, WormholeConfig, } from '@moonbeam-network/xcm-builder'; import type { AssetRoute, FeeConfig } from '@moonbeam-network/xcm-config'; import { - type SourceChainTransferData, getAssetMin, getBalance, getContractFee, @@ -21,8 +21,13 @@ import { type EvmChain, type EvmParachain, } from '@moonbeam-network/xcm-types'; +import type { SourceTransferData } from '../mrl.interfaces'; import { WormholeService } from '../services/wormhole'; -import { buildTransfer } from './getTransferData.utils'; +import { + type BuildTransferParams, + buildTransfer, + getMrlBuilderParams, +} from './getTransferData.utils'; export interface GetSourceDataParams { route: AssetRoute; @@ -36,7 +41,7 @@ export async function getSourceData({ destinationAddress, destinationFee, sourceAddress, -}: GetSourceDataParams): Promise { +}: GetSourceDataParams): Promise { if (!route.mrl) { throw new Error( `MrlConfigBuilder is not defined for source chain ${route.source.chain.name} and asset ${route.source.asset.originSymbol}`, @@ -95,6 +100,16 @@ export async function getSourceData({ sourceAddress, }); + const relayerFee = await getRelayerFee({ + chain: source, + transfer, + asset: balance, + destinationAddress, + destinationFee, + route, + sourceAddress, + }); + const max = getMax({ balance, existentialDeposit, @@ -111,6 +126,7 @@ export async function getSourceData({ feeBalance, max, min, + relayerFee, }; } @@ -124,6 +140,17 @@ export interface GetFeeParams { transfer: ContractConfig | ExtrinsicConfig | WormholeConfig; } +export interface GetRelayFeeParams extends BuildTransferParams { + chain: AnyChain; + transfer: ContractConfig | ExtrinsicConfig | WormholeConfig; +} + +export interface GetWormholeFeeParams { + asset: AssetAmount; + chain: AnyChain; + config: ContractConfig | ExtrinsicConfig | WormholeConfig; +} + export async function getFee({ balance, feeBalance, @@ -134,15 +161,9 @@ export async function getFee({ sourceAddress, }: GetFeeParams): Promise { if (WormholeConfig.is(transfer)) { - const wh = WormholeService.create(chain as EvmChain | EvmParachain); - const fee = await wh.getFee(transfer); - - console.log('fee in getFee.WormholeConfig', fee); - - // TODO technically this is not the fee on source chain, it's relayer fee - // source fee should be the fee paid to send the message in polkadot to eth or to sign the transaction in eth to polkadot - return AssetAmount.fromChainAsset(chain.getChainAsset(balance), { - amount: fee.relayFee?.amount || 0n, + // TODO + return AssetAmount.fromChainAsset(chain.getChainAsset(feeBalance), { + amount: 0n, }); } @@ -161,8 +182,56 @@ export async function getFee({ address: sourceAddress, balance, chain: chain as AnyParachain, - extrinsic: transfer as ExtrinsicConfig, + extrinsic: transfer, feeBalance, feeConfig, }); } + +export async function getRelayerFee({ + asset, + chain, + destinationAddress, + destinationFee, + route, + sourceAddress, + transfer, +}: GetRelayFeeParams): Promise { + if (WormholeConfig.is(transfer)) { + return getWormholeFee({ asset, chain, config: transfer }); + } + + // TODO this is only valid for Wormhole Provider + const builderParams = await getMrlBuilderParams({ + asset, + destinationAddress, + destinationFee, + route, + sourceAddress, + }); + + const wormholeConfig = MrlBuilder() + .wormhole() + .wormhole() + .tokenTransfer() + .build(builderParams); + + return getWormholeFee({ asset, chain, config: wormholeConfig }); +} + +async function getWormholeFee({ + asset, + chain, + config, +}: GetWormholeFeeParams): Promise { + if (WormholeConfig.is(config)) { + const wh = WormholeService.create(chain as EvmChain | EvmParachain); + const fee = await wh.getFee(config); + + return AssetAmount.fromChainAsset(chain.getChainAsset(asset), { + amount: fee.relayFee?.amount || 0n, + }); + } + + return; +} diff --git a/packages/mrl/src/getTransferData/getTransferData.utils.ts b/packages/mrl/src/getTransferData/getTransferData.utils.ts index a76bed5b..93c1b94c 100644 --- a/packages/mrl/src/getTransferData/getTransferData.utils.ts +++ b/packages/mrl/src/getTransferData/getTransferData.utils.ts @@ -93,19 +93,35 @@ export interface BuildTransferParams { sourceAddress: string; } -export async function buildTransfer({ +export async function buildTransfer(params: BuildTransferParams) { + const { route } = params; + if (!route.mrl) { + throw new Error( + `MrlConfigBuilder is not defined for source chain ${route.source.chain.name} and asset ${route.source.asset.originSymbol}`, + ); + } + const builderParams = await getMrlBuilderParams(params); + + return route.mrl.transfer.build({ + ...builderParams, + transact: EvmParachain.isAnyParachain(route.source.chain) + ? await getTransact(builderParams) + : undefined, + }); +} + +export async function getMrlBuilderParams({ asset, destinationAddress, destinationFee, route, sourceAddress, -}: BuildTransferParams) { +}: BuildTransferParams): Promise { if (!route.mrl) { throw new Error( `MrlConfigBuilder is not defined for source chain ${route.source.chain.name} and asset ${route.source.asset.originSymbol}`, ); } - const source = route.source.chain; const destination = route.destination.chain; @@ -118,13 +134,13 @@ export async function buildTransfer({ getPolkadotApi(moonChain.ws), ]); - const params: MrlBuilderParams = { + return { asset, destination, destinationAddress, destinationApi, fee: destinationFee, - isAutomatic: route.mrl.isAutomatic, // TODO + isAutomatic: route.mrl.isAutomaticPossible, moonApi, moonAsset: moonChain.nativeAsset, moonChain, @@ -132,13 +148,6 @@ export async function buildTransfer({ sourceAddress, sourceApi, }; - - return route.mrl.transfer.build({ - ...params, - transact: EvmParachain.isAnyParachain(source) - ? await getTransact(params) - : undefined, - }); } export async function getTransact(params: MrlBuilderParams): Promise { diff --git a/packages/mrl/src/mrl.interfaces.ts b/packages/mrl/src/mrl.interfaces.ts index 29e02134..f8de15d3 100644 --- a/packages/mrl/src/mrl.interfaces.ts +++ b/packages/mrl/src/mrl.interfaces.ts @@ -1,3 +1,4 @@ +import type { SourceChainTransferData } from '@moonbeam-network/xcm-sdk'; import type { AnyChain, AssetAmount } from '@moonbeam-network/xcm-types'; import type { Signer } from '@polkadot/api/types'; import type { IKeyringPair } from '@polkadot/types/types'; @@ -21,8 +22,9 @@ export interface TransferData { ): Promise; } -export interface SourceTransferData extends ChainTransferData { +export interface SourceTransferData extends SourceChainTransferData { destinationFeeBalance: AssetAmount; + relayerFee?: AssetAmount; feeBalance: AssetAmount; max: AssetAmount; } diff --git a/packages/sdk/src/getTransferData/getDestinationData.ts b/packages/sdk/src/getTransferData/getDestinationData.ts index 8dbba997..b45359bd 100644 --- a/packages/sdk/src/getTransferData/getDestinationData.ts +++ b/packages/sdk/src/getTransferData/getDestinationData.ts @@ -31,10 +31,10 @@ export async function getDestinationData({ }); const fee = await getDestinationFee({ address: destinationAddress, - asset: route.destination.fee.asset, + feeAsset: route.destination.fee.asset, destination, fee: route.destination.fee.amount, - transferAsset: route.source.asset, + asset: route.source.asset, }); const existentialDeposit = await getExistentialDeposit(destination); diff --git a/packages/sdk/src/getTransferData/getTransferData.utils.ts b/packages/sdk/src/getTransferData/getTransferData.utils.ts index ee56e94b..f376cfa8 100644 --- a/packages/sdk/src/getTransferData/getTransferData.utils.ts +++ b/packages/sdk/src/getTransferData/getTransferData.utils.ts @@ -157,9 +157,9 @@ export function getMax({ export interface GetDestinationFeeParams { address: string; asset: Asset; + feeAsset: Asset; destination: AnyChain; fee: number | FeeConfigBuilder; - transferAsset: Asset; } export async function getDestinationFee({ @@ -167,9 +167,9 @@ export async function getDestinationFee({ asset, destination, fee, - transferAsset, + feeAsset, }: GetDestinationFeeParams): Promise { - const zero = AssetAmount.fromChainAsset(destination.getChainAsset(asset), { + const zero = AssetAmount.fromChainAsset(destination.getChainAsset(feeAsset), { amount: 0n, }); @@ -184,9 +184,9 @@ export async function getDestinationFee({ const cfg = (fee as FeeConfigBuilder).build({ address, api: polkadot.api, - asset: destination.getChainAsset(transferAsset), - feeAsset: destination.getChainAsset(asset), + asset: destination.getChainAsset(asset), destination, + feeAsset: destination.getChainAsset(feeAsset), }); return zero.copyWith({