Newer
Older
/**
* @ignore Don't show this file in documentation.
*/ /** */
import { Keyring } from '@polkadot/api';
import { cryptoWaitReady } from '@polkadot/util-crypto';
import {
createSignedTx,
createSigningPayload,
decode,
deriveAddress,
getRegistry,
getTxHash,
methods,
POLKADOT_SS58_FORMAT,
} from '../src';
import { rpcToNode, signWith } from './util';
* Entry point of the script. This script assumes a Polkadot dev node is
* running locally on `http://localhost:9933`.
*/
async function main(): Promise<void> {
// Wait for the promise to resolve async WASM
await cryptoWaitReady();
// Create a new keyring, and add an "Alice" account
const keyring = new Keyring();
const alice = keyring.addFromUri('//Alice', { name: 'Alice' }, 'sr25519');
console.log(
"Alice's SS58-Encoded Address:",
deriveAddress(alice.publicKey, POLKADOT_SS58_FORMAT)
);
// Construct a balance transfer transaction offline.
// To construct the tx, we need some up-to-date information from the node.
// `txwrapper` is offline-only, so does not care how you retrieve this info.
// In this tutorial, we simply send RPC requests to the node.
const { block } = await rpcToNode('chain_getBlock');
const blockHash = await rpcToNode('chain_getBlockHash');
const genesisHash = await rpcToNode('chain_getBlockHash', [0]);
const metadataRpc = await rpcToNode('state_getMetadata');
const { specVersion } = await rpcToNode('state_getRuntimeVersion');
// Create Polkadot's type registry.
// Right now, we hardcode the specVersion to `9999`, to use the always latest
// type overrides for Polkadot. In real-life, you should use the specVersion
// returned by `state_getRuntimeVersion` RPC.
const registry = getRegistry('Polkadot', 'polkadot', 9999);
// Now we can create our `balances.transfer` unsigned tx. The following
// function takes the above data as arguments, so can be performed offline
// if desired.
const unsigned = methods.balances.transfer(
{
value: 12,
dest: '14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3', // Bob
},
{
address: deriveAddress(alice.publicKey, POLKADOT_SS58_FORMAT),
blockHash,
blockNumber: registry
.createType('BlockNumber', block.header.number)
.toNumber(),
eraPeriod: 64,
nonce: 0, // Assuming this is Alice's first tx on the chain
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
specVersion,
tip: 0,
},
{
metadata: metadataRpc,
registry,
}
);
// Decode an unsigned transaction.
const decodedUnsigned = decode(unsigned, {
metadata: metadataRpc,
registry,
});
console.log(
`\nDecoded Transaction\n To: ${decodedUnsigned.method.args.dest}\n` +
` Amount: ${decodedUnsigned.method.args.value}`
);
// Construct the signing payload from an unsigned transaction.
const signingPayload = createSigningPayload(unsigned, { registry });
console.log(`\nPayload to Sign: ${signingPayload}`);
// Decode the information from a signing payload.
const payloadInfo = decode(signingPayload, {
metadata: metadataRpc,
registry,
});
console.log(
`\nDecoded Transaction\n To: ${payloadInfo.method.args.dest}\n` +
` Amount: ${payloadInfo.method.args.value}`
);
// Sign a payload. This operation should be performed on an offline device.
const signature = signWith(registry, alice, signingPayload);
console.log(`\nSignature: ${signature}`);
// Serialize a signed transaction.
const tx = createSignedTx(unsigned, signature, { registry });
console.log(`\nTransaction to Submit: ${tx}`);
// Derive the tx hash of a signed transaction offline.
const exptectedTxHash = getTxHash(tx);
console.log(`\nExpected Tx Hash: ${exptectedTxHash}`);
// Send the tx to the node. Again, since `txwrapper` is offline-only, this
// operation should be handled externally. Here, we just send a JSONRPC
// request directly to the node.
const actualTxHash = await rpcToNode('author_submitExtrinsic', [tx]);
console.log(`Actual Tx Hash: ${actualTxHash}`);
// Decode a signed payload.
const txInfo = decode(tx, {
metadata: metadataRpc,
registry,
});
console.log(
`\nDecoded Transaction\n To: ${txInfo.method.args.dest}\n` +
` Amount: ${txInfo.method.args.value}\n`
);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});