Skip to content

Commit

Permalink
-wip- implement relay fee to transfers coming from parachains
Browse files Browse the repository at this point in the history
  • Loading branch information
mmaurello committed Oct 4, 2024
1 parent fcc496e commit e06f299
Show file tree
Hide file tree
Showing 13 changed files with 294 additions and 92 deletions.
8 changes: 7 additions & 1 deletion packages/builder/src/mrl/MrlBuilder.interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ import type { ExtrinsicConfig } from '../extrinsic';
import type { WormholeConfig } from './providers/wormhole/wormhole';

export type MrlConfigBuilder = ConfigBuilder<
ContractConfig | ExtrinsicConfig | WormholeConfig,
ContractConfig | ExtrinsicConfig | ExtrinsicWormholeConfig | WormholeConfig,
MrlBuilderParams
>;

// TODO mjm improve this
export interface ExtrinsicWormholeConfig {
extrinsic: ExtrinsicConfig;
wormholeConfig: WormholeConfig;
}

export interface MrlBuilderParams extends BuilderPrams<AnyChain> {
isAutomatic: boolean;
moonApi: ApiPromise;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { type AnyParachain, AssetAmount } from '@moonbeam-network/xcm-types';
import { getMultilocationDerivedAddresses } from '@moonbeam-network/xcm-utils';
import { ExtrinsicBuilder } from '../../../../../extrinsic/ExtrinsicBuilder';
import { ExtrinsicConfig } from '../../../../../types/substrate/ExtrinsicConfig';
import { MrlBuilder } from '../../../../MrlBuilder';
import type { MrlConfigBuilder } from '../../../../MrlBuilder.interfaces';
import type { WormholeConfig } from '../../wormhole';

// TODO: Can we move them somewhere?
const BUY_EXECUTION_FEE = 100_000_000_000_000_000n;
Expand All @@ -11,20 +13,20 @@ const CROSS_CHAIN_FEE = 100_000_000_000_000_000n;
export function polkadotXcm() {
return {
send: (): MrlConfigBuilder => ({
build: ({
asset,
destination,
destinationAddress,
destinationApi,
fee,
moonAsset,
moonChain,
moonApi,
source,
sourceAddress,
sourceApi,
transact,
}) => {
build: (params) => {
const {
asset,
destination,
fee,
moonAsset,
moonChain,
moonApi,
source,
sourceAddress,
sourceApi,
transact,
} = params;

if (!destination.wh?.name) {
throw new Error('Destination chain does not have a wormhole name');
}
Expand Down Expand Up @@ -165,11 +167,19 @@ export function polkadotXcm() {
);

// TODO add here ability to only send the remote execution (only `send`)
return new ExtrinsicConfig({
const extrinsic = new ExtrinsicConfig({
module: 'utility',
func: 'batchAll',
getArgs: () => [[assetTransferTx, feeAssetTransferTx, send]],
});

const wormholeConfig = MrlBuilder()
.wormhole()
.wormhole()
.tokenTransfer()
.build(params) as WormholeConfig; // TODO make wormhole build to return this?

return { extrinsic, wormholeConfig };
},
}),
};
Expand Down
147 changes: 101 additions & 46 deletions packages/builder/src/mrl/providers/wormhole/wormhole/wormhole.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {
MrlBuilderParams,
MrlConfigBuilder,
} from '../../../MrlBuilder.interfaces';
import { WormholeConfig } from './WormholeConfig';
import { WormholeConfig, type WormholeFunctionArgs } from './WormholeConfig';
import { wormholeFactory } from './wormholeFactory';

export const GMP_CONTRACT_ADDRESS =
Expand All @@ -15,60 +15,69 @@ export const GMP_CONTRACT_ADDRESS =
export function wormhole() {
return {
tokenTransfer: (): MrlConfigBuilder => ({
build: ({
asset,
destination,
destinationAddress,
isAutomatic,
moonApi,
moonChain,
source,
sourceAddress,
}) => {
const isNativeAsset = asset.isSame(source.nativeAsset);
const isDestinationMoonChain = destination.isEqual(moonChain);
const isDestinationEvmChain = EvmChain.is(destination);
const tokenAddress = isNativeAsset ? 'native' : asset.address;

if (!tokenAddress) {
throw new Error(`Asset ${asset.key} has no address`);
}

const wh = wormholeFactory(source);
const whSource = 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,
);
const whDestinationAddress = Wormhole.chainAddress(
whDestination.chain,
isDestinationMoonChain || isDestinationEvmChain
? destinationAddress
: GMP_CONTRACT_ADDRESS,
);
build: (params): WormholeConfig => {
const isDestinationEvmChain = EvmChain.is(params.destination);

// TODO unify this, this is just as demonstration
const args = isDestinationEvmChain
? generateDemoArgs(params)
: generateWormholeArgs(params);

return new WormholeConfig({
args: [
whAsset,
asset.amount,
whSourceAddress,
whDestinationAddress,
isAutomatic,
isDestinationMoonChain || isDestinationEvmChain
? undefined
: getPayload({ destination, destinationAddress, moonApi }),
],
args,
func: 'tokenTransfer',
});
},
}),
};
}

// TODO mjm move from here?
export function generateWormholeArgs({
asset,
destination,
destinationAddress,
isAutomatic,
moonApi,
moonChain,
source,
sourceAddress,
}: MrlBuilderParams): WormholeFunctionArgs {
const isNativeAsset = asset.isSame(source.nativeAsset);
const isDestinationMoonChain = destination.isEqual(moonChain);
const isDestinationEvmChain = EvmChain.is(destination);
const tokenAddress = isNativeAsset ? 'native' : asset.address;

if (!tokenAddress) {
throw new Error(`Asset ${asset.key} has no address`);
}

const wh = wormholeFactory(source);
const whSource = 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);
const whDestinationAddress = Wormhole.chainAddress(
whDestination.chain,
isDestinationMoonChain || isDestinationEvmChain
? destinationAddress
: GMP_CONTRACT_ADDRESS,
);

return [
whAsset,
asset.amount,
whSourceAddress,
whDestinationAddress,
isAutomatic,
isDestinationMoonChain || isDestinationEvmChain
? undefined
: getPayload({ destination, destinationAddress, moonApi }),
];
}

/*
* Extrinsic to GMP precompile
* https://docs.moonbeam.network/builders/ethereum/precompiles/interoperability/gmp/
Expand Down Expand Up @@ -114,3 +123,49 @@ export function getPayload({

return versioned.toU8a();
}

// TODO remove this, this is just as demonstration
function generateDemoArgs({
asset,
destination,
destinationAddress,
isAutomatic,
moonChain,
source,
}: MrlBuilderParams): WormholeFunctionArgs {
console.log('moonchain', moonChain);
const isNativeAsset = asset.isSame(moonChain.nativeAsset);
// const isDestinationMoonChain = destination.isEqual(moonChain);
const isDestinationEvmChain = EvmChain.is(destination);
const tokenAddress = isNativeAsset
? 'native'
: moonChain.getChainAsset(asset).address;

if (!tokenAddress) {
throw new Error(`Asset ${asset.key} has no address`);
}

const wh = wormholeFactory(source);
const whSource = wh.getChain(moonChain.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,
destinationAddress,
); // really it is computedOriginAccount
const whDestinationAddress = Wormhole.chainAddress(
whDestination.chain,
destinationAddress,
);

return [
whAsset,
asset.amount,
whSourceAddress,
whDestinationAddress,
isAutomatic,
undefined,
];
}
6 changes: 5 additions & 1 deletion packages/config/src/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
44 changes: 40 additions & 4 deletions packages/config/src/mrl-configs/fantomTestnet.ts
Original file line number Diff line number Diff line change
@@ -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({
Expand All @@ -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,
Expand Down Expand Up @@ -56,7 +92,7 @@ export const fantomTestnetRoutes = new ChainRoutes({
},
},
mrl: {
isAutomatic: true,
isAutomaticPossible: true,
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: ftmwh,
Expand Down Expand Up @@ -87,7 +123,7 @@ export const fantomTestnetRoutes = new ChainRoutes({
},
},
mrl: {
isAutomatic: false,
isAutomaticPossible: true,
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: dev,
Expand Down
2 changes: 2 additions & 0 deletions packages/config/src/mrl-configs/index.ts
Original file line number Diff line number Diff line change
@@ -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,
];

Expand Down
4 changes: 2 additions & 2 deletions packages/config/src/mrl-configs/moonbaseAlpha.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const moonbaseAlphaRoutes = new ChainRoutes({
},
},
mrl: {
isAutomatic: true,
isAutomaticPossible: true,
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: ftmwh,
Expand Down Expand Up @@ -56,7 +56,7 @@ export const moonbaseAlphaRoutes = new ChainRoutes({
},
},
mrl: {
isAutomatic: true,
isAutomaticPossible: true,
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: dev,
Expand Down
Loading

0 comments on commit e06f299

Please sign in to comment.