Skip to content

Instantly share code, notes, and snippets.

@axelchalon
Last active March 12, 2020 16:49
Show Gist options
  • Save axelchalon/3293102df160d997a00fbff6f3038c52 to your computer and use it in GitHub Desktop.
Save axelchalon/3293102df160d997a00fbff6f3038c52 to your computer and use it in GitHub Desktop.
TxWrapper example
/*
yarn init
yarn add @substrate/txwrapper @polkadot/types
touch index.ts
npx ts-node index.ts
*/
import {
deriveAddress, methods, createSigningPayload, getTxHash,
createSignedTx, decode, importPrivateKey, KeyringPair
} from '@substrate/txwrapper';
import metadataRpc from '@polkadot/metadata/Metadata/v9/static';
import { cryptoWaitReady } from '@polkadot/util-crypto';
import { createType, TypeRegistry } from '@polkadot/types';
import { Keyring } from '@polkadot/api';
import { TRANSACTION_VERSION } from '@polkadot/types/extrinsic/v4/Extrinsic';
import AccountId from '@polkadot/types/generic/AccountId';
// Dummy signing function. Implement this on the OFFLINE signing device.
async function signWithAlice(signingPayload: string): Promise<string> {
// We're creating an Alice account that will sign the payload
// Wait for the promise to resolve async WASM
await cryptoWaitReady();
const registry = new TypeRegistry();
registry.register('Address', AccountId); // when in dev mode
const keyring = new Keyring({ type: 'ed25519' }); // Can be ed25519 or sr25519
// Example seed phrase, obviously do not use.
const alice = keyring.addFromMnemonic(
'toward hole salute sock muscle whisper federal lawsuit dismiss gun verify diary'
);
const { signature } = createType(
registry,
'ExtrinsicPayload',
signingPayload,
{
version: TRANSACTION_VERSION
}
).sign(alice);
return signature;
}
// No-logic function with all the parameters of a BalanceTransfer.
function createUnsignedBalanceTransfer(): /*UnsignedTransaction*/ any {
const unsigned = methods.balances.transferKeepAlive({
value: 12,
dest: '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', // local bob
},{
address: '5CWah4o8iiK3p2jVbaNvcuTyThuGHTMFfBdmDjvD8E9MWAG9', // alice joe
blockHash: '0x6106e67a13199c668858fc16b199c45a1b0e3c91a4239d45b26da4b0897014d2',
blockNumber: 1,
genesisHash: '0x4239a0acfdfa1c9e8e9a11c82022ccc3d93f48c9606b2fd1f22e5fbdbcdb597',
metadataRpc, // from state_getMetadata
nonce: 1,
specVersion: 1004,
tip: 0,
validityPeriod: 240,
});
return unsigned;
}
// No-logic function with a keypair generated. Other info included so you can test/compare output.
function getAPublicKey(): string {
const publicKey = '0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48'; // public key of 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty (bob)
return publicKey;
}
function getKeyPair(): KeyringPair {
const PRIVATE_KEY =
'0x3783aab61e91d11a8334012c75666b52c39730d75ef2cc4b96b0362d6b0d6b0a';
return importPrivateKey(PRIVATE_KEY);
}
async function main() {
// Generate a valid public/private keypair offline.
const keypair = getKeyPair();
console.log(`Kusama-Encoded Address: ${keypair.address}`);
// Derive an address from a cryptographic public key offline.
const publicKey = getAPublicKey();
const address = deriveAddress(publicKey);
console.log(`Address from Public Key: ${address}`);
// Construct a balance transfer transaction offline.
const unsigned = createUnsignedBalanceTransfer();
// console.log('\nUnsigned Balance Transfer:');
// console.log(unsigned);
// Decode an unsigned transaction.
const decodedUnsigned = decode(unsigned, metadataRpc);
console.log(`\nDecoded Transaction\n To: ${decodedUnsigned.method.args.dest}\n` +
` Amount: ${decodedUnsigned.method.args.value}\n`);
// Construct the signing payload from an unsigned transaction.
const signingPayload = createSigningPayload(unsigned);
console.log(`\nPayload to Sign: ${signingPayload}`);
// Decode the information from a signing payload.
const payloadInfo = decode(signingPayload, metadataRpc);
console.log(`\nDecoded Transaction\n To: ${payloadInfo.method.args.dest}\n` +
` Amount: ${payloadInfo.method.args.value}\n`);
// Sign a payload.
const signature = await signWithAlice(signingPayload);
console.log(`\nSignature: ${signature}`);
// Serialize a signed transaction.
const tx = createSignedTx(unsigned, signature);
console.log(`\nTransaction to Submit: ${tx}`);
// Derive the tx hash of a signed transaction offline.
const txHash = getTxHash(tx);
console.log(`\nTx Hash: ${txHash}`);
// Decode a signed payload.
const txInfo = decode(tx, metadataRpc);
console.log(`\nDecoded Transaction\n To: ${txInfo.method.args.dest}\n` +
` Amount: ${txInfo.method.args.value}\n`);
process.exit(0);
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment