Skip to content

Commit

Permalink
Reserve transfer: Fee payment with relay chain native token
Browse files Browse the repository at this point in the history
  • Loading branch information
Szegoo committed Aug 22, 2023
1 parent dde0fb3 commit 8292ac4
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 33 deletions.
14 changes: 9 additions & 5 deletions src/utils/transactionRouter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ApiPromise, WsProvider } from "@polkadot/api";

import ReserveTransfer from "./reserveTransfer";
import TransferAsset from "./transferAsset";
import { Fungible, Receiver, Sender } from "./types";
import { FeePayment, Fungible, Receiver, Sender } from "./types";
import IdentityContract from "../../../types/contracts/identity";

// Responsible for handling all the transfer logic.
Expand Down Expand Up @@ -32,7 +32,8 @@ class TransactionRouter {
sender: Sender,
receiver: Receiver,
reserveChainId: number,
asset: Fungible
asset: Fungible,
feePayment: FeePayment = FeePayment.Asset,
): Promise<void> {
if (sender.network === receiver.network && sender.keypair.addressRaw === receiver.addressRaw) {
throw new Error("Cannot send tokens to yourself");
Expand Down Expand Up @@ -63,7 +64,8 @@ class TransactionRouter {
destApi,
sender.keypair,
receiver,
asset
asset,
feePayment
);
} else if (receiver.network == reserveChainId) {
// The destination chain is the reserve chain of the asset:
Expand All @@ -72,7 +74,8 @@ class TransactionRouter {
destApi,
sender.keypair,
receiver,
asset
asset,
feePayment
);
} else {
// The most complex case, the reserve chain is neither the sender or the destination chain.
Expand All @@ -86,7 +89,8 @@ class TransactionRouter {
reserveChain,
sender.keypair,
receiver,
asset
asset,
feePayment
);
}
}
Expand Down
80 changes: 52 additions & 28 deletions src/utils/transactionRouter/reserveTransfer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ApiPromise } from "@polkadot/api";
import { KeyringPair } from "@polkadot/keyring/types";

import { Fungible, Receiver } from "./types";
import { FeePayment, Fungible, Receiver } from "./types";
import { getParaId } from "..";
import { AccountType } from "../../../types/types-arguments/identity";

Expand All @@ -14,7 +14,8 @@ class ReserveTransfer {
destinationApi: ApiPromise,
sender: KeyringPair,
receiver: Receiver,
asset: Fungible
asset: Fungible,
feePayment: FeePayment
): Promise<void> {
this.ensureContainsXcmPallet(originApi);
this.ensureContainsXcmPallet(destinationApi);
Expand Down Expand Up @@ -61,7 +62,8 @@ class ReserveTransfer {
destinationApi: ApiPromise,
sender: KeyringPair,
receiver: Receiver,
asset: Fungible
asset: Fungible,
feePayment: FeePayment
): Promise<void> {
this.ensureContainsXcmPallet(originApi);
this.ensureContainsXcmPallet(destinationApi);
Expand All @@ -70,7 +72,7 @@ class ReserveTransfer {

// eslint-disable-next-line no-prototype-builtins
const isOriginPara = originApi.query.hasOwnProperty("parachainInfo");
const xcmProgram = this.getSendToReserveChainInstructions(asset, destinationParaId, receiver, isOriginPara);
const xcmProgram = this.getSendToReserveChainInstructions(asset, destinationParaId, receiver, isOriginPara, feePayment);

const xcmPallet = originApi.tx.xcmPallet || originApi.tx.polkadotXcm;

Expand Down Expand Up @@ -99,7 +101,8 @@ class ReserveTransfer {
reserveChainApi: ApiPromise,
sender: KeyringPair,
receiver: Receiver,
asset: Fungible
asset: Fungible,
feePayment: FeePayment
): Promise<void> {
this.ensureContainsXcmPallet(originApi);
this.ensureContainsXcmPallet(destinationApi);
Expand All @@ -110,7 +113,14 @@ class ReserveTransfer {

// eslint-disable-next-line no-prototype-builtins
const isOriginPara = originApi.query.hasOwnProperty("parachainInfo");
const xcmProgram = this.getTwoHopTransferInstructions(asset, reserveParaId, destinationParaId, receiver, isOriginPara);
const xcmProgram = this.getTwoHopTransferInstructions(
asset,
reserveParaId,
destinationParaId,
receiver,
isOriginPara,
feePayment
);

const xcmPallet = originApi.tx.xcmPallet || originApi.tx.polkadotXcm;

Expand Down Expand Up @@ -147,19 +157,12 @@ class ReserveTransfer {
reserveParaId: number,
destParaId: number,
beneficiary: Receiver,
isOriginPara: boolean
isOriginPara: boolean,
feePayment: FeePayment
): any {
const reserve = this.getReserve(reserveParaId, isOriginPara);

// NOTE: we use parse and stringify to make a hard copy of the asset.
const assetFromReservePerspective = JSON.parse(JSON.stringify(asset.multiAsset));
if (reserveParaId > 0) {
// The location of the asset will always start with the parachain if the reserve is a parachain.
this.assetFromReservePerspective(assetFromReservePerspective);
} else {
// The reserve is the relay chain.
assetFromReservePerspective.parents = 0;
}
const feeAsset = this.getFeePaymentAsset(feePayment, asset, isOriginPara, reserveParaId);

return {
V2: [
Expand All @@ -172,7 +175,7 @@ class ReserveTransfer {
reserve,
xcm: [
// TODO: the hardcoded number isn't really accurate to what we actually need.
this.buyExecution(assetFromReservePerspective, 450000000000),
this.buyExecution(feeAsset, 4500000000000),
this.depositReserveAsset({ Wild: "All" }, 1, {
parents: 1,
interior: {
Expand Down Expand Up @@ -204,19 +207,12 @@ class ReserveTransfer {
asset: Fungible,
destParaId: number,
beneficiary: Receiver,
isOriginPara: boolean
isOriginPara: boolean,
feePayment: FeePayment
): any {
const reserve = this.getReserve(destParaId, isOriginPara);

// NOTE: we use parse and stringify to make a hard copy of the asset.
const assetFromReservePerspective = JSON.parse(JSON.stringify(asset.multiAsset));
if (destParaId >= 0) {
// The location of the asset will always start with the parachain if the reserve is a parachain.
this.assetFromReservePerspective(assetFromReservePerspective);
} else {
// The reserve is the relay chain.
assetFromReservePerspective.parents = 0;
}
const feeAsset = this.getFeePaymentAsset(feePayment, asset, isOriginPara, destParaId);

return {
V2: [
Expand All @@ -229,7 +225,7 @@ class ReserveTransfer {
reserve,
xcm: [
// TODO: the hardcoded number isn't really accurate to what we actually need.
this.buyExecution(assetFromReservePerspective, 450000000000),
this.buyExecution(feeAsset, 450000000000),
this.depositAsset({ Wild: "All" }, 1, beneficiary)
]
}
Expand Down Expand Up @@ -428,6 +424,34 @@ class ReserveTransfer {
location.parents = 0;
}

private static getFeePaymentAsset(feePayment: FeePayment, asset: Fungible, isOriginPara: boolean, reserveParaId: number): any {
if (feePayment == FeePayment.RelayChainNative) {
if (isOriginPara) {
return {
parents: 1,
interior: "Here"
};
} else {
return {
parents: 0,
interior: "Here"
}
}
} else if (feePayment == FeePayment.Asset) {
// NOTE: we use parse and stringify to make a hard copy of the asset.
const assetFromReservePerspective = JSON.parse(JSON.stringify(asset.multiAsset));
if (reserveParaId > 0) {
// The location of the asset will always start with the parachain if the reserve is a parachain.
this.assetFromReservePerspective(assetFromReservePerspective);
} else {
// The reserve is the relay chain.
assetFromReservePerspective.parents = 0;
}

return assetFromReservePerspective;
}
}

private static extractJunctions(location: any): any {
const keyPattern = /^X\d$/;

Expand Down
11 changes: 11 additions & 0 deletions src/utils/transactionRouter/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,14 @@ export type Fungible = {
multiAsset: any,
amount: number
}

export enum FeePayment {
// Pay with the asset you are transfering.
//
// NOTE: the asset has to be sufficient to be able to pay for fees.
Asset,
// Pay with the relay chain token.
//
// The relay chain native token is usually allowed for fee payment on parachains.
RelayChainNative,
}

0 comments on commit 8292ac4

Please sign in to comment.