Skip to content

Commit 7d5dfae

Browse files
nhussein11raymondkfcheungfranciscoaguirreeshaben
authored
[FIX] - Add chopsticks replay and dry-run XCMs tutorial (#840)
* Add Guide: Replay & Dry Run XCMs with Full Logging Using Chopsticks (#734) * Update Introduction * Update Prerequisites * Update Steps 1-2 * Remove Enable Full Logging * Update Step 2 * Update Step 3 * Update Additional Resources * Update content * Update content v2 * Update develop/toolkit/parachains/fork-chains/chopsticks/replay-xcm.md Co-authored-by: Francisco Aguirre <[email protected]> * Fix link * Update content * Update content v2 * Update content v3 * Update content v4 * Update content v5 * Update content v6 * Update content v7 * Update content v8 * Update content v9 * Add link to fork * Remove release flag * Update to debug * Update to debug wasm * Add Dry Run the XCM * Proofread * Rename to Replay and Dry Run XCMs * Update setup * Fix debug * Update develop/toolkit/parachains/fork-chains/chopsticks/replay-and-dry-run-xcms.md Co-authored-by: Nicolás Hussein <[email protected]> * Update develop/toolkit/parachains/fork-chains/chopsticks/replay-and-dry-run-xcms.md Co-authored-by: Nicolás Hussein <[email protected]> * Update develop/toolkit/parachains/fork-chains/chopsticks/replay-and-dry-run-xcms.md Co-authored-by: Nicolás Hussein <[email protected]> * Remove all numbers from headers * Remove ~/projects * Update Project Setup * Add {target=\_blank} * Update format * Use code snippet * Use Termynal snippet * Fix Termynal snippet * Add <Your Working Directory> * Fix path * Fix Termynal snippet * Add more Termynal snippet * Update reply-xcm.ts * Remember to add import * Update Copy the Call Data * Explain a Port in Chopsticks Config * Improve "Enable Logging and Wasm Override" Clarity * Enhance "Replay the XCM" Section * Expand "Dry Run the XCM" Explanations * Move Page Location * Fix indentations * Fix format * Use polkadot-labs * Optimise imports * Keep code consistent * Use emoji * Update tutorials/interoperability/replay-and-dry-run-xcms.md Co-authored-by: Francisco Aguirre <[email protected]> * Add papi console * Default to use release --------- Co-authored-by: Francisco Aguirre <[email protected]> Co-authored-by: Nicolás Hussein <[email protected]> * fix: formatting details * Apply suggestions from code review Co-authored-by: Erin Shaben <[email protected]> * fix: grammarly * Dependency upgrade (#784) * switch .pages to .nav.yml * update snippet lines now that plugin takes into account comments at top of page * update llms * update new section to .nav.yml * fix: 404s (#835) * fix: 404s * Update develop/smart-contracts/precompiles/xcm-precompile.md Co-authored-by: Erin Shaben <[email protected]> * fix: llms --------- Co-authored-by: Erin Shaben <[email protected]> * fix: prettier --------- Co-authored-by: Raymond Cheung <[email protected]> Co-authored-by: Francisco Aguirre <[email protected]> Co-authored-by: Erin Shaben <[email protected]>
1 parent 7ca0298 commit 7d5dfae

File tree

9 files changed

+1026
-0
lines changed

9 files changed

+1026
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Binary, createClient, Enum } from 'polkadot-api';
2+
import { withPolkadotSdkCompat } from 'polkadot-api/polkadot-sdk-compat';
3+
import { getWsProvider } from 'polkadot-api/ws-provider/web';
4+
import { assetHub } from '@polkadot-api/descriptors';
5+
import { sr25519CreateDerive } from '@polkadot-labs/hdkd';
6+
import {
7+
DEV_PHRASE,
8+
entropyToMiniSecret,
9+
mnemonicToEntropy,
10+
ss58Address,
11+
} from '@polkadot-labs/hdkd-helpers';
12+
13+
const XCM_VERSION = 5;
14+
15+
async function main() {
16+
const provider = withPolkadotSdkCompat(getWsProvider('ws://localhost:8000'));
17+
const client = createClient(provider);
18+
const api = client.getTypedApi(assetHub);
19+
20+
const entropy = mnemonicToEntropy(DEV_PHRASE);
21+
const miniSecret = entropyToMiniSecret(entropy);
22+
const derive = sr25519CreateDerive(miniSecret);
23+
const alice = derive('//Alice');
24+
const aliceAddress = ss58Address(alice.publicKey);
25+
26+
const callData = Binary.fromHex(
27+
'0x1f0803010100411f0300010100fc39fcf04a8071b7409823b7c82427ce67910c6ed80aa0e5093aff234624c8200304000002043205011f0092e81d790000000000',
28+
);
29+
const tx: any = await api.txFromCallData(callData);
30+
const origin = Enum('system', Enum('Signed', aliceAddress));
31+
const dryRunResult: any = await api.apis.DryRunApi.dry_run_call(
32+
origin,
33+
tx.decodedCall,
34+
XCM_VERSION,
35+
);
36+
console.dir(dryRunResult.value, { depth: null });
37+
38+
client.destroy();
39+
}
40+
41+
main().catch(console.error);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<div class="termynal" data-termynal>
2+
<span data-ty="input">npx tsx dry-run-call.ts</span>
3+
<pre data-ty>
4+
execution_result: {
5+
"success": false,
6+
"value": {
7+
"post_info": { "actual_weight": 123456, "pays_fee": "Yes" },
8+
"error": {
9+
"type": "Module",
10+
"value": {
11+
"type": "PolkadotXcm",
12+
"value": { "type": "LocalExecutionIncomplete", "value": null }
13+
}
14+
}
15+
}
16+
}
17+
</pre>
18+
<span data-ty>❌ Dry run failed: LocalExecutionIncomplete</span>
19+
<span data-ty>✅ Process completed, exiting...</span>
20+
</div>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<div class="termynal" data-termynal>
2+
<span data-ty="input">npx tsx dry-run-call.ts</span>
3+
<pre data-ty>
4+
execution_result: {
5+
"success": true,
6+
"value": {
7+
"post_info": { "actual_weight": 123456, "pays_fee": "Yes" },
8+
"result": "Ok"
9+
}
10+
}
11+
emitted_events: [ { "section": "Balances", "method": "Transfer", "data": { "from": "0x...", "to": "0x...", "amount": 1000000000 } } ]
12+
local_xcm: { "type": "SomeType", "value": { ... } }
13+
forwarded_xcms: []
14+
</pre>
15+
<span data-ty>✅ Dry run succeeded</span>
16+
<span data-ty>✅ Process completed, exiting...</span>
17+
</div>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<div class="termynal" data-termynal>
2+
<span data-ty="input">npx @acala-network/chopsticks xcm \ -r polkadot \ -p configs/polkadot-asset-hub-override.yaml \ -p acala</span>
3+
<span data-ty>[09:29:14.988] INFO: Polkadot Asset Hub RPC listening on http://[::]:8000 and ws://[::]:8000</span>
4+
<span data-ty>[09:29:14.988] INFO: Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/acala.yml</span>
5+
<span data-ty>[09:29:15.984] INFO: Acala RPC listening on http://[::]:8001 and ws://[::]:8001</span>
6+
<span data-ty>[09:29:15.990] INFO (xcm): Connected parachains [1000,2000]</span>
7+
<span data-ty>[09:29:15.990] INFO: Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/polkadot.yml</span>
8+
<span data-ty>[09:29:16.927] INFO: Polkadot RPC listening on http://[::]:8002 and ws://[::]:8002</span>
9+
<span data-ty>[09:29:16.984] INFO (xcm): Connected relaychain 'Polkadot' with parachain 'Polkadot Asset Hub'</span>
10+
<span data-ty>[09:29:17.028] INFO (xcm): Connected relaychain 'Polkadot' with parachain 'Acala'</span>
11+
</div>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<div class="termynal" data-termynal>
2+
<span data-ty="input">npx tsx replay-xcm.ts</span>
3+
<pre data-ty>
4+
executing xcm: {
5+
"type": "polkadotxcm",
6+
"value": {
7+
"type": "limited_reserve_transfer_assets",
8+
"value": {
9+
"dest": { "parents": 0, "interior": { "X1": [{ "Parachain": 2006 }] } },
10+
"beneficiary": { "parents": 0, "interior": { "X1": [{ "AccountId32": { "network": null, "id": "0x..." } }] } },
11+
"assets": [{ "id": { "Concrete": { "parents": 0, "interior": "Here" } }, "fun": { "Fungible": 120000000000 } }],
12+
"fee_asset_item": 0,
13+
"weight_limit": { "type": "Unlimited" }
14+
}
15+
}
16+
}
17+
</pre>
18+
<span data-ty>📦 Included in block #9079592: 0x227a11c64f6051ba2e090a13abd17e5f7581640a80f6c03fc2d43fac66ab7949</span>
19+
<span data-ty>📣 Event: Balances { "type": "Upgraded", "value": { ... } }</span>
20+
<span data-ty>📣 Event: Balances { "type": "Withdraw", "value": { ... } }</span>
21+
<span data-ty>📣 Event: Assets { "type": "Transferred", "value": { ... } }</span>
22+
<span data-ty>📣 Event: PolkadotXcm { "type": "Attempted", "value": { ... } }</span>
23+
<span data-ty>📣 Event: Balances { "type": "Burned", "value": { ... } }</span>
24+
<span data-ty>📣 Event: Balances { "type": "Minted", "value": { ... } }</span>
25+
<span data-ty>📣 Event: PolkadotXcm { "type": "FeesPaid", "value": { ... } }</span>
26+
<span data-ty>📣 Event: XcmpQueue { "type": "XcmpMessageSent", "value": { ... } }</span>
27+
<span data-ty>📣 Event: PolkadotXcm { "type": "Sent", "value": { ... } }</span>
28+
<span data-ty>📣 Event: Balances { "type": "Deposit", "value": { ... } }</span>
29+
<span data-ty>📣 Event: TransactionPayment { "type": "TransactionFeePaid", "value": { ... } }</span>
30+
<span data-ty>📣 Event: System { "type": "ExtrinsicSuccess", "value": { ... } }</span>
31+
<span data-ty>✅ Process completed, exiting...</span>
32+
</div>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { Binary, createClient, Transaction } from 'polkadot-api';
2+
import { withPolkadotSdkCompat } from 'polkadot-api/polkadot-sdk-compat';
3+
import { getPolkadotSigner } from 'polkadot-api/signer';
4+
import { getWsProvider } from 'polkadot-api/ws-provider/web';
5+
import { assetHub } from '@polkadot-api/descriptors';
6+
import { sr25519CreateDerive } from '@polkadot-labs/hdkd';
7+
import {
8+
DEV_PHRASE,
9+
entropyToMiniSecret,
10+
mnemonicToEntropy,
11+
} from '@polkadot-labs/hdkd-helpers';
12+
13+
const toHuman = (_key: any, value: any) => {
14+
if (typeof value === 'bigint') {
15+
return Number(value);
16+
}
17+
18+
if (value && typeof value === 'object' && typeof value.asHex === 'function') {
19+
return value.asHex();
20+
}
21+
22+
return value;
23+
};
24+
25+
function getSigner() {
26+
const entropy = mnemonicToEntropy(DEV_PHRASE);
27+
const miniSecret = entropyToMiniSecret(entropy);
28+
const derive = sr25519CreateDerive(miniSecret);
29+
const alice = derive('//Alice');
30+
31+
return getPolkadotSigner(alice.publicKey, 'Sr25519', alice.sign);
32+
}
33+
34+
async function main() {
35+
const provider = withPolkadotSdkCompat(getWsProvider('ws://localhost:8000'));
36+
const client = createClient(provider);
37+
const api = client.getTypedApi(assetHub);
38+
const aliceSigner = getSigner();
39+
40+
const callData = Binary.fromHex(
41+
'0x1f0803010100411f0300010100fc39fcf04a8071b7409823b7c82427ce67910c6ed80aa0e5093aff234624c8200304000002043205011f0092e81d790000000000',
42+
);
43+
const tx: Transaction<any, string, string, any> =
44+
await api.txFromCallData(callData);
45+
console.log('👀 Executing XCM:', JSON.stringify(tx.decodedCall, toHuman, 2));
46+
47+
await new Promise<void>((resolve) => {
48+
const subscription = tx.signSubmitAndWatch(aliceSigner).subscribe((ev) => {
49+
if (
50+
ev.type === 'finalized' ||
51+
(ev.type === 'txBestBlocksState' && ev.found)
52+
) {
53+
console.log(
54+
`📦 Included in block #${ev.block.number}: ${ev.block.hash}`,
55+
);
56+
57+
if (!ev.ok) {
58+
const dispatchError = ev.dispatchError;
59+
if (dispatchError.type === 'Module') {
60+
const modErr: any = dispatchError.value;
61+
console.error(
62+
`❌ Dispatch error in module: ${modErr.type}${modErr.value?.type}`,
63+
);
64+
} else {
65+
console.error(
66+
'❌ Dispatch error:',
67+
JSON.stringify(dispatchError, toHuman, 2),
68+
);
69+
}
70+
}
71+
72+
for (const event of ev.events) {
73+
console.log(
74+
'📣 Event:',
75+
event.type,
76+
JSON.stringify(event.value, toHuman, 2),
77+
);
78+
}
79+
80+
console.log('✅ Process completed, exiting...');
81+
subscription.unsubscribe();
82+
resolve();
83+
}
84+
});
85+
});
86+
87+
client.destroy();
88+
}
89+
90+
main().catch(console.error);

0 commit comments

Comments
 (0)