Skip to content

Commit

Permalink
Return balance and address in MoonChainData (#408)
Browse files Browse the repository at this point in the history
* return computed origin account info in moonChainData for parachain to evm transactions

* fix in moonchain address

* add balance in moonbase beta

* remove unused import

* improve code comprehension

* add tests
  • Loading branch information
mmaurello authored Dec 18, 2024
1 parent b094a24 commit 6d608e1
Show file tree
Hide file tree
Showing 12 changed files with 361 additions and 25 deletions.
7 changes: 7 additions & 0 deletions packages/config/src/mrl-configs/fantomTestnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const fantomTestnetRoutes = new MrlChainRoutes({
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: ftmwh,
balance: BalanceBuilder().evm().erc20(),
fee: {
asset: dev,
amount: 0.1,
Expand Down Expand Up @@ -66,6 +67,7 @@ export const fantomTestnetRoutes = new MrlChainRoutes({
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: ftmwh,
balance: BalanceBuilder().evm().erc20(),
fee: {
asset: dev,
amount: 0.1,
Expand Down Expand Up @@ -97,6 +99,8 @@ export const fantomTestnetRoutes = new MrlChainRoutes({
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: agng,
balance: BalanceBuilder().substrate().assets().account(),

fee: {
asset: dev,
amount: 0.1,
Expand Down Expand Up @@ -128,6 +132,7 @@ export const fantomTestnetRoutes = new MrlChainRoutes({
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: ftmwh,
balance: BalanceBuilder().evm().erc20(),
fee: {
asset: dev,
amount: 0.1,
Expand Down Expand Up @@ -159,6 +164,7 @@ export const fantomTestnetRoutes = new MrlChainRoutes({
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: ftmwh,
balance: BalanceBuilder().evm().erc20(),
fee: {
asset: dev,
amount: 0.1,
Expand Down Expand Up @@ -190,6 +196,7 @@ export const fantomTestnetRoutes = new MrlChainRoutes({
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: dev,
balance: BalanceBuilder().substrate().system().account(),
fee: {
asset: dev,
amount: 0.1,
Expand Down
4 changes: 3 additions & 1 deletion packages/config/src/mrl-configs/moonbaseAlpha.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ export const moonbaseAlphaRoutes = new MrlChainRoutes({
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: ftmwh,
balance: BalanceBuilder().evm().erc20(),
fee: {
asset: dev,
amount: 0.1, // TODO not really, it would be the source fee as source is moonChain
amount: 0.1,
balance: BalanceBuilder().substrate().system().account(),
},
},
Expand Down Expand Up @@ -64,6 +65,7 @@ export const moonbaseAlphaRoutes = new MrlChainRoutes({
transfer: MrlBuilder().wormhole().wormhole().tokenTransfer(),
moonChain: {
asset: dev,
balance: BalanceBuilder().evm().erc20(),
fee: {
asset: dev,
amount: 0,
Expand Down
1 change: 1 addition & 0 deletions packages/config/src/mrl-configs/moonbaseBeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const moonbaseBetaRoutes = new MrlChainRoutes({
transfer: MrlBuilder().wormhole().extrinsic().polkadotXcm().send(),
moonChain: {
asset: ftmwh,
balance: BalanceBuilder().substrate().assets().account(),
fee: {
asset: dev,
amount: 0.1,
Expand Down
2 changes: 2 additions & 0 deletions packages/config/src/mrl-configs/peaqAlphanet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const peaqAlphanetRoutes = new MrlChainRoutes({
transfer: MrlBuilder().wormhole().extrinsic().polkadotXcm().send(),
moonChain: {
asset: ftmwh,
balance: BalanceBuilder().evm().erc20(),
fee: {
asset: dev,
amount: 0.1,
Expand Down Expand Up @@ -72,6 +73,7 @@ export const peaqAlphanetRoutes = new MrlChainRoutes({
transfer: MrlBuilder().wormhole().extrinsic().polkadotXcm().send(),
moonChain: {
asset: agng,
balance: BalanceBuilder().substrate().assets().account(),
fee: {
asset: dev,
amount: 0.1,
Expand Down
1 change: 1 addition & 0 deletions packages/config/src/mrl-configs/peaqEvmAlphanet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const peaqEvmAlphanetRoutes = new MrlChainRoutes({
.transferAssetsAndMessage(),
moonChain: {
asset: ftmwh,
balance: BalanceBuilder().evm().erc20(),
fee: {
asset: dev,
amount: 0.1,
Expand Down
1 change: 1 addition & 0 deletions packages/config/src/types/AssetRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export interface DestinationFeeConfig

export interface MoonChainConfig {
asset: Asset;
balance: BalanceConfigBuilder;
fee: MoonChainFeeConfig;
}

Expand Down
6 changes: 5 additions & 1 deletion packages/mrl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
"build": "tsup",
"dev": "tsup --watch",
"link": "pnpm ln --global",
"typecheck": "tsc --noEmit"
"typecheck": "tsc --noEmit",
"test": "vitest --run",
"test:watch": "vitest",
"test:update": "vitest -u"
},
"repository": {
"directory": "packages/mrl",
Expand Down Expand Up @@ -42,6 +45,7 @@
"@polkadot/api-augment": "14.3.1",
"@polkadot/types": "14.3.1",
"@polkadot/util": "13.2.3",
"@polkadot/util-crypto": "13.2.3",
"@wormhole-foundation/sdk-connect": "^0.10.7",
"@wormhole-foundation/sdk-evm": "^0.10.7",
"viem": "^2.21.7"
Expand Down
60 changes: 60 additions & 0 deletions packages/mrl/src/getTransferData/getMoonChainData.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { describe, expect, it } from 'vitest';

import {
fantomTestnet,
moonbaseAlpha,
peaqAlphanet,
} from '@moonbeam-network/xcm-config';
import { getMoonChainAddress } from './getMoonChainData';

describe('mrl - getMoonChainData', () => {
describe('getMoonChainAddress', () => {
it('should return the correct moonchain address for a parachain to evm transaction', () => {
const params = {
source: peaqAlphanet,
destination: fantomTestnet,
sourceAddress: '5GWpSdqkkKGZmdKQ9nkSF7TmHp6JWt28BMGQNuG4MXtSvq3e',
destinationAddress: '0x08480769599E23F626efff39B89F3137e9917a40',
};

const result = getMoonChainAddress(params);
expect(result).toBe('0xa18b59fcd9d8a76c3cb16dc6dc42296ebb66a57a'); // computed origin account
});

it('should return the correct moonchain address for a evm to parachain transaction', () => {
const params = {
source: fantomTestnet,
destination: peaqAlphanet,
sourceAddress: '0x08480769599E23F626efff39B89F3137e9917a40',
destinationAddress: '5GWpSdqkkKGZmdKQ9nkSF7TmHp6JWt28BMGQNuG4MXtSvq3e',
};

const result = getMoonChainAddress(params);
expect(result).toBe('0x08480769599E23F626efff39B89F3137e9917a40');
});

it('should return the source chain address when source is a moonchain', () => {
const params = {
source: moonbaseAlpha,
destination: fantomTestnet,
sourceAddress: '0x08480769599E23F626efff39B89F3137e9917a40',
destinationAddress: '0x08480769599E23F626efff39B89F3137e9917a40',
};

const result = getMoonChainAddress(params);
expect(result).toBe('0x08480769599E23F626efff39B89F3137e9917a40');
});

it('should return the destination chain address when destination is a moonchain', () => {
const params = {
source: fantomTestnet,
destination: moonbaseAlpha,
sourceAddress: '0x08480769599E23F626efff39B89F3137e9917a40',
destinationAddress: '0x08480769599E23F626efff39B89F3137e9917a40',
};

const result = getMoonChainAddress(params);
expect(result).toBe('0x08480769599E23F626efff39B89F3137e9917a40');
});
});
});
82 changes: 65 additions & 17 deletions packages/mrl/src/getTransferData/getMoonChainData.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { type MrlAssetRoute, getMoonChain } from '@moonbeam-network/xcm-config';
import { getBalance, getDestinationFee } from '@moonbeam-network/xcm-sdk';
import { Parachain } from '@moonbeam-network/xcm-types';
import {
type AnyChain,
EvmParachain,
Parachain,
} from '@moonbeam-network/xcm-types';
import { getMultilocationDerivedAddresses } from '@moonbeam-network/xcm-utils';
import { evmToAddress } from '@polkadot/util-crypto';
import type { MoonChainTransferData } from '../mrl.interfaces';

interface GetMoonChainDataParams {
route: MrlAssetRoute;
sourceAddress: string;
destinationAddress: string;
}

export async function getMoonChainData({
route,
sourceAddress,
destinationAddress,
}: GetMoonChainDataParams): Promise<MoonChainTransferData> {
if (!route.mrl) {
throw new Error(
Expand All @@ -20,40 +27,81 @@ export async function getMoonChainData({
}

const moonChain = getMoonChain(route.source.chain);
const moonChainAddress = getMoonChainAddress({
source: route.source.chain,
destination: route.destination.chain,
sourceAddress,
destinationAddress,
});

console.log('sourceAddress', sourceAddress);
const fee = await getDestinationFee({
address: sourceAddress, // TODO not correct
address: moonChainAddress,
asset: route.source.asset,
destination: moonChain,
fee: route.mrl.moonChain.fee.amount,
feeAsset: route.mrl.moonChain.fee.asset,
});

let address = sourceAddress;

if (
Parachain.is(route.source.chain) &&
!route.source.chain.isEqual(moonChain)
) {
const { address20 } = getMultilocationDerivedAddresses({
address: sourceAddress,
paraId: route.source.chain.parachainId,
isParents: true,
});

address = address20;
}
const balance = await getBalance({
address: moonChainAddress,
asset: moonChain.getChainAsset(route.mrl.moonChain.asset),
builder: route.mrl.moonChain.balance,
chain: moonChain,
});

const feeBalance = await getBalance({
address,
address: moonChainAddress,
asset: moonChain.getChainAsset(route.mrl.moonChain.fee.asset),
builder: route.mrl.moonChain.fee.balance,
chain: moonChain,
});

return {
address: moonChainAddress,
balance,
feeBalance,
chain: moonChain,
fee,
};
}

interface GetMoonChainAddressParams {
source: AnyChain;
destination: AnyChain;
sourceAddress: string;
destinationAddress: string;
}

export function getMoonChainAddress({
source,
destination,
sourceAddress,
destinationAddress,
}: GetMoonChainAddressParams): string {
const moonChain = getMoonChain(source);
const isDestinationMoonChain = moonChain.isEqual(destination);
const isSourceMoonChain = moonChain.isEqual(source);

let moonChainAddress = isDestinationMoonChain
? destinationAddress
: sourceAddress;

// for Parachain to EVM transactions, we use the computed origin account in the moonchain
if (Parachain.is(source) && !isSourceMoonChain) {
const isSourceEvmSigner = EvmParachain.is(source) && source.isEvmSigner;

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

moonChainAddress = computedOriginAccount;
}

return moonChainAddress;
}
1 change: 1 addition & 0 deletions packages/mrl/src/getTransferData/getTransferData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export async function getTransferData({
const moonChainData = await getMoonChainData({
route,
sourceAddress,
destinationAddress,
});

return {
Expand Down
6 changes: 2 additions & 4 deletions packages/mrl/src/mrl.interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,8 @@ export interface SourceTransferData extends SourceChainTransferData {

export interface DestinationTransferData extends ChainTransferData {}

export type MoonChainTransferData = Omit<
ChainTransferData,
'min' | 'balance'
> & {
export type MoonChainTransferData = Omit<ChainTransferData, 'min'> & {
address: string;
feeBalance: AssetAmount;
};

Expand Down
Loading

0 comments on commit 6d608e1

Please sign in to comment.