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: support relay to bridge tx construction #409

Merged
merged 48 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
c200fb6
test bridge tx interface
marshacb Mar 7, 2024
66d5ca8
add system to bridge direction
marshacb Mar 14, 2024
7dfb859
update rococo bridge tx example
marshacb Mar 14, 2024
fc38d48
remove unused const
marshacb Mar 14, 2024
b10f6bc
update resolveMultilocation to account for XCM V4 X1 junction asset l…
marshacb Mar 19, 2024
c288c8a
revert polkadot local transfer example changes
marshacb Mar 19, 2024
56d8495
update dest address in rococo bridge example
marshacb Mar 19, 2024
eee0347
lint
marshacb Mar 19, 2024
ca8136c
add error validation tests
marshacb Mar 19, 2024
e93abdd
lint
marshacb Mar 19, 2024
fd3429f
test teleports
marshacb Apr 1, 2024
5cb9fc0
update assethub metadata
marshacb May 7, 2024
d437df2
add tests for transferAssetsUsingTypeAndThen
marshacb May 10, 2024
0b69a73
update example text
marshacb May 10, 2024
16758d8
revert fetchCallType naming
marshacb May 10, 2024
69d9e9d
lint
marshacb May 10, 2024
961ad43
update default xcm on dest to account for assets length
marshacb May 10, 2024
d067eff
update examples
marshacb May 15, 2024
cda636e
add tests for checkSystemToBridgeInputs
marshacb May 15, 2024
95489ee
update system to bridge integration tests
marshacb May 15, 2024
2f15edc
update chainDestIsBridge check
marshacb May 15, 2024
6582115
add interior check to chainDestIsBridge
marshacb May 15, 2024
b08e7a5
update README
marshacb May 15, 2024
63d0931
update global consensus destination location creation
marshacb May 15, 2024
16efb17
update assetHubROCToWestend example to create transferAssets call
marshacb May 15, 2024
6b1b9a3
update assetHubROCToWestend example
marshacb May 15, 2024
20b59e1
update assetHubROCToWestend example to use LocalReserve as the assetT…
marshacb May 15, 2024
dc75c00
lint
marshacb May 15, 2024
8e53456
update example
marshacb May 16, 2024
03ab6ea
add relay to bridge direction
marshacb May 16, 2024
c5cbe5d
test relay to bridge
marshacb May 17, 2024
ea44ea4
add relay to bridge integration tests
marshacb May 20, 2024
68d17e4
update bridgeTransfer dest locations to explicitly be global consensu…
marshacb May 21, 2024
2fa9e8c
update test description
marshacb May 21, 2024
c256e6f
lint
marshacb May 21, 2024
260a657
fix spelling
marshacb May 21, 2024
f767fd5
add relay chain bridge transfer examples
marshacb May 22, 2024
59c05da
Merge branch 'main' into cameron-support-relay-to-bridge-tx-construction
marshacb May 22, 2024
d65cfdb
remove unused code
marshacb May 22, 2024
dac8718
Merge branch 'main' into cameron-support-relay-to-bridge-tx-construction
marshacb May 24, 2024
2b2b52b
update integration tests
marshacb May 24, 2024
96340cc
update examples
marshacb May 24, 2024
47e4142
update examples
marshacb May 24, 2024
c65f53b
remove examples
marshacb May 24, 2024
2755b7b
update RelayToBridge inline docs
marshacb May 24, 2024
e380a03
update metadata files
marshacb May 24, 2024
8255815
update dest parents value from 2 to 1 for RelayToBridge transfers
marshacb Jun 12, 2024
1e7e6a2
update check to explicitly check for version 3
marshacb Jun 12, 2024
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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ The below chart is focusing on what directions are supported for constructing as
| System to System | ✅ | ✅ | ✅ |
| System to Bridge | ❌ | ✅ | ✅ |
| System to Parachain | ✅ | ✅ | ✅ |
| Relay to Parachain | ✅ | ✅ | ✅ |
| Relay to Parachain | ✅ | ✅ | ✅ |
| Relay to Bridge | ❌ | ✅ | ✅ |
| Relay to System | ✅ | ✅ | ✅ |
| Parachain to Parachain | ✅ | ✅ | ✅ |
| Parachain to Relay | ✅ | ✅ | ✅ |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* 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 an `xcmPallet` `transferAssetsUsingTypeAndThen` call to send 1 ROC (asset with location `{"parents":"0","interior":{"Here":""}}`)
* from a Rococo (Relay Chain) account
* to a Westend Asset Hub account, where the `xcmVersion` is set to 4 and no `weightLimit` option is provided declaring that
* the tx will allow unlimited weight to be used for fees.
* The `paysWithFeeDest` value is set to pay fees with KSM and the values for `assetTransferType` and `feesTransferType`
* are both set to the `RemoteReserve` location of Rococo AssetHub, specifying that the reserve location to be used for transferring and fees is Rococo AssetHub.
*
* NOTE: To specify the amount of weight for the tx to use provide a `weightLimit` option containing desired values for `refTime` and `proofSize`.
*/
const main = async () => {
const { api, specName, safeXcmVersion } = await constructApiPromise('wss://rococo-rpc.polkadot.io');
const assetApi = new AssetTransferApi(api, specName, safeXcmVersion);

let callInfo: TxResult<'call'>;
try {
callInfo = await assetApi.createTransferTransaction(
`{"parents":"1","interior":{"X2":[{"GlobalConsensus":"Westend"},{"Parachain":"1000"}]}}`,
'13EoPU88424tufnjevEYbbvZ7sGV3q1uhuN4ZbUaoTsnLHYt',
[`{"parents":"0","interior":{"Here":""}}`],
['1000000000000'],
{
format: 'call',
xcmVersion: 4,
paysWithFeeDest: `{"parents":"0","interior":{"Here":""}}`,
assetTransferType: 'RemoteReserve',
remoteReserveAssetTransferTypeLocation: '{"parents":"0","interior":{"X1":{"Parachain":"1000"}}}',
feesTransferType: 'RemoteReserve',
remoteReserveFeesTransferTypeLocation: '{"parents":"0","interior":{"X1":{"Parachain":"1000"}}}',
},
);

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());
9 changes: 8 additions & 1 deletion src/AssetTransferApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,10 @@ export class AssetTransferApi {
return Direction.RelayToPara;
}

if (isOriginRelayChain && isDestBridge) {
return Direction.RelayToBridge;
}

/**
* Check if the origin is a Parachain or Parathread
*/
Expand Down Expand Up @@ -1125,7 +1129,6 @@ export class AssetTransferApi {
paysWithFeeDest?: string,
): Promise<ResolvedCallInfo> {
const { api } = baseArgs;

let txMethod: Methods | undefined = undefined;

const isXtokensPallet = xcmPallet === XcmPalletName.xTokens || xcmPallet === XcmPalletName.xtokens;
Expand Down Expand Up @@ -1159,6 +1162,10 @@ export class AssetTransferApi {
throw new BaseError(`Unable to resolve correct transfer call`, BaseErrorsEnum.InternalError);
}

if (!txMethod) {
throw new BaseError(`Unable to resolve correct transfer call`, BaseErrorsEnum.InternalError);
}

if (!callExistsInRuntime(api, txMethod, xcmPallet)) {
throw new BaseError(
`Did not find ${txMethod} from pallet ${xcmPallet} in the current runtime`,
Expand Down
209 changes: 209 additions & 0 deletions src/createXcmTypes/RelayToBridge.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
// Copyright 2024 Parity Technologies (UK) Ltd.

import { Registry } from '../registry';
import { adjustedMockSystemApiV1011000 } from '../testHelpers/adjustedMockSystemApiV1011000';
import { RelayToBridge } from './RelayToBridge';

describe('RelayToBridge', () => {
const registry = new Registry('rococo', {});
const isForeignAssetsTransfer = true;
const isLiquidTokenTransfer = false;
describe('Beneficiary', () => {
it('Should work for V3', () => {
const beneficiary = RelayToBridge.createBeneficiary(
'0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b',
3,
);

const expectedRes = {
V3: {
parents: 0,
interior: {
X1: {
AccountId32: {
id: '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b',
},
},
},
},
};

expect(beneficiary).toStrictEqual(expectedRes);
});
it('Should work for V3 for an Ethereum Address', () => {
const beneficiary = RelayToBridge.createBeneficiary('0x96Bd611EbE3Af39544104e26764F4939924F6Ece', 3);

const expectedRes = {
V3: {
parents: 0,
interior: {
X1: {
AccountKey20: {
key: '0x96Bd611EbE3Af39544104e26764F4939924F6Ece',
},
},
},
},
};

expect(beneficiary).toStrictEqual(expectedRes);
});
it('Should work for V4', () => {
const beneficiary = RelayToBridge.createBeneficiary(
'0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b',
4,
);

const expectedRes = {
V4: {
parents: 0,
interior: {
X1: [
{
AccountId32: {
id: '0xf5d5714c084c112843aca74f8c498da06cc5a2d63153b825189baa51043b1f0b',
},
},
],
},
},
};

expect(beneficiary).toStrictEqual(expectedRes);
});
it('Should work for V4 for an Ethereum Address', () => {
const beneficiary = RelayToBridge.createBeneficiary('0x96Bd611EbE3Af39544104e26764F4939924F6Ece', 4);

const expectedRes = {
V4: {
parents: 0,
interior: {
X1: [
{
AccountKey20: {
key: '0x96Bd611EbE3Af39544104e26764F4939924F6Ece',
},
},
],
},
},
};

expect(beneficiary).toStrictEqual(expectedRes);
});
});
describe('Destination', () => {
it('Should work for V3', () => {
const destId = `{"parents":"2","interior":{"X1":{"GlobalConsensus":{"Ethereum":{"chainId":"11155111"}}}}}`;
const destination = RelayToBridge.createDest(destId, 3);

const expectedRes = {
V3: {
parents: 1,
interior: {
X1: {
GlobalConsensus: {
Ethereum: {
chainId: '11155111',
},
},
},
},
},
};

expect(destination).toStrictEqual(expectedRes);
});
it('Should work for V4', () => {
const destId = `{"parents":"2","interior":{"X2":[{"GlobalConsensus":"Kusama"},{"Parachain":"1000"}]}}`;

const destination = RelayToBridge.createDest(destId, 4);

const expectedRes = {
V4: {
parents: 1,
interior: {
X2: [
{
GlobalConsensus: 'Kusama',
},
{
Parachain: '1000',
},
],
},
},
};

expect(destination).toStrictEqual(expectedRes);
});
});
describe('Assets', () => {
it('Should work for V3', async () => {
const assets = await RelayToBridge.createAssets(
['10000000000'],
3,
'rococo',
[`{"parents":"0","interior":{"Here":""}}`],
{
registry,
isForeignAssetsTransfer,
isLiquidTokenTransfer,
api: adjustedMockSystemApiV1011000,
},
);

const expectedRes = {
V3: [
{
id: {
Concrete: {
parents: 0,
interior: {
Here: '',
},
},
},
fun: {
Fungible: '10000000000',
},
},
],
};

expect(assets).toStrictEqual(expectedRes);
});
it('Should work for V4', async () => {
const assets = await RelayToBridge.createAssets(
['10000000000'],
4,
'rococo',
[`{"parents":"0","interior":{"Here":""}}`],
{
registry,
isForeignAssetsTransfer,
isLiquidTokenTransfer,
api: adjustedMockSystemApiV1011000,
},
);

const expectedRes = {
V4: [
{
id: {
parents: 0,
interior: {
Here: '',
},
},
fun: {
Fungible: '10000000000',
},
},
],
};

expect(assets).toStrictEqual(expectedRes);
});
});
});
Loading