Hello ❗
This article is addressed to everyone interested in a simplified way of operating with Hive blockchain (what should allow you to drop the beekeeping suit from the picture above). 😊
Here is a wax, the library which allows you to perform API calls, build transactions, then use another tool beekeeper (responsible for holding your keys) to sign them and finally do broadcast.
The library contains several parts:
hive::protocol code (directly shared to Hived repo). Here you can find a specific code to transaction/operation serialization (JSON and binary), transaction static validation (a step performed also by Hived node before transaction is evaluated) as well as finally a code able to calculate sig-digest, TAPOS and transaction signatures by executing exactly the same code C++ as Hive Protocol does.So let's focus on Typescript version.
We have decided to create two layers in the Typescript implementation of Wax:
createWaxFoundation function.IWaxBaseInterface to provide its methods too. One of the advanced usage scenarios is extending a set of APIs being supported by Hive Chain which can provide you an IDE support while calling their methods. It also allows to verify request and response.You can find some examples presenting the usage at some interesting scenarios here: Wax-NPM.
Wax library supports both: direct webbrowser as well as NodeJS environments.
An Important note: before playing with this library, you probably need to define/change your local .npmrc file to resolve package registry address correctly .
echo @hive:registry=https://gitlab.syncad.com/api/v4/packages/npm/ >> .npmrc
I'd like to discuss one scenario in deeper details: where we're creating a transaction: https://gitlab.syncad.com/hive/wax/-/blob/develop/npm.ts.md#create-a-signed-transaction
In the very beginning. we're performing the setup of another tool: beekeeper, which initially has imported a private key 🔑 (next to be used to sign your transaction). This part is actually out of Wax library scope, but we decided to put it here to show a complete operation flow needed to build, sign and broadcast transaction.
Another thing that is worth mentioning is the fact that this step can be made separately since beekeeper finally stores imported private keys (inside a defined wallet) and next it only allows to use them (i.e. to generate a signature). It is impossible to read private keys back (using beekeeper API) from its encrypted storage. Before accessing the wallet, you have to unlock it (and provide initialy configured password) 🔓.
import beekeeperFactory from '@hive/beekeeper';
/// Build the beekeeper instance
const beekeeper = await beekeeperFactory();
/// First thing to start operating with beekeeper is establishing a session, which is additionally secured by specified salt.
const session = beekeeper.createSession("salt");
/// Once we got session, it's a time to create a wallet. Wallets are persisted to the WebBrower storage (IndexDB) or in NodeJS case to local filesystem.
const { wallet } = await session.createWallet("w0");
const myWifPrivateKey: string = '5JkFnXrLM2ap9t3AmAxBJvQHF7xSKtnTrCTginQCkhzU5S7ecPT'
/// Last action - we need to import private key
const publicKey = await wallet.importKey(myWifPrivateKey);
Once beekeeper is ready to operate, we can start to play with Wax interfaces itself. Let's use a mentioned above IHiveChainInterface:
The purpose of this interface is to join static parts together (provided by IWaxBaseInterface) and online Hive features (mostly available by Hive APIs).
import { createHiveChain } from '@hive/wax';
/// Here important thing to note: there are (default) parameters passed to `createHiveChain` function: pointing default Hive API node instance used for communication (api.hive.blog)
const chain = await createHiveChain();
To make transaction processing simpler, the Wax library provides a TransactionBuilder tool which can build a transaction for you and provide its several intresting properties like id, sigDigest as well.
Accessing its instance from the chain interface level, allows you to have automatically filled several important transaction properties as described below:
/** Now let's create a transaction builder. Important things:
* - getTransactionBuilder takes optional `expirationTime parameter`
* - getTransactionBuilder implicitly reads current Hive head block and correctly configures TAPOS for transaction you want to build
*/
const txBuilder = await chain.getTransactionBuilder();
/// Now let's add some operation to internally held transaction and at the end validate it:
txBuilder.push({
vote: {
voter: "otom",
author: "c0ff33a",
permlink: "ewxhnjbj",
weight: 2200
}
}).validate();
It is worth noting that TransactionBuilder offers much more operation building features (than specifying them as Typescipt object). To encapsulate blockchain complexity and allow seamless use of this interface the Wax library offers several complex operation builders whose description is probably a good opportunity for another post 📜.
// Build and sign the transaction object. Here is passed a **public key** to identify previously imported private one.
const signedTx = txBuilder.build(wallet, publicKey);
Behind the scenes, several important things happen - very specific to blockchain internals:
hive::protocol::signed_transaction objectid (hash), its sigDigest (basing also on passed chain-id)sigDigest, by calling IBeekeeperUnlockedWaller.signDigestOnce transaction has been signed, you can broadcast it by (of course) using a chain object:
/** First let's create a broadcast request: it can be built in 2 ways:
* - by passing a transaction builder object already holding your signed transaction (like in this example)
* - by passing a signed transaction object directly
*/
const request = new BroadcastTransactionRequest(txBuilder);
// Transmit
await chain.api.network_broadcast_api.broadcast_transaction(request);
🏁 Thats all ❗ Thanks for reading 🏅. We are waiting for your comments ;-)