Skip to content

Commit ea574c0

Browse files
authored
Merge branch 'master' into bruno/revert-pr-774
2 parents 43d4a49 + 6ad64bf commit ea574c0

File tree

28 files changed

+4188
-297
lines changed

28 files changed

+4188
-297
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
// `ahp` is the name given to `npx papi add`
2+
import {
3+
ahp,
4+
people,
5+
XcmV2OriginKind,
6+
XcmV3Junction,
7+
XcmV3Junctions,
8+
XcmV3MultiassetFungibility,
9+
XcmV5AssetFilter,
10+
XcmV5Instruction,
11+
XcmV5Junction,
12+
XcmV5Junctions,
13+
XcmV5WildAsset,
14+
XcmVersionedXcm,
15+
} from '@polkadot-api/descriptors';
16+
import { Binary, createClient, Enum, FixedSizeBinary } from 'polkadot-api';
17+
// import from "polkadot-api/ws-provider/node"
18+
// if running in a NodeJS environment
19+
import { getWsProvider } from 'polkadot-api/ws-provider/web';
20+
import { withPolkadotSdkCompat } from 'polkadot-api/polkadot-sdk-compat';
21+
import { sr25519CreateDerive } from '@polkadot-labs/hdkd';
22+
import {
23+
DEV_PHRASE,
24+
entropyToMiniSecret,
25+
mnemonicToEntropy,
26+
ss58Address,
27+
} from '@polkadot-labs/hdkd-helpers';
28+
import { getPolkadotSigner } from 'polkadot-api/signer';
29+
30+
const entropy = mnemonicToEntropy(DEV_PHRASE);
31+
const miniSecret = entropyToMiniSecret(entropy);
32+
const derive = sr25519CreateDerive(miniSecret);
33+
const keyPair = derive('//Alice');
34+
35+
const polkadotSigner = getPolkadotSigner(
36+
keyPair.publicKey,
37+
'Sr25519',
38+
keyPair.sign
39+
);
40+
41+
// Connect to Polkadot Asset Hub.
42+
// Pointing to localhost since this example uses chopsticks.
43+
const client = createClient(
44+
withPolkadotSdkCompat(getWsProvider('ws://localhost:8000'))
45+
);
46+
47+
// Get the typed API, a typesafe API for interacting with the chain.
48+
const ahpApi = client.getTypedApi(ahp);
49+
50+
const PEOPLE_PARA_ID = 1004;
51+
// The identifier for DOT is the location of the Polkadot Relay Chain,
52+
// which is 1 up relative to any parachain.
53+
const DOT = {
54+
parents: 1,
55+
interior: XcmV3Junctions.Here(),
56+
};
57+
// DOT has 10 decimals.
58+
const DOT_UNITS = 10_000_000_000n;
59+
60+
// The DOT to withdraw for both fees and transfer.
61+
const dotToWithdraw = {
62+
id: DOT,
63+
fun: XcmV3MultiassetFungibility.Fungible(10n * DOT_UNITS),
64+
};
65+
// The DOT to use for local fee payment.
66+
const dotToPayFees = {
67+
id: DOT,
68+
fun: XcmV3MultiassetFungibility.Fungible(1n * DOT_UNITS),
69+
};
70+
// The location of the People Chain from Asset Hub.
71+
const destination = {
72+
parents: 1,
73+
interior: XcmV3Junctions.X1(XcmV3Junction.Parachain(PEOPLE_PARA_ID)),
74+
};
75+
// Pay for fees on the People Chain with teleported DOT.
76+
// This is specified independently of the transferred assets since they're used
77+
// exclusively for fees. Also because fees can be paid in a different
78+
// asset from the transferred assets.
79+
const remoteFees = Enum(
80+
'Teleport',
81+
XcmV5AssetFilter.Definite([
82+
{
83+
id: DOT,
84+
fun: XcmV3MultiassetFungibility.Fungible(1n * DOT_UNITS),
85+
},
86+
])
87+
);
88+
// No need to preserve origin for this example.
89+
const preserveOrigin = false;
90+
// The assets to transfer are whatever remains in the
91+
// holding register at the time of executing the `InitiateTransfer`
92+
// instruction. DOT in this case, teleported.
93+
const assets = [
94+
Enum('Teleport', XcmV5AssetFilter.Wild(XcmV5WildAsset.AllCounted(1))),
95+
];
96+
// The beneficiary is the same account but on the People Chain.
97+
// This is a very common pattern for one public/private key pair
98+
// to hold assets on multiple chains.
99+
const beneficiary = FixedSizeBinary.fromBytes(keyPair.publicKey);
100+
// The call to be executed on the destination chain.
101+
// It's a simple remark with an event.
102+
// Create the call on Asset Hub since the system pallet is present in
103+
// every runtime, but if using any other pallet, connect to
104+
// the destination chain and create the call there.
105+
const remark = Binary.fromText('Hello, cross-chain!');
106+
const call = await ahpApi.tx.System.remark_with_event({
107+
remark,
108+
}).getEncodedData();
109+
// The XCM to be executed on the destination chain.
110+
// It's basically depositing everything to the beneficiary.
111+
const remoteXcm = [
112+
XcmV5Instruction.Transact({
113+
origin_kind: XcmV2OriginKind.SovereignAccount(),
114+
fallback_max_weight: undefined,
115+
call,
116+
}),
117+
XcmV5Instruction.RefundSurplus(),
118+
XcmV5Instruction.DepositAsset({
119+
assets: XcmV5AssetFilter.Wild(XcmV5WildAsset.AllCounted(1)),
120+
beneficiary: {
121+
parents: 0,
122+
interior: XcmV5Junctions.X1(
123+
XcmV5Junction.AccountId32({
124+
id: beneficiary,
125+
network: undefined,
126+
})
127+
),
128+
},
129+
}),
130+
];
131+
132+
// The message assembles all the previously defined parameters.
133+
const xcm = XcmVersionedXcm.V5([
134+
XcmV5Instruction.WithdrawAsset([dotToWithdraw]),
135+
XcmV5Instruction.PayFees({ asset: dotToPayFees }),
136+
XcmV5Instruction.InitiateTransfer({
137+
destination,
138+
remote_fees: remoteFees,
139+
preserve_origin: preserveOrigin,
140+
assets,
141+
remote_xcm: remoteXcm,
142+
}),
143+
// Return any leftover fees from the fees register back to holding.
144+
XcmV5Instruction.RefundSurplus(),
145+
// Deposit remaining assets (refunded fees) to the originating account.
146+
// Using AllCounted(1) since only one asset type (DOT) remains - a minor optimization.
147+
XcmV5Instruction.DepositAsset({
148+
assets: XcmV5AssetFilter.Wild(XcmV5WildAsset.AllCounted(1)),
149+
beneficiary: {
150+
parents: 0,
151+
interior: XcmV5Junctions.X1(
152+
XcmV5Junction.AccountId32({
153+
id: beneficiary, // The originating account.
154+
network: undefined,
155+
})
156+
),
157+
},
158+
}),
159+
]);
160+
161+
// The XCM weight is needed to set the `max_weight` parameter
162+
// on the actual `PolkadotXcm.execute()` call.
163+
const weightResult = await ahpApi.apis.XcmPaymentApi.query_xcm_weight(xcm);
164+
165+
if (weightResult.success) {
166+
const weight = weightResult.success
167+
? weightResult.value
168+
: { ref_time: 0n, proof_size: 0n };
169+
170+
console.dir(weight);
171+
172+
// The actual transaction to submit.
173+
// This tells Asset Hub to execute the XCM.
174+
const tx = ahpApi.tx.PolkadotXcm.execute({
175+
message: xcm,
176+
max_weight: weight,
177+
});
178+
179+
// Sign and propagate to the network.
180+
const result = await tx.signAndSubmit(polkadotSigner);
181+
console.log(stringify(result));
182+
}
183+
184+
client.destroy();
185+
186+
// A helper function to print numbers inside of the result.
187+
function stringify(obj: any) {
188+
return JSON.stringify(
189+
obj,
190+
(_, v) => (typeof v === 'bigint' ? v.toString() : v),
191+
2
192+
);
193+
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
// `ahp` is the name given to `npx papi add`
2+
import {
3+
ahp,
4+
XcmV3Junction,
5+
XcmV3Junctions,
6+
XcmV3MultiassetFungibility,
7+
XcmV5AssetFilter,
8+
XcmV5Instruction,
9+
XcmV5Junction,
10+
XcmV5Junctions,
11+
XcmV5WildAsset,
12+
XcmVersionedXcm,
13+
} from '@polkadot-api/descriptors';
14+
import { createClient, Enum, FixedSizeBinary } from 'polkadot-api';
15+
// import from "polkadot-api/ws-provider/node"
16+
// if running in a NodeJS environment
17+
import { getWsProvider } from 'polkadot-api/ws-provider/web';
18+
import { withPolkadotSdkCompat } from 'polkadot-api/polkadot-sdk-compat';
19+
import { sr25519CreateDerive } from '@polkadot-labs/hdkd';
20+
import {
21+
DEV_PHRASE,
22+
entropyToMiniSecret,
23+
mnemonicToEntropy,
24+
} from '@polkadot-labs/hdkd-helpers';
25+
import { getPolkadotSigner } from 'polkadot-api/signer';
26+
27+
const entropy = mnemonicToEntropy(DEV_PHRASE);
28+
const miniSecret = entropyToMiniSecret(entropy);
29+
const derive = sr25519CreateDerive(miniSecret);
30+
const keyPair = derive('//Alice');
31+
32+
const polkadotSigner = getPolkadotSigner(
33+
keyPair.publicKey,
34+
'Sr25519',
35+
keyPair.sign
36+
);
37+
38+
// Connect to Polkadot Asset Hub.
39+
// Pointing to localhost since this example uses chopsticks.
40+
const client = createClient(
41+
withPolkadotSdkCompat(getWsProvider('ws://localhost:8000'))
42+
);
43+
44+
// Get the typed API, a typesafe API for interacting with the chain.
45+
const ahpApi = client.getTypedApi(ahp);
46+
47+
const PEOPLE_PARA_ID = 1004;
48+
// The identifier for DOT is the location of the Polkadot Relay Chain,
49+
// which is 1 up relative to any parachain.
50+
const DOT = {
51+
parents: 1,
52+
interior: XcmV3Junctions.Here(),
53+
};
54+
// DOT has 10 decimals.
55+
const DOT_UNITS = 10_000_000_000n;
56+
57+
// The DOT to withdraw for both fees and transfer.
58+
const dotToWithdraw = {
59+
id: DOT,
60+
fun: XcmV3MultiassetFungibility.Fungible(10n * DOT_UNITS),
61+
};
62+
// The DOT to use for local fee payment.
63+
const dotToPayFees = {
64+
id: DOT,
65+
fun: XcmV3MultiassetFungibility.Fungible(1n * DOT_UNITS),
66+
};
67+
// The location of the People Chain from Asset Hub.
68+
const destination = {
69+
parents: 1,
70+
interior: XcmV3Junctions.X1(XcmV3Junction.Parachain(PEOPLE_PARA_ID)),
71+
};
72+
// Pay for fees on the People Chain with teleported DOT.
73+
// This is specified independently of the transferred assets since they're used
74+
// exclusively for fees. Also because fees can be paid in a different
75+
// asset from the transferred assets.
76+
const remoteFees = Enum(
77+
'Teleport',
78+
XcmV5AssetFilter.Definite([
79+
{
80+
id: DOT,
81+
fun: XcmV3MultiassetFungibility.Fungible(1n * DOT_UNITS),
82+
},
83+
])
84+
);
85+
// No need to preserve origin for this example.
86+
const preserveOrigin = false;
87+
// The assets to transfer are whatever remains in the
88+
// holding register at the time of executing the `InitiateTransfer`
89+
// instruction. DOT in this case, teleported.
90+
const assets = [
91+
Enum('Teleport', XcmV5AssetFilter.Wild(XcmV5WildAsset.AllCounted(1))),
92+
];
93+
// The beneficiary is the same account but on the People Chain.
94+
// This is a very common pattern for one public/private key pair
95+
// to hold assets on multiple chains.
96+
const beneficiary = FixedSizeBinary.fromBytes(keyPair.publicKey);
97+
// The XCM to be executed on the destination chain.
98+
// It's basically depositing everything to the beneficiary.
99+
const remoteXcm = [
100+
XcmV5Instruction.DepositAsset({
101+
assets: XcmV5AssetFilter.Wild(XcmV5WildAsset.AllCounted(1)),
102+
beneficiary: {
103+
parents: 0,
104+
interior: XcmV5Junctions.X1(
105+
XcmV5Junction.AccountId32({
106+
id: beneficiary,
107+
network: undefined,
108+
})
109+
),
110+
},
111+
}),
112+
];
113+
114+
// The message assembles all the previously defined parameters.
115+
const xcm = XcmVersionedXcm.V5([
116+
XcmV5Instruction.WithdrawAsset([dotToWithdraw]),
117+
XcmV5Instruction.PayFees({ asset: dotToPayFees }),
118+
XcmV5Instruction.InitiateTransfer({
119+
destination,
120+
remote_fees: remoteFees,
121+
preserve_origin: preserveOrigin,
122+
assets,
123+
remote_xcm: remoteXcm,
124+
}),
125+
// Return any leftover fees from the fees register back to holding.
126+
XcmV5Instruction.RefundSurplus(),
127+
// Deposit remaining assets (refunded fees) to the originating account.
128+
// Using AllCounted(1) since only one asset type (DOT) remains - a minor optimization.
129+
XcmV5Instruction.DepositAsset({
130+
assets: XcmV5AssetFilter.Wild(XcmV5WildAsset.AllCounted(1)),
131+
beneficiary: {
132+
parents: 0,
133+
interior: XcmV5Junctions.X1(
134+
XcmV5Junction.AccountId32({
135+
id: beneficiary, // The originating account.
136+
network: undefined,
137+
})
138+
),
139+
},
140+
}),
141+
]);
142+
143+
// The XCM weight is needed to set the `max_weight` parameter
144+
// on the actual `PolkadotXcm.execute()` call.
145+
const weightResult = await ahpApi.apis.XcmPaymentApi.query_xcm_weight(xcm);
146+
147+
if (weightResult.success) {
148+
const weight = weightResult.success
149+
? weightResult.value
150+
: { ref_time: 0n, proof_size: 0n };
151+
152+
console.dir(weight);
153+
154+
// The actual transaction to submit.
155+
// This tells Asset Hub to execute the XCM.
156+
const tx = ahpApi.tx.PolkadotXcm.execute({
157+
message: xcm,
158+
max_weight: weight,
159+
});
160+
161+
// Sign and propagate to the network.
162+
const result = await tx.signAndSubmit(polkadotSigner);
163+
console.log(stringify(result));
164+
}
165+
166+
client.destroy();
167+
168+
// A helper function to print numbers inside of the result.
169+
function stringify(obj: any) {
170+
return JSON.stringify(
171+
obj,
172+
(_, v) => (typeof v === 'bigint' ? v.toString() : v),
173+
2
174+
);
175+
}

develop/interoperability/.nav.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ title: Interoperability
22
nav:
33
- index.md
44
- 'Introduction to XCM': intro-to-xcm.md
5-
- 'XCM Channels': xcm-channels.md
6-
- 'XCM Configuration': xcm-config.md
5+
- 'Channels': xcm-channels.md
6+
- 'XCM Runtime Configuration': xcm-config.md
77
- 'Send Messages': send-messages.md
88
- 'XCM Runtime APIs': xcm-runtime-apis.md
99
- 'Test and Debug': test-and-debug.md
10+
- xcm-guides
11+
- versions

0 commit comments

Comments
 (0)