-
Notifications
You must be signed in to change notification settings - Fork 117
Expand file tree
/
Copy pathbalance-transfer-tx-wrapper.ts
More file actions
93 lines (77 loc) · 3.1 KB
/
balance-transfer-tx-wrapper.ts
File metadata and controls
93 lines (77 loc) · 3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
/*
Example in three steps of how to create a signed transfer transaction, using txwrapper sdk.
This allows the construction of the unsigned transaction on one machine which doesn't hold the
private key and needs to be online, and the signing on another machine which does hold the private key.
*/
import { ApiPromise, HttpProvider } from '@polkadot/api'
import { methods } from './helpers/txwrapper'
import { construct } from '@substrate/txwrapper-core'
import { Keyring } from '@polkadot/keyring'
import { cryptoWaitReady } from '@polkadot/util-crypto'
import { signWith } from './helpers/signWith'
import { JOYSTREAM_CHAIN_CONFIG } from './helpers/ChainConfig'
async function signOfflineTransaction() {
await cryptoWaitReady()
const senderAddress = 'j4W7rVcUCxi2crhhjRq46fNDRbVHTjJrz6bKxZwehEMQxZeSf' // Signer (Alice)
const recipientAddress = 'j4UYhDYJ4pz2ihhDDzu69v2JTVeGaGmTebmBdWaX2ANVinXyE' // Destination (Bob)
const transferAmount = `${1e10}` // 10_000_000_000 = 1 Joy
const tip = 0
const { registry, metadataRpc, specVersion, transactionVersion } = JOYSTREAM_CHAIN_CONFIG
const HTTP_RPC_URI = process.env.HTTP_RPC_URI || 'http://127.0.0.1:9933'
const provider = new HttpProvider(HTTP_RPC_URI)
const api = await ApiPromise.create({ provider })
const genesisHash = (await api.rpc.chain.getBlockHash(0)).toHex()
const nonce = (await api.rpc.system.accountNextIndex(senderAddress)).toNumber()
const lastHeader = await api.rpc.chain.getHeader()
// Step 1: Construct the unsigned transaction
const unsignedTransaction = methods.balances.transfer(
{
value: transferAmount,
dest: recipientAddress,
},
{
address: senderAddress,
blockHash: lastHeader.hash.toHex(),
blockNumber: lastHeader.number.toNumber(),
eraPeriod: 128,
genesisHash,
metadataRpc,
nonce,
specVersion,
transactionVersion,
tip,
},
{
registry,
metadataRpc,
}
)
console.log('Unsigned Transaction:', unsignedTransaction)
const exportedTx = JSON.stringify(unsignedTransaction)
// Transport the transaction to the offline signer...
const importedTx = JSON.parse(exportedTx)
// Step 2: Sign the transaction offline
const keyring = new Keyring({ type: 'sr25519' })
const senderKeyPair = keyring.addFromUri('//Alice') // Replace with the private key or mnemonic of the sender
const signature = signWith(senderKeyPair, importedTx, {
metadataRpc,
registry,
})
console.log(`\nSignature: ${signature}`)
// Encode a signed transaction.
const tx = construct.signedTx(importedTx, signature, {
metadataRpc,
registry,
})
console.log(`\nTransaction to Submit: ${tx}`)
// Calculate the tx hash of the signed transaction offline.
const expectedTxHash = construct.txHash(tx)
console.log(`\nExpected Tx Hash: ${expectedTxHash}`)
// Step 3: Move the signed transaction to an online node and submit it to the network.
const actualTxHash = await api.rpc.author.submitExtrinsic(tx)
console.log(`\nActual Tx Hash: ${actualTxHash}`)
}
signOfflineTransaction().catch((error) => {
console.error(error)
process.exit(1)
})