hive-tx v7
GitHub npm

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>