hive-stream 3.0.0 → 3.0.1

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.
Files changed (101) hide show
  1. package/AGENTS.md +35 -0
  2. package/DOCUMENTATION.md +380 -0
  3. package/README.md +113 -22
  4. package/dist/actions.d.ts +3 -3
  5. package/dist/actions.js +7 -7
  6. package/dist/actions.js.map +1 -1
  7. package/dist/adapters/base.adapter.d.ts +19 -1
  8. package/dist/adapters/base.adapter.js +16 -0
  9. package/dist/adapters/base.adapter.js.map +1 -1
  10. package/dist/adapters/mongodb.adapter.d.ts +5 -11
  11. package/dist/adapters/mongodb.adapter.js +10 -10
  12. package/dist/adapters/mongodb.adapter.js.map +1 -1
  13. package/dist/adapters/postgresql.adapter.d.ts +17 -0
  14. package/dist/adapters/postgresql.adapter.js +99 -8
  15. package/dist/adapters/postgresql.adapter.js.map +1 -1
  16. package/dist/adapters/sqlite.adapter.d.ts +17 -0
  17. package/dist/adapters/sqlite.adapter.js +99 -8
  18. package/dist/adapters/sqlite.adapter.js.map +1 -1
  19. package/dist/api.js +86 -0
  20. package/dist/api.js.map +1 -1
  21. package/dist/config.d.ts +3 -0
  22. package/dist/config.js +6 -3
  23. package/dist/config.js.map +1 -1
  24. package/dist/contracts/coinflip.contract.d.ts +8 -26
  25. package/dist/contracts/coinflip.contract.js +123 -144
  26. package/dist/contracts/coinflip.contract.js.map +1 -1
  27. package/dist/contracts/contract.d.ts +3 -0
  28. package/dist/contracts/contract.js +26 -0
  29. package/dist/contracts/contract.js.map +1 -0
  30. package/dist/contracts/dice.contract.d.ts +9 -36
  31. package/dist/contracts/dice.contract.js +135 -200
  32. package/dist/contracts/dice.contract.js.map +1 -1
  33. package/dist/contracts/exchange.contract.d.ts +11 -0
  34. package/dist/contracts/exchange.contract.js +492 -0
  35. package/dist/contracts/exchange.contract.js.map +1 -0
  36. package/dist/contracts/lotto.contract.d.ts +15 -19
  37. package/dist/contracts/lotto.contract.js +154 -162
  38. package/dist/contracts/lotto.contract.js.map +1 -1
  39. package/dist/contracts/nft.contract.d.ts +4 -0
  40. package/dist/contracts/nft.contract.js +65 -0
  41. package/dist/contracts/nft.contract.js.map +1 -1
  42. package/dist/contracts/poll.contract.d.ts +4 -0
  43. package/dist/contracts/poll.contract.js +105 -0
  44. package/dist/contracts/poll.contract.js.map +1 -0
  45. package/dist/contracts/rps.contract.d.ts +9 -0
  46. package/dist/contracts/rps.contract.js +217 -0
  47. package/dist/contracts/rps.contract.js.map +1 -0
  48. package/dist/contracts/tipjar.contract.d.ts +4 -0
  49. package/dist/contracts/tipjar.contract.js +60 -0
  50. package/dist/contracts/tipjar.contract.js.map +1 -0
  51. package/dist/contracts/token.contract.d.ts +3 -17
  52. package/dist/contracts/token.contract.js +128 -80
  53. package/dist/contracts/token.contract.js.map +1 -1
  54. package/dist/exchanges/coingecko.d.ts +7 -1
  55. package/dist/exchanges/coingecko.js +38 -21
  56. package/dist/exchanges/coingecko.js.map +1 -1
  57. package/dist/exchanges/exchange.d.ts +15 -8
  58. package/dist/exchanges/exchange.js +65 -11
  59. package/dist/exchanges/exchange.js.map +1 -1
  60. package/dist/hive-rates.d.ts +29 -4
  61. package/dist/hive-rates.js +179 -92
  62. package/dist/hive-rates.js.map +1 -1
  63. package/dist/index.d.ts +10 -3
  64. package/dist/index.js +18 -4
  65. package/dist/index.js.map +1 -1
  66. package/dist/streamer.d.ts +101 -8
  67. package/dist/streamer.js +410 -140
  68. package/dist/streamer.js.map +1 -1
  69. package/dist/test.js +11 -12
  70. package/dist/test.js.map +1 -1
  71. package/dist/types/hive-stream.d.ts +85 -14
  72. package/dist/types/rates.d.ts +47 -0
  73. package/dist/types/rates.js +29 -0
  74. package/dist/types/rates.js.map +1 -0
  75. package/dist/utils.d.ts +318 -11
  76. package/dist/utils.js +804 -115
  77. package/dist/utils.js.map +1 -1
  78. package/examples/contracts/README.md +8 -0
  79. package/examples/contracts/exchange.ts +38 -0
  80. package/examples/contracts/poll.ts +21 -0
  81. package/examples/contracts/rps.ts +19 -0
  82. package/examples/contracts/tipjar.ts +19 -0
  83. package/package.json +20 -19
  84. package/tests/actions.spec.ts +7 -7
  85. package/tests/adapters/actions-persistence.spec.ts +4 -4
  86. package/tests/adapters/sqlite.adapter.spec.ts +2 -2
  87. package/tests/contracts/coinflip.contract.spec.ts +26 -154
  88. package/tests/contracts/dice.contract.spec.ts +24 -140
  89. package/tests/contracts/exchange.contract.spec.ts +84 -0
  90. package/tests/contracts/lotto.contract.spec.ts +30 -295
  91. package/tests/contracts/token.contract.spec.ts +72 -316
  92. package/tests/exchanges/coingecko.exchange.spec.ts +169 -0
  93. package/tests/exchanges/exchange.base.spec.ts +246 -0
  94. package/tests/helpers/mock-fetch.ts +165 -0
  95. package/tests/hive-chain-features.spec.ts +238 -0
  96. package/tests/hive-rates.spec.ts +443 -0
  97. package/tests/integration/hive-rates.integration.spec.ts +35 -0
  98. package/tests/streamer-actions.spec.ts +29 -18
  99. package/tests/streamer.spec.ts +142 -49
  100. package/tests/types/rates.spec.ts +216 -0
  101. package/tests/utils.spec.ts +27 -6
package/AGENTS.md ADDED
@@ -0,0 +1,35 @@
1
+ # Repository Guidelines
2
+
3
+ ## Project Structure & Module Organization
4
+ - `src/` holds TypeScript source. Core entry points are `streamer.ts`, `api.ts`, and `index.ts`.
5
+ - `src/adapters/` contains SQLite/Mongo/Postgres adapters; `src/contracts/` has contract examples; `src/exchanges/` has rate helpers; `src/types/` centralizes shared types.
6
+ - `tests/` contains Jest specs (`**/*.spec.ts`) plus `tests/integration/` and `tests/helpers/`.
7
+ - `dist/` is generated build output; `examples/` provides usage samples; `ecosystem.config.js` is a PM2 reference.
8
+
9
+ ## Build, Test, and Development Commands
10
+ - `npm install` installs dependencies.
11
+ - `npm run build` compiles TypeScript to `dist/`.
12
+ - `npm run start` runs the local dev harness (`src/test.ts`) via ts-node.
13
+ - `npm run watch` enables TypeScript watch mode.
14
+ - `npm test` runs the Jest suite.
15
+ - `npm run clean-tests` clears Jest cache if tests act stale.
16
+
17
+ ## Coding Style & Naming Conventions
18
+ - TypeScript with CommonJS output; keep module boundaries within `src/`.
19
+ - Indent 4 spaces; prefer single quotes (see `tslint.json`).
20
+ - File naming conventions: `*.adapter.ts`, `*.contract.ts`, `*.spec.ts`; shared types live in `src/types/`.
21
+ - TSLint rules in `tslint.json` are the baseline; match existing style before introducing new tooling.
22
+
23
+ ## Testing Guidelines
24
+ - Framework: Jest + `ts-jest` (see `jest.config.js`).
25
+ - Place specs under `tests/` and name `*.spec.ts` (example: `tests/utils.spec.ts`).
26
+ - Use `tests/setup.ts` for shared mocks; integration tests live under `tests/integration/`.
27
+ - No coverage thresholds are configured; add focused tests for new adapters, contracts, or API routes.
28
+
29
+ ## Commit & Pull Request Guidelines
30
+ - Follow Conventional Commits with scopes, as in history: `feat(api): ...`, `fix(contract): ...`, `chore(deps): ...`, `docs(readme): ...`.
31
+ - PRs should include: a clear summary, testing notes (`npm test`/`npm run build`), and docs/CHANGELOG updates for user-facing changes.
32
+
33
+ ## Configuration & Security Notes
34
+ - Keys and usernames should come from env/config (see `src/config.ts`); never commit secrets.
35
+ - When adding new config, document defaults and keep backward compatibility.
@@ -0,0 +1,380 @@
1
+ # Hive-Stream Documentation
2
+
3
+ ## Introduction
4
+ Hive Stream is a Node.js library for streaming Hive blockchain activity and routing it to contracts you define. Contracts can react to:
5
+ - `custom_json` operations
6
+ - transfer memos
7
+ - time-based actions
8
+ - escrow operations
9
+
10
+ This document focuses on the contract system and how to build robust contracts using the new `defineContract`/`action` API.
11
+
12
+ ---
13
+
14
+ ## Concepts
15
+
16
+ ### Contracts
17
+ A **contract** is a definition object with:
18
+ - a **name**
19
+ - one or more **actions**
20
+ - optional **lifecycle hooks**
21
+
22
+ Contracts are registered with the `Streamer` and called when a payload matches `contract` + `action`.
23
+
24
+ ### Actions
25
+ An **action** is a handler function plus metadata such as:
26
+ - the trigger (`custom_json`, `transfer`, or `time`)
27
+ - the trigger (`custom_json`, `transfer`, `time`, `escrow_transfer`, `escrow_approve`, `escrow_dispute`, `escrow_release`, or `recurrent_transfer`)
28
+ - an optional Zod schema to validate payloads
29
+ - whether it requires an active key signature
30
+
31
+ ### Payload Identifier
32
+ Hive Stream extracts payloads from:
33
+ - **custom_json**: `op[1].json`
34
+ - **transfer memo**: `op[1].memo`
35
+
36
+ It expects a wrapper object that looks like:
37
+
38
+ ```
39
+ {
40
+ "hive_stream": {
41
+ "contract": "mycontract",
42
+ "action": "doSomething",
43
+ "payload": { "any": "data" },
44
+ "meta": { "optional": true }
45
+ }
46
+ }
47
+ ```
48
+
49
+ The wrapper key `hive_stream` is the default `PAYLOAD_IDENTIFIER`. You can change it in config.
50
+
51
+ ---
52
+
53
+ ## Contract API
54
+
55
+ ### Define a Contract
56
+
57
+ ```ts
58
+ import { defineContract, action } from 'hive-stream';
59
+
60
+ const MyContract = defineContract({
61
+ name: 'mycontract',
62
+ actions: {
63
+ hello: action(async (payload, ctx) => {
64
+ console.log('hello', payload.name, ctx.sender);
65
+ }, {
66
+ trigger: 'custom_json'
67
+ })
68
+ }
69
+ });
70
+ ```
71
+
72
+ ### Register a Contract
73
+
74
+ ```ts
75
+ import { Streamer } from 'hive-stream';
76
+
77
+ const streamer = new Streamer();
78
+ await streamer.registerContract(MyContract);
79
+ ```
80
+
81
+ ### Unregister a Contract
82
+
83
+ ```ts
84
+ await streamer.unregisterContract('mycontract');
85
+ ```
86
+
87
+ ### Contract Lifecycle Hooks
88
+
89
+ ```ts
90
+ const MyContract = defineContract({
91
+ name: 'mycontract',
92
+ hooks: {
93
+ create: async ({ streamer, adapter, config }) => {
94
+ // initialize tables, cache config, etc
95
+ },
96
+ destroy: async ({ streamer, adapter }) => {
97
+ // cleanup resources
98
+ }
99
+ },
100
+ actions: { ... }
101
+ });
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Contract Context
107
+
108
+ Every action receives a `ContractContext` with:
109
+
110
+ - `trigger`: `custom_json | transfer | time | escrow_transfer | escrow_approve | escrow_dispute | escrow_release | recurrent_transfer`
111
+ - `streamer`: access to Hive client and helpers
112
+ - `adapter`: database adapter
113
+ - `config`: resolved config values
114
+ - `block`: `{ number, id, previousId, time }`
115
+ - `transaction`: `{ id }`
116
+ - `sender`: Hive account invoking the action
117
+ - `transfer`: transfer details (only for `transfer` trigger)
118
+ - `customJson`: custom JSON details (only for `custom_json` trigger)
119
+ - `escrow`: escrow details (only for escrow triggers)
120
+ - `operation`: raw operation data and operation type for advanced use cases
121
+
122
+ ### Example
123
+
124
+ ```ts
125
+ action((payload, ctx) => {
126
+ console.log(ctx.trigger);
127
+ console.log(ctx.block.number, ctx.transaction.id);
128
+ if (ctx.transfer) {
129
+ console.log(ctx.transfer.amount, ctx.transfer.asset);
130
+ }
131
+ });
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Payload Validation (Zod)
137
+
138
+ Use Zod to validate payloads and enforce strong inputs:
139
+
140
+ ```ts
141
+ import { z } from 'zod';
142
+
143
+ const schema = z.object({
144
+ amount: z.string().min(1),
145
+ to: z.string().min(1)
146
+ });
147
+
148
+ const MyContract = defineContract({
149
+ name: 'payments',
150
+ actions: {
151
+ send: action((payload, ctx) => {
152
+ // payload is validated here
153
+ }, { schema, trigger: 'custom_json' })
154
+ }
155
+ });
156
+ ```
157
+
158
+ If validation fails, the action is not executed and the error is logged.
159
+
160
+ ---
161
+
162
+ ## Triggers
163
+
164
+ Actions can be scoped to a trigger:
165
+
166
+ - `custom_json`: called when a custom JSON payload matches
167
+ - `transfer`: called when a transfer memo matches
168
+ - `time`: called by a `TimeAction`
169
+ - `escrow_transfer`: called when escrow transfer payload in `json_meta` matches
170
+ - `escrow_approve`: available as a trigger for escrow-related contracts
171
+ - `escrow_dispute`: available as a trigger for escrow-related contracts
172
+ - `escrow_release`: available as a trigger for escrow-related contracts
173
+ - `recurrent_transfer`: called when recurrent transfer memo payload matches
174
+
175
+ ```ts
176
+ action(handler, { trigger: 'transfer' });
177
+ ```
178
+
179
+ You can also allow multiple triggers:
180
+
181
+ ```ts
182
+ action(handler, { trigger: ['custom_json', 'transfer'] });
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Active Key Enforcement
188
+
189
+ Some actions should only run when the transaction is signed with an active key. Mark them with:
190
+
191
+ ```ts
192
+ action(handler, { trigger: 'custom_json', requiresActiveKey: true });
193
+ ```
194
+
195
+ This prevents posting-key JSONs from triggering sensitive actions like withdrawals.
196
+
197
+ ---
198
+
199
+ ## Error Handling
200
+
201
+ - Errors inside contract actions are caught and logged.
202
+ - **Time actions** bubble errors back into the scheduler so the action does **not** increment execution count if it fails.
203
+
204
+ Write actions defensively and always validate inputs.
205
+
206
+ ---
207
+
208
+ ## Time-Based Actions
209
+
210
+ Time-based actions let you run contract logic on a schedule:
211
+
212
+ ```ts
213
+ import { TimeAction } from 'hive-stream';
214
+
215
+ const matchAction = new TimeAction('30s', 'exchange-matcher', 'exchange', 'matchOrders', { limit: 50 });
216
+ await streamer.registerAction(matchAction);
217
+ ```
218
+
219
+ The action must have `trigger: 'time'` in its definition.
220
+
221
+ ---
222
+
223
+ ## Adapter Requirements
224
+
225
+ Contracts can use any adapter, but some require SQL features:
226
+
227
+ - **SQL adapters** (SQLite/Postgres) support `adapter.query(...)`.
228
+ - **MongoDB adapter** does not support raw SQL.
229
+
230
+ If a contract uses `adapter.query`, it must document that it requires a SQL adapter.
231
+
232
+ ---
233
+
234
+ ## Building Contracts Step-by-Step
235
+
236
+ 1. **Define the contract** with `defineContract`.
237
+ 2. **Define actions** with `action`, specifying trigger and optional schema.
238
+ 3. **Use hooks** (`create`, `destroy`) to initialize tables or cache configuration.
239
+ 4. **Validate input** using Zod.
240
+ 5. **Use `ctx`** for block/transaction context.
241
+ 6. **Return void** (actions are fire-and-forget).
242
+ 7. **Register the contract** with the streamer.
243
+
244
+ ---
245
+
246
+ ## Example Contract
247
+
248
+ ```ts
249
+ import { defineContract, action } from 'hive-stream';
250
+ import { z } from 'zod';
251
+
252
+ const tipSchema = z.object({
253
+ message: z.string().max(280).optional()
254
+ });
255
+
256
+ export const TipJar = defineContract({
257
+ name: 'tipjar',
258
+ actions: {
259
+ tip: action(async (payload, ctx) => {
260
+ if (!ctx.transfer) {
261
+ throw new Error('Transfer context required');
262
+ }
263
+
264
+ console.log(`Tip from ${ctx.sender}: ${ctx.transfer.amount} ${ctx.transfer.asset}`);
265
+ if (payload.message) {
266
+ console.log(`Message: ${payload.message}`);
267
+ }
268
+ }, {
269
+ schema: tipSchema,
270
+ trigger: 'transfer'
271
+ })
272
+ }
273
+ });
274
+ ```
275
+
276
+ ---
277
+
278
+ ## Built-in Contract Examples
279
+
280
+ - `createDiceContract` - Dice game using transfer bets
281
+ - `createCoinflipContract` - Coin flip game using transfer bets
282
+ - `createLottoContract` - Lottery system with scheduled draws
283
+ - `createTokenContract` - SQL-backed fungible tokens
284
+ - `createNFTContract` - SQL-backed NFTs
285
+ - `createRpsContract` - Rock/Paper/Scissors
286
+ - `createPollContract` - Polls and votes
287
+ - `createTipJarContract` - Tip jar + message log
288
+ - `createExchangeContract` - Deposits/withdrawals/orders/matching (SQL)
289
+
290
+ ### Example Snippets
291
+
292
+ Quick-start snippets live in `examples/contracts/`:
293
+
294
+ - `examples/contracts/rps.ts`
295
+ - `examples/contracts/poll.ts`
296
+ - `examples/contracts/tipjar.ts`
297
+ - `examples/contracts/exchange.ts`
298
+
299
+ ---
300
+
301
+ ## Exchange Contract Guide
302
+
303
+ The exchange contract gives you a basic on-chain orderbook experience backed by a SQL adapter.
304
+
305
+ ### Features
306
+ - Deposits via transfer memo
307
+ - Internal balances (available + locked)
308
+ - Order placement and cancellation
309
+ - Order matching
310
+ - Withdrawals (active key required)
311
+ - Internal transfers between exchange users
312
+ - Maker/taker fees (basis points)
313
+ - Order book snapshots for API consumption
314
+
315
+ ### Notes
316
+ - Requires a SQL adapter (SQLite or Postgres).
317
+ - Uses `TimeAction` to run `matchOrders` periodically.
318
+ - Fees are charged on received assets (base for buyers, quote for sellers).
319
+
320
+ ### Configuration Options
321
+ ```
322
+ createExchangeContract({
323
+ name: 'exchange',
324
+ account: 'my-exchange',
325
+ feeAccount: 'my-exchange-fees',
326
+ makerFeeBps: 10,
327
+ takerFeeBps: 20
328
+ })
329
+ ```
330
+
331
+ ### Example Payloads
332
+
333
+ **Create pair**
334
+ ```
335
+ {"hive_stream": {"contract":"exchange","action":"createPair","payload":{"base":"HIVE","quote":"HBD"}}}
336
+ ```
337
+
338
+ **Deposit** (send transfer to exchange account with memo)
339
+ ```
340
+ {"hive_stream": {"contract":"exchange","action":"deposit","payload":{}}}
341
+ ```
342
+
343
+ **Place order**
344
+ ```
345
+ {"hive_stream": {"contract":"exchange","action":"placeOrder","payload":{"side":"buy","base":"HIVE","quote":"HBD","price":"2","amount":"5"}}}
346
+ ```
347
+
348
+ **Cancel order**
349
+ ```
350
+ {"hive_stream": {"contract":"exchange","action":"cancelOrder","payload":{"orderId":"..."}}}
351
+ ```
352
+
353
+ **Snapshot orderbook**
354
+ ```
355
+ {"hive_stream": {"contract":"exchange","action":"snapshotOrderBook","payload":{"base":"HIVE","quote":"HBD","depth":20}}}
356
+ ```
357
+
358
+ **Withdraw**
359
+ ```
360
+ {"hive_stream": {"contract":"exchange","action":"withdraw","payload":{"asset":"HBD","amount":"5.000"}}}
361
+ ```
362
+
363
+ ### API Endpoints
364
+
365
+ If you run the built-in API server, the following endpoints are available:
366
+
367
+ - `GET /exchange/balances` (optional query `?account=alice`)
368
+ - `GET /exchange/orders` (query `account`, `base`, `quote`, `status`)
369
+ - `GET /exchange/trades` (query `account`, `base`, `quote`)
370
+ - `GET /exchange/orderbook` (query `base`, `quote`, `limit`)
371
+
372
+ ---
373
+
374
+ ## Utilities
375
+ The library includes helpers for JSON parsing, randomness, and transfer verification. See `src/utils.ts` for details.
376
+
377
+ ---
378
+
379
+ ## Tests
380
+ Contract tests live under `tests/contracts/`. Time action tests are in `tests/streamer-actions.spec.ts`.
package/README.md CHANGED
@@ -29,6 +29,10 @@ The `BLOCK_CHECK_INTERVAL` value is how often to check for new blocks or in case
29
29
 
30
30
  The `BLOCKS_BEHIND_WARNING` value is a numeric value of the number of blocks your API will fall behind from the master before warning to the console.
31
31
 
32
+ To resume automatically from stored state, keep `RESUME_FROM_STATE` enabled (default). To force a specific start block, set `RESUME_FROM_STATE` to `false` and supply `LAST_BLOCK_NUMBER`.
33
+
34
+ For faster catch-up, `CATCH_UP_BATCH_SIZE` controls how many blocks are processed per polling cycle, and `CATCH_UP_DELAY_MS` controls the delay between catch-up batches (set to `0` for fastest catch-up).
35
+
32
36
  The `API_NODES` are the Hive API endpoints used for failover. If you want to enable debug mode, set `DEBUG_MODE` to `true`. The configuration values and their defaults can be found in `src/config.ts`.
33
37
 
34
38
  ```
@@ -40,6 +44,9 @@ const options = {
40
44
  LAST_BLOCK_NUMBER: 0,
41
45
  BLOCK_CHECK_INTERVAL: 1000,
42
46
  BLOCKS_BEHIND_WARNING: 25,
47
+ RESUME_FROM_STATE: true,
48
+ CATCH_UP_BATCH_SIZE: 50,
49
+ CATCH_UP_DELAY_MS: 0,
43
50
  API_NODES: ['https://api.hive.blog', 'https://api.openhive.network', 'https://rpc.ausbit.dev'],
44
51
  DEBUG_MODE: false
45
52
  }
@@ -70,6 +77,25 @@ ss.onTransfer((op, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
70
77
  })
71
78
  ```
72
79
 
80
+ #### Watch for escrow operations
81
+ ```javascript
82
+ ss.onEscrowTransfer((op, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
83
+
84
+ });
85
+
86
+ ss.onEscrowApprove((op, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
87
+
88
+ });
89
+
90
+ ss.onEscrowDispute((op, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
91
+
92
+ });
93
+
94
+ ss.onEscrowRelease((op, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
95
+
96
+ });
97
+ ```
98
+
73
99
  #### Watch for custom JSON operations
74
100
  ```javascript
75
101
  ss.onCustomJson((op, { sender, isSignedWithActiveKey }, blockNumber, blockId, prevBlockId, trxId, blockTime) => {
@@ -145,6 +171,42 @@ issueHiveEngineTokensMultiple(from, accounts = [], symbol, memo = '', amount = '
145
171
  }
146
172
  ```
147
173
 
174
+ ### Escrow Operations
175
+ ```javascript
176
+ escrowTransfer({
177
+ from,
178
+ to,
179
+ agent,
180
+ escrow_id,
181
+ hive_amount = '0.000 HIVE',
182
+ hbd_amount = '0.000 HBD',
183
+ fee,
184
+ ratification_deadline,
185
+ escrow_expiration,
186
+ json_meta
187
+ }, signingKeys?)
188
+
189
+ escrowApprove({ from, to, agent, who, escrow_id, approve }, signingKeys?)
190
+ escrowDispute({ from, to, agent, who, escrow_id }, signingKeys?)
191
+ escrowRelease({ from, to, agent, who, receiver, escrow_id, hive_amount, hbd_amount }, signingKeys?)
192
+ ```
193
+
194
+ ### Multisig + Authority Helpers
195
+ ```javascript
196
+ broadcastOperations(operations, signingKeys?)
197
+ broadcastMultiSigOperations(operations, signingKeys)
198
+ createAuthority(keyAuths, accountAuths, weightThreshold)
199
+ updateAccountAuthorities(account, authorityUpdate, signingKeys?)
200
+ ```
201
+
202
+ ### Recurrent Transfers + Governance
203
+ ```javascript
204
+ recurrentTransfer({ from, to, amount, memo, recurrence, executions }, signingKeys?)
205
+ createProposal({ creator, receiver, start_date, end_date, daily_pay, subject, permlink }, signingKeys?)
206
+ updateProposalVotes({ voter, proposal_ids, approve }, signingKeys?)
207
+ removeProposals({ proposal_owner, proposal_ids }, signingKeys?)
208
+ ```
209
+
148
210
  ### Upvote/Downvote Posts
149
211
  ```javascript
150
212
  upvote(votePercentage = '100.0', username, permlink) {
@@ -158,28 +220,38 @@ downvote(votePercentage = '100.0', username, permlink) {
158
220
 
159
221
  ## Contracts
160
222
 
161
- Hive Stream allows you to write contracts which get executed when a custom JSON operation matches. The only requirement is sending a payload which contains `hivePayload` inside of it.
162
-
163
- The payload consists of:
164
-
165
- `name` the name of the smart contract you registered.
223
+ Hive Stream allows you to register contract definitions that execute when a transfer memo or custom JSON operation matches. The payload lives under the `PAYLOAD_IDENTIFIER` (default: `hive_stream`).
166
224
 
167
- `action` matches the name of a function defined inside of your contract
225
+ The payload shape is:
168
226
 
169
- `payload` an object of data which will be provided to the action
227
+ - `contract`: the name of the contract you registered
228
+ - `action`: the action name defined in your contract
229
+ - `payload`: data passed to the action
230
+ - `meta`: optional metadata
170
231
 
171
232
  ### Writing contracts
172
233
 
173
- Really, a contract is nothing more than a bunch of functions which get matched to values inside of JSON payloads.
234
+ Contracts are defined with `defineContract` + `action`. Each action can specify a trigger (`custom_json`, `transfer`, `time`, `escrow_transfer`, `escrow_approve`, `escrow_dispute`, `escrow_release`, or `recurrent_transfer`) and an optional Zod schema for payload validation.
235
+
236
+ For a full contract-building guide (payloads, context, triggers, validation, error handling, and exchange setup), see `DOCUMENTATION.md`.
174
237
 
175
238
  ### Register a contract
176
239
 
177
- Register a file containing contract code which will be executed.
240
+ Register a contract definition. Registration is async so hooks can initialize state.
178
241
 
179
242
  ```javascript
180
- import contract from './my-contract';
243
+ import { defineContract, action } from 'hive-stream';
244
+
245
+ const MyContract = defineContract({
246
+ name: 'mycontract',
247
+ actions: {
248
+ hello: action(async (payload, ctx) => {
249
+ console.log('hello', payload, ctx.sender);
250
+ }, { trigger: 'custom_json' })
251
+ }
252
+ });
181
253
 
182
- registerContract('mycontract', Contract);
254
+ await streamer.registerContract(MyContract);
183
255
  ```
184
256
 
185
257
  ### Unregister a contract
@@ -187,33 +259,52 @@ registerContract('mycontract', Contract);
187
259
  Unregister a contract that has been registered.
188
260
 
189
261
  ```javascript
190
- unregisterContract('mycontract');
262
+ await streamer.unregisterContract('mycontract');
191
263
  ```
192
264
 
193
265
  ### Example Payload
194
266
 
195
267
  ```javascript
196
- JSON.stringify({ hivePayload: { name: 'hivedice', action: 'roll', payload: { roll: 22, amount: '1'} } })
268
+ JSON.stringify({
269
+ hive_stream: {
270
+ contract: 'hivedice',
271
+ action: 'roll',
272
+ payload: { roll: 22 }
273
+ }
274
+ })
197
275
  ```
198
276
 
199
- This will match a registered contract called `hivedice` and inside of the contract code, a function called `roll` and finally, the payload is sent to the function as an argument, allowing you to access the values inside of it.
277
+ This will match a registered contract called `hivedice`, run the `roll` action, and pass the payload into your handler.
200
278
 
201
279
  ### Built-in Contract Examples
202
280
 
203
281
  The library includes several built-in contract examples in the `src/contracts` folder:
204
282
 
205
- - `DiceContract` - A dice rolling game contract
206
- - `CoinflipContract` - A coin flip game contract
207
- - `LottoContract` - A lottery-style game contract
208
- - `TokenContract` - A contract for token operations
209
- - `NFTContract` - A contract for NFT operations
283
+ - `createDiceContract` - A dice rolling game contract
284
+ - `createCoinflipContract` - A coin flip game contract
285
+ - `createLottoContract` - A lottery-style game contract
286
+ - `createTokenContract` - A contract for token operations
287
+ - `createNFTContract` - A contract for NFT operations
288
+ - `createRpsContract` - A rock-paper-scissors game contract
289
+ - `createPollContract` - A poll/voting contract
290
+ - `createTipJarContract` - A tip jar + message board contract
291
+ - `createExchangeContract` - A basic exchange with deposits, withdrawals, balances, and order matching (SQL adapter required)
210
292
 
211
293
  These can be imported and used as examples for building your own contracts:
212
294
 
213
295
  ```javascript
214
- import { DiceContract, CoinflipContract, LottoContract } from 'hive-stream';
296
+ import { createDiceContract, createCoinflipContract, createLottoContract } from 'hive-stream';
215
297
  ```
216
298
 
299
+ ### Example Snippets
300
+
301
+ Sample snippets for the newest contracts live in `examples/contracts/`:
302
+
303
+ - `examples/contracts/rps.ts`
304
+ - `examples/contracts/poll.ts`
305
+ - `examples/contracts/tipjar.ts`
306
+ - `examples/contracts/exchange.ts`
307
+
217
308
  ## Time-based Actions
218
309
 
219
310
  It's like a cron job for your contracts. Time-based actions allow you to execute contract functions over a wide variety of different periods. Want to call a function every 3 seconds block time or want to call a function once per day? Time-based actions are an easy way to run time code.
@@ -239,11 +330,11 @@ The `TimeAction` instance accepts the following values:
239
330
  - timeValue - When should this action be run?
240
331
  - uniqueId - A unique ID to describe your action
241
332
  - contractName - The name of the contract
242
- - contractMethod - The method we are calling inside of the contract
333
+ - contractAction - The action we are calling inside of the contract
243
334
  - date - An optional final parameter that accepts a date of creation
244
335
 
245
336
  ```
246
- new TimeAction(timeValue, uniqueId, contractName, contractMethod, date)
337
+ new TimeAction(timeValue, uniqueId, contractName, contractAction, date)
247
338
  ```
248
339
 
249
340
  ### Valid time values
package/dist/actions.d.ts CHANGED
@@ -2,7 +2,7 @@ export interface TimeActionInterface {
2
2
  timeValue: string;
3
3
  id: string;
4
4
  contractName: string;
5
- contractMethod: string;
5
+ contractAction: string;
6
6
  payload: any;
7
7
  date: Date;
8
8
  enabled: boolean;
@@ -15,7 +15,7 @@ export declare class TimeAction implements TimeActionInterface {
15
15
  timeValue: string;
16
16
  id: string;
17
17
  contractName: string;
18
- contractMethod: string;
18
+ contractAction: string;
19
19
  payload: any;
20
20
  date: Date;
21
21
  enabled: boolean;
@@ -24,7 +24,7 @@ export declare class TimeAction implements TimeActionInterface {
24
24
  maxExecutions?: number;
25
25
  timezone?: string;
26
26
  private static readonly VALID_TIME_VALUES;
27
- constructor(timeValue: string, id: string, contractName: string, contractMethod: string, payload?: any, date?: Date | string, enabled?: boolean, executionCount?: number, maxExecutions?: number, timezone?: string);
27
+ constructor(timeValue: string, id: string, contractName: string, contractAction: string, payload?: any, date?: Date | string, enabled?: boolean, executionCount?: number, maxExecutions?: number, timezone?: string);
28
28
  private validateTimeValue;
29
29
  private validateId;
30
30
  private validateContractName;