hive-stream 3.0.4 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/DOCUMENTATION.md +775 -2
- package/README.md +34 -1
- package/dist/adapters/mongodb.adapter.js +21 -30
- package/dist/adapters/mongodb.adapter.js.map +1 -1
- package/dist/adapters/postgresql.adapter.js +16 -16
- package/dist/adapters/postgresql.adapter.js.map +1 -1
- package/dist/adapters/sqlite.adapter.js +17 -17
- package/dist/adapters/sqlite.adapter.js.map +1 -1
- package/dist/api.js +2 -0
- package/dist/api.js.map +1 -1
- package/dist/builders.d.ts +269 -1
- package/dist/builders.js +883 -1
- package/dist/builders.js.map +1 -1
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +209 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +17 -0
- package/dist/cli/prompts.js +109 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/cli/scaffold.d.ts +21 -0
- package/dist/cli/scaffold.js +281 -0
- package/dist/cli/scaffold.js.map +1 -0
- package/dist/cli/templates.d.ts +28 -0
- package/dist/cli/templates.js +329 -0
- package/dist/cli/templates.js.map +1 -0
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/contracts/checkpoint.contract.d.ts +6 -0
- package/dist/contracts/checkpoint.contract.js +196 -0
- package/dist/contracts/checkpoint.contract.js.map +1 -0
- package/dist/contracts/nft.contract.d.ts +2 -0
- package/dist/contracts/nft.contract.js +174 -0
- package/dist/contracts/nft.contract.js.map +1 -1
- package/dist/contracts/roulette.contract.d.ts +9 -0
- package/dist/contracts/roulette.contract.js +365 -0
- package/dist/contracts/roulette.contract.js.map +1 -0
- package/dist/contracts/ticketing.contract.js +158 -1
- package/dist/contracts/ticketing.contract.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/metadata.js +1 -0
- package/dist/metadata.js.map +1 -1
- package/dist/streamer.d.ts +105 -10
- package/dist/streamer.js +539 -61
- package/dist/streamer.js.map +1 -1
- package/dist/types/hive-stream.d.ts +306 -0
- package/dist/utils.d.ts +442 -0
- package/dist/utils.js +1423 -0
- package/dist/utils.js.map +1 -1
- package/package.json +7 -5
package/DOCUMENTATION.md
CHANGED
|
@@ -13,6 +13,30 @@ This document focuses on the contract system and how to build robust contracts u
|
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
+
## CLI
|
|
17
|
+
|
|
18
|
+
Hive Stream ships a scaffolding CLI. It generates a complete TypeScript app — package.json, tsconfig, `.env.example`, a wired-up `src/index.ts`, a starter custom contract, and a README with payload examples for every registered contract action.
|
|
19
|
+
|
|
20
|
+
```shell
|
|
21
|
+
npx hive-stream new <name> [options] # scaffold a new app
|
|
22
|
+
npx hive-stream list # show templates and adapters
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Run `new` without options for interactive prompts, or pass flags for non-interactive use:
|
|
26
|
+
|
|
27
|
+
| Flag | Description |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `-t, --template <id>` | `minimal`, `game`, `exchange`, `social`, `blog`, `token`, or `assets` |
|
|
30
|
+
| `-a, --adapter <id>` | `sqlite` (default), `mongodb`, or `postgresql` |
|
|
31
|
+
| `-u, --username <name>` | Hive account the app runs as |
|
|
32
|
+
| `--api` | Enable the built-in HTTP API server |
|
|
33
|
+
| `--install` | Run `npm install` after scaffolding |
|
|
34
|
+
| `-y, --yes` | Skip prompts and accept defaults |
|
|
35
|
+
|
|
36
|
+
Generated apps read `HIVE_USERNAME`, `HIVE_POSTING_KEY`, and `HIVE_ACTIVE_KEY` from `.env` via `new Streamer({ env: true })`.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
16
40
|
## Concepts
|
|
17
41
|
|
|
18
42
|
### Contracts
|
|
@@ -299,6 +323,7 @@ export const TipJar = defineContract({
|
|
|
299
323
|
- `createTokenContract` - SQL-backed fungible tokens
|
|
300
324
|
- `createNFTContract` - SQL-backed NFTs
|
|
301
325
|
- `createRpsContract` - Rock/Paper/Scissors
|
|
326
|
+
- `createRouletteContract` - Roulette with straight, color, parity, dozen, column, and low/high bets
|
|
302
327
|
- `createPollContract` - Polls and votes
|
|
303
328
|
- `createTipJarContract` - Tip jar + message log
|
|
304
329
|
- `createExchangeContract` - Deposits/withdrawals/orders/matching (SQL)
|
|
@@ -329,14 +354,16 @@ export const TipJar = defineContract({
|
|
|
329
354
|
- `createPayrollContract` - Recurring payroll budgets with scheduled runs and recipient balances
|
|
330
355
|
- `createProposalTimelockContract` - Timelock approval queues for delayed governance-style actions
|
|
331
356
|
- `createBundleMarketplaceContract` - Bundle storefronts with inventory, purchases, and fulfillment tracking
|
|
332
|
-
- `createTicketingContract` - Event ticket sales with check-ins, refunds, and
|
|
357
|
+
- `createTicketingContract` - Event ticket sales with check-ins, refunds, capacity limits, transfers, and peer-to-peer resale
|
|
333
358
|
- `createFanClubContract` - Paid clubs with member renewals, points, and perk redemptions
|
|
359
|
+
- `createCheckpointContract` - Periodic on-chain state hashes so independent operators can verify they derive identical state
|
|
334
360
|
|
|
335
361
|
### Example Snippets
|
|
336
362
|
|
|
337
363
|
Quick-start snippets live in `examples/contracts/`:
|
|
338
364
|
|
|
339
365
|
- `examples/contracts/rps.ts`
|
|
366
|
+
- `examples/contracts/roulette.ts`
|
|
340
367
|
- `examples/contracts/poll.ts`
|
|
341
368
|
- `examples/contracts/tipjar.ts`
|
|
342
369
|
- `examples/contracts/exchange.ts`
|
|
@@ -435,8 +462,754 @@ When the built-in API server is running, the following endpoints are available:
|
|
|
435
462
|
|
|
436
463
|
---
|
|
437
464
|
|
|
465
|
+
## Non-Custodial Assets Guide
|
|
466
|
+
|
|
467
|
+
The NFT and ticketing contracts support fully non-custodial trading: buyers pay sellers **directly**, and the contract only verifies the on-chain payment and flips ownership. Funds never pass through the app account.
|
|
468
|
+
|
|
469
|
+
### Direct NFT sales
|
|
470
|
+
|
|
471
|
+
1. The owner lists with `listNFT` (custom_json): `{"collectionSymbol":"ART","tokenId":"piece-1","price":"10.000","currency":"HIVE"}`.
|
|
472
|
+
2. The buyer sends the exact price **to the seller's account** with the memo `{"hive_stream":{"contract":"nft","action":"buyNFTDirect","payload":{"collectionSymbol":"ART","tokenId":"piece-1"}}}`.
|
|
473
|
+
3. The contract verifies the transfer recipient is the seller and the amount/currency match the listing, then transfers ownership.
|
|
474
|
+
|
|
475
|
+
The examples above assume the contract was registered as `createNFTContract({ name: 'nft' })` (what scaffolded apps do); the default registered name is `hivenft`.
|
|
476
|
+
|
|
477
|
+
Royalties cannot be enforced on a peer-to-peer payment; `buyNFTDirect` records the royalty owed (`royaltyDue`, `royaltyRecipient`) in the emitted event so marketplaces and sellers can honour them. The custodial `buyNFT` flow (payment to the app account, which pays out the seller and royalties) remains available.
|
|
478
|
+
|
|
479
|
+
### Batch minting
|
|
480
|
+
|
|
481
|
+
`mintBatchNFT` (custom_json, collection creator only) mints many tokens in one operation, either as numbered editions or an explicit list:
|
|
482
|
+
|
|
483
|
+
```json
|
|
484
|
+
{"collectionSymbol":"TICKETS","to":"some-account","editions":{"baseTokenId":"GA","count":100}}
|
|
485
|
+
{"collectionSymbol":"TICKETS","to":"some-account","tokens":[{"tokenId":"VIP-1","metadata":"{\"seat\":\"A1\"}"}]}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Editions mint `GA-1` … `GA-100` (up to 1,000 per operation); explicit lists allow up to 50 tokens with per-token metadata. Both respect the collection's maximum supply atomically.
|
|
489
|
+
|
|
490
|
+
### Ticket transfers and resale
|
|
491
|
+
|
|
492
|
+
Tickets from the ticketing contract are bearer assets:
|
|
493
|
+
|
|
494
|
+
- `transferTicket` (custom_json, owner only): `{"ticketId":"ticket-1","to":"friend-account"}`
|
|
495
|
+
- `listTicket` / `unlistTicket` (custom_json, owner only): `{"ticketId":"ticket-1","price":"3.000"}` — asset defaults to the event's asset
|
|
496
|
+
- `buyTicketDirect` (transfer memo): buyer pays the listed price **directly to the seller** with `{"hive_stream":{"contract":"ticketing","action":"buyTicketDirect","payload":{"ticketId":"ticket-1"}}}`
|
|
497
|
+
|
|
498
|
+
Transferring a ticket deactivates any active resale listing, and stale listings (where the seller no longer owns the ticket) are rejected at purchase time.
|
|
499
|
+
|
|
500
|
+
### State checkpoints
|
|
501
|
+
|
|
502
|
+
Because contract state is derived off-chain, anyone can verify an app by replaying the chain. `createCheckpointContract` makes that verification cheap: it periodically publishes a deterministic sha256 hash of your contract tables as a custom_json operation, and records other operators' published hashes with a match/mismatch verdict.
|
|
503
|
+
|
|
504
|
+
```ts
|
|
505
|
+
import { createCheckpointContract, TimeAction } from 'hive-stream';
|
|
506
|
+
|
|
507
|
+
await streamer.registerContract(createCheckpointContract({
|
|
508
|
+
account: 'my-app-account',
|
|
509
|
+
tables: ['nft_collections', 'nft_tokens', 'nft_listings']
|
|
510
|
+
}));
|
|
511
|
+
|
|
512
|
+
await streamer.registerAction(new TimeAction('1h', 'state-checkpoint', 'checkpoint', 'publishCheckpoint', {}));
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
The hash is order-independent (rows are hashed individually and sorted), so any adapter backend that holds the same logical state produces the same digest. Publishing requires a posting key for the configured account. Results land in the `state_checkpoints` table; a `matched = 0` row means your node's state diverges from the publisher's (or the hash was computed after state moved on — recompute at the same cadence to confirm).
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## Social Operations
|
|
520
|
+
|
|
521
|
+
Follow, unfollow, mute, and reblog users directly from the streamer:
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
// Direct methods
|
|
525
|
+
await streamer.follow('myaccount', 'targetuser');
|
|
526
|
+
await streamer.unfollow('myaccount', 'targetuser');
|
|
527
|
+
await streamer.mute('myaccount', 'spammer');
|
|
528
|
+
await streamer.reblog('myaccount', 'author', 'great-post');
|
|
529
|
+
|
|
530
|
+
// Or use builders
|
|
531
|
+
await streamer.ops.follow().follower('myaccount').following('targetuser').send();
|
|
532
|
+
await streamer.ops.unfollow().follower('myaccount').following('targetuser').send();
|
|
533
|
+
await streamer.ops.mute().follower('myaccount').following('spammer').send();
|
|
534
|
+
await streamer.ops.reblog().account('myaccount').author('author').permlink('great-post').send();
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
## Staking Operations
|
|
540
|
+
|
|
541
|
+
Power up, power down, delegate, and undelegate Hive Power:
|
|
542
|
+
|
|
543
|
+
```typescript
|
|
544
|
+
// Power up HIVE to HP
|
|
545
|
+
await streamer.powerUp('myaccount', 'myaccount', '100.000');
|
|
546
|
+
await streamer.ops.powerUp().from('myaccount').to('myaccount').amount(100).send();
|
|
547
|
+
|
|
548
|
+
// Power down (withdraw vesting)
|
|
549
|
+
await streamer.powerDown('myaccount', '50000.000000 VESTS');
|
|
550
|
+
await streamer.ops.powerDown().account('myaccount').vestingShares('50000.000000 VESTS').send();
|
|
551
|
+
|
|
552
|
+
// Cancel active power down
|
|
553
|
+
await streamer.cancelPowerDown('myaccount');
|
|
554
|
+
await streamer.ops.cancelPowerDown().account('myaccount').send();
|
|
555
|
+
|
|
556
|
+
// Delegate HP to another account
|
|
557
|
+
await streamer.delegateVestingShares('myaccount', 'recipient', '10000.000000 VESTS');
|
|
558
|
+
await streamer.ops.delegate().delegator('myaccount').delegatee('recipient').vestingShares('10000.000000 VESTS').send();
|
|
559
|
+
|
|
560
|
+
// Remove delegation
|
|
561
|
+
await streamer.undelegateVestingShares('myaccount', 'recipient');
|
|
562
|
+
await streamer.ops.undelegate().delegator('myaccount').delegatee('recipient').send();
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
---
|
|
566
|
+
|
|
567
|
+
## Account Operations
|
|
568
|
+
|
|
569
|
+
### Claim Rewards
|
|
570
|
+
```typescript
|
|
571
|
+
await streamer.claimRewards('myaccount', '1.000 HIVE', '0.500 HBD', '100.000000 VESTS');
|
|
572
|
+
await streamer.ops.claimRewards()
|
|
573
|
+
.account('myaccount')
|
|
574
|
+
.rewardHive('1.000 HIVE')
|
|
575
|
+
.rewardHbd('0.500 HBD')
|
|
576
|
+
.rewardVests('100.000000 VESTS')
|
|
577
|
+
.send();
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### Witness Voting
|
|
581
|
+
```typescript
|
|
582
|
+
await streamer.witnessVote('myaccount', 'goodwitness', true);
|
|
583
|
+
await streamer.ops.witnessVote().account('myaccount').witness('goodwitness').approve().send();
|
|
584
|
+
|
|
585
|
+
// Remove witness vote
|
|
586
|
+
await streamer.witnessVote('myaccount', 'badwitness', false);
|
|
587
|
+
await streamer.ops.witnessVote().account('myaccount').witness('badwitness').unapprove().send();
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Governance Proxy
|
|
591
|
+
```typescript
|
|
592
|
+
await streamer.setProxy('myaccount', 'trustedvoter');
|
|
593
|
+
await streamer.ops.setProxy().account('myaccount').proxy('trustedvoter').send();
|
|
594
|
+
|
|
595
|
+
// Remove proxy
|
|
596
|
+
await streamer.clearProxy('myaccount');
|
|
597
|
+
await streamer.ops.clearProxy().account('myaccount').send();
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### Update Profile
|
|
601
|
+
```typescript
|
|
602
|
+
await streamer.updateProfile('myaccount', {
|
|
603
|
+
name: 'My Display Name',
|
|
604
|
+
about: 'Hive developer',
|
|
605
|
+
location: 'Decentralized',
|
|
606
|
+
website: 'https://example.com',
|
|
607
|
+
profile_image: 'https://example.com/avatar.png',
|
|
608
|
+
cover_image: 'https://example.com/cover.png'
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
// Or use the builder
|
|
612
|
+
await streamer.ops.updateProfile()
|
|
613
|
+
.account('myaccount')
|
|
614
|
+
.name('My Display Name')
|
|
615
|
+
.about('Hive developer')
|
|
616
|
+
.website('https://example.com')
|
|
617
|
+
.profileImage('https://example.com/avatar.png')
|
|
618
|
+
.set('custom_field', 'custom_value')
|
|
619
|
+
.send();
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Account Lookup
|
|
623
|
+
```typescript
|
|
624
|
+
const account = await streamer.getAccount('alice');
|
|
625
|
+
const accounts = await streamer.getAccounts(['alice', 'bob', 'charlie']);
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
## Event Subscriptions
|
|
631
|
+
|
|
632
|
+
In addition to the existing `onTransfer`, `onCustomJson`, `onComment`, `onPost`, and escrow subscriptions, you can now subscribe to:
|
|
633
|
+
|
|
634
|
+
```typescript
|
|
635
|
+
// Watch all votes on the blockchain
|
|
636
|
+
streamer.onVote((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
637
|
+
console.log(`${data.voter} voted on @${data.author}/${data.permlink} with weight ${data.weight}`);
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
// Watch delegations
|
|
641
|
+
streamer.onDelegate((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
642
|
+
console.log(`${data.delegator} delegated ${data.vesting_shares} to ${data.delegatee}`);
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
// Watch power ups
|
|
646
|
+
streamer.onPowerUp((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
647
|
+
console.log(`${data.from} powered up ${data.amount} to ${data.to}`);
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
// Watch power downs
|
|
651
|
+
streamer.onPowerDown((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
652
|
+
console.log(`${data.account} started power down of ${data.vesting_shares}`);
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
// Watch reward claims
|
|
656
|
+
streamer.onClaimRewards((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
657
|
+
console.log(`${data.account} claimed rewards`);
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
// Watch witness votes
|
|
661
|
+
streamer.onAccountWitnessVote((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
662
|
+
console.log(`${data.account} ${data.approve ? 'voted for' : 'unvoted'} witness ${data.witness}`);
|
|
663
|
+
});
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
---
|
|
667
|
+
|
|
668
|
+
## Blockchain Helpers
|
|
669
|
+
|
|
670
|
+
### Reputation Score
|
|
671
|
+
```typescript
|
|
672
|
+
import { Utils } from 'hive-stream';
|
|
673
|
+
|
|
674
|
+
// Convert raw blockchain reputation to human-readable score (25-75 range)
|
|
675
|
+
const score = Utils.calculateReputation('253948692668213'); // e.g. 73.64
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
### VESTS / HP Conversion
|
|
679
|
+
```typescript
|
|
680
|
+
// Convert VESTS to Hive Power
|
|
681
|
+
const hp = Utils.vestToHP('1000000', totalVestingFundHive, totalVestingShares); // '500.000'
|
|
682
|
+
|
|
683
|
+
// Convert HP to VESTS
|
|
684
|
+
const vests = Utils.hpToVest('500', totalVestingFundHive, totalVestingShares); // '1000000.000000'
|
|
685
|
+
|
|
686
|
+
// Get formatted VESTS string for delegation/power down
|
|
687
|
+
const vestsStr = Utils.hpToVestString('500', totalVestingFundHive, totalVestingShares); // '1000000.000000 VESTS'
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
### Parse Profile Metadata
|
|
691
|
+
```typescript
|
|
692
|
+
const profile = Utils.parseProfileMetadata(account.posting_json_metadata);
|
|
693
|
+
// { name: 'Alice', about: '...', location: '...', website: '...', profile_image: '...', cover_image: '...' }
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
---
|
|
697
|
+
|
|
698
|
+
## Query Namespace
|
|
699
|
+
|
|
700
|
+
The `streamer.query` namespace provides read-only access to the entire Hive blockchain. No keys required.
|
|
701
|
+
|
|
702
|
+
### Chain State
|
|
703
|
+
```typescript
|
|
704
|
+
const props = await streamer.query.getDynamicGlobalProperties();
|
|
705
|
+
const chainProps = await streamer.query.getChainProperties();
|
|
706
|
+
const config = await streamer.query.getConfig();
|
|
707
|
+
const price = await streamer.query.getCurrentMedianHistoryPrice();
|
|
708
|
+
const rewardFund = await streamer.query.getRewardFund('post');
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
### Content & Discussions
|
|
712
|
+
```typescript
|
|
713
|
+
const post = await streamer.query.getContent('author', 'permlink');
|
|
714
|
+
const replies = await streamer.query.getContentReplies('author', 'permlink');
|
|
715
|
+
const votes = await streamer.query.getActiveVotes('author', 'permlink');
|
|
716
|
+
|
|
717
|
+
const trending = await streamer.query.getTrending({ tag: 'hive', limit: 10 });
|
|
718
|
+
const hot = await streamer.query.getHot({ limit: 20 });
|
|
719
|
+
const newPosts = await streamer.query.getCreated({ tag: 'dev', limit: 10 });
|
|
720
|
+
const blog = await streamer.query.getBlog('alice');
|
|
721
|
+
const feed = await streamer.query.getFeed('alice');
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
### Social Graph
|
|
725
|
+
```typescript
|
|
726
|
+
const followers = await streamer.query.getFollowers('alice', '', 'blog', 100);
|
|
727
|
+
const following = await streamer.query.getFollowing('alice', '', 'blog', 100);
|
|
728
|
+
const counts = await streamer.query.getFollowCount('alice');
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
### Delegations & Vesting
|
|
732
|
+
```typescript
|
|
733
|
+
const delegations = await streamer.query.getVestingDelegations('alice');
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
### Account History
|
|
737
|
+
```typescript
|
|
738
|
+
const history = await streamer.query.getAccountHistory('alice', -1, 100);
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
### Market & Orders
|
|
742
|
+
```typescript
|
|
743
|
+
const orderBook = await streamer.query.getOrderBook(50);
|
|
744
|
+
const openOrders = await streamer.query.getOpenOrders('alice');
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
### Resource Credits & Voting Power
|
|
748
|
+
```typescript
|
|
749
|
+
const rc = await streamer.query.getRCMana('alice');
|
|
750
|
+
const vp = await streamer.query.getVPMana('alice');
|
|
751
|
+
const rcAccounts = await streamer.query.findRCAccounts(['alice', 'bob']);
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
### Communities & Notifications
|
|
755
|
+
```typescript
|
|
756
|
+
const community = await streamer.query.getCommunity('hive-12345');
|
|
757
|
+
const communities = await streamer.query.listCommunities({ limit: 50 });
|
|
758
|
+
const notifications = await streamer.query.getAccountNotifications('alice');
|
|
759
|
+
const subs = await streamer.query.listAllSubscriptions('alice');
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
### Witnesses
|
|
763
|
+
```typescript
|
|
764
|
+
const witness = await streamer.query.getWitnessByAccount('someguy');
|
|
765
|
+
const topWitnesses = await streamer.query.getWitnessesByVote('', 100);
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
### Blocks & Transactions
|
|
769
|
+
```typescript
|
|
770
|
+
const block = await streamer.query.getBlock(12345678);
|
|
771
|
+
const header = await streamer.query.getBlockHeader(12345678);
|
|
772
|
+
const ops = await streamer.query.getOperations(12345678);
|
|
773
|
+
const txStatus = await streamer.query.findTransaction('trx-id-here');
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
### Conversions & Savings
|
|
777
|
+
```typescript
|
|
778
|
+
const conversions = await streamer.query.getConversionRequests('alice');
|
|
779
|
+
const collateralized = await streamer.query.getCollateralizedConversionRequests('alice');
|
|
780
|
+
const savingsWithdrawals = await streamer.query.getSavingsWithdrawFrom('alice');
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
### Proposals & Account Lookup
|
|
784
|
+
```typescript
|
|
785
|
+
const proposals = await streamer.query.getProposals({ status: 'votable', limit: 50 });
|
|
786
|
+
const accounts = await streamer.query.lookupAccounts('ali', 10);
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
---
|
|
790
|
+
|
|
791
|
+
## Savings Operations
|
|
792
|
+
|
|
793
|
+
```typescript
|
|
794
|
+
// Transfer to savings
|
|
795
|
+
await streamer.transferToSavings('myaccount', 'myaccount', '100', 'HIVE');
|
|
796
|
+
await streamer.ops.transferToSavings().from('myaccount').hive(100).send();
|
|
797
|
+
|
|
798
|
+
// Transfer from savings (3-day delay)
|
|
799
|
+
await streamer.transferFromSavings('myaccount', 'myaccount', '50', 'HBD', 1);
|
|
800
|
+
await streamer.ops.transferFromSavings().from('myaccount').hbd(50).requestId(1).send();
|
|
801
|
+
|
|
802
|
+
// Cancel pending savings withdrawal
|
|
803
|
+
await streamer.cancelTransferFromSavings('myaccount', 1);
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
---
|
|
807
|
+
|
|
808
|
+
## Convert Operations
|
|
809
|
+
|
|
810
|
+
```typescript
|
|
811
|
+
// Convert HBD to HIVE (3.5-day delay)
|
|
812
|
+
await streamer.convert('myaccount', '10.000 HBD');
|
|
813
|
+
await streamer.ops.convert().from('myaccount').hbd(10).send();
|
|
814
|
+
|
|
815
|
+
// Collateralized convert HIVE to HBD (instant, with collateral)
|
|
816
|
+
await streamer.collateralizedConvert('myaccount', '10.000 HIVE');
|
|
817
|
+
await streamer.ops.collateralizedConvert().from('myaccount').hive(10).send();
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
---
|
|
821
|
+
|
|
822
|
+
## Market Operations
|
|
823
|
+
|
|
824
|
+
```typescript
|
|
825
|
+
// Create a limit order (sell HIVE for HBD)
|
|
826
|
+
await streamer.ops.limitOrder()
|
|
827
|
+
.owner('myaccount')
|
|
828
|
+
.amountToSell('10.000 HIVE')
|
|
829
|
+
.minToReceive('4.000 HBD')
|
|
830
|
+
.expiration(new Date(Date.now() + 7 * 24 * 60 * 60 * 1000))
|
|
831
|
+
.send();
|
|
832
|
+
|
|
833
|
+
// Cancel an order
|
|
834
|
+
await streamer.ops.cancelOrder().owner('myaccount').orderId(12345).send();
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
---
|
|
838
|
+
|
|
839
|
+
## Content Operations
|
|
840
|
+
|
|
841
|
+
```typescript
|
|
842
|
+
// Delete a post or comment
|
|
843
|
+
await streamer.deleteComment('myaccount', 'my-permlink');
|
|
844
|
+
await streamer.ops.deleteComment().author('myaccount').permlink('my-permlink').send();
|
|
845
|
+
|
|
846
|
+
// Set post options with beneficiaries
|
|
847
|
+
await streamer.ops.commentOptions()
|
|
848
|
+
.author('myaccount')
|
|
849
|
+
.permlink('my-post')
|
|
850
|
+
.maxAcceptedPayout('1000.000 HBD')
|
|
851
|
+
.percentHbd(5000)
|
|
852
|
+
.beneficiary('devfund', 500)
|
|
853
|
+
.beneficiary('curator', 1000)
|
|
854
|
+
.send();
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
---
|
|
858
|
+
|
|
859
|
+
## Vesting Withdrawal Routes
|
|
860
|
+
|
|
861
|
+
```typescript
|
|
862
|
+
// Route 50% of power-down to another account
|
|
863
|
+
await streamer.ops.withdrawRoute()
|
|
864
|
+
.from('myaccount')
|
|
865
|
+
.to('savings-account')
|
|
866
|
+
.percent(5000)
|
|
867
|
+
.autoVest(true) // Auto power-up at destination
|
|
868
|
+
.send();
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
---
|
|
872
|
+
|
|
873
|
+
## Witness Operations
|
|
874
|
+
|
|
875
|
+
```typescript
|
|
876
|
+
// Publish price feed (witnesses only)
|
|
877
|
+
await streamer.feedPublish('mywitness', '0.400 HBD', '1.000 HIVE');
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
---
|
|
881
|
+
|
|
882
|
+
## Additional Event Subscriptions
|
|
883
|
+
|
|
884
|
+
```typescript
|
|
885
|
+
// Watch follows/unfollows/mutes
|
|
886
|
+
streamer.onFollow((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
887
|
+
console.log(`${data.follower} ${data.what.length ? 'followed' : 'unfollowed'} ${data.following}`);
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
// Watch reblogs
|
|
891
|
+
streamer.onReblog((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
892
|
+
console.log(`${data.account} reblogged @${data.author}/${data.permlink}`);
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
// Watch account updates
|
|
896
|
+
streamer.onAccountUpdate((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
897
|
+
console.log(`${data.account} updated their account`);
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
// Watch comment deletions
|
|
901
|
+
streamer.onDeleteComment((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
902
|
+
console.log(`${data.author} deleted ${data.permlink}`);
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
// Watch market activity
|
|
906
|
+
streamer.onLimitOrder((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
907
|
+
console.log('Market order activity:', data);
|
|
908
|
+
});
|
|
909
|
+
|
|
910
|
+
// Watch savings transfers
|
|
911
|
+
streamer.onSavingsTransfer((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
912
|
+
console.log('Savings transfer:', data);
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
// Watch HBD/HIVE conversions
|
|
916
|
+
streamer.onConvert((data, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
|
|
917
|
+
console.log('Conversion:', data);
|
|
918
|
+
});
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
---
|
|
922
|
+
|
|
923
|
+
## Content Helpers
|
|
924
|
+
|
|
925
|
+
```typescript
|
|
926
|
+
import { Utils } from 'hive-stream';
|
|
927
|
+
|
|
928
|
+
// Generate a permlink from a title
|
|
929
|
+
const permlink = Utils.generatePermlink('My Awesome Post!'); // 'my-awesome-post'
|
|
930
|
+
|
|
931
|
+
// Generate a reply permlink
|
|
932
|
+
const replyPermlink = Utils.generateReplyPermlink('parent-post'); // 're-parent-post-20260318...'
|
|
933
|
+
|
|
934
|
+
// Create post metadata JSON
|
|
935
|
+
const metadata = Utils.createPostMetadata({
|
|
936
|
+
tags: ['hive', 'development'],
|
|
937
|
+
image: ['https://example.com/hero.png'],
|
|
938
|
+
description: 'A great post about Hive development',
|
|
939
|
+
app: 'my-app/1.0'
|
|
940
|
+
});
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
---
|
|
944
|
+
|
|
945
|
+
## Account Validation
|
|
946
|
+
|
|
947
|
+
```typescript
|
|
948
|
+
// Validate account name format
|
|
949
|
+
const error = Utils.validateAccountName('alice'); // null (valid)
|
|
950
|
+
const error2 = Utils.validateAccountName('AB'); // 'Account name must be at least 3 characters'
|
|
951
|
+
|
|
952
|
+
// Quick boolean check
|
|
953
|
+
const valid = Utils.isValidAccountName('alice'); // true
|
|
954
|
+
|
|
955
|
+
// Check if account exists on chain
|
|
956
|
+
const exists = await Utils.accountExists(client, 'alice'); // true/false
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
---
|
|
960
|
+
|
|
961
|
+
## URL & Link Parsing
|
|
962
|
+
|
|
963
|
+
```typescript
|
|
964
|
+
// Parse Hive URLs
|
|
965
|
+
Utils.parseHiveUrl('@alice/my-post');
|
|
966
|
+
// { author: 'alice', permlink: 'my-post' }
|
|
967
|
+
|
|
968
|
+
Utils.parseHiveUrl('https://hive.blog/hive-12345/@alice/my-post');
|
|
969
|
+
// { author: 'alice', permlink: 'my-post', category: 'hive-12345' }
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
---
|
|
973
|
+
|
|
974
|
+
## Voting Power & Vote Value
|
|
975
|
+
|
|
976
|
+
```typescript
|
|
977
|
+
// Calculate current voting mana %
|
|
978
|
+
const mana = Utils.calculateVotingMana(account); // 98.5
|
|
979
|
+
|
|
980
|
+
// Get effective vesting shares (own + received - delegated)
|
|
981
|
+
const effectiveVests = Utils.getEffectiveVestingShares(account);
|
|
982
|
+
|
|
983
|
+
// Estimate vote value in USD
|
|
984
|
+
const voteValue = Utils.estimateVoteValue(
|
|
985
|
+
mana, // current voting mana %
|
|
986
|
+
100, // vote weight %
|
|
987
|
+
effectiveVests, // effective vesting shares
|
|
988
|
+
rewardFund, // from query.getRewardFund()
|
|
989
|
+
medianPrice // from query.getCurrentMedianHistoryPrice()
|
|
990
|
+
);
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
---
|
|
994
|
+
|
|
995
|
+
## Memo Encryption
|
|
996
|
+
|
|
997
|
+
```typescript
|
|
998
|
+
// Encode a private memo
|
|
999
|
+
const encoded = Utils.encodeMemo(privateMemoKey, receiverPublicMemoKey, 'secret message');
|
|
1000
|
+
|
|
1001
|
+
// Decode a private memo
|
|
1002
|
+
const decoded = Utils.decodeMemo(privateMemoKey, encodedMemo);
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
---
|
|
1006
|
+
|
|
1007
|
+
## Post Builder
|
|
1008
|
+
|
|
1009
|
+
The post builder is the easiest way to create posts and replies on Hive. It atomically combines `comment` + `comment_options` in a single transaction, handling beneficiaries, metadata, communities, and more.
|
|
1010
|
+
|
|
1011
|
+
```typescript
|
|
1012
|
+
// Create a post with beneficiaries
|
|
1013
|
+
await streamer.ops.post()
|
|
1014
|
+
.author('alice')
|
|
1015
|
+
.title('My First dApp Post')
|
|
1016
|
+
.body('Hello from hive-stream!')
|
|
1017
|
+
.tags('hive', 'dev', 'tutorial')
|
|
1018
|
+
.community('hive-169321')
|
|
1019
|
+
.beneficiary('devfund', 500) // 5%
|
|
1020
|
+
.beneficiary('alice-savings', 1000) // 10%
|
|
1021
|
+
.maxAcceptedPayout(100, 'HBD')
|
|
1022
|
+
.percentHbd(5000) // 50% HBD
|
|
1023
|
+
.app('my-app/1.0')
|
|
1024
|
+
.image('https://example.com/hero.png')
|
|
1025
|
+
.description('A tutorial on building dApps')
|
|
1026
|
+
.metadata('canonical_url', 'https://myapp.com/posts/1')
|
|
1027
|
+
.send();
|
|
1028
|
+
|
|
1029
|
+
// Reply to a post
|
|
1030
|
+
await streamer.ops.post()
|
|
1031
|
+
.author('bob')
|
|
1032
|
+
.parentAuthor('alice')
|
|
1033
|
+
.parentPermlink('my-first-dapp-post')
|
|
1034
|
+
.body('Great post! Very helpful.')
|
|
1035
|
+
.send();
|
|
1036
|
+
|
|
1037
|
+
// Post with zero payout (decline rewards)
|
|
1038
|
+
await streamer.ops.post()
|
|
1039
|
+
.author('alice')
|
|
1040
|
+
.title('PSA: Important Announcement')
|
|
1041
|
+
.body('This is a community announcement.')
|
|
1042
|
+
.tags('psa')
|
|
1043
|
+
.maxAcceptedPayout(0, 'HBD')
|
|
1044
|
+
.send();
|
|
1045
|
+
```
|
|
1046
|
+
|
|
1047
|
+
---
|
|
1048
|
+
|
|
1049
|
+
## Batch Operations
|
|
1050
|
+
|
|
1051
|
+
Batch multiple operations into a single atomic transaction:
|
|
1052
|
+
|
|
1053
|
+
```typescript
|
|
1054
|
+
// Vote + comment in one transaction
|
|
1055
|
+
await streamer.batch()
|
|
1056
|
+
.vote('alice', 'bob', 'great-post', 10000)
|
|
1057
|
+
.comment('alice', 're-great-post-reply', 'bob', 'great-post', '', 'Love this!', '{}')
|
|
1058
|
+
.send();
|
|
1059
|
+
|
|
1060
|
+
// Multiple transfers in one transaction
|
|
1061
|
+
await streamer.batch()
|
|
1062
|
+
.transfer('alice', 'bob', '1.000 HIVE', 'payment 1')
|
|
1063
|
+
.transfer('alice', 'carol', '2.000 HIVE', 'payment 2')
|
|
1064
|
+
.transfer('alice', 'dave', '3.000 HIVE', 'payment 3')
|
|
1065
|
+
.send();
|
|
1066
|
+
|
|
1067
|
+
// Mix different operation types
|
|
1068
|
+
await streamer.batch()
|
|
1069
|
+
.add(['transfer', { from: 'alice', to: 'bob', amount: '1.000 HIVE', memo: '' }])
|
|
1070
|
+
.customJson('myapp', { action: 'register' }, 'alice')
|
|
1071
|
+
.send();
|
|
1072
|
+
```
|
|
1073
|
+
|
|
1074
|
+
---
|
|
1075
|
+
|
|
1076
|
+
## Authority Management
|
|
1077
|
+
|
|
1078
|
+
Manage posting authority for Hive apps:
|
|
1079
|
+
|
|
1080
|
+
```typescript
|
|
1081
|
+
// Check if an app has posting authority
|
|
1082
|
+
const hasAuth = await streamer.hasPostingAuth('alice', 'myapp');
|
|
1083
|
+
|
|
1084
|
+
// Grant posting authority to an app
|
|
1085
|
+
await streamer.grantPostingAuth('alice', 'myapp');
|
|
1086
|
+
|
|
1087
|
+
// Revoke posting authority
|
|
1088
|
+
await streamer.revokePostingAuth('alice', 'myapp');
|
|
1089
|
+
```
|
|
1090
|
+
|
|
1091
|
+
---
|
|
1092
|
+
|
|
1093
|
+
## Power Down Schedule
|
|
1094
|
+
|
|
1095
|
+
Calculate when power down payments arrive:
|
|
1096
|
+
|
|
1097
|
+
```typescript
|
|
1098
|
+
const schedule = Utils.calculatePowerDownSchedule(account);
|
|
1099
|
+
// [
|
|
1100
|
+
// { week: 1, date: 2026-03-25T..., amount: '1000.000000', vestingShares: '1000.000000 VESTS' },
|
|
1101
|
+
// { week: 2, date: 2026-04-01T..., amount: '1000.000000', vestingShares: '1000.000000 VESTS' },
|
|
1102
|
+
// ...up to 13 weeks
|
|
1103
|
+
// ]
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
---
|
|
1107
|
+
|
|
1108
|
+
## HBD Savings Interest
|
|
1109
|
+
|
|
1110
|
+
```typescript
|
|
1111
|
+
const interest = Utils.calculateHbdInterest(
|
|
1112
|
+
account.savings_hbd_balance, // '1000.000 HBD'
|
|
1113
|
+
account.savings_hbd_last_interest_payment,
|
|
1114
|
+
15 // current APR %
|
|
1115
|
+
);
|
|
1116
|
+
// '12.328' (pending interest in HBD)
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1119
|
+
---
|
|
1120
|
+
|
|
1121
|
+
## Payout Helpers
|
|
1122
|
+
|
|
1123
|
+
```typescript
|
|
1124
|
+
// Is the post still earning?
|
|
1125
|
+
Utils.isInPayoutWindow(post); // true/false
|
|
1126
|
+
|
|
1127
|
+
// How long until payout?
|
|
1128
|
+
Utils.timeUntilPayout(post); // milliseconds (0 if already paid)
|
|
1129
|
+
|
|
1130
|
+
// What's the payout value?
|
|
1131
|
+
Utils.getPendingPayout(post); // '10.500' (HBD)
|
|
1132
|
+
```
|
|
1133
|
+
|
|
1134
|
+
---
|
|
1135
|
+
|
|
1136
|
+
## Account Value Calculator
|
|
1137
|
+
|
|
1138
|
+
```typescript
|
|
1139
|
+
const value = Utils.calculateAccountValue(
|
|
1140
|
+
account,
|
|
1141
|
+
hivePrice, // e.g. 0.40 USD
|
|
1142
|
+
hbdPrice, // e.g. 1.00 USD
|
|
1143
|
+
totalVestingFundHive,
|
|
1144
|
+
totalVestingShares
|
|
1145
|
+
);
|
|
1146
|
+
// {
|
|
1147
|
+
// hive: 100, // liquid HIVE
|
|
1148
|
+
// hbd: 50, // liquid HBD
|
|
1149
|
+
// savings_hive: 200, // savings HIVE
|
|
1150
|
+
// savings_hbd: 100, // savings HBD
|
|
1151
|
+
// hp: 500, // Hive Power (HP)
|
|
1152
|
+
// total_hive: 800, // total in HIVE terms
|
|
1153
|
+
// total_usd: 470.0 // total in USD
|
|
1154
|
+
// }
|
|
1155
|
+
```
|
|
1156
|
+
|
|
1157
|
+
---
|
|
1158
|
+
|
|
1159
|
+
## Content Extraction
|
|
1160
|
+
|
|
1161
|
+
```typescript
|
|
1162
|
+
// Extract all images from a post body (for thumbnails, galleries)
|
|
1163
|
+
const images = Utils.extractImagesFromBody(post.body);
|
|
1164
|
+
// ['https://example.com/img1.png', 'https://example.com/img2.jpg']
|
|
1165
|
+
|
|
1166
|
+
// Extract all hyperlinks (excluding images)
|
|
1167
|
+
const links = Utils.extractLinksFromBody(post.body);
|
|
1168
|
+
|
|
1169
|
+
// Generate a plain-text summary (for previews, SEO)
|
|
1170
|
+
const summary = Utils.generatePostSummary(post.body, 200);
|
|
1171
|
+
// 'Hello world. This is a great post about...'
|
|
1172
|
+
```
|
|
1173
|
+
|
|
1174
|
+
---
|
|
1175
|
+
|
|
1176
|
+
## Hivesigner URLs
|
|
1177
|
+
|
|
1178
|
+
```typescript
|
|
1179
|
+
// Generate signing URLs for any operation
|
|
1180
|
+
const transferUrl = Utils.getTransferUrl('bob', 'thanks', '1.000 HIVE', 'https://myapp.com');
|
|
1181
|
+
const voteUrl = Utils.getVoteUrl('alice', 'bob', 'great-post', 10000);
|
|
1182
|
+
const delegateUrl = Utils.getDelegateUrl('alice', 'bob', '1000.000000 VESTS');
|
|
1183
|
+
const followUrl = Utils.getFollowUrl('alice', 'bob');
|
|
1184
|
+
|
|
1185
|
+
// Generic signing URL for any operation type
|
|
1186
|
+
const url = Utils.getHivesignerSignUrl('transfer', {
|
|
1187
|
+
from: 'alice', to: 'bob', amount: '1.000 HIVE'
|
|
1188
|
+
}, 'https://myapp.com/callback');
|
|
1189
|
+
```
|
|
1190
|
+
|
|
1191
|
+
---
|
|
1192
|
+
|
|
1193
|
+
## Transfer Memo Helpers
|
|
1194
|
+
|
|
1195
|
+
```typescript
|
|
1196
|
+
// Check if a memo is encrypted
|
|
1197
|
+
Utils.isEncryptedMemo('#encrypted-content'); // true
|
|
1198
|
+
Utils.isEncryptedMemo('regular memo'); // false
|
|
1199
|
+
|
|
1200
|
+
// Create structured JSON memos (for exchanges, apps)
|
|
1201
|
+
const memo = Utils.createJsonMemo({ action: 'deposit', orderId: 12345 });
|
|
1202
|
+
|
|
1203
|
+
// Parse JSON memos from transfers
|
|
1204
|
+
const data = Utils.parseJsonMemo('{"action":"deposit","orderId":12345}');
|
|
1205
|
+
// { action: 'deposit', orderId: 12345 }
|
|
1206
|
+
Utils.parseJsonMemo('regular memo'); // null
|
|
1207
|
+
```
|
|
1208
|
+
|
|
1209
|
+
---
|
|
1210
|
+
|
|
438
1211
|
## Utilities
|
|
439
|
-
The library includes helpers for JSON parsing, randomness, and transfer verification. See `src/utils.ts` for
|
|
1212
|
+
The library includes additional helpers for JSON parsing, randomness, seeded RNG, and transfer verification. See `src/utils.ts` for the complete API.
|
|
440
1213
|
|
|
441
1214
|
---
|
|
442
1215
|
|