Start
Examples
Copy these patterns. Replace keys and account names with your values.
Transfer HIVE
import { Transaction, PrivateKey } from 'hive-tx'
async function transferHive() {
const tx = new Transaction()
await tx.addOperation('transfer', {
from: 'myaccount',
to: 'recipient',
amount: '1.000 HIVE',
memo: 'Thank you!'
})
const privateKey = PrivateKey.from('5J...active-key')
tx.sign(privateKey)
const result = await tx.broadcast()
console.log(result.tx_id, result.status)
}
v7 returns { tx_id, status }. It does not return result.result.tx_id.
Comment
const tx = new Transaction()
await tx.addOperation('comment', {
parent_author: '',
parent_permlink: 'hive',
author: 'myaccount',
permlink: 'hello-hive',
title: 'Hello',
body: 'First post',
json_metadata: JSON.stringify({ tags: ['hive'], app: 'hive-tx' })
})
tx.sign(PrivateKey.from('5J...posting-key'))
await tx.broadcast()
A root post uses an empty parent_author. A reply sets parent_author and parent_permlink to the parent comment.
custom_json
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['myaccount'],
id: 'follow',
json: JSON.stringify(['follow', {
follower: 'myaccount',
following: 'alice',
what: ['blog']
}])
})
Sign and verify
import { Transaction, PrivateKey, Signature } from 'hive-tx'
const tx = new Transaction()
await tx.addOperation('vote', {
voter: 'myaccount',
author: 'some-author',
permlink: 'some-post-permlink',
weight: 10000
})
const privateKey = PrivateKey.from(
'5JRaypasxMx1L97ZUX7YuC5Psb5EAbF821kkAGtBj7xCJFQcbLg'
)
tx.sign(privateKey)
const signature = tx.transaction.signatures[0]
const digest = tx.digest().digest
const ok1 = privateKey.createPublic().verify(digest, signature)
const ok2 =
Signature.from(signature).getPublicKey(digest).toString() ===
privateKey.createPublic().toString()
console.log(ok1, ok2)
Multi-signature
tx.sign([ownerKey, activeKey])
// or
tx.sign(ownerKey)
tx.sign(activeKey)
Wait for an irreversible block
const result = await tx.broadcast(true)
console.log(result.status)
// 'within_irreversible_block' | 'expired_irreversible' | 'too_old' | 'unknown'
JSON-RPC
import { callRPC } from 'hive-tx'
const accounts = await callRPC('condenser_api.get_accounts', [['hiveio']])
const props = await callRPC('condenser_api.get_dynamic_global_properties')
console.log(accounts[0].name, props.head_block_number)
API method names: Hive API definitions.
Quorum
import { callWithQuorum } from 'hive-tx'
const accounts = await callWithQuorum(
'condenser_api.get_accounts',
[['hiveio']],
2
)
Quorum is JSON equality across nodes. It is not a head-lag check.
Account history filter
import { callRPC, utils } from 'hive-tx'
const filter = utils.makeBitMaskFilter([
utils.operations.transfer,
utils.operations.vote,
utils.operations.comment
])
const history = await callRPC('condenser_api.get_account_history', [
'myaccount',
-1,
100,
...filter
])
REST
import { callREST } from 'hive-tx'
const balance = await callREST('balance', '/accounts/{account-name}/balances', {
'account-name': 'alice'
})
REST nodes are in config.restNodes. Browse endpoints on a node such as rpc.mahdiyari.info.
Encrypt a memo
import { Memo, PrivateKey } from 'hive-tx'
const senderMemoKey = PrivateKey.from('5J...sender-memo-key')
const encrypted = Memo.encode(
senderMemoKey,
'STM...recipient-memo-public-key',
'#Hello World!'
)
await tx.addOperation('transfer', {
from: 'sender',
to: 'receiver',
amount: '0.001 HIVE',
memo: encrypted
})
Text without a leading # is not encrypted.
Decrypt a memo
const text = Memo.decode(
PrivateKey.from('5J...recipient-memo-key'),
encryptedMemo
)
Generate keys
import { PrivateKey } from 'hive-tx'
const privateKey = PrivateKey.randomKey()
const publicKey = privateKey.createPublic()
console.log(privateKey.inspect())
console.log(publicKey.toString())
Keys from a master password
const owner = PrivateKey.fromLogin('username', 'master-password', 'owner')
const active = PrivateKey.fromLogin('username', 'master-password', 'active')
const posting = PrivateKey.fromLogin('username', 'master-password', 'posting')
const memo = PrivateKey.fromLogin('username', 'master-password', 'memo')
fromLogin is a static method on PrivateKey. Do not call it on a key instance.
Validate a username
import { utils } from 'hive-tx'
for (const name of ['alice', 'a', 'BadName']) {
const error = utils.validateUsername(name)
console.log(name, error === null ? 'valid' : error)
}
Witness set properties
import { utils, Transaction } from 'hive-tx'
const operation = utils.buildWitnessSetProperties('mywitness', {
key: 'STM1111111111111111111111111111111114T1Anm',
account_creation_fee: '0.000 HIVE',
account_subsidy_budget: 10000,
account_subsidy_decay: 330782,
maximum_block_size: 65536,
hbd_interest_rate: 0,
hbd_exchange_rate: { base: '0.250 HBD', quote: '1.000 HIVE' },
url: 'https://example.com'
})
const tx = new Transaction()
await tx.addOperation(operation[0], operation[1])
tx.sign(PrivateKey.from('5J...active-key'))
await tx.broadcast()
key is required. It is the current signing public key.
Handle RPC errors
import { callRPC } from 'hive-tx'
try {
await callRPC('condenser_api.get_accounts', [['alice']])
} catch (e) {
if (e && e.name === 'RPCError') {
console.log(e.code, e.message, e.data)
} else {
throw e
}
}
RPCError is thrown for Hive JSON-RPC errors. Network failures retry, then throw a normal error.
Browser
<script type="module">
import { PrivateKey } from
'https://cdn.jsdelivr.net/npm/hive-tx@7/dist/index.mjs'
const pub = PrivateKey.fromLogin('alice', 'x', 'posting').createPublic()
console.log(pub.toString())
</script>