Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add paysWithFeeOrigin support for MultiLocations #333

Merged
merged 18 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"typescript": "4.9.4"
},
"dependencies": {
"@polkadot/api": "^10.9.1",
"@polkadot/api": "^10.11.1",
"@substrate/asset-transfer-api-registry": "^0.2.11"
}
}
28 changes: 5 additions & 23 deletions src/AssetTransferApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe('AssetTransferAPI', () => {
direction: 'SystemToPara',
format: 'payload',
method: 'limitedReserveTransferAssets',
tx: '0xf81f0801010100411f0100010100c224aad9c6f3bbd784120e9fceee5bfd22a62c69144ee673f76d6a34d280de160104000002043205040091010000000000450228000100000000cc240000040000000000000000000000000000000000000000000000000000000000000000000000be2554aa8a0151eb4d706308c47d16996af391e4c5e499c7cbef24259b7d4503',
tx: '0xf81f0801010100411f0100010100c224aad9c6f3bbd784120e9fceee5bfd22a62c69144ee673f76d6a34d280de16010400000204320504009101000000000045022800010000cc240000040000000000000000000000000000000000000000000000000000000000000000000000be2554aa8a0151eb4d706308c47d16996af391e4c5e499c7cbef24259b7d4503',
xcmVersion: 2,
});
});
Expand Down Expand Up @@ -713,14 +713,15 @@ describe('AssetTransferAPI', () => {
});
describe('paysWithFeeOrigin', () => {
it('Should correctly assign the assedId field to an unsigned transaction when a valid sufficient paysWithFeeOrigin option is provided', async () => {
const expected = '1,984';
const expected = { parents: '0', interior: { X2: [{ PalletInstance: '50' }, { GeneralIndex: '1,984' }] } };
const payload = await systemAssetsApi.createTransferTransaction(
'2023',
'0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b',
['1984', 'usdc'],
['5000000', '4000000000'],
{
paysWithFeeOrigin: '1984',
paysWithFeeOrigin:
'{"parents": "0", "interior": { "X2": [{"PalletInstance": "50"},{"GeneralIndex": "1984"}]}}',
format: 'payload',
keepAlive: true,
paysWithFeeDest: 'USDC',
Expand All @@ -734,26 +735,7 @@ describe('AssetTransferAPI', () => {
});
const unsigned = result.toHuman() as unknown as UnsignedTransaction;

expect(unsigned.assetId).toEqual(expected);
});

it('Should error during payload construction when a paysWithFeeOrigin is provided that is not a number', async () => {
await expect(async () => {
await systemAssetsApi.createTransferTransaction(
'2023',
'0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b',
['1984', 'usdc'],
['5000000', '4000000000'],
{
paysWithFeeOrigin: 'hello there',
format: 'payload',
keepAlive: true,
paysWithFeeDest: 'USDC',
xcmVersion: 3,
sendersAddr: 'FBeL7DanUDs5SZrxZY1CizMaPgG9vZgJgvr52C2dg81SsF1',
}
);
}).rejects.toThrowError('paysWithFeeOrigin value must be a valid number. Received: hello there');
expect(unsigned.assetId).toStrictEqual(expected);
});

it('Should error during payload construction when a paysWithFeeOrigin is provided that matches a non sufficient asset', async () => {
Expand Down
38 changes: 22 additions & 16 deletions src/AssetTransferApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { ApiPromise } from '@polkadot/api';
import type { SubmittableExtrinsic } from '@polkadot/api/submittable/types';
import { EXTRINSIC_VERSION } from '@polkadot/types/extrinsic/v4/Extrinsic';
import type { RuntimeDispatchInfo, RuntimeDispatchInfoV1 } from '@polkadot/types/interfaces';
import type { ISubmittableResult } from '@polkadot/types/types';
import type { AnyJson, ISubmittableResult } from '@polkadot/types/types';
import BN from 'bn.js';

import { CDN_URL, RELAY_CHAIN_IDS, RELAY_CHAIN_NAMES, SYSTEM_PARACHAINS_NAMES } from './consts';
Expand Down Expand Up @@ -736,7 +736,7 @@ export class AssetTransferApi {
opts: { paysWithFeeOrigin?: string; sendersAddr: string }
): Promise<`0x${string}`> => {
const { paysWithFeeOrigin, sendersAddr } = opts;
let assetId = new BN(0);
let assetId: BN | AnyJson = new BN(0);

// if a paysWithFeeOrigin is provided and the chain is of system origin
// we assign the assetId to the value of paysWithFeeOrigin
Expand All @@ -745,21 +745,27 @@ export class AssetTransferApi {
if (paysWithFeeOrigin && isOriginSystemParachain) {
const isValidInt = validateNumber(paysWithFeeOrigin);

if (!isValidInt) {
throw new BaseError(
`paysWithFeeOrigin value must be a valid number. Received: ${paysWithFeeOrigin}`,
BaseErrorsEnum.InvalidInput
);
}

assetId = new BN(paysWithFeeOrigin);
const isSufficient = await this.checkAssetIsSufficient(assetId);
if (isValidInt) {
assetId = new BN(paysWithFeeOrigin);
const isSufficient = await this.checkAssetIsSufficient(assetId);

if (!isSufficient) {
throw new BaseError(
`asset with assetId ${assetId.toString()} is not a sufficient asset to pay for fees`,
BaseErrorsEnum.InvalidAsset
);
if (!isSufficient) {
throw new BaseError(
`asset with assetId ${assetId.toString()} is not a sufficient asset to pay for fees`,
BaseErrorsEnum.InvalidAsset
);
}
} else {
try {
assetId = JSON.parse(paysWithFeeOrigin) as AnyJson;
} catch (e) {
throw new BaseError(
`paysWithFeeOrigin is an invalid asset. The asset must be a valid integer or multiLocation depending on the runtime: ${
e as string
}`,
BaseErrorsEnum.InvalidAsset
);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/config/disabledOpts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export const disabledOpts: DisabledOptions = {
error: (opt: string, chain: string) => callError(opt, chain),
},
paysWithFeeOrigin: {
disabled: true,
chains: ['westmint'],
disabled: false,
chains: [],
error: (opt: string, chain: string) => callError(opt, chain),
},
paysWithFeeDest: {
Expand Down
2 changes: 1 addition & 1 deletion src/createCalls/balances/transfer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ import { transfer } from './transfer';
describe('transfer', () => {
it('Should construct a valid transfer extrinsic', () => {
const res = transfer(mockSystemApi, '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b', '10000');
expect(res.toHex()).toEqual('0x98040a0700f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b419c');
expect(res.toHex()).toEqual('0x98040a0000f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b419c');
});
});
6 changes: 5 additions & 1 deletion src/createCalls/balances/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ export const transfer = (
destAddr: string,
amount: string
): SubmittableExtrinsic<'promise', ISubmittableResult> => {
return api.tx.balances.transfer(destAddr, amount);
if (api.tx.balances.transferAllowDeath) {
return api.tx.balances.transferAllowDeath(destAddr, amount);
} else {
return api.tx.balances.transfer(destAddr, amount);
}
};
10 changes: 0 additions & 10 deletions src/errors/disableOpts.spec.ts

This file was deleted.

Loading