Last active
March 12, 2020 16:49
-
-
Save axelchalon/3293102df160d997a00fbff6f3038c52 to your computer and use it in GitHub Desktop.
TxWrapper example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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