I've been working on improving hive-stream a lot lately. What started as a blockchain streaming library with some contract helpers has turned into something much bigger. The goal was simple: if you're building on Hive, you shouldn't have to keep rewriting the same boilerplate. One library should just handle it.
So that's what I did. Driven by work I've been doing on many of the apps I've shipped over the past couple of months, I've been improving it like there is no tomorrow.
The problem
Anyone who's built a Hive app knows the drill. You want to follow someone? Better remember the exact format. Post with beneficiaries? That's two operations that need to go out in the same transaction, and the beneficiaries need to be sorted alphabetically or the node rejects it. Want to know someone's HP? Hope you enjoy doing math with VESTS and global properties every time.
I kept solving the same problems in different projects, so I put the solutions in one place. There are other libraries like dhive which alleviate some of the concerns working with Hive, but they don't do everything for you.
Query namespace
The biggest thing missing before was extensively reading data. Hive Stream was great at streaming blocks and reacting to operations, but if you wanted to look up an account's followers or check the internal market, you were writing raw API calls.
Now there's streamer.query:
const followers = await streamer.query.getFollowers('alice');
const trending = await streamer.query.getTrending({ limit: 10 });
const rc = await streamer.query.getRCMana('alice');
const community = await streamer.query.getCommunity('hive-169321');
const witnesses = await streamer.query.getWitnessesByVote('', 100);
42 methods covering content, social, delegations, market, resource credits, communities, witnesses, blocks, proposals, and more.
Hive Engine
This was the other big gap. Most dApps on Hive use Layer 2 tokens, but there was no clean way to query or interact with Hive Engine through hive-stream. I did have some stuff, but it wasn't overly comprehensive.
const balances = await streamer.engine.getTokenBalances('alice');
const token = await streamer.engine.getToken('BEE');
const buyBook = await streamer.engine.getMarketBuyBook('BEE');
await streamer.ops.stakeEngine().from('alice').symbol('BEE').quantity(100).send();
await streamer.ops.buyEngine().from('alice').symbol('BEE').quantity(10).price('0.5').send();
Token balances, market order books, trade history, NFTs, pending unstakes, delegations - all queryable. Plus builders for staking, market orders, and token delegation.
Post builder
This one I'm really happy with. Posting with beneficiaries on Hive means you need to broadcast a comment and comment_options together atomically. It's not hard, but it's annoying boilerplate that every app reimplements.
await streamer.ops.post()
.author('alice')
.title('My Post')
.body('Hello from hive-stream!')
.tags('hive', 'dev')
.community('hive-169321')
.beneficiary('devfund', 500)
.beneficiary('curator', 1000)
.maxAcceptedPayout(100, 'HBD')
.app('my-app/1.0')
.send();
It generates the permlink from your title, builds the json_metadata, pulls images out of your post body automatically, sorts the beneficiaries, and broadcasts both operations in one transaction. Replies work the same way, just set parentAuthor and parentPermlink.
Batch operations
Sometimes you need to do multiple things atomically:
await streamer.batch()
.vote('alice', 'bob', 'great-post', 10000)
.transfer('alice', 'bob', '1.000 HIVE', 'thanks')
.customJson('myapp', { action: 'track' }, 'alice')
.send();
All the operations
I went through the Hive operation list and added builders for pretty much everything:
- Social: follow, unfollow, mute, reblog
- Staking: power up, power down, delegate, undelegate
- Account: claim rewards, witness vote, proxy, profile updates, posting authority management
- Financial: savings transfers, HBD/HIVE conversions, limit orders, vesting routes
- Content: posts with beneficiaries, delete, comment options
- Communities: subscribe, unsubscribe, pin/unpin, mute/unmute
- Hive Engine: stake, unstake, buy, sell, cancel orders, delegate
They all follow the same pattern:
await streamer.ops.delegate()
.delegator('alice')
.delegatee('bob')
.vestingShares('10000.000000 VESTS')
.send();
More event subscriptions
Beyond the original transfer/custom_json/comment subscriptions, you can now watch for votes, delegations, power ups/downs, reward claims, witness votes, follows, reblogs, account updates, market orders, savings transfers, conversions, and more.
There's also onBlock for every new block and onAnyOperation as a raw firehose of everything happening on chain.
streamer.onVote((data) => {
console.log(`${data.voter} voted on @${data.author}/${data.permlink}`);
});
streamer.onFollow((data) => {
console.log(`${data.follower} followed ${data.following}`);
});
Utility functions
These are the things I got tired of reimplementing:
// Key derivation from master password
const keys = Utils.deriveKeys('alice', 'masterpassword');
// Reputation
Utils.calculateReputation('253948692668213'); // 73.64
// VESTS <-> HP conversion
Utils.vestToHP('1000000', totalVestingFund, totalVestingShares);
// Voting power and vote value
const mana = Utils.calculateVotingMana(account);
const voteValue = Utils.estimateVoteValue(mana, 100, effectiveVests, rewardFund, medianPrice);
// Account value
Utils.calculateAccountValue(account, hivePrice, hbdPrice, vestingFund, vestingShares);
// HBD interest, power down schedule
Utils.calculateHbdInterest('1000.000 HBD', lastPaymentDate, 15);
Utils.calculatePowerDownSchedule(account);
// Content
Utils.extractImagesFromBody(post.body);
Utils.generatePostSummary(post.body, 200);
Utils.generatePermlink('My Post Title');
// Account validation
Utils.isValidAccountName('alice'); // true
Utils.parseHiveUrl('https://hive.blog/hive-12345/@alice/my-post');
// Posting authority
await streamer.hasPostingAuth('alice', 'myapp');
await streamer.grantPostingAuth('alice', 'myapp');
Testing
Tested against real Hive mainnet. 34 live API tests, 11 Hive Engine tests, 33 operation structure validations, and 21 broadcast operations confirmed on chain (follow, post, delete, profile update, delegation, authority management, transfers, power up, batch ops). 532 tests total, all passing.
What's in the box now
| L1 query methods | 42 |
| Hive Engine queries | 17 |
| Write operation builders | 46 |
| Event subscriptions | 21 |
| Utility functions | 50+ |
| Built-in contracts | 40+ |
| Database adapters | 3 |
Five namespaces: ops, query, engine, flows, money.
What's next
If there's something you keep having to build yourself when working with Hive, open an issue or let me know. The whole point is to not have to solve the same problems twice.