Skip to content

Commit

Permalink
fix(xcm-router): Add missing methods to Router builder
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeldev5 authored and dudo50 committed Aug 14, 2024
1 parent 65c7a72 commit fac5bc0
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 32 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,29 @@ jobs:
token: ${{ secrets.CODECOV_TOKEN }}
directory: packages/sdk
flags: xcm-sdk
fail_ci_if_error: false
verbose: true
- name: Upload XCM Analyser coverage report to Codecov
uses: codecov/[email protected]
with:
token: ${{ secrets.CODECOV_TOKEN }}
directory: packages/xcm-analyser
flags: xcm-analyser
fail_ci_if_error: false
verbose: true
- name: Upload XCM Router coverage report to Codecov
uses: codecov/[email protected]
with:
token: ${{ secrets.CODECOV_TOKEN }}
directory: packages/xcm-router
flags: xcm-router
fail_ci_if_error: false
verbose: true
- name: Upload Visualizator BE coverage report to Codecov
uses: codecov/[email protected]
with:
token: ${{ secrets.CODECOV_TOKEN }}
directory: apps/visualizator-be
flags: visualizator-be
fail_ci_if_error: false
verbose: true
1 change: 1 addition & 0 deletions apps/playground/src/components/RouterTransferForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export type FormValues = {
useApi: boolean;
evmSigner?: Signer;
evmInjectorAddress?: string;
assetHubAddress?: string;
ethSigner?: ethers.Signer;
};

Expand Down
44 changes: 34 additions & 10 deletions apps/playground/src/routes/RouterTransferPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import {
Center,
} from "@mantine/core";
import {
transfer,
TransactionType,
TTxProgressInfo,
TExchangeNode,
TransactionStatus,
RouterBuilder,
} from "@paraspell/xcm-router";
import { web3FromAddress } from "@polkadot/extension-dapp";
import { useDisclosure, useScrollIntoView } from "@mantine/hooks";
Expand Down Expand Up @@ -76,15 +76,39 @@ const RouterTransferPage = () => {
injectorAddress: string,
signer: Signer
) => {
const { transactionType } = formValues;
await transfer({
...formValues,
injectorAddress: injectorAddress,
signer: signer,
type: TransactionType[transactionType],
exchange: exchange ?? undefined,
onStatusChange,
});
const {
from,
to,
currencyFrom,
currencyTo,
amount,
recipientAddress,
evmInjectorAddress,
assetHubAddress,
slippagePct,
evmSigner,
ethSigner,
transactionType,
} = formValues;

await RouterBuilder()
.from(from)
.to(to)
.exchange(exchange)
.currencyFrom(currencyFrom)
.currencyTo(currencyTo)
.amount(amount)
.injectorAddress(injectorAddress)
.recipientAddress(recipientAddress)
.evmInjectorAddress(evmInjectorAddress)
.assetHubAddress(assetHubAddress)
.signer(signer)
.ethSigner(ethSigner)
.evmSigner(evmSigner)
.slippagePct(slippagePct)
.transactionType(TransactionType[transactionType])
.onStatusChange(onStatusChange)
.build();
};

const submitUsingApi = async (
Expand Down
81 changes: 78 additions & 3 deletions packages/xcm-router/src/RouterBuilder.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { describe, expect, it, vi, beforeEach, type MockInstance } from 'vitest';
import * as index from './index';
import RouterBuilder from './RouterBuilder';
import { RouterBuilder } from './RouterBuilder';
import { type Signer } from '@polkadot/api/types';
import { Signer as EthSigner } from 'ethers';
import { type Signer as EthSigner } from 'ethers';
import { TransactionType } from './index';

export const transferParams: index.TTransferOptions = {
from: 'Astar',
Expand Down Expand Up @@ -77,6 +78,35 @@ describe('Builder', () => {
expect(spy).toHaveBeenCalledWith({ ...transferParams, onStatusChange });
});

it('should construct a transfer using RouterBuilder with evmInjectorAddress and evmSigner', async () => {
const onStatusChange = vi.fn();
const evmInjectorAddress = '0x1234567890';
const evmSigner = {} as Signer;

await RouterBuilder()
.from(from)
.exchange(exchange)
.to(to)
.currencyFrom(currencyFrom)
.currencyTo(currencyTo)
.amount(amount)
.injectorAddress(injectorAddress)
.recipientAddress(recipientAddress)
.signer(signer)
.slippagePct(slippagePct)
.evmInjectorAddress(evmInjectorAddress)
.evmSigner(evmSigner)
.onStatusChange(onStatusChange)
.build();

expect(spy).toHaveBeenCalledWith({
...transferParams,
onStatusChange,
evmInjectorAddress,
evmSigner,
});
});

it('should construct a transfer using RouterBuilder with assetHubAddress and ethSigner', async () => {
const onStatusChange = vi.fn();
const assetHubAddress = '0x1234567890';
Expand All @@ -93,9 +123,9 @@ describe('Builder', () => {
.recipientAddress(recipientAddress)
.signer(signer)
.slippagePct(slippagePct)
.onStatusChange(onStatusChange)
.assetHubAddress(assetHubAddress)
.ethSigner(ethSigner)
.onStatusChange(onStatusChange)
.build();

expect(spy).toHaveBeenCalledWith({
Expand All @@ -106,6 +136,51 @@ describe('Builder', () => {
});
});

it('should construct a transfer using RouterBuilder with automatic selection', async () => {
const onStatusChange = vi.fn();

await RouterBuilder()
.from(from)
.to(to)
.currencyFrom(currencyFrom)
.currencyTo(currencyTo)
.amount(amount)
.injectorAddress(injectorAddress)
.recipientAddress(recipientAddress)
.signer(signer)
.slippagePct(slippagePct)
.onStatusChange(onStatusChange)
.build();

expect(spy).toHaveBeenCalledWith({ ...transferParams, onStatusChange, exchange: undefined });
});

it('should construct a transfer using RouterBuilder with defined transaction type', async () => {
const onStatusChange = vi.fn();
const type = TransactionType.SWAP;

await RouterBuilder()
.from(from)
.exchange(exchange)
.to(to)
.currencyFrom(currencyFrom)
.currencyTo(currencyTo)
.amount(amount)
.injectorAddress(injectorAddress)
.recipientAddress(recipientAddress)
.signer(signer)
.slippagePct(slippagePct)
.onStatusChange(onStatusChange)
.transactionType(type)
.build();

expect(spy).toHaveBeenCalledWith({
...transferParams,
onStatusChange,
type,
});
});

it('should fail to construct a transfer using RouterBuilder when missing some params', async () => {
await expect(async () => {
await RouterBuilder()
Expand Down
33 changes: 18 additions & 15 deletions packages/xcm-router/src/RouterBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
type TTransferOptions,
} from '.';
import { type TNodeWithRelayChains } from '@paraspell/sdk';
import { Signer as EthSigner } from 'ethers';
import { type Signer as EthSigner } from 'ethers';

export interface TRouterBuilderOptions {
from?: TNodeWithRelayChains;
Expand All @@ -21,9 +21,10 @@ export interface TRouterBuilderOptions {
recipientAddress?: string;
assetHubAddress?: string;
slippagePct?: string;
ethSigner?: EthSigner;
signer?: Signer;
evmSigner?: Signer;
ethSigner?: EthSigner;
type?: TransactionType;
onStatusChange?: (info: TTxProgressInfo) => void;
}

Expand All @@ -39,7 +40,7 @@ export class RouterBuilderObject {
return this;
}

exchange(node: TExchangeNode): this {
exchange(node: TExchangeNode | undefined): this {
this._routerBuilderOptions.exchange = node;
return this;
}
Expand Down Expand Up @@ -74,7 +75,7 @@ export class RouterBuilderObject {
return this;
}

assetHubAddress(assetHubAddress: string): this {
assetHubAddress(assetHubAddress: string | undefined): this {
this._routerBuilderOptions.assetHubAddress = assetHubAddress;
return this;
}
Expand All @@ -84,18 +85,18 @@ export class RouterBuilderObject {
return this;
}

evmInjectorAddress(evmInjectorAddress: string): this {
this._routerBuilderOptions.evmInjectorAddress = evmInjectorAddress;
ethSigner(ethSigner: EthSigner | undefined): this {
this._routerBuilderOptions.ethSigner = ethSigner;
return this;
}

evmSigner(evmSigner: Signer): this {
this._routerBuilderOptions.evmSigner = evmSigner;
evmInjectorAddress(evmInjectorAddress: string | undefined): this {
this._routerBuilderOptions.evmInjectorAddress = evmInjectorAddress;
return this;
}

ethSigner(ethSigner: EthSigner): this {
this._routerBuilderOptions.ethSigner = ethSigner;
evmSigner(evmSigner: Signer | undefined): this {
this._routerBuilderOptions.evmSigner = evmSigner;
return this;
}

Expand All @@ -104,6 +105,11 @@ export class RouterBuilderObject {
return this;
}

transactionType(transactionType: TransactionType): this {
this._routerBuilderOptions.type = transactionType;
return this;
}

onStatusChange(callback: (status: TTxProgressInfo) => void): this {
this._routerBuilderOptions.onStatusChange = callback;
return this;
Expand All @@ -112,7 +118,6 @@ export class RouterBuilderObject {
async build(): Promise<void> {
const requiredParams: Array<keyof TRouterBuilderOptions> = [
'from',
'exchange',
'to',
'currencyFrom',
'currencyTo',
Expand All @@ -131,11 +136,9 @@ export class RouterBuilderObject {

await transfer({
...(this._routerBuilderOptions as TTransferOptions),
type: TransactionType.FULL_TRANSFER,
type: this._routerBuilderOptions.type ?? TransactionType.FULL_TRANSFER,
});
}
}

const RouterBuilder = (): RouterBuilderObject => new RouterBuilderObject();

export default RouterBuilder;
export const RouterBuilder = (): RouterBuilderObject => new RouterBuilderObject();
1 change: 1 addition & 0 deletions packages/xcm-router/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './transfer/transfer';
export * from './transfer/buildTransferExtrinsics';
export * from './types';
export * from './consts/consts';
export * from './RouterBuilder';
1 change: 1 addition & 0 deletions packages/xcm-router/src/transfer/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const transfer = async (options: TTransferOptions): Promise<void> => {
assetHubAddress,
type,
} = options;

if (evmSigner !== undefined && evmInjectorAddress === undefined) {
throw new Error('evmInjectorAddress is required when evmSigner is provided');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('transferToEthereum', () => {
type: TransactionType.TO_ETH,
status: TransactionStatus.IN_PROGRESS,
});
expect(submitTransferToDestination).toHaveBeenCalledWith(mockApi, options, amountOut);
expect(submitTransferToDestination).toHaveBeenCalledWith(mockApi, options, amountOut, true);
expect(maybeUpdateTransferStatus).toHaveBeenCalledWith(options.onStatusChange, {
type: TransactionType.TO_ETH,
status: TransactionStatus.SUCCESS,
Expand Down
2 changes: 1 addition & 1 deletion packages/xcm-router/src/transfer/transferToEthereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const transferToEthereum = async (options: TTransferOptionsModified, amou
status: TransactionStatus.IN_PROGRESS,
});
const assetHubApi = await createApiInstanceForNode('AssetHubPolkadot');
await submitTransferToDestination(assetHubApi, options, amountOut);
await submitTransferToDestination(assetHubApi, options, amountOut, true);
maybeUpdateTransferStatus(onStatusChange, {
type: TransactionType.TO_ETH,
status: TransactionStatus.SUCCESS,
Expand Down
6 changes: 4 additions & 2 deletions packages/xcm-router/src/transfer/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const buildFromExchangeExtrinsic = async (
api: ApiPromise,
{ to, exchange, currencyTo, recipientAddress: address }: TCommonTransferOptionsModified,
amountOut: string,
isToEth = false,
): Promise<Extrinsic> => {
const builder = Builder(api);
if (to === 'Polkadot' || to === 'Kusama') {
Expand All @@ -37,7 +38,7 @@ export const buildFromExchangeExtrinsic = async (

return await builder
.from(exchange)
.to(to === 'Ethereum' ? 'AssetHubPolkadot' : to)
.to(to === 'Ethereum' && !isToEth ? 'AssetHubPolkadot' : to)
.currency({
symbol: currencyTo,
})
Expand Down Expand Up @@ -75,10 +76,11 @@ export const submitTransferToDestination = async (
api: ApiPromise,
options: TTransferOptionsModified,
amountOut: string,
isToEth = false,
): Promise<string> => {
const { to, currencyTo, signer, injectorAddress } = options;
validateRelayChainCurrency(to, currencyTo);
const tx = await buildFromExchangeExtrinsic(api, options, amountOut);
const tx = await buildFromExchangeExtrinsic(api, options, amountOut, isToEth);
return await submitTransaction(api, tx, signer, injectorAddress);
};

Expand Down

0 comments on commit fac5bc0

Please sign in to comment.