polkadot.ts 4.06 KiB
Newer Older
/**
 * @ignore Don't show this file in documentation.
 */ /** */

import { Keyring } from '@polkadot/api';
import metadataV11 from '@polkadot/metadata/Metadata/v11/static.polkadot';
import { cryptoWaitReady } from '@polkadot/util-crypto';

import {
  createSignedTx,
  createSigningPayload,
  decode,
  deriveAddress,
  getRegistry,
  getTxHash,
  methods,
  POLKADOT_SS58_FORMAT,
} from '../src';
import { signWith } from './util';

/**
 * Entry point of the script. This script is not doing anything for now,
 * because we don't have a Polkadot node to play with yet. For now, it assumes
 * a Polkadot mainnet chain (SS58, types), but is filled with dummy data.
 */
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.
  // Since we don't have any Polkadot mainnet node yet, for now I'm just
  // putting some dummy data here.
  // From RPC `chain_getBlock`
  const blockNumber = '0x56b';
  // From RPC `chain_getBlockHash`
  const blockHash =
    '0x95711f74edcb52c518c070f91570f2f01dfa5c80fc926379b34142f287bbb221';
  // From RPC `chain_getBlockHash`
  const genesisHash =
    '0x22d37976435629a7d027f8113391cfaec285e7c3a63a982aa9f649873afcb82c';
  // From RPC `state_getMetadata`
  const metadataRpc = metadataV11;
  // From RPC `state_getRuntimeVersion`
  const specVersion = 9999;

  // Create Polkadot's type registry.
  const registry = getRegistry('Polkadot', 'polkadot', specVersion);

  // 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', blockNumber).toNumber(),
      genesisHash,
      metadataRpc,
      nonce: 1, // Assuming this is Alice's first tx on the chain
      specVersion,
      tip: 0,
      validityPeriod: 240,
    },
    {
      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}`);

  // 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);
});