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

fix: update foreign asset location construction #377

Merged
merged 3 commits into from
Mar 1, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
*
* import { AssetTransferApi, constructApiPromise } from '@substrate/asset-transfer-api'
*/
import { AssetTransferApi, constructApiPromise } from '../src';
import { TxResult } from '../src/types';
import { GREEN, PURPLE, RESET } from './colors';
import { AssetTransferApi, constructApiPromise } from '../../../../../src';
import { TxResult } from '../../../../../src/types';
import { GREEN, PURPLE, RESET } from '../../../../colors';

/**
* In this example we are creating a call to send foreign asset '{"parents":"1","interior":{"X2":[{"Parachain":"2125"},{"GeneralIndex":"0"}]}}'
* In this example we are creating a `foreignAssets` pallet `transfer` call to send TNKR (foreign asset with location `{"parents":"1","interior":{"X2":[{"Parachain":"2125"},{"GeneralIndex":"0"}]}}`)
* from a Kusama Asset Hub (System Parachain) account
* to a Kusama Asset Hub (System Parachain) account, where the `xcmVersion` is set to 2, and the `isLimited` declaring that
* it will be `unlimited` since there is no `weightLimit` option as well.
* to a Kusama Asset Hub (System Parachain) account.
*
* NOTE: When `isLimited` is true it will use the `limited` version of the either `reserveAssetTransfer`, or `teleportAssets`.
*/
Expand All @@ -28,8 +27,6 @@ const main = async () => {
['1000000000000'],
{
format: 'call',
isLimited: true,
xcmVersion: 2,
},
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* When importing from @substrate/asset-transfer-api it would look like the following
*
* import { AssetTransferApi, constructApiPromise } from '@substrate/asset-transfer-api'
*/
import { AssetTransferApi, constructApiPromise } from '../../../../../src';
import { TxResult } from '../../../../../src/types';
import { GREEN, PURPLE, RESET } from '../../../../colors';

/**
* In this example we are creating a `polkadotXcm` pallet `limitedReserveTransferAssets` call to send MOVR (foreign asset with location `{"parents":"1","interior":{"X2":[{"Parachain":"2125"},{"GeneralIndex":"0"}]}}`)
* from a Kusama Asset Hub (System Parachain) account
* to a Bifrost (ParaChain) account, where the `xcmVersion` is set to 3, the `isLimited` option is set to true and there is no
* `weightLimit` option provided which declares that the tx will allow unlimited weight to be used for fees.
*
* NOTE: When `isLimited` is true it will use the `limited` version of the either `reserveAssetTransfer`, or `teleportAssets`.
*/
const main = async () => {
const { api, specName, safeXcmVersion } = await constructApiPromise('wss://kusama-asset-hub-rpc.polkadot.io');
const assetApi = new AssetTransferApi(api, specName, safeXcmVersion);

let callInfo: TxResult<'call'>;
try {
callInfo = await assetApi.createTransferTransaction(
'2001', // Note: Parachain ID 2001 (Bifrost) is different than the asset location's `Parachain` Id, making this a `reserveTransferAssets` call
'5EWNeodpcQ6iYibJ3jmWVe85nsok1EDG8Kk3aFg8ZzpfY1qX',
['{"parents":"1","interior":{"X2":[{"Parachain":"2023"},{"PalletInstance":"10"}]}}'],
['1000000000000'],
{
format: 'call',
isLimited: true,
xcmVersion: 3,
},
);

console.log(callInfo);
} catch (e) {
console.error(e);
throw Error(e as string);
}

const decoded = assetApi.decodeExtrinsic(callInfo.tx, 'call');
console.log(`\n${PURPLE}The following decoded tx:\n${GREEN} ${JSON.stringify(JSON.parse(decoded), null, 4)}${RESET}`);
};

main()
.catch((err) => console.error(err))
.finally(() => process.exit());
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
*
* import { AssetTransferApi, constructApiPromise } from '@substrate/asset-transfer-api'
*/
import { AssetTransferApi, constructApiPromise } from '../src';
import { TxResult } from '../src/types';
import { GREEN, PURPLE, RESET } from './colors';
import { AssetTransferApi, constructApiPromise } from '../../../../../src';
import { TxResult } from '../../../../../src/types';
import { GREEN, PURPLE, RESET } from '../../../../colors';

/**
* In this example we are creating a reserve call to send foreign asset '{"parents":"1","interior":{"X2":[{"Parachain":"2125"},{"GeneralIndex":"0"}]}}'
* In this example we are creating a `polkadotXcm` pallet `limitedTeleportAssets` call to send MOVR (foreign asset with location `{"parents":"1","interior":{"X2":[{"Parachain":"2023"},{"PalletInstance":"10"}]}}`)
* from a Kusama Asset Hub (System Parachain) account
* to a Moonriver (ParaChain) account, where the `xcmVersion` is set to 3, and the `isLimited` declaring that
* it will be `unlimited` since there is no `weightLimit` option as well.
* to a Moonriver (ParaChain) account, where the `xcmVersion` is set to 3, the `isLimited` option is set to true and there is no
* `weightLimit` option provided which declares that the tx will allow unlimited weight to be used for fees.
*
* NOTE: When `isLimited` is true it will use the `limited` version of the either `reserveAssetTransfer`, or `teleportAssets`.
*/
Expand All @@ -22,9 +22,9 @@ const main = async () => {
let callInfo: TxResult<'call'>;
try {
callInfo = await assetApi.createTransferTransaction(
'2023', // Note: Parachain ID 2023(Moonriver) is different than MultiLocations 'Parachain' ID, making this a reserveTransfer
'2023', // Note: Parachain ID 2023 (Moonriver) is identical to the asset location's `Parachain` Id, making this a `teleportAssets` call
'5EWNeodpcQ6iYibJ3jmWVe85nsok1EDG8Kk3aFg8ZzpfY1qX',
['{"parents":"1","interior":{"X2":[{"Parachain":"2125"},{"GeneralIndex":"0"}]}}'],
['{"parents":"1","interior":{"X2":[{"Parachain":"2023"},{"PalletInstance":"10"}]}}'],
['1000000000000'],
{
format: 'call',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* When importing from @substrate/asset-transfer-api it would look like the following
*
* import { AssetTransferApi, constructApiPromise } from '@substrate/asset-transfer-api'
*/
import { AssetTransferApi, constructApiPromise } from '../../../../../src';
import { TxResult } from '../../../../../src/types';
import { GREEN, PURPLE, RESET } from '../../../../colors';

/**
* In this example we are creating a `foreignAssets` pallet `transfer` call to send EQD (foreign asset with location `{"parents":"1","interior":{"X2":[{"Parachain":"2011"},{"GeneralKey":{"length":"3","data":"0x6571640000000000000000000000000000000000000000000000000000000000"}}]}}`)
* from a Polkadot Asset Hub (System Parachain) account
* to a Polkadot Asset Hub (System Parachain) account.
*
* NOTE: When `isLimited` is true it will use the `limited` version of the either `reserveAssetTransfer`, or `teleportAssets`.
*/
const main = async () => {
const { api, specName, safeXcmVersion } = await constructApiPromise('wss://polkadot-asset-hub-rpc.polkadot.io');
const assetApi = new AssetTransferApi(api, specName, safeXcmVersion);

let callInfo: TxResult<'call'>;
try {
callInfo = await assetApi.createTransferTransaction(
'1000', // NOTE: The destination id is `1000` and matches the origin chain making this a local transfer
'5EWNeodpcQ6iYibJ3jmWVe85nsok1EDG8Kk3aFg8ZzpfY1qX',
[
'{"parents":"1","interior":{"X2":[{"Parachain":"2011"},{"GeneralKey":{"length":"3","data":"0x6571640000000000000000000000000000000000000000000000000000000000"}}]}}',
],
['1000000000000'],
{
format: 'call',
},
);

console.log(callInfo);
} catch (e) {
console.error(e);
throw Error(e as string);
}

const decoded = assetApi.decodeExtrinsic(callInfo.tx, 'call');
console.log(`\n${PURPLE}The following decoded tx:\n${GREEN} ${JSON.stringify(JSON.parse(decoded), null, 4)}${RESET}`);
};

main()
.catch((err) => console.error(err))
.finally(() => process.exit());
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* When importing from @substrate/asset-transfer-api it would look like the following
*
* import { AssetTransferApi, constructApiPromise } from '@substrate/asset-transfer-api'
*/
import { AssetTransferApi, constructApiPromise } from '../../../../../src';
import { TxResult } from '../../../../../src/types';
import { GREEN, PURPLE, RESET } from '../../../../colors';

/**
* In this example we are creating a `foreignAssets` pallet `transfer` call to send KSM (foreign asset with location {"parents":"2","interior":{"X1":{"GlobalConsensus":"Kusama"}}}`)
* from a Polkadot Asset Hub (System Parachain) account
* to a Polkadot Asset Hub (System Parachain) account.
*
* NOTE: When `isLimited` is true it will use the `limited` version of the either `reserveAssetTransfer`, or `teleportAssets`.
*/
const main = async () => {
const { api, specName, safeXcmVersion } = await constructApiPromise('wss://polkadot-asset-hub-rpc.polkadot.io');
const assetApi = new AssetTransferApi(api, specName, safeXcmVersion);

let callInfo: TxResult<'call'>;
try {
callInfo = await assetApi.createTransferTransaction(
'1000', // NOTE: The destination id is `1000` and matches the origin chain making this a local transfer
'5EWNeodpcQ6iYibJ3jmWVe85nsok1EDG8Kk3aFg8ZzpfY1qX',
['{"parents":"2","interior":{"X1":{"GlobalConsensus":"Kusama"}}}'],
['1000000000000'],
{
format: 'call',
xcmVersion: 3, // Note: GlobalConsensus junctions require XCM V3 or higher
},
);

console.log(callInfo);
} catch (e) {
console.error(e);
throw Error(e as string);
}

const decoded = assetApi.decodeExtrinsic(callInfo.tx, 'call');
console.log(`\n${PURPLE}The following decoded tx:\n${GREEN} ${JSON.stringify(JSON.parse(decoded), null, 4)}${RESET}`);
};

main()
.catch((err) => console.error(err))
.finally(() => process.exit());
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* When importing from @substrate/asset-transfer-api it would look like the following
*
* import { AssetTransferApi, constructApiPromise } from '@substrate/asset-transfer-api'
*/
import { AssetTransferApi, constructApiPromise } from '../../../../../src';
import { TxResult } from '../../../../../src/types';
import { GREEN, PURPLE, RESET } from '../../../../colors';

/**
* In this example we are creating a `polkadotXcm` pallet `limitedReserveTransferAssets` call to send KSM (foreign asset with location '{"parents":"1","interior":{"X1":{"GlobalConsensus":"Kusama"}}}')
* from a Polkadot Asset Hub (System Parachain) account
* to a Moonbeam (ParaChain) account, where the `xcmVersion` is set to 3, the `isLimited` option is set to true and there is no
* `weightLimit` option provided which declares that the tx will allow unlimited weight to be used for fees.
*
* NOTE: When `isLimited` is true it will use the `limited` version of either `reserveTransferAssets`, or `teleportAssets`.
*/
const main = async () => {
const { api, specName, safeXcmVersion } = await constructApiPromise('wss://polkadot-asset-hub-rpc.polkadot.io');
const assetApi = new AssetTransferApi(api, specName, safeXcmVersion);

let callInfo: TxResult<'call'>;
try {
callInfo = await assetApi.createTransferTransaction(
'2004', // Note: Parachain ID 2004 (Moonbeam) is different than the asset location's `Parachain` Id, making this a `reserveTransferAssets` call
'5EWNeodpcQ6iYibJ3jmWVe85nsok1EDG8Kk3aFg8ZzpfY1qX',
['{"parents":"2","interior":{"X1":{"GlobalConsensus":"Kusama"}}}'],
['1000000000000'],
{
format: 'call',
isLimited: true,
xcmVersion: 3,
},
);

console.log(callInfo);
} catch (e) {
console.error(e);
throw Error(e as string);
}

const decoded = assetApi.decodeExtrinsic(callInfo.tx, 'call');
console.log(`\n${PURPLE}The following decoded tx:\n${GREEN} ${JSON.stringify(JSON.parse(decoded), null, 4)}${RESET}`);
};

main()
.catch((err) => console.error(err))
.finally(() => process.exit());
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* When importing from @substrate/asset-transfer-api it would look like the following
*
* import { AssetTransferApi, constructApiPromise } from '@substrate/asset-transfer-api'
*/
import { AssetTransferApi, constructApiPromise } from '../../../../../src';
import { TxResult } from '../../../../../src/types';
import { GREEN, PURPLE, RESET } from '../../../../colors';

/**
* In this example we are creating a `polkadotXcm` pallet `limitedTeleportAssets` call to send EQ (foreign asset with location `{"parents":"1","interior":{"X1":{"Parachain":"2011"}}}`)
* from a Polkadot Asset Hub (System Parachain) account
* to an Equilibrium (ParaChain) account, where the `xcmVersion` is set to 3, the `isLimited` option is set to true and there is no
* `weightLimit` option provided which declares that the tx will allow unlimited weight to be used for fees.
*
* NOTE: When `isLimited` is true it will use the `limited` version of the either `reserveAssetTransfer`, or `teleportAssets`.
*/
const main = async () => {
const { api, specName, safeXcmVersion } = await constructApiPromise('wss://polkadot-asset-hub-rpc.polkadot.io');
const assetApi = new AssetTransferApi(api, specName, safeXcmVersion);

let callInfo: TxResult<'call'>;
try {
callInfo = await assetApi.createTransferTransaction(
'2011', // Note: Parachain ID 2011 (Equilibrium) is identical to the asset location's `Parachain` Id, making this a `teleportAssets` call
'5EWNeodpcQ6iYibJ3jmWVe85nsok1EDG8Kk3aFg8ZzpfY1qX',
['{"parents":"1","interior":{"X1":{"Parachain":"2011"}}}'],
['1000000000000'],
{
format: 'call',
isLimited: true,
xcmVersion: 3,
},
);

console.log(callInfo);
} catch (e) {
console.error(e);
throw Error(e as string);
}

const decoded = assetApi.decodeExtrinsic(callInfo.tx, 'call');
console.log(`\n${PURPLE}The following decoded tx:\n${GREEN} ${JSON.stringify(JSON.parse(decoded), null, 4)}${RESET}`);
};

main()
.catch((err) => console.error(err))
.finally(() => process.exit());
2 changes: 2 additions & 0 deletions examples/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
],
"include": [
"./*",
"./kusama/**/*.ts",
"./polkadot/**/*.ts",
"../src/**/*.ts",
"../src/**/*.json",
]
Expand Down
2 changes: 1 addition & 1 deletion src/AssetTransferApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ describe('AssetTransferAPI', () => {

it('Should decode a foreign asset tx submittable extrinsic given its hash for SystemToPara', async () => {
const expected =
'{"args":{"dest":{"V2":{"parents":"1","interior":{"X1":{"Parachain":"2,023"}}}},"beneficiary":{"V2":{"parents":"0","interior":{"X1":{"AccountId32":{"network":"Any","id":"0xc224aad9c6f3bbd784120e9fceee5bfd22a62c69144ee673f76d6a34d280de16"}}}}},"assets":{"V2":[{"id":{"Concrete":{"parents":"1","interior":{"X3":[{"PalletInstance":"53"},{"Parachain":"2,125"},{"GeneralIndex":"0"}]}}},"fun":{"Fungible":"10,000,000,000,000"}}]},"fee_asset_item":"0"},"method":"reserveTransferAssets","section":"polkadotXcm"}';
'{"args":{"dest":{"V2":{"parents":"1","interior":{"X1":{"Parachain":"2,023"}}}},"beneficiary":{"V2":{"parents":"0","interior":{"X1":{"AccountId32":{"network":"Any","id":"0xc224aad9c6f3bbd784120e9fceee5bfd22a62c69144ee673f76d6a34d280de16"}}}}},"assets":{"V2":[{"id":{"Concrete":{"parents":"1","interior":{"X2":[{"Parachain":"2,125"},{"GeneralIndex":"0"}]}}},"fun":{"Fungible":"10,000,000,000,000"}}]},"fee_asset_item":"0"},"method":"reserveTransferAssets","section":"polkadotXcm"}';

const callTxResult = await systemAssetsApi.createTransferTransaction(
'2023',
Expand Down
11 changes: 8 additions & 3 deletions src/AssetTransferApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -906,8 +906,8 @@ export class AssetTransferApi {
opts.isForeignAssetsTransfer,
opts.isLiquidTokenTransfer,
); // Throws an error when any of the inputs are incorrect.
let tx: SubmittableExtrinsic<'promise', ISubmittableResult>;
let palletMethod: LocalTransferTypes;
let tx: SubmittableExtrinsic<'promise', ISubmittableResult> | undefined;
let palletMethod: LocalTransferTypes | undefined;

if (localAssetType === LocalTxType.Balances) {
tx =
Expand All @@ -927,13 +927,18 @@ export class AssetTransferApi {
? poolAssets.transferKeepAlive(api, addr, assetId, amount)
: poolAssets.transfer(api, addr, assetId, amount);
palletMethod = `poolAssets::${method}`;
} else {
} else if (localAssetType === LocalTxType.ForeignAssets) {
const multiLocation = resolveMultiLocation(assetId, declaredXcmVersion);
tx =
method === 'transferKeepAlive'
? foreignAssets.transferKeepAlive(api, addr, multiLocation, amount)
: foreignAssets.transfer(api, addr, multiLocation, amount);
palletMethod = `foreignAssets::${method}`;
} else {
throw new BaseError(
'No supported pallets were found for local transfers. Supported pallets include: balances, tokens.',
BaseErrorsEnum.PalletNotFound,
);
}

return await this.constructFormat(tx, 'local', null, palletMethod, destChainId, this.specName, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe('limitedReserveTransferAssets', () => {
});

expect(ext.toHex()).toBe(
'0x0901041f08010101009d1f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b0104000103043500352105000091010000000000',
'0x0101041f08010101009d1f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b010400010200352105000091010000000000',
);
});

Expand All @@ -129,7 +129,7 @@ describe('limitedReserveTransferAssets', () => {
});

expect(ext.toHex()).toBe(
'0x2101041f08010101009d1f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b010400010304350035210500009101000000000102286bee411f',
'0x1901041f08010101009d1f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b01040001020035210500009101000000000102286bee411f',
);
});
});
Expand Down
4 changes: 2 additions & 2 deletions src/createXcmCalls/polkadotXcm/reserveTransferAssets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ describe('reserveTransferAssets', () => {
});

expect(ext.toHex()).toBe(
'0x0501041f02010101009d1f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b01040001030435003521050000910100000000',
'0xfc041f02010101009d1f0100010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b0104000102003521050000910100000000',
);
});

Expand All @@ -85,7 +85,7 @@ describe('reserveTransferAssets', () => {
});

expect(ext.toHex()).toBe(
'0x0501041f02030101009d1f0300010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b03040001030435003521050000910100000000',
'0xfc041f02030101009d1f0300010100f5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b0304000102003521050000910100000000',
);
});
});
Expand Down
Loading