Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions utils/api-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"@polkadot/types": "10.7.1",
"@polkadot/util": "^12.6.2",
"@polkadot/util-crypto": "^12.6.2",
"@substrate/txwrapper-substrate": "6.0.1",
"@substrate/txwrapper-registry": "6.0.1",
"@types/bn.js": "^5.1.0",
"bfj": "^8.0.0",
"bn.js": "^5.2.1"
Expand Down
21 changes: 21 additions & 0 deletions utils/api-scripts/src/account-free-balance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ApiPromise, WsProvider } from '@polkadot/api'
import { cryptoWaitReady } from '@polkadot/util-crypto'
import { DeriveBalancesAll } from '@polkadot/api-derive/types'

async function main() {
await cryptoWaitReady()

// Initialise the provider to connect to the local node
const WS_URI = process.env.WS_URI || 'ws://127.0.0.1:9944'
const provider = new WsProvider(WS_URI)

// Create the API and wait until ready
const api = await ApiPromise.create({ provider })
const addr = process.argv[2] || 'j4W7rVcUCxi2crhhjRq46fNDRbVHTjJrz6bKxZwehEMQxZeSf'
const balances: DeriveBalancesAll = await api.derive.balances.all(addr)
console.log(`${addr} ${balances.freeBalance.toHuman()}`)
}

main()
.catch(console.error)
.finally(() => process.exit())
15 changes: 14 additions & 1 deletion utils/api-scripts/src/address-format.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
// @ts-check
import { cryptoWaitReady } from '@polkadot/util-crypto'
import { cryptoWaitReady, decodeAddress } from '@polkadot/util-crypto'
import { Keyring } from '@polkadot/keyring'
import { JOYSTREAM_ADDRESS_PREFIX } from '@joystream/types'

export function validateAddress(address: string, errorMessage = 'Invalid address'): string | true {
try {
decodeAddress(address)
} catch (e) {
return errorMessage
}

return true
}

async function main() {
await cryptoWaitReady()

Expand All @@ -12,6 +22,9 @@ async function main() {

const suri = '//Alice'
const userAddress = keyring.addFromUri(suri, undefined, 'sr25519').address

validateAddress(userAddress)

console.log(userAddress)
}

Expand Down
58 changes: 58 additions & 0 deletions utils/api-scripts/src/balance-transfer-http-rpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* eslint-disable @typescript-eslint/no-unused-vars */

/*
Example of how to create a signed transfer transaction using HTTP RPC interface.
The output of the program is the hex encoded transaction hash and the signed transaction.
The transaction hash must be used to find the transaction success or failure result on the blockchain.
*/

import { ApiPromise, HttpProvider } from '@polkadot/api'
import { cryptoWaitReady } from '@polkadot/util-crypto'
import { Keyring } from '@polkadot/keyring'
import { BN } from '@polkadot/util'
import { JOYSTREAM_ADDRESS_PREFIX } from '@joystream/types'

async function main() {
await cryptoWaitReady()

// Create the API and wait until ready
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 keyring = new Keyring({ type: 'sr25519', ss58Format: JOYSTREAM_ADDRESS_PREFIX })
const keyringPair = keyring.addFromUri('//Alice', undefined, 'sr25519')

// Create a transfer transaction
const OneJoy = new BN(`${1e10}`, 10) // 10_000_000_000 = 1 Joy
const destination = 'j4UYhDYJ4pz2ihhDDzu69v2JTVeGaGmTebmBdWaX2ANVinXyE'
const tx = api.tx.balances.transfer(destination, OneJoy)

const { partialFee } = await tx.paymentInfo(keyringPair.address)
console.error('Estimated Fee:', partialFee.toHuman())

// Get the next account nonce
const senderAddress = keyringPair.address

// const accountNonce = await fetchAccountNextIndex(senderAddress, HTTP_RPC_URI)
const accountNonce = await api.rpc.system.accountNextIndex(senderAddress)

// Sign the transaction
const signedTx = await tx.signAsync(keyringPair, { nonce: accountNonce })
console.error('Transaction:', signedTx.toHuman())

// Transaction Hash can be used to find the transaction on the blockchain
console.log('TxHash:', signedTx.hash.toHex())

// Paste the hex here to decode it.
// https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frpc.joystream.org#/extrinsics/decode
console.log('Tx:', signedTx.toHex())

// Submit the transaction
// await submitExtrinsic(signedTx.toHex(), HTTP_RPC_URI)
await api.rpc.author.submitExtrinsic(signedTx)
}

main()
.catch(console.error)
.finally(() => process.exit())
93 changes: 93 additions & 0 deletions utils/api-scripts/src/balance-transfer-tx-wrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,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)
})
94 changes: 94 additions & 0 deletions utils/api-scripts/src/balance-transfer-websocket-rpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
Example of how to create a signed transfer transaction using Websocket RPC interface.
The program will wait for the transaction is finalized.
The finalized blockhash, transaction index will be printed.
*/

import { ApiPromise, WsProvider } from '@polkadot/api'
import { cryptoWaitReady } from '@polkadot/util-crypto'
import { Keyring } from '@polkadot/keyring'
import { BN } from '@polkadot/util'
import { decodeError } from './helpers/decodeError'

async function main() {
await cryptoWaitReady()

// Initialise the provider to connect to the local node
const WS_URI = process.env.WS_URI || 'ws://127.0.0.1:9944'
const provider = new WsProvider(WS_URI)

// Create the API and wait until ready
const api = await ApiPromise.create({ provider })

const keyring = new Keyring({ type: 'sr25519', ss58Format: 126 })

// const keyringPair = keyring.addFromMnemonic('your mnemonic phrase', {}, 'sr25519')
const keyringPair = keyring.addFromUri('//Alice', undefined, 'sr25519')

// Create a transfer transaction
const OneJoy = new BN(`${1e10}`, 10) // 10_000_000_000 = 1 Joy
const tx = api.tx.balances.transfer('j4UYhDYJ4pz2ihhDDzu69v2JTVeGaGmTebmBdWaX2ANVinXyE', OneJoy)

const { partialFee } = await tx.paymentInfo(keyringPair.address)
console.error('Estimated Fee:', partialFee.toHuman())

// Get the next account nonce
const nonce = await api.rpc.system.accountNextIndex(keyringPair.address)

const signedTx = await tx.signAsync(keyringPair, { nonce })
console.error('Transaction:', signedTx.toHuman())

console.error('TxHash:', signedTx.hash.toHex())

await signedTx.send((result) => {
if (result.status.isReady) {
// The transaction has been successfully validated by the transaction pool
// and is ready to be included in a block by the block producer.
console.error('Tx Submitted, waiting for inclusion...')
}

if (result.status.isInBlock) {
// console.error('Tx in block', result.status.asInBlock.toHex())
console.error('Tx in Block, waiting for finalization...')
}

if (result.status.isFinalized) {
console.error('Tx Finalized.')
const blockHash = result.status.asFinalized
console.log(
JSON.stringify(
{
'blockHash': blockHash.toHex(),
'txIndex': result.txIndex,
// 'txHash': result.txHash.toHex(),
// 'txSignature': signedTx.signature.toHex(),
},
null,
2
)
)
const success = result.findRecord('system', 'ExtrinsicSuccess')
if (success) {
console.error('Transfer successful.')
process.exit(0)
} else {
const failed = result.findRecord('system', 'ExtrinsicFailed')
if (failed) {
console.error('Transfer Failed.', failed.event.data.toString())
console.error('Error:', decodeError(api, failed.event))
}
process.exit(3)
}
}

if (result.isError) {
console.error('Error', result.toHuman())
process.exit(2)
}
})
}

main().catch((err) => {
console.error(err)
process.exit(1)
})
28 changes: 28 additions & 0 deletions utils/api-scripts/src/create-account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// @ts-check
import { cryptoWaitReady, mnemonicGenerate } from '@polkadot/util-crypto'
import { Keyring } from '@polkadot/keyring'

async function main() {
await cryptoWaitReady()

// https://polkadot.js.org/docs/keyring/start/create
const keyring = new Keyring({
type: 'sr25519',
ss58Format: 126,
})

// Generate a new mnemonic
const mnemonic = mnemonicGenerate()

const keyringPair = keyring.addFromMnemonic(
mnemonic,
{
name: 'User 1',
},
'sr25519'
)

console.log(keyringPair.address)
}

main().catch(console.error)
Loading
Loading