const { ApiPromise, WsProvider } = require('@polkadot/api'); const { Keyring } = require('@polkadot/keyring'); const { construct, decode, deriveAddress, getRegistry, methods, PolkadotSS58Format, } = require('@substrate/txwrapper-polkadot'); const { cryptoWaitReady } = require('@polkadot/util-crypto'); const fetch = require('node-fetch'); const { createMetadata, OptionsWithMeta } = require('@substrate/txwrapper-polkadot'); const { EXTRINSIC_VERSION } = require('@polkadot/types/extrinsic/v4/Extrinsic'); async function rpcToLocalNode( method, params ) { return await fetch('http://localhost:9933', { body: JSON.stringify({ id: 1, jsonrpc: '2.0', method, params, }), headers: { 'Content-Type': 'application/json', }, method: 'POST', }) .then((response) => response.json()) .then(({ error, result }) => { if (error) { throw new Error( `${error.code} ${error.message}: ${JSON.stringify(error.data)}` ); } return result; }); } async function signWith( pair, signingPayload, options ) { const { registry, metadataRpc } = options; // Important! The registry needs to be updated with latest metadata, so make // sure to run `registry.setMetadata(metadata)` before signing. registry.setMetadata(createMetadata(registry, metadataRpc)); const { signature } = registry .createType('ExtrinsicPayload', signingPayload, { version: EXTRINSIC_VERSION, }) .sign(pair); return signature; } async function test5() { await cryptoWaitReady(); const keyring = new Keyring({ type: 'sr25519' }); // Add Alice to our keyring with a hard-deived path (empty phrase, so uses dev) const alice = keyring.addFromUri('//Alice'); const bob = keyring.addFromUri('//Bob'); const { specVersion, transactionVersion, specName } = await rpcToLocalNode( 'state_getRuntimeVersion' ); const { block } = await rpcToLocalNode('chain_getBlock'); const blockHash = await rpcToLocalNode('chain_getBlockHash'); const genesisHash = await rpcToLocalNode('chain_getBlockHash', [0]); const metadataRpc = await rpcToLocalNode('state_getMetadata'); // const index = await httpRequest({ ...params, method: 'system_accountNextIndex', params: [pair.address] }); const index = await rpcToLocalNode('system_accountNextIndex', [alice.address]); const registry = getRegistry({ chainName: 'Polkadot', specName, specVersion, metadataRpc, }); const unsigned = methods.balances.transfer( { dest: bob.address, value: 100, }, { address: deriveAddress(alice.publicKey, PolkadotSS58Format.polkadot), blockHash, blockNumber: registry .createType('BlockNumber', block.header.number) .toNumber(), eraPeriod: 64, genesisHash, metadataRpc, nonce: index, // Assuming this is Alice's first tx on the chain specVersion, tip: 0, transactionVersion, }, { metadataRpc, registry } ); const signingPayload = construct.signingPayload(unsigned, { registry }); // On your offline device, sign the payload. // const signature = myOfflineSigning(signingPayload); const signature = await signWith(alice, signingPayload, { metadataRpc, registry, }); // `tx` is ready to be broadcasted. const tx = construct.signedTx(unsigned, signature, { metadataRpc, registry }); console.log('tx', tx); const actualTxHash = await rpcToLocalNode('author_submitExtrinsic', [tx]); console.log(`Actual Tx Hash: ${actualTxHash}`); console.log('block_hash', blockHash, block, index); } test5()