Skip to content

Commit

Permalink
fix issues with transfers from all different sources and destinations
Browse files Browse the repository at this point in the history
  • Loading branch information
mmaurello committed Oct 14, 2024
1 parent ad009de commit acd0160
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import { type AnyParachain, AssetAmount } from '@moonbeam-network/xcm-types';
import {
type AnyParachain,
AssetAmount,
Parachain,
} from '@moonbeam-network/xcm-types';
import { getMultilocationDerivedAddresses } from '@moonbeam-network/xcm-utils';
import type { ApiPromise } from '@polkadot/api';
import type { SubmittableExtrinsic } from '@polkadot/api/types';
import type { ISubmittableResult } from '@polkadot/types/types';
import { ExtrinsicBuilder } from '../../../../../extrinsic/ExtrinsicBuilder';
import { ExtrinsicConfig } from '../../../../../types/substrate/ExtrinsicConfig';
import type { MrlConfigBuilder } from '../../../../MrlBuilder.interfaces';
import type {
MrlBuilderParams,
MrlConfigBuilder,
} from '../../../../MrlBuilder.interfaces';

// TODO: these have to come from the configs
const BUY_EXECUTION_FEE = 100_000_000_000_000_000n; // moonChainFee
Expand All @@ -14,7 +24,9 @@ export function polkadotXcm() {
build: ({
asset,
destination,
destinationAddress,
fee,
isAutomatic,
moonAsset,
moonChain,
moonApi,
Expand All @@ -35,56 +47,31 @@ export function polkadotXcm() {
throw new Error('Source API needs to be defined');
}

if (!Parachain.is(source)) {
throw new Error('Source chain needs to be a parachain');
}

const { address20: computedOriginAccount } =
getMultilocationDerivedAddresses({
address: sourceAddress,
paraId: moonChain.parachainId,
paraId: source.parachainId,
isParents: true,
});

const { transfer } = sourceApi.tx.xTokens;
const builder = ExtrinsicBuilder().xTokens().transfer();

const assetTransferTx = transfer(
...builder
.build({
asset,
destination: moonChain,
destinationAddress: computedOriginAccount,
destinationApi: moonApi,
fee,
// TODO: This is a workaround. xTokens.transfer doesn't need source chain but the interfaces requires it.
// In this case we know that a source chain is not a Parachain.
source: source as AnyParachain,
sourceAddress,
sourceApi,
})
.getArgs(transfer),
);
/*
* TODO: Can we move it to AssetRoute and receive it in build params?
* In the future we could also check if wallet already has necessary DEV/GLMR to pay execution fees on Moonbase/Moonbeam.
* Also we need to move fees to AssetRoute.
*/
const feeAssetTransferTx = transfer(
...builder
.build({
asset: AssetAmount.fromChainAsset(
source.getChainAsset(moonAsset),
{
amount: CROSS_CHAIN_FEE + BUY_EXECUTION_FEE,
},
),
destination: moonChain,
destinationAddress: computedOriginAccount,
destinationApi: moonApi,
fee,
source: source as AnyParachain,
sourceAddress,
sourceApi,
})
.getArgs(transfer),
);
const assetTransferTxs = getAssetTransferTxs({
asset,
computedOriginAccount,
destination,
destinationAddress,
fee,
isAutomatic,
moonApi,
moonAsset,
moonChain,
source,
sourceAddress,
sourceApi,
});

const send = sourceApi.tx.polkadotXcm.send(
{
Expand Down Expand Up @@ -166,9 +153,95 @@ export function polkadotXcm() {
return new ExtrinsicConfig({
module: 'utility',
func: 'batchAll',
getArgs: () => [[assetTransferTx, feeAssetTransferTx, send]],
getArgs: () => [[...assetTransferTxs, send]],
});
},
}),
};
}

interface GetAssetTransferTxsParams extends MrlBuilderParams {
computedOriginAccount: string;
source: AnyParachain;
sourceApi: ApiPromise;
}

function getAssetTransferTxs({
asset,
computedOriginAccount,
fee,
moonApi,
moonAsset,
moonChain,
source,
sourceAddress,
sourceApi,
}: GetAssetTransferTxsParams): SubmittableExtrinsic<
'promise',
ISubmittableResult
>[] {
const { transfer, transferMulticurrencies } = sourceApi.tx.xTokens;
const transferBuilder = ExtrinsicBuilder().xTokens().transfer();
const transferMulticurrenciesBuilder = ExtrinsicBuilder()
.xTokens()
.transferMultiCurrencies();
/**
* TODO here we should compare the asset with the cross chain fee asset.
* For example, FTM cannot pay for fees in Moonbase while AGNG can, so for FTM we have to send a transferMulticurrencies
* This "if" is a workaround, change when we implement properly the concept of cross-chain fee (different from moonChainFee)
*/
if (asset.isSame(fee)) {
const assetTransferTx = transfer(
...transferBuilder
.build({
asset: asset.copyWith({
// TODO for the moment this is only applicable to peaq, AGNG pays for fees and we have to include the cross chain fee
// for this we have to add a new concept in the config (Cross Chain Fee), and get the value from there
amount: asset.amount + 10n * CROSS_CHAIN_FEE,
}),
destination: moonChain,
destinationAddress: computedOriginAccount,
destinationApi: moonApi,
fee,
source: source,
sourceAddress,
sourceApi,
})
.getArgs(transfer),
);
const feeAssetTransferTx = transfer(
...transferBuilder
.build({
asset: AssetAmount.fromChainAsset(source.getChainAsset(moonAsset), {
amount: CROSS_CHAIN_FEE + BUY_EXECUTION_FEE,
}),
destination: moonChain,
destinationAddress: computedOriginAccount,
destinationApi: moonApi,
fee,
source: source,
sourceAddress,
sourceApi,
})
.getArgs(transfer),
);
return [assetTransferTx, feeAssetTransferTx];
}
const multiCurrenciesTransferTx = transferMulticurrencies(
...transferMulticurrenciesBuilder
.build({
asset,
destination: moonChain,
destinationAddress: computedOriginAccount,
destinationApi: moonApi,
fee: AssetAmount.fromChainAsset(source.getChainAsset(moonAsset), {
amount: CROSS_CHAIN_FEE + BUY_EXECUTION_FEE,
}),
source: source as AnyParachain,
sourceAddress,
sourceApi,
})
.getArgs(transferMulticurrencies),
);
return [multiCurrenciesTransferTx];
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EvmChain, EvmParachain } from '@moonbeam-network/xcm-types';
import { EvmChain, EvmParachain, Parachain } 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';
Expand Down Expand Up @@ -26,6 +26,7 @@ export function wormhole() {
source,
sourceAddress,
}): WormholeConfig => {
const isSourceParachain = Parachain.is(source);
const isDestinationMoonChain = destination.isEqual(moonChain);
const isDestinationEvmChain = EvmChain.is(destination);
const isNativeAsset = asset.isSame(
Expand All @@ -40,7 +41,7 @@ export function wormhole() {
const { address20: computedOriginAccount } =
getMultilocationDerivedAddresses({
address: sourceAddress,
paraId: moonChain.parachainId,
paraId: isSourceParachain ? source.parachainId : undefined,
isParents: true,
});

Expand Down
2 changes: 1 addition & 1 deletion packages/config/src/mrl-configs/fantomTestnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const fantomTestnetRoutes = new MrlChainRoutes({
},
},
mrl: {
isAutomaticPossible: true,
isAutomaticPossible: false, // TODO
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: ftmwh,
Expand Down
2 changes: 1 addition & 1 deletion packages/config/src/mrl-configs/moonbaseAlpha.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const moonbaseAlphaRoutes = new MrlChainRoutes({
},
},
mrl: {
isAutomaticPossible: true,
isAutomaticPossible: false, // TODO
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: ftmwh,
Expand Down
2 changes: 1 addition & 1 deletion packages/mrl/src/getTransferData/getMoonChainData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export async function getMoonChainData({
if (Parachain.is(route.source.chain)) {
const { address20 } = getMultilocationDerivedAddresses({
address: sourceAddress,
paraId: moonChain.parachainId,
paraId: route.source.chain.parachainId,
isParents: true,
});

Expand Down
8 changes: 4 additions & 4 deletions packages/mrl/src/getTransferData/getSourceData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export async function getSourceData({
const transfer = await buildTransfer({
asset: balance,
destinationAddress,
destinationFee,
feeAsset: feeBalance,
route,
sourceAddress,
});
Expand All @@ -112,8 +112,8 @@ export async function getSourceData({
chain: source,
transfer,
asset: balance,
feeAsset: feeBalance,
destinationAddress,
destinationFee,
route,
sourceAddress,
});
Expand Down Expand Up @@ -201,7 +201,7 @@ export async function getRelayerFee({
asset,
chain,
destinationAddress,
destinationFee,
feeAsset,
route,
sourceAddress,
transfer,
Expand All @@ -214,7 +214,7 @@ export async function getRelayerFee({
const builderParams = await getMrlBuilderParams({
asset,
destinationAddress,
destinationFee,
feeAsset,
route,
sourceAddress,
});
Expand Down
9 changes: 7 additions & 2 deletions packages/mrl/src/getTransferData/getTransferData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,16 @@ export async function getTransferData({
route.source.chain.getChainAsset(route.source.asset),
{ amount: bigintAmount },
);

const feeAsset = AssetAmount.fromChainAsset(
route.source.chain.getChainAsset(
route.source.fee?.asset || route.source.asset,
),
{ amount: sourceData.fee.amount },
);
const transfer = await buildTransfer({
asset,
destinationAddress,
destinationFee,
feeAsset,
route,
sourceAddress,
});
Expand Down
6 changes: 3 additions & 3 deletions packages/mrl/src/getTransferData/getTransferData.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export function getMrlMin({
export interface BuildTransferParams {
asset: AssetAmount;
destinationAddress: string;
destinationFee: AssetAmount;
feeAsset: AssetAmount;
route: AssetRoute;
sourceAddress: string;
}
Expand All @@ -124,7 +124,7 @@ export async function buildTransfer(params: BuildTransferParams) {
export async function getMrlBuilderParams({
asset,
destinationAddress,
destinationFee,
feeAsset,
route,
sourceAddress,
}: BuildTransferParams): Promise<MrlBuilderParams> {
Expand All @@ -150,7 +150,7 @@ export async function getMrlBuilderParams({
destination,
destinationAddress,
destinationApi,
fee: destinationFee,
fee: feeAsset,
isAutomatic: route.mrl.isAutomaticPossible,
moonApi,
moonAsset: moonChain.nativeAsset,
Expand Down
13 changes: 6 additions & 7 deletions packages/mrl/src/services/wormhole/WormholeWagmiSigner.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { wormholeFactory } from '@moonbeam-network/xcm-builder';
import type { EvmSigner } from '@moonbeam-network/xcm-sdk';
import type { EvmChain, EvmParachain } from '@moonbeam-network/xcm-types';
import type {
Expand All @@ -7,7 +6,6 @@ import type {
SignAndSendSigner,
SignedTx,
UnsignedTransaction,
Wormhole,
} from '@wormhole-foundation/sdk-connect';
import {
http,
Expand All @@ -28,21 +26,18 @@ export class WormholeWagmiSigner<

readonly #publicClient: PublicClient<HttpTransport>;

readonly #wh: Wormhole<N>;

constructor(chain: EvmChain | EvmParachain, signer: EvmSigner) {
this.#chain = chain;
this.#signer = signer;
this.#publicClient = createPublicClient({
chain: chain.getViemChain(),
transport: http(),
});
this.#wh = wormholeFactory(chain) as Wormhole<N>;
}

chain(): C {
// biome-ignore lint/suspicious/noExplicitAny: need to fix types
return this.#wh.getChain(this.#chain.getWormholeName()) as any as C;
return this.#chain.getWormholeName() as any as C;
}

address(): Address {
Expand All @@ -61,13 +56,17 @@ export class WormholeWagmiSigner<
transactions: UnsignedTransaction<Network, Chain>[],
): Promise<SignedTx[]> {
const signed = [];
const signerChainID = await this.#signer.getChainId();

let nonce = await this.#publicClient.getTransactionCount({
address: this.address(),
});

for (const tx of transactions) {
const { transaction, parallelizable } = tx;
const { transaction, description, parallelizable } = tx;
console.log(
`Signing: ${description} for ${this.address()}, chainId: ${signerChainID}`,
);

const signedTx = await this.#signer.sendTransaction({
...transaction,
Expand Down

0 comments on commit acd0160

Please sign in to comment.