@msgboard/sdk 0.0.28

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/README.md ADDED
@@ -0,0 +1,314 @@
1
+ # @msgboard/sdk
2
+
3
+ Distribute ephemeral messages across EVM networks using proof of work as the gate — no gas, no token, no account. You mint your own proof-of-work "stamp" for each message; that stamp is what keeps the board spam-resistant.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm i --save @msgboard/sdk
9
+ ```
10
+
11
+ ## Quickstart
12
+
13
+ You need an RPC endpoint whose node runs the `msgboard_` module. Public PulseChain/Ethereum RPCs do **not** run it yet; valve.city does (for example `https://one.valve.city/rpc/vk_demo/evm/369`). You can also run your own node with the module.
14
+
15
+ ### with viem
16
+
17
+ ```ts
18
+ import * as msgboard from '@msgboard/sdk'
19
+ import { createPublicClient, http } from 'viem'
20
+ import { pulsechain } from 'viem/chains'
21
+
22
+ const client = createPublicClient({
23
+ chain: pulsechain,
24
+ transport: http('https://one.valve.city/rpc/vk_demo/evm/369'),
25
+ })
26
+ const board = new msgboard.MsgBoardClient(client)
27
+
28
+ // do the work for your category and data
29
+ const work = await board.doPoW('gasmoneyplease', 'hello board')
30
+ // submit the valid message
31
+ const hash = await board.addMessage(work.message)
32
+ ```
33
+
34
+ ### with ethers
35
+
36
+ ```ts
37
+ import * as msgboard from '@msgboard/sdk'
38
+ import { providers } from 'ethers'
39
+
40
+ const provider = new providers.JsonRpcProvider('https://one.valve.city/rpc/vk_demo/evm/369')
41
+ const board = new msgboard.MsgBoardClient(msgboard.wrapLegacySend(provider))
42
+
43
+ const work = await board.doPoW('gasmoneyplease', 'hello board')
44
+ const hash = await board.addMessage(work.message)
45
+ ```
46
+
47
+ ### read the board
48
+
49
+ ```ts
50
+ const status = await board.status() // enabled, counts, difficulty factors
51
+ const categories = await board.categories()
52
+ const content = await board.content() // messages grouped by category
53
+ ```
54
+
55
+ ## Finding a node
56
+
57
+ A node must run the `msgboard_` module to serve these methods. If `status()` reports `enabled: false`, or a call returns JSON-RPC error `-32601` (method not found), the node does not have the module — point at one that does. See the live status badge on https://msgboard.xyz for working endpoints.
58
+
59
+ ## Proof of work and difficulty
60
+
61
+ Submission is gated by proof of work, not a fee. Difficulty scales with message size:
62
+
63
+ ```ts
64
+ ((2n ** 24n + BigInt(dataLen) * 10_000n) * workMultiplier) / workDivisor
65
+ ```
66
+
67
+ `dataLen` is measured in **bytes** (not hex characters); each byte adds 10,000 to the difficulty under the default factors, which rewards compact message packing. Compute the difficulty for a payload with:
68
+
69
+ ```ts
70
+ board.getDifficulty('0x...') // bigint
71
+ ```
72
+
73
+ `workMultiplier` and `workDivisor` come from `status()` and are applied automatically by `doPoW`.
74
+
75
+ ## Categories
76
+
77
+ A category is a 32-byte hash. Pass a string and the client hashes it for you (`categoryHash`); pass hex and it is used as-is. The demo board uses the `gasmoneyplease` category.
78
+
79
+ ## Ephemerality
80
+
81
+ Messages are short-lived: the board retains roughly the last 120 blocks of messages, so the board is a live signal, not durable storage.
82
+
83
+ ## Keeping work off the UI thread
84
+
85
+ `doPoW` is a busy loop; JavaScript blocks while it runs. In a browser, run it in a Web Worker so the interface stays responsive. The client yields periodically (`breakInterval`) to let block updates resolve, but the heavy hashing still occupies the thread it runs on.
86
+
87
+ <!-- GENERATED:OPENRPC:START -->
88
+
89
+ ## JSON-RPC methods
90
+
91
+ ### msgboard_status
92
+
93
+ Board status and the difficulty factors required for valid messages.
94
+
95
+ | Parameter | Type | Required |
96
+ | --- | --- | --- |
97
+ | _(none)_ | | |
98
+
99
+ **Returns:** `Status`
100
+
101
+ ```json
102
+ {
103
+ "jsonrpc": "2.0",
104
+ "id": 1,
105
+ "method": "msgboard_status",
106
+ "params": []
107
+ }
108
+ ```
109
+
110
+ ```json
111
+ {
112
+ "jsonrpc": "2.0",
113
+ "id": 1,
114
+ "result": {
115
+ "enabled": true,
116
+ "count": "0x0",
117
+ "size": "0x0",
118
+ "workMultiplier": "0x2710",
119
+ "workDivisor": "0xf4240"
120
+ }
121
+ }
122
+ ```
123
+
124
+ ### msgboard_categories
125
+
126
+ The list of 32-byte category hashes currently present on the board.
127
+
128
+ | Parameter | Type | Required |
129
+ | --- | --- | --- |
130
+ | _(none)_ | | |
131
+
132
+ **Returns:** `Categories`
133
+
134
+ ```json
135
+ {
136
+ "jsonrpc": "2.0",
137
+ "id": 1,
138
+ "method": "msgboard_categories",
139
+ "params": []
140
+ }
141
+ ```
142
+
143
+ ```json
144
+ {
145
+ "jsonrpc": "2.0",
146
+ "id": 1,
147
+ "result": [
148
+ "0x6761736d6f6e6579706c65617365000000000000000000000000000000000000"
149
+ ]
150
+ }
151
+ ```
152
+
153
+ ### msgboard_content
154
+
155
+ All messages on the board, grouped by category hash. Optionally filtered.
156
+
157
+ | Parameter | Type | Required |
158
+ | --- | --- | --- |
159
+ | `filter` | `ContentFilter` | no |
160
+
161
+ **Returns:** `Content`
162
+
163
+ ```json
164
+ {
165
+ "jsonrpc": "2.0",
166
+ "id": 1,
167
+ "method": "msgboard_content",
168
+ "params": [
169
+ {}
170
+ ]
171
+ }
172
+ ```
173
+
174
+ ```json
175
+ {
176
+ "jsonrpc": "2.0",
177
+ "id": 1,
178
+ "result": {}
179
+ }
180
+ ```
181
+
182
+ ### msgboard_addMessage
183
+
184
+ Submit a proof-of-work message (RLP-encoded) to the board.
185
+
186
+ | Parameter | Type | Required |
187
+ | --- | --- | --- |
188
+ | `rlp` | `Hex` | yes |
189
+
190
+ **Returns:** `Hex`
191
+
192
+ ```json
193
+ {
194
+ "jsonrpc": "2.0",
195
+ "id": 1,
196
+ "method": "msgboard_addMessage",
197
+ "params": [
198
+ "0xf800"
199
+ ]
200
+ }
201
+ ```
202
+
203
+ ```json
204
+ {
205
+ "jsonrpc": "2.0",
206
+ "id": 1,
207
+ "result": "0x0d1e2f00000000000000000000000000000000000000000000000000c46845f9"
208
+ }
209
+ ```
210
+
211
+ ### msgboard_getMessage
212
+
213
+ Fetch a single message by its hash.
214
+
215
+ | Parameter | Type | Required |
216
+ | --- | --- | --- |
217
+ | `hash` | `Hex` | yes |
218
+
219
+ **Returns:** `RPCMessage`
220
+
221
+ ```json
222
+ {
223
+ "jsonrpc": "2.0",
224
+ "id": 1,
225
+ "method": "msgboard_getMessage",
226
+ "params": [
227
+ "0x0000000000000000000000000000000000000000000000000000000000000000"
228
+ ]
229
+ }
230
+ ```
231
+
232
+ ```json
233
+ {
234
+ "jsonrpc": "2.0",
235
+ "id": 1,
236
+ "result": {
237
+ "version": "0x1",
238
+ "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
239
+ "blockNumber": "0x0",
240
+ "category": "0x0000000000000000000000000000000000000000000000000000000000000000",
241
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000000",
242
+ "nonce": "0x0",
243
+ "hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
244
+ "workMultiplier": "0x0",
245
+ "workDivisor": "0x0"
246
+ }
247
+ }
248
+ ```
249
+
250
+ ## Schemas
251
+
252
+ ### Hex
253
+
254
+ String matching `^0x[0-9a-fA-F]*$`.
255
+
256
+ ### Status
257
+
258
+ | Field | Type | Description |
259
+ | --- | --- | --- |
260
+ | `enabled` (required) | `boolean` | Whether the module is enabled on this node. |
261
+ | `count` (required) | `Hex` | Overall count of messages stored on the board. |
262
+ | `size` (required) | `Hex` | Overall size of messages stored on the board. |
263
+ | `workMultiplier` (required) | `Hex` | Factor that increases required work. |
264
+ | `workDivisor` (required) | `Hex` | Factor that decreases required work. |
265
+
266
+ ### Categories
267
+
268
+ Array of `Hex`.
269
+
270
+ ### ContentFilter
271
+
272
+ | Field | Type | Description |
273
+ | --- | --- | --- |
274
+ | `category` | `Hex` | Restrict to one category hash. |
275
+ | `fromBlock` | `Hex` | Lower block bound (hex quantity). |
276
+ | `toBlock` | `Hex` | Upper block bound (hex quantity). |
277
+
278
+ ### RPCMessage
279
+
280
+ | Field | Type | Description |
281
+ | --- | --- | --- |
282
+ | `version` (required) | `Hex` | Message/encoding version. |
283
+ | `blockHash` (required) | `Hex` | Hash of the block the message is rooted to. |
284
+ | `blockNumber` (required) | `Hex` | Number of the block the message is rooted to. |
285
+ | `category` (required) | `Hex` | 32-byte category hash. |
286
+ | `data` (required) | `Hex` | Arbitrary message data. |
287
+ | `nonce` (required) | `Hex` | Nonce discovered through proof of work. |
288
+ | `hash` (required) | `Hex` | The message hash. |
289
+ | `workMultiplier` (required) | `Hex` | Work multiplier in force when posted. |
290
+ | `workDivisor` (required) | `Hex` | Work divisor in force when posted. |
291
+
292
+ ### Content
293
+
294
+ Messages grouped by category hash.
295
+
296
+ Object whose values are `RPCMessage[]`.
297
+
298
+ <!-- GENERATED:OPENRPC:END -->
299
+
300
+ ## Client methods (not JSON-RPC)
301
+
302
+ These run in the client, not on the node, so they are not in the OpenRPC spec:
303
+
304
+ - `doPoW(category, data, limit?)` — grind a valid proof-of-work message. Returns `{ message, stats }`.
305
+ - `getDifficulty(data)` — the difficulty for a given payload, as a `bigint`.
306
+ - Utilities: `categoryHash`, `checkWork`, `difficulty`, `encodeData`, `toRLP`, `fromRLP`, `fromRPCMessage`, `toRPCMessage`, `wrapLegacySend`.
307
+
308
+ ## Machine-readable spec
309
+
310
+ The JSON-RPC surface is published as an OpenRPC document at `openrpc.json` in this package. Point the OpenRPC Playground or a code generator at it.
311
+
312
+ ## License
313
+
314
+ MIT
@@ -0,0 +1,96 @@
1
+ import { type Hex } from 'viem';
2
+ import type { Config, Content, ContentFilter, DifficultyFactors, Logger, MessageSeed, Provider, RPCMessage, Status, WorkResult, WorkStats } from '@msgboard/core';
3
+ export * from '@msgboard/core';
4
+ /**
5
+ * MsgboardClient can be used for interacting with the msgboard API
6
+ * and performing necessary work to find valid messages.
7
+ */
8
+ export declare class MsgBoardClient {
9
+ protected provider: Provider;
10
+ private _difficultyFactors;
11
+ log: Logger;
12
+ breakInterval: bigint;
13
+ cancelled: boolean;
14
+ progressHandler: (stats: WorkStats) => void;
15
+ version: number;
16
+ constructor(provider: Provider, config?: Config);
17
+ get difficultyFactors(): DifficultyFactors;
18
+ set difficultyFactors(factors: DifficultyFactors);
19
+ /** Can be called to cancel a doPoW operation in progress. */
20
+ cancel(): void;
21
+ /**
22
+ * Starts a busy work loop, in search of a nonce to create a valid pow message
23
+ * with the given inputs and configured difficulty.
24
+ * @param category The 32-byte hash or string to be used as the message category
25
+ * @param data the data bytes or string to embed in the message
26
+ * @param limit an optional limit to the number of iterations that will be attempted
27
+ * @returns a promise that will resolve with a valid work object, containing a pow
28
+ * message that can be submitted to the API and a stats object about the work that was done
29
+ */
30
+ doPoW(category: Hex | string, data: Hex | string, limit?: bigint): Promise<WorkResult>;
31
+ /**
32
+ * Fetches the latest block from the RPC.
33
+ * @returns the block details
34
+ * @throws error responses from the RPC
35
+ */
36
+ lastestBlock(): Promise<{
37
+ hash: Hex;
38
+ number: Hex;
39
+ }>;
40
+ /**
41
+ * Submits a message to the board RPC.
42
+ * @param input the RLP encoded message to add
43
+ * @returns the message hash
44
+ * @throws error responses from the RPC
45
+ */
46
+ addMessage(input: Hex | MessageSeed): Promise<`0x${string}`>;
47
+ /**
48
+ * Fetches a message from the board RPC.
49
+ * @param category category to lookup message
50
+ * @param msgHash hash of the message to look up message on RPC
51
+ * @returns a message from the RPC
52
+ * @throws error responses from the RPC
53
+ */
54
+ getMessage(msgHash: Hex): Promise<RPCMessage>;
55
+ /**
56
+ * Fetches message categories from the board RPC.
57
+ * @returns the list category hashes available on the board
58
+ * @throws error responses from the RPC
59
+ */
60
+ categories(): Promise<`0x${string}`[]>;
61
+ /**
62
+ * Fetches all messages from the board RPC.
63
+ * @returns the board messages, grouped by category
64
+ * @throws error responses from the RPC
65
+ */
66
+ content(filter?: ContentFilter): Promise<Content>;
67
+ /**
68
+ * Fetches the status of the msgboard from the board RPC.
69
+ * @returns the status info of the msgboard
70
+ * @throws error responses from the RPC
71
+ */
72
+ status(): Promise<Status>;
73
+ /**
74
+ * Updates the difficulty factors for performing message work.
75
+ * @param workMultiplier the work multiplier increases difficulty
76
+ * @param workDivisor the work divisor decreases difficulty
77
+ */
78
+ setDifficultyFactors(workMultiplier: bigint, workDivisor: bigint): void;
79
+ /**
80
+ * Calculates the difficulty for a given message.
81
+ * @param data the data bytes or string to embed in the message
82
+ * @returns the difficulty
83
+ */
84
+ getDifficulty(data: Hex): bigint;
85
+ /**
86
+ * Calls the provider RPC directly
87
+ * @param method the method to call
88
+ * @param params the parameters to pass to the method
89
+ * @returns the response from the RPC
90
+ */
91
+ request<T, U extends unknown[]>(arg: {
92
+ method: string;
93
+ params: U;
94
+ }): Promise<T>;
95
+ }
96
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAwB,MAAM,MAAM,CAAA;AAErD,OAAO,KAAK,EACV,MAAM,EACN,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,MAAM,EAEN,WAAW,EACX,QAAQ,EACR,UAAU,EACV,MAAM,EACN,UAAU,EACV,SAAS,EACV,MAAM,gBAAgB,CAAA;AAGvB,cAAc,gBAAgB,CAAA;AAO9B;;;GAGG;AACH,qBAAa,cAAc;IAcvB,SAAS,CAAC,QAAQ,EAAE,QAAQ;IAb9B,OAAO,CAAC,kBAAkB,CAAmB;IAE7C,GAAG,EAAE,MAAM,CAAA;IAEX,aAAa,EAAE,MAAM,CAAA;IAErB,SAAS,EAAE,OAAO,CAAQ;IAE1B,eAAe,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAA;IAE3C,OAAO,EAAE,MAAM,CAAI;gBAGP,QAAQ,EAAE,QAAQ,EAC5B,MAAM,GAAE,MAAW;IAYrB,IAAI,iBAAiB,IAMU,iBAAiB,CAD/C;IACD,IAAI,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,EAK/C;IAED,6DAA6D;IAC7D,MAAM;IAIN;;;;;;;;OAQG;IACG,KAAK,CAAC,QAAQ,EAAE,GAAG,GAAG,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,MAAM,EAAE,KAAK,SAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IA8EnG;;;;OAIG;IACG,YAAY;cACY,GAAG;gBAAU,GAAG;;IAM9C;;;;;OAKG;IACG,UAAU,CAAC,KAAK,EAAE,GAAG,GAAG,WAAW;IAKzC;;;;;;OAMG;IACG,UAAU,CAAC,OAAO,EAAE,GAAG;IAI7B;;;;OAIG;IACG,UAAU;IAIhB;;;;OAIG;IACG,OAAO,CAAC,MAAM,GAAE,aAAkB;IAIxC;;;;OAIG;IACG,MAAM;IAIZ;;;;OAIG;IACH,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAGhE;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,GAAG;IAIvB;;;;;OAKG;IACG,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,OAAO,EAAE,EAAE,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,CAAC,CAAC;CAItF"}
package/dist/index.js ADDED
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.MsgBoardClient = void 0;
21
+ const viem_1 = require("viem");
22
+ const logger_js_1 = __importDefault(require("./logger.js"));
23
+ const core_1 = require("@msgboard/core");
24
+ __exportStar(require("@msgboard/core"), exports);
25
+ const veryHighLimit = 100000000n;
26
+ // eslint-disable-next-line
27
+ const defaultLogger = (prefix, ...args) => (0, logger_js_1.default)(prefix, ...args);
28
+ /**
29
+ * MsgboardClient can be used for interacting with the msgboard API
30
+ * and performing necessary work to find valid messages.
31
+ */
32
+ class MsgBoardClient {
33
+ provider;
34
+ _difficultyFactors;
35
+ log;
36
+ breakInterval;
37
+ cancelled = false;
38
+ progressHandler;
39
+ version = 1;
40
+ constructor(provider, config = {}) {
41
+ this.provider = provider;
42
+ this._difficultyFactors = {
43
+ workMultiplier: 10000n,
44
+ workDivisor: 1000000n,
45
+ ...(config.difficultyFactors ?? {}),
46
+ };
47
+ this.log = config.logger || defaultLogger;
48
+ this.breakInterval = config.breakInterval || 10000n;
49
+ this.progressHandler = config.progress || (() => { });
50
+ }
51
+ get difficultyFactors() {
52
+ return {
53
+ workMultiplier: this._difficultyFactors.workMultiplier,
54
+ workDivisor: this._difficultyFactors.workDivisor,
55
+ };
56
+ }
57
+ set difficultyFactors(factors) {
58
+ this._difficultyFactors = {
59
+ ...this._difficultyFactors,
60
+ ...factors,
61
+ };
62
+ }
63
+ /** Can be called to cancel a doPoW operation in progress. */
64
+ cancel() {
65
+ this.cancelled = true;
66
+ }
67
+ /**
68
+ * Starts a busy work loop, in search of a nonce to create a valid pow message
69
+ * with the given inputs and configured difficulty.
70
+ * @param category The 32-byte hash or string to be used as the message category
71
+ * @param data the data bytes or string to embed in the message
72
+ * @param limit an optional limit to the number of iterations that will be attempted
73
+ * @returns a promise that will resolve with a valid work object, containing a pow
74
+ * message that can be submitted to the API and a stats object about the work that was done
75
+ */
76
+ async doPoW(category, data, limit = veryHighLimit) {
77
+ this.log('starting pow on message');
78
+ this.cancelled = false;
79
+ let killPoll = false;
80
+ const message = {
81
+ blockHash: viem_1.zeroHash,
82
+ blockNumber: 0n,
83
+ category: (0, core_1.categoryHash)(category),
84
+ data: (0, core_1.encodeData)(data),
85
+ hash: viem_1.zeroHash,
86
+ nonce: 0n,
87
+ version: this.version,
88
+ workMultiplier: this.difficultyFactors.workMultiplier,
89
+ workDivisor: this.difficultyFactors.workDivisor,
90
+ };
91
+ const dataLen = (0, viem_1.hexToBytes)(message.data).length;
92
+ const stats = {
93
+ difficulty: (0, core_1.difficulty)(this.difficultyFactors, dataLen),
94
+ duration: 0,
95
+ isValid: false,
96
+ iterations: 0n,
97
+ };
98
+ // if we want to support multiple pow searches,
99
+ // then we need to move this polling outside of this method
100
+ // otherwise get block will be fetching at a commenserate rate
101
+ // to the number of outstanding pow searches are currently running
102
+ const getBlock = async () => {
103
+ if (killPoll)
104
+ return;
105
+ const { hash, ...block } = await this.lastestBlock();
106
+ const number = BigInt(block.number);
107
+ if (!killPoll && (message.blockNumber === 0n || message.blockNumber !== number)) {
108
+ message.blockHash = hash;
109
+ message.blockNumber = number;
110
+ this.log('updated block info %o@%o', hash, number);
111
+ }
112
+ // queue next operation
113
+ setTimeout(() => {
114
+ getBlock().catch(logger_js_1.default);
115
+ }, 1_000);
116
+ };
117
+ // start the polling for block updates
118
+ await getBlock();
119
+ const { breakInterval } = this;
120
+ const start = Date.now();
121
+ this.progressHandler({ ...stats });
122
+ while (true) {
123
+ if (this.cancelled) {
124
+ killPoll = true;
125
+ return { message, stats };
126
+ }
127
+ message.nonce += 1n;
128
+ stats.duration = Date.now() - start;
129
+ stats.iterations += 1n;
130
+ const hash = (0, core_1.checkWork)(message, stats.difficulty);
131
+ if (hash) {
132
+ message.hash = hash;
133
+ stats.isValid = true;
134
+ killPoll = true;
135
+ return { message, stats };
136
+ }
137
+ if (stats.iterations >= limit) {
138
+ killPoll = true;
139
+ throw new Error('limit met');
140
+ }
141
+ if (breakInterval && message.nonce % breakInterval === 0n) {
142
+ this.progressHandler({ ...stats });
143
+ // pauses the PoW busy loop to allow the event loop to resolve the block updates
144
+ await new Promise((resolve) => {
145
+ setTimeout(resolve, 10);
146
+ });
147
+ }
148
+ }
149
+ }
150
+ /**
151
+ * Fetches the latest block from the RPC.
152
+ * @returns the block details
153
+ * @throws error responses from the RPC
154
+ */
155
+ async lastestBlock() {
156
+ return this.request({
157
+ method: 'eth_getBlockByNumber',
158
+ params: ['latest', false],
159
+ });
160
+ }
161
+ /**
162
+ * Submits a message to the board RPC.
163
+ * @param input the RLP encoded message to add
164
+ * @returns the message hash
165
+ * @throws error responses from the RPC
166
+ */
167
+ async addMessage(input) {
168
+ const rlp = typeof input !== 'string' ? (0, core_1.toRLP)(input) : input;
169
+ return this.request({ method: 'msgboard_addMessage', params: [rlp] });
170
+ }
171
+ /**
172
+ * Fetches a message from the board RPC.
173
+ * @param category category to lookup message
174
+ * @param msgHash hash of the message to look up message on RPC
175
+ * @returns a message from the RPC
176
+ * @throws error responses from the RPC
177
+ */
178
+ async getMessage(msgHash) {
179
+ return this.request({ method: 'msgboard_getMessage', params: [msgHash] });
180
+ }
181
+ /**
182
+ * Fetches message categories from the board RPC.
183
+ * @returns the list category hashes available on the board
184
+ * @throws error responses from the RPC
185
+ */
186
+ async categories() {
187
+ return this.request({ method: 'msgboard_categories', params: [] });
188
+ }
189
+ /**
190
+ * Fetches all messages from the board RPC.
191
+ * @returns the board messages, grouped by category
192
+ * @throws error responses from the RPC
193
+ */
194
+ async content(filter = {}) {
195
+ return this.request({ method: 'msgboard_content', params: [filter] });
196
+ }
197
+ /**
198
+ * Fetches the status of the msgboard from the board RPC.
199
+ * @returns the status info of the msgboard
200
+ * @throws error responses from the RPC
201
+ */
202
+ async status() {
203
+ return this.request({ method: 'msgboard_status', params: [] });
204
+ }
205
+ /**
206
+ * Updates the difficulty factors for performing message work.
207
+ * @param workMultiplier the work multiplier increases difficulty
208
+ * @param workDivisor the work divisor decreases difficulty
209
+ */
210
+ setDifficultyFactors(workMultiplier, workDivisor) {
211
+ this.difficultyFactors = { workMultiplier, workDivisor };
212
+ }
213
+ /**
214
+ * Calculates the difficulty for a given message.
215
+ * @param data the data bytes or string to embed in the message
216
+ * @returns the difficulty
217
+ */
218
+ getDifficulty(data) {
219
+ return (0, core_1.difficulty)(this.difficultyFactors, (0, viem_1.hexToBytes)(data).length);
220
+ }
221
+ /**
222
+ * Calls the provider RPC directly
223
+ * @param method the method to call
224
+ * @param params the parameters to pass to the method
225
+ * @returns the response from the RPC
226
+ */
227
+ async request(arg) {
228
+ this.log('%s(%o)', arg.method, arg.params);
229
+ return this.provider.request(arg);
230
+ }
231
+ }
232
+ exports.MsgBoardClient = MsgBoardClient;
233
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import Debug from 'debug';
2
+ declare const _default: Debug.Debugger;
3
+ export default _default;
4
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;;AAEzB,wBAAgC"}
package/dist/logger.js ADDED
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const debug_1 = __importDefault(require("debug"));
7
+ exports.default = (0, debug_1.default)('msgboard');
8
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";;;;;AAAA,kDAAyB;AAEzB,kBAAe,IAAA,eAAK,EAAC,UAAU,CAAC,CAAA"}
@@ -0,0 +1,44 @@
1
+ /** Renders an OpenRPC document into a markdown API reference. Pure: no file I/O. */
2
+ type Schema = {
3
+ $ref?: string;
4
+ title?: string;
5
+ type?: string;
6
+ description?: string;
7
+ pattern?: string;
8
+ items?: Schema;
9
+ properties?: Record<string, Schema>;
10
+ required?: string[];
11
+ additionalProperties?: Schema | boolean;
12
+ };
13
+ type Param = {
14
+ name: string;
15
+ required?: boolean;
16
+ schema: Schema;
17
+ };
18
+ type Method = {
19
+ name: string;
20
+ summary?: string;
21
+ params: Param[];
22
+ result: {
23
+ name: string;
24
+ schema: Schema;
25
+ };
26
+ examples?: Array<{
27
+ name: string;
28
+ params: Array<{
29
+ value: unknown;
30
+ }>;
31
+ result: {
32
+ value: unknown;
33
+ };
34
+ }>;
35
+ };
36
+ type Doc = {
37
+ methods: Method[];
38
+ components: {
39
+ schemas: Record<string, Schema>;
40
+ };
41
+ };
42
+ export declare const renderReference: (doc: Doc) => string;
43
+ export {};
44
+ //# sourceMappingURL=render-reference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-reference.d.ts","sourceRoot":"","sources":["../src/render-reference.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,KAAK,MAAM,GAAG;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,oBAAoB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACxC,CAAA;AACD,KAAK,KAAK,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AACjE,KAAK,MAAM,GAAG;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;QAAC,MAAM,EAAE;YAAE,KAAK,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE,CAAC,CAAA;CAClG,CAAA;AACD,KAAK,GAAG,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;CAAE,CAAA;AA0DjF,eAAO,MAAM,eAAe,GAAI,KAAK,GAAG,KAAG,MAO1C,CAAA"}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /** Renders an OpenRPC document into a markdown API reference. Pure: no file I/O. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.renderReference = void 0;
5
+ const refName = (schema) => {
6
+ if (schema.$ref)
7
+ return schema.$ref.split('/').pop();
8
+ if (schema.type === 'array' && schema.items)
9
+ return `${refName(schema.items)}[]`;
10
+ return schema.type ?? 'any';
11
+ };
12
+ const renderMethod = (m) => {
13
+ const lines = [];
14
+ lines.push(`### ${m.name}`, '');
15
+ if (m.summary)
16
+ lines.push(m.summary, '');
17
+ lines.push('| Parameter | Type | Required |', '| --- | --- | --- |');
18
+ if (m.params.length === 0) {
19
+ lines.push('| _(none)_ | | |');
20
+ }
21
+ else {
22
+ for (const p of m.params) {
23
+ lines.push(`| \`${p.name}\` | \`${refName(p.schema)}\` | ${p.required ? 'yes' : 'no'} |`);
24
+ }
25
+ }
26
+ lines.push('', `**Returns:** \`${refName(m.result.schema)}\``, '');
27
+ const example = m.examples?.[0];
28
+ if (example) {
29
+ const req = { jsonrpc: '2.0', id: 1, method: m.name, params: example.params.map((p) => p.value) };
30
+ const res = { jsonrpc: '2.0', id: 1, result: example.result.value };
31
+ lines.push('```json', JSON.stringify(req, null, 2), '```', '');
32
+ lines.push('```json', JSON.stringify(res, null, 2), '```', '');
33
+ }
34
+ return lines.join('\n');
35
+ };
36
+ const renderSchema = (name, schema) => {
37
+ const lines = [];
38
+ lines.push(`### ${name}`, '');
39
+ if (schema.description)
40
+ lines.push(schema.description, '');
41
+ if (schema.type === 'string' && schema.pattern) {
42
+ lines.push(`String matching \`${schema.pattern}\`.`, '');
43
+ return lines.join('\n');
44
+ }
45
+ if (schema.type === 'array' && schema.items) {
46
+ lines.push(`Array of \`${refName(schema.items)}\`.`, '');
47
+ return lines.join('\n');
48
+ }
49
+ if (schema.properties) {
50
+ lines.push('| Field | Type | Description |', '| --- | --- | --- |');
51
+ for (const [field, prop] of Object.entries(schema.properties)) {
52
+ const required = schema.required?.includes(field) ? ' (required)' : '';
53
+ lines.push(`| \`${field}\`${required} | \`${refName(prop)}\` | ${prop.description ?? ''} |`);
54
+ }
55
+ lines.push('');
56
+ return lines.join('\n');
57
+ }
58
+ if (typeof schema.additionalProperties === 'object') {
59
+ lines.push(`Object whose values are \`${refName(schema.additionalProperties)}\`.`, '');
60
+ }
61
+ return lines.join('\n');
62
+ };
63
+ const renderReference = (doc) => {
64
+ const out = [];
65
+ out.push('## JSON-RPC methods', '');
66
+ for (const m of doc.methods)
67
+ out.push(renderMethod(m));
68
+ out.push('## Schemas', '');
69
+ for (const [name, schema] of Object.entries(doc.components.schemas))
70
+ out.push(renderSchema(name, schema));
71
+ return out.join('\n').trimEnd() + '\n';
72
+ };
73
+ exports.renderReference = renderReference;
74
+ //# sourceMappingURL=render-reference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-reference.js","sourceRoot":"","sources":["../src/render-reference.ts"],"names":[],"mappings":"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"}
package/openrpc.json ADDED
@@ -0,0 +1,97 @@
1
+ {
2
+ "openrpc": "1.2.6",
3
+ "info": {
4
+ "title": "MsgBoard JSON-RPC API",
5
+ "version": "0.0.28",
6
+ "description": "JSON-RPC methods exposed by the msgboard_ module. Any node running the module serves these methods. Proof of work, not a fee, gates message submission.",
7
+ "license": { "name": "MIT" }
8
+ },
9
+ "methods": [
10
+ {
11
+ "name": "msgboard_status",
12
+ "summary": "Board status and the difficulty factors required for valid messages.",
13
+ "params": [],
14
+ "result": { "name": "status", "schema": { "$ref": "#/components/schemas/Status" } },
15
+ "examples": [
16
+ { "name": "default", "params": [], "result": { "name": "status", "value": { "enabled": true, "count": "0x0", "size": "0x0", "workMultiplier": "0x2710", "workDivisor": "0xf4240" } } }
17
+ ]
18
+ },
19
+ {
20
+ "name": "msgboard_categories",
21
+ "summary": "The list of 32-byte category hashes currently present on the board.",
22
+ "params": [],
23
+ "result": { "name": "categories", "schema": { "$ref": "#/components/schemas/Categories" } },
24
+ "examples": [
25
+ { "name": "gasmoneyplease", "params": [], "result": { "name": "categories", "value": ["0x6761736d6f6e6579706c65617365000000000000000000000000000000000000"] } }
26
+ ]
27
+ },
28
+ {
29
+ "name": "msgboard_content",
30
+ "summary": "All messages on the board, grouped by category hash. Optionally filtered.",
31
+ "params": [ { "name": "filter", "required": false, "schema": { "$ref": "#/components/schemas/ContentFilter" } } ],
32
+ "result": { "name": "content", "schema": { "$ref": "#/components/schemas/Content" } },
33
+ "examples": [
34
+ { "name": "empty", "params": [{ "name": "filter", "value": {} }], "result": { "name": "content", "value": {} } }
35
+ ]
36
+ },
37
+ {
38
+ "name": "msgboard_addMessage",
39
+ "summary": "Submit a proof-of-work message (RLP-encoded) to the board.",
40
+ "params": [ { "name": "rlp", "required": true, "schema": { "$ref": "#/components/schemas/Hex" } } ],
41
+ "result": { "name": "hash", "schema": { "$ref": "#/components/schemas/Hex" } },
42
+ "examples": [
43
+ { "name": "submit", "params": [{ "name": "rlp", "value": "0xf800" }], "result": { "name": "hash", "value": "0x0d1e2f00000000000000000000000000000000000000000000000000c46845f9" } }
44
+ ]
45
+ },
46
+ {
47
+ "name": "msgboard_getMessage",
48
+ "summary": "Fetch a single message by its hash.",
49
+ "params": [ { "name": "hash", "required": true, "schema": { "$ref": "#/components/schemas/Hex" } } ],
50
+ "result": { "name": "message", "schema": { "$ref": "#/components/schemas/RPCMessage" } },
51
+ "examples": [
52
+ { "name": "zero", "params": [{ "name": "hash", "value": "0x0000000000000000000000000000000000000000000000000000000000000000" }], "result": { "name": "message", "value": { "version": "0x1", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockNumber": "0x0", "category": "0x0000000000000000000000000000000000000000000000000000000000000000", "data": "0x0000000000000000000000000000000000000000000000000000000000000000", "nonce": "0x0", "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", "workMultiplier": "0x0", "workDivisor": "0x0" } } }
53
+ ]
54
+ }
55
+ ],
56
+ "components": {
57
+ "schemas": {
58
+ "Hex": { "title": "Hex", "type": "string", "pattern": "^0x[0-9a-fA-F]*$" },
59
+ "Status": {
60
+ "title": "Status", "type": "object",
61
+ "required": ["enabled", "count", "size", "workMultiplier", "workDivisor"],
62
+ "properties": {
63
+ "enabled": { "type": "boolean", "description": "Whether the module is enabled on this node." },
64
+ "count": { "$ref": "#/components/schemas/Hex", "description": "Overall count of messages stored on the board." },
65
+ "size": { "$ref": "#/components/schemas/Hex", "description": "Overall size of messages stored on the board." },
66
+ "workMultiplier": { "$ref": "#/components/schemas/Hex", "description": "Factor that increases required work." },
67
+ "workDivisor": { "$ref": "#/components/schemas/Hex", "description": "Factor that decreases required work." }
68
+ }
69
+ },
70
+ "Categories": { "title": "Categories", "type": "array", "items": { "$ref": "#/components/schemas/Hex" } },
71
+ "ContentFilter": {
72
+ "title": "ContentFilter", "type": "object",
73
+ "properties": {
74
+ "category": { "$ref": "#/components/schemas/Hex", "description": "Restrict to one category hash." },
75
+ "fromBlock": { "$ref": "#/components/schemas/Hex", "description": "Lower block bound (hex quantity)." },
76
+ "toBlock": { "$ref": "#/components/schemas/Hex", "description": "Upper block bound (hex quantity)." }
77
+ }
78
+ },
79
+ "RPCMessage": {
80
+ "title": "RPCMessage", "type": "object",
81
+ "required": ["version", "blockHash", "blockNumber", "category", "data", "nonce", "hash", "workMultiplier", "workDivisor"],
82
+ "properties": {
83
+ "version": { "$ref": "#/components/schemas/Hex", "description": "Message/encoding version." },
84
+ "blockHash": { "$ref": "#/components/schemas/Hex", "description": "Hash of the block the message is rooted to." },
85
+ "blockNumber": { "$ref": "#/components/schemas/Hex", "description": "Number of the block the message is rooted to." },
86
+ "category": { "$ref": "#/components/schemas/Hex", "description": "32-byte category hash." },
87
+ "data": { "$ref": "#/components/schemas/Hex", "description": "Arbitrary message data." },
88
+ "nonce": { "$ref": "#/components/schemas/Hex", "description": "Nonce discovered through proof of work." },
89
+ "hash": { "$ref": "#/components/schemas/Hex", "description": "The message hash." },
90
+ "workMultiplier": { "$ref": "#/components/schemas/Hex", "description": "Work multiplier in force when posted." },
91
+ "workDivisor": { "$ref": "#/components/schemas/Hex", "description": "Work divisor in force when posted." }
92
+ }
93
+ },
94
+ "Content": { "title": "Content", "type": "object", "description": "Messages grouped by category hash.", "additionalProperties": { "type": "array", "items": { "$ref": "#/components/schemas/RPCMessage" } } }
95
+ }
96
+ }
97
+ }
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@msgboard/sdk",
3
+ "version": "0.0.28",
4
+ "description": "MsgBoard client SDK for the msgboard_ JSON-RPC module",
5
+ "repository": "github:valve-tech/msgboard",
6
+ "author": "MsgBoard",
7
+ "license": "MIT",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "main": "./dist/index.js",
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "commonjs": "./dist/index.js",
15
+ "exports": {
16
+ ".": {
17
+ "require": "./dist/index.js",
18
+ "default": "./dist/index.js",
19
+ "import": "./dist/index.js",
20
+ "types": "./dist/index.d.ts"
21
+ }
22
+ },
23
+ "keywords": [
24
+ "ethereum",
25
+ "smart-contracts",
26
+ "pow",
27
+ "proof-of-work"
28
+ ],
29
+ "scripts": {
30
+ "lint:fix": "eslint --fix --format=stylish src",
31
+ "lint": "eslint --format=stylish src",
32
+ "test": "DEBUG=msgboard vitest run",
33
+ "prebuild": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
34
+ "build": "tsc",
35
+ "watch": "tsc -w",
36
+ "gen:docs": "tsx scripts/generate-reference.ts"
37
+ },
38
+ "files": [
39
+ "dist/",
40
+ "openrpc.json"
41
+ ],
42
+ "devDependencies": {
43
+ "@eslint/js": "^9.25.1",
44
+ "@open-rpc/schema-utils-js": "^2.2.1",
45
+ "@types/bn.js": "^5.1.6",
46
+ "@types/debug": "^4.1.12",
47
+ "@types/elliptic": "^6.4.18",
48
+ "@typescript-eslint/eslint-plugin": "^8.29.0",
49
+ "@typescript-eslint/parser": "^8.29.0",
50
+ "eslint": "^9.23.0",
51
+ "eslint-config-prettier": "^10.1.2",
52
+ "eslint-plugin-prettier": "^5.2.6",
53
+ "ethers": "^6.13.5",
54
+ "globals": "^16.0.0",
55
+ "jiti": "^2.4.2",
56
+ "tsx": "^4.19.3",
57
+ "typescript": "^5.8.2",
58
+ "typescript-eslint": "^8.31.0",
59
+ "vitest": "^3.1.1"
60
+ },
61
+ "dependencies": {
62
+ "@msgboard/core": "^0.0.1",
63
+ "bn.js": "^5.2.1",
64
+ "debug": "^4.4.0",
65
+ "elliptic": "^6.6.1",
66
+ "viem": "^2.25.0"
67
+ }
68
+ }