@riseandshaheen/libcma 0.1.0-alpha.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.
Files changed (33) hide show
  1. package/ARCHITECTURE.md +348 -0
  2. package/LICENSE +21 -0
  3. package/README.md +157 -0
  4. package/binding.gyp +52 -0
  5. package/deps/machine-asset-tools/LICENSE +202 -0
  6. package/deps/machine-asset-tools/README.md +237 -0
  7. package/deps/machine-asset-tools/include/libcma/ledger.h +161 -0
  8. package/deps/machine-asset-tools/include/libcma/parser.h +305 -0
  9. package/deps/machine-asset-tools/include/libcma/types.h +22 -0
  10. package/deps/machine-guest-tools/LICENSE +202 -0
  11. package/deps/machine-guest-tools/README.md +57 -0
  12. package/deps/machine-guest-tools/sys-utils/libcmt/README.md +130 -0
  13. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/abi.h +578 -0
  14. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/buf.h +82 -0
  15. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/io.h +168 -0
  16. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/keccak.h +131 -0
  17. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/merkle.h +118 -0
  18. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/rollup.h +260 -0
  19. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/util.h +34 -0
  20. package/lib/index.cjs +445 -0
  21. package/lib/index.cjs.map +1 -0
  22. package/lib/index.d.cts +156 -0
  23. package/lib/index.d.ts +156 -0
  24. package/lib/index.js +428 -0
  25. package/lib/index.js.map +1 -0
  26. package/native/addon.cc +268 -0
  27. package/native/ledger_backend.h +28 -0
  28. package/native/mock/ledger_mock.cc +185 -0
  29. package/native/real/ledger_real.cc +271 -0
  30. package/package.json +74 -0
  31. package/scripts/build-libcma-riscv64.sh +80 -0
  32. package/scripts/build-native-riscv64.sh +40 -0
  33. package/scripts/install-native.mjs +94 -0
@@ -0,0 +1,348 @@
1
+ # Architecture — Phase 1 (generic Node libcma)
2
+
3
+ ## Status
4
+
5
+ | Milestone | State |
6
+ | --- | --- |
7
+ | M0 Scaffold | **Done** — package, TS build, binding.gyp, deps clones |
8
+ | M1 Ether buffer MVP | **Done** — TS `Ledger` + memory backend + host native-mock addon |
9
+ | M2 File-backed path | **Done (API)** — `openEtherFile` → `cma_ledger_init_single_file` on real path; host mock ignores path |
10
+ | M3 riscv64 + real libcma | **Done (code path)** — `native/real/ledger_real.cc` + `build:libcma:riscv64` / `build:native:riscv64`; needs riscv64 toolchain or Docker to produce artifacts |
11
+ | M4 Docs | Updated |
12
+ | M5 Publish alpha | **Not started** |
13
+
14
+ ---
15
+
16
+ ## 1. Decision: TypeScript for the public API
17
+
18
+ **Yes — implement the user-facing package in TypeScript.**
19
+
20
+ Reasons:
21
+
22
+ 1. Target apps are JS/TS (Cartesi CLI templates, Deroll ecosystem).
23
+ 2. Ledger values are naturally `bigint`; addresses/`0x` hex benefit from branded types (`Hex`, `Address`) compatible with viem.
24
+ 3. Dual publish (ESM + CJS) + `.d.ts` matches [`@deroll/cmio`](https://www.npmjs.com/package/@deroll/cmio).
25
+ 4. The hard part is still C++: N-API addon + linking libcma. TS only wraps that surface.
26
+
27
+ What TypeScript is **not**:
28
+
29
+ - Not a reimplementation of the accounts-drive format.
30
+ - Not a substitute for linking real `libcma` on riscv64.
31
+ - Not required inside `addon.cc` (keep native code C++ with `node-addon-api`).
32
+
33
+ ### Pattern to copy
34
+
35
+ Follow `@deroll/cmio` / [tuler/libcmt-node](https://github.com/tuler/libcmt-node):
36
+
37
+ ```text
38
+ TypeScript (src/*.ts) → tsc/tsup → lib/ (JS + types)
39
+
40
+ node-gyp-build loads
41
+
42
+ prebuilds/<plat>-<arch>/*.node
43
+ or compile from binding.gyp + deps/
44
+ ```
45
+
46
+ API inspiration from [libcma_binding_rust](https://github.com/Mugen-Builders/libcma_binding_rust): `Ledger`, file/buffer init configs, deposit/transfer/withdraw/balance — not a 1:1 FFI dump of every C symbol in Phase 1.
47
+
48
+ ---
49
+
50
+ ## 2. Problem and non-goals
51
+
52
+ ### Problem
53
+
54
+ Emergency withdrawal proves balances from a dedicated flash drive whose bytes must match libcma’s ledger layout. In-memory wallets (e.g. `@deroll/wallet`) cannot be proved after foreclosure.
55
+
56
+ ### Phase 1 goals
57
+
58
+ - Generic npm package usable by **any** Cartesi JS/TS dApp.
59
+ - File-backed ledger on `/dev/pmem1` (machine) + buffer/file mode (host tests).
60
+ - Ether MVP: credit, transfer, withdraw (debit), getBalance.
61
+ - Host mock / buffer path so `npm test` runs without a Cartesi Machine.
62
+ - riscv64 prebuild (or documented cross-build) for Docker/`cartesi build` images.
63
+ - Document drive size / config knobs that must match `[withdrawal.config]` in `cartesi.toml`.
64
+
65
+ ### Phase 1 non-goals
66
+
67
+ | Deferred | Why |
68
+ | --- | --- |
69
+ | App integration examples | Separate app PR after the package is testable |
70
+ | Full ERC-20 / 721 / 1155 ledger API | Ether MVP first; extend with same patterns |
71
+ | Portal decode / voucher encode (`cma_decode_*`, `cma_encode_voucher`) | Apps keep viem for Phase 1; add as Phase 1.5/2 |
72
+ | `@deroll/cmio` migration | Orthogonal (rollup I/O, not ledger) |
73
+ | Publishing under `@cartesi/*` | Org decision; start under `@riseandshaheen/*` |
74
+ | Pure-JS ledger clone | Forbidden — proof mismatch risk |
75
+
76
+ ---
77
+
78
+ ## 3. Layered design
79
+
80
+ ```mermaid
81
+ flowchart TB
82
+ subgraph apps [JS/TS dApps]
83
+ WalletEx[typescript-wallet example]
84
+ Other[Other cartesi create apps]
85
+ end
86
+
87
+ subgraph pkg [libcma-binding-node]
88
+ TS[TypeScript API\nLedger / errors / types]
89
+ NAPI[C++ N-API addon]
90
+ Mock[Host mock / buffer backend]
91
+ end
92
+
93
+ subgraph core [Upstream]
94
+ CMA[libcma C++\nmachine-asset-tools]
95
+ Drive["/dev/pmem1 accounts drive"]
96
+ end
97
+
98
+ WalletEx --> TS
99
+ Other --> TS
100
+ TS --> NAPI
101
+ TS --> Mock
102
+ NAPI --> CMA
103
+ CMA --> Drive
104
+ ```
105
+
106
+ | Layer | Responsibility |
107
+ | --- | --- |
108
+ | **TypeScript API** | Idiomatic `Ledger` class; validate args; map errno → `LedgerError`; sync API (ledger ops are in-process, not rollup yields). |
109
+ | **N-API addon** | Thin wrappers around `cma_ledger_*`; open file/mmap; no business logic. |
110
+ | **Host mock** | Same TS API; in-memory or buffer-backed behavior for unit tests on darwin/linux-x64/arm64. Prefer calling real libcma in buffer mode when a host-buildable archive exists; otherwise a **behavioral** mock with clear “not proof-identical” labeling for CI that cannot link C++. |
111
+ | **libcma** | Sole authority for account/asset/balance records and drive layout. |
112
+
113
+ **One ledger instance per process** (same discipline as `@deroll/cmio`’s single open Rollup): document that apps must not open two file-backed ledgers on the same device.
114
+
115
+ ---
116
+
117
+ ## 4. Repository layout (target)
118
+
119
+ ```text
120
+ libcma-binding-node/
121
+ ├── README.md
122
+ ├── ARCHITECTURE.md # this file
123
+ ├── package.json # name, exports, install: node-gyp-build
124
+ ├── tsconfig.json
125
+ ├── tsup.config.ts # or tsc — dual ESM/CJS
126
+ ├── binding.gyp # native addon build
127
+ ├── src/
128
+ │ ├── index.ts # public exports
129
+ │ ├── ledger.ts # Ledger class
130
+ │ ├── types.ts # Hex, Address, configs, enums
131
+ │ ├── errors.ts # LedgerError
132
+ │ └── native.ts # load .node via node-gyp-build
133
+ ├── native/ # or src/addon/
134
+ │ └── addon.cc # N-API bindings
135
+ ├── deps/ # git submodule(s)
136
+ │ └── machine-asset-tools/ # libcma headers + source
137
+ │ └── machine-guest-tools/ # libcmt headers if required by libcma includes
138
+ ├── prebuilds/ # CI artifacts (linux-riscv64 required)
139
+ ├── test/
140
+ │ ├── ledger.buffer.test.ts
141
+ │ └── ledger.ether.test.ts
142
+ └── .github/workflows/
143
+ └── build.yml # host tests + riscv64 prebuild
144
+ ```
145
+
146
+ Keep this directory as the package root so it can be split into its own git repo under riseandshaheen without restructuring.
147
+
148
+ ---
149
+
150
+ ## 5. Phase 1 public API (sketch)
151
+
152
+ Keep the surface close to the Rust binding’s ledger helpers, but Ether-first and ergonomic for Node.
153
+
154
+ ```ts
155
+ import { Ledger } from "@riseandshaheen/libcma"; // proposed name
156
+
157
+ /** File-backed (machine: "/dev/pmem1") or host test file. */
158
+ export type LedgerFileConfig = {
159
+ mode: "create-only" | "open-only";
160
+ offset?: number; // default 0
161
+ memoryLength: number; // e.g. 4 MiB for log2_max_num_of_accounts = 17
162
+ maxAccounts: number;
163
+ maxAssets: number;
164
+ maxBalances: number;
165
+ };
166
+
167
+ export type LedgerBufferConfig = {
168
+ maxAccounts: number;
169
+ maxAssets: number;
170
+ maxBalances: number;
171
+ };
172
+
173
+ export class Ledger {
174
+ static openFile(path: string, config: LedgerFileConfig): Ledger;
175
+ static openBuffer(config: LedgerBufferConfig): Ledger;
176
+
177
+ /** Credit Ether (AssetType::Base) for an account. */
178
+ depositEther(account: Address, amount: bigint): void;
179
+
180
+ /** Internal L2 move — no voucher. */
181
+ transferEther(from: Address, to: Address, amount: bigint): void;
182
+
183
+ /**
184
+ * Debit Ether. Does NOT emit a rollup voucher — the app emits via HTTP / @deroll/cmio.
185
+ * Returns the amount debited (or void); voucher encoding stays in the app for Phase 1.
186
+ */
187
+ withdrawEther(account: Address, amount: bigint): void;
188
+
189
+ getEtherBalance(account: Address): bigint;
190
+
191
+ close(): void;
192
+ }
193
+
194
+ export class LedgerError extends Error {
195
+ readonly code: number; // libcma negative errno-style code
196
+ }
197
+ ```
198
+
199
+ ### Design notes
200
+
201
+ 1. **Withdraw = debit only** in Phase 1. Voucher emission stays in the dApp (`POST /voucher` or `@deroll/cmio.emitVoucher`). Apps keep voucher fields separate from rollup I/O. Phase 2 may add optional `encodeEtherWithdrawVoucher` if we bind `cma_encode_voucher`.
202
+ 2. **Addresses** accept `0x${string}` / `Uint8Array`; normalize with checksummed hex at the TS boundary.
203
+ 3. **Amounts** are `bigint` only (reject `number` to avoid precision bugs).
204
+ 4. **Synchronous API** — unlike rollup `finish()`, ledger calls do not yield the machine; no need for async.
205
+ 5. **Bundlers** — mark the native addon as external; document `esbuild`/`webpack` config (`external: ['@riseandshaheen/libcma']` or createRequire for `.node`). Do not bundle the `.node` into `dist/index.js`.
206
+
207
+ ### Convenience for portal deposits (optional Phase 1)
208
+
209
+ Apps already decode packed EtherPortal payloads with viem. Optional helper (pure TS, no libcma):
210
+
211
+ ```ts
212
+ parseEtherPortalDeposit(payload: Hex): { sender: Address; value: bigint; execLayerData?: Hex };
213
+ ```
214
+
215
+ Does not replace portal address checks — the app still routes when `msg_sender === etherPortal`.
216
+
217
+ ---
218
+
219
+ ## 6. Native addon responsibilities
220
+
221
+ `addon.cc` should expose a minimal set of methods, e.g.:
222
+
223
+ | Native method | Maps to |
224
+ | --- | --- |
225
+ | `ledgerInitFile(path, config)` | `cma_ledger_init` + file/mmap path used by Rust `init_from_file` |
226
+ | `ledgerInitBuffer(config)` | buffer-backed init |
227
+ | `ledgerDepositEther(...)` / transfer / withdraw / balance | `cma_ledger_*` for Base asset + account retrieve |
228
+ | `ledgerClose()` | `cma_ledger_fini` |
229
+
230
+ Prefer **high-level** native methods (Ether helpers) over exporting every C enum in Phase 1, to keep the addon small. Lower-level `retrieve_account` / `retrieve_asset` can wait until multi-token support.
231
+
232
+ Linking:
233
+
234
+ | Target | Link |
235
+ | --- | --- |
236
+ | `linux-riscv64` (inside machine) | Static `libcma.a` (+ `libstdc++` as needed), built from `deps/machine-asset-tools` or CI-produced archive |
237
+ | Host (darwin/linux x64/arm64) | Prefer buffer mock **or** host-built libcma if feasible; document which mode CI uses |
238
+
239
+ Reuse lessons from the Rust binding / CMA wallet demo: GCC ≥ 14 for libcma C++, link `stdc++`, submodule init in install/build scripts.
240
+
241
+ ---
242
+
243
+ ## 7. Alignment with emergency-withdrawal config
244
+
245
+ Apps (not this library) own `cartesi.toml`, but the library must document defaults that match the contracts/docs convention:
246
+
247
+ | Knob | Typical value | Library impact |
248
+ | --- | --- | --- |
249
+ | Drive path | `/dev/pmem1` | Default path in docs / helper constant `DEFAULT_ACCOUNTS_DRIVE` |
250
+ | Drive size | `4194304` (4 MiB) | `memoryLength` / file size |
251
+ | `log2_max_num_of_accounts` | `17` | Must match drive capacity and withdrawal config |
252
+ | `log2_leaves_per_account` | `0` | Document only in Phase 1 |
253
+ | `accounts_drive_start_index` | From machine `config.json` after build | App/deploy concern |
254
+
255
+ Export named constants where useful:
256
+
257
+ ```ts
258
+ export const ACCOUNTS_DRIVE_PATH = "/dev/pmem1";
259
+ export const ACCOUNTS_DRIVE_SIZE_4MIB = 4_194_304;
260
+ export const LOG2_MAX_NUM_OF_ACCOUNTS_DEFAULT = 17;
261
+ ```
262
+
263
+ ---
264
+
265
+ ## 8. Build, test, and CI
266
+
267
+ ### Local (host)
268
+
269
+ ```sh
270
+ npm install # node-gyp-build: prebuild or compile
271
+ npm test # buffer / mock ledger
272
+ npm run build # tsup/tsc → lib/
273
+ ```
274
+
275
+ ### Machine (riscv64)
276
+
277
+ - CI job cross-builds `prebuilds/linux-riscv64/` (same idea as `@deroll/cmio`).
278
+ - dApp Dockerfile copies prebuild or runs `npm install` with the riscv64 binary present.
279
+ - Smoke test: open `/dev/pmem1` in a minimal machine image (optional Phase 1 exit criterion; can be Phase 1.5).
280
+
281
+ ### Test matrix
282
+
283
+ | Test | Purpose |
284
+ | --- | --- |
285
+ | Buffer deposit/transfer/withdraw/balance | API correctness |
286
+ | Insufficient balance throws `LedgerError` | Error mapping |
287
+ | Determinism: same ops → same balances | Replay safety |
288
+ | (Later) golden vectors vs Rust/Python | Cross-binding compatibility |
289
+
290
+ ---
291
+
292
+ ## 9. Phase 1 milestones
293
+
294
+ | # | Milestone | Exit criteria |
295
+ | --- | --- | --- |
296
+ | M0 | Scaffold | `package.json`, `binding.gyp`, TS build, empty addon loads |
297
+ | M1 | Buffer ledger Ether MVP | Unit tests green on host without machine |
298
+ | M2 | File-backed path | `openFile` works against a temp file; mmap/persist sanity check |
299
+ | M3 | riscv64 prebuild | CI artifact; installable in `cartesi/node` riscv64 image |
300
+ | M4 | Docs + example snippet | README quickstart; “how to size the accounts drive” |
301
+ | M5 | Publish alpha | npm alpha tag; apps can depend on it |
302
+
303
+ After M5 → **Phase 2:** integrate into example/apps — `cartesi.toml` accounts drive + `[withdrawal.config]`, regression + foreclosure E2E.
304
+
305
+ ---
306
+
307
+ ## 10. Phase 2 preview (app integration — not Phase 1 work)
308
+
309
+ ```text
310
+ examples/typescript-wallet/ (or any JS/TS dApp)
311
+ src/ → Ledger instead of in-memory wallet
312
+ cartesi.toml → drives.accounts + withdrawal.config
313
+ Dockerfile → ensure native .node + libcma available on riscv64
314
+ package.json → dependency on @riseandshaheen/libcma
315
+ ```
316
+
317
+ Only the ETH ledger moves onto the drive; app business logic stays unchanged.
318
+
319
+ ---
320
+
321
+ ## 11. Risks and mitigations
322
+
323
+ | Risk | Mitigation |
324
+ | --- | --- |
325
+ | Drive layout drift vs C++ libcma | Always link upstream `machine-asset-tools`; never reimplement records in TS |
326
+ | esbuild bundles/breaks `.node` | Document external; use `createRequire` or leave package unbundled |
327
+ | Host cannot build libcma | Buffer mock for unit tests; real file tests in Docker CI |
328
+ | GCC 14 / cross-compile pain | Steal recipe from Rust binding / CMA wallet `INTEGRATION_NOTES` |
329
+ | Scope creep into full parser | Ether-only Phase 1; parser as Phase 1.5 with separate milestone |
330
+ | Dual ownership with Deroll | Ship under riseandshaheen for now; optional later contribution of a drive-backed wallet backend to Deroll |
331
+
332
+ ---
333
+
334
+ ## 12. Open questions (resolve before M1)
335
+
336
+ 1. **Package scope name:** `@riseandshaheen/libcma` vs `@riseandshaheen/libcma-node`?
337
+ 2. **Host backend:** behavioral mock vs requiring a host-linked libcma for all tests?
338
+ 3. **Monorepo vs standalone repo:** develop here then extract, or create `riseandshaheen/libcma-binding-node` immediately?
339
+ 4. **License:** match Rust binding (MIT) vs Apache-2.0 (cmio)? Prefer MIT unless Cartesi packaging requires otherwise.
340
+
341
+ ---
342
+
343
+ ## 13. Suggested next actions
344
+
345
+ 1. Answer open questions in §12 (especially package name + repo home).
346
+ 2. Scaffold M0 in this directory (or new GitHub repo).
347
+ 3. Implement M1 Ether buffer API + tests.
348
+ 4. Only after M3/M5: open app-integration PRs that depend on the published package.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mugen Builders
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # libcma-binding-node
2
+
3
+ Node.js / TypeScript bindings for **[libcma](https://github.com/Mugen-Builders/machine-asset-tools)** — the Cartesi proveable asset ledger used for **contracts v3 emergency withdrawal**.
4
+
5
+ | | |
6
+ | --- | --- |
7
+ | **npm** | [`@riseandshaheen/libcma`](https://www.npmjs.com/package/@riseandshaheen/libcma) (alpha — not published yet) |
8
+ | **repo** | [riseandshaheen/libcma-binding-node](https://github.com/riseandshaheen/libcma-binding-node) |
9
+ | **status** | Phase 1 — Ether MVP + host / riscv64 backends. See [ARCHITECTURE.md](./ARCHITECTURE.md). |
10
+
11
+ ## Quick start
12
+
13
+ ```sh
14
+ git clone --recurse-submodules https://github.com/riseandshaheen/libcma-binding-node.git
15
+ cd libcma-binding-node
16
+ npm install
17
+ npm test
18
+ ```
19
+
20
+ ```ts
21
+ import { Ledger, ACCOUNTS_DRIVE_PATH } from "@riseandshaheen/libcma";
22
+
23
+ // Host / unit tests — TypeScript memory backend (or native mock if built)
24
+ const ledger = Ledger.openEtherBuffer(
25
+ { maxAccounts: 4096 },
26
+ { backend: "memory" }, // force host memory; omit for auto (native if available)
27
+ );
28
+
29
+ ledger.depositEther("0x1111111111111111111111111111111111111111", 10n ** 18n);
30
+ ledger.transferEther(
31
+ "0x1111111111111111111111111111111111111111",
32
+ "0x2222222222222222222222222222222222222222",
33
+ 25n * 10n ** 16n,
34
+ );
35
+ ledger.withdrawEther("0x2222222222222222222222222222222222222222", 10n ** 16n);
36
+ console.log(ledger.getEtherBalance("0x1111111111111111111111111111111111111111"));
37
+ ledger.close();
38
+ ```
39
+
40
+ ## What’s in this repo
41
+
42
+ | Path | Role |
43
+ | --- | --- |
44
+ | [`src/`](./src) + [`native/`](./native) | Published package: TypeScript API + N-API addon |
45
+ | [`templates/`](./templates) | Minimal JS/TS app boilerplates (start here for a new dApp) |
46
+ | [`examples/typescript-wallet`](./examples/typescript-wallet) | Fuller wallet demo (portals, transfer/withdraw actions, EW notes) |
47
+
48
+ ## Templates
49
+
50
+ Copy-ready Cartesi Rollups v2 scaffolds with a libcma Ether ledger on `/dev/pmem1` — same idea as `cartesi create --template javascript|typescript`, plus the accounts drive and withdrawal config.
51
+
52
+ | Template | Entry | Host check |
53
+ | --- | --- | --- |
54
+ | [`templates/javascript`](./templates/javascript) | `src/index.js` (plain ESM) | `npm install && npm test` |
55
+ | [`templates/typescript`](./templates/typescript) | `src/index.ts` → esbuild | `npm install && npm test && npm run build` |
56
+
57
+ Both include:
58
+
59
+ - EtherPortal deposit → `ledger.creditEtherDeposit`
60
+ - `inspect balance/<address>`
61
+ - `sync` flush of the accounts drive before each yield
62
+ - `cartesi.toml` with a 4 MiB accounts drive and `[withdrawal.config]` (4096 × 32-byte leaves)
63
+
64
+ Add your logic in `handleInput` / `handleQuery`. Machine build:
65
+
66
+ ```sh
67
+ cd templates/typescript # or templates/javascript
68
+ ./scripts/vendor-libcma.sh
69
+ cartesi build
70
+ cartesi run
71
+ ```
72
+
73
+ Details: [`templates/README.md`](./templates/README.md).
74
+
75
+ ## Example: TypeScript wallet
76
+
77
+ [`examples/typescript-wallet`](./examples/typescript-wallet) is a richer reference app on top of the same stack (`@deroll/cmio` + this package): portal address book, L2 transfer / withdraw vouchers, and an end-to-end emergency-withdrawal path (including `EtherWithdrawalOutputBuilder`).
78
+
79
+ Prefer the **templates** for greenfield apps; use the **wallet example** when you need the fuller feature set.
80
+
81
+ ## Language choice
82
+
83
+ | Layer | Language |
84
+ | --- | --- |
85
+ | Public API | **TypeScript** |
86
+ | Native bridge | C++ (N-API) |
87
+ | Ledger core (production) | C++ libcma (`machine-asset-tools`) |
88
+
89
+ ## Backends
90
+
91
+ | Backend | When | Proof-identical? |
92
+ | --- | --- | --- |
93
+ | `memory` | Default host fallback / `{ backend: "memory" }` | **No** — tests & local only |
94
+ | `native-mock` | Host after `npm run build:native` | **No** — API smoke tests |
95
+ | `native-libcma` | riscv64 (or `LIBCMA_FORCE_REAL=1`) + `libcma.a` | **Yes** — required for emergency withdrawal |
96
+
97
+ ### Real libcma on riscv64
98
+
99
+ Same recipe as the Rust binding (`build.rs`). Requires the git submodules under `deps/` (`--recurse-submodules` on clone).
100
+
101
+ ```sh
102
+ # 1) Build static archive (cross on x86/arm, or native on riscv64)
103
+ npm run build:libcma:riscv64
104
+
105
+ # 2) Inside a riscv64 Node environment, build the addon against it
106
+ npm run build:native:riscv64
107
+ ```
108
+
109
+ Docker example (Apple Silicon / amd64 host):
110
+
111
+ ```sh
112
+ docker run --rm --platform linux/riscv64 \
113
+ -v "$PWD":/work -w /work cartesi/node:22.14.0-noble \
114
+ bash -lc 'apt-get update -qq && apt-get install -y -qq build-essential python3 make g++ wget \
115
+ && npm ci && npm run build:native:riscv64'
116
+ ```
117
+
118
+ On install inside the Cartesi machine / riscv64 image, `scripts/install-native.mjs` detects `process.arch === "riscv64"`, builds `libcma.a` if missing, and links the real backend (`kind === "native-libcma"`).
119
+
120
+ Machine usage (match `log2_max_num_of_accounts = 12` → 4096 slots in a 4 MiB drive):
121
+
122
+ ```ts
123
+ import {
124
+ Ledger,
125
+ ACCOUNTS_DRIVE_PATH,
126
+ ACCOUNTS_DRIVE_SIZE_4MIB,
127
+ } from "@riseandshaheen/libcma";
128
+
129
+ const ledger = Ledger.openEtherFile(
130
+ ACCOUNTS_DRIVE_PATH,
131
+ { maxAccounts: 4096, memoryLength: ACCOUNTS_DRIVE_SIZE_4MIB },
132
+ { backend: "native" },
133
+ );
134
+ ```
135
+
136
+ Uses `cma_ledger_init_single_file` with `ASSET_TYPE_BASE` (Ether) — the compact 32-byte account layout expected by contracts v3 withdrawal config.
137
+
138
+ ## Scripts
139
+
140
+ | Command | Purpose |
141
+ | --- | --- |
142
+ | `npm run build` | Compile TypeScript → `lib/` |
143
+ | `npm test` | Build + run Ether unit tests |
144
+ | `npm run build:native` | Compile N-API addon (host mock on non-riscv64) |
145
+ | `npm run build:libcma:riscv64` | Cross/native build `deps/.../build/riscv64/libcma.a` |
146
+ | `npm run build:native:riscv64` | Build addon linked to real libcma (riscv64 / `LIBCMA_FORCE_REAL`) |
147
+ | `LIBCMA_SKIP_NATIVE=1 npm install` | Skip native compile on install |
148
+
149
+ ## Phase 1 scope
150
+
151
+ - Ether deposit / transfer / withdraw (debit) / balance
152
+ - Portal deposit helper `creditEtherDeposit` / `parseEtherPortalDeposit`
153
+ - Host tests without a Cartesi Machine
154
+ - Native addon: host mock + **real libcma path for riscv64**
155
+ - JS/TS app templates + wallet example (accounts drive + EW-ready `cartesi.toml`)
156
+
157
+ **Not yet:** ERC-20/721/1155 multi-asset ledger, parser/voucher encode, published riscv64 prebuilds on npm.
package/binding.gyp ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "variables": {
3
+ "libcma_include%": "<!(node -p \"process.env.LIBCMA_INCLUDE || 'deps/machine-asset-tools/include'\")",
4
+ "libcmt_include%": "<!(node -p \"process.env.LIBCMT_INCLUDE || 'deps/machine-guest-tools/sys-utils/libcmt/include'\")",
5
+ "libcma_lib_dir%": "<!(node -p \"process.env.LIBCMA_LIB_DIR || 'deps/machine-asset-tools/build/riscv64'\")",
6
+ "libcma_use_real%": "<!(node -p \"(process.env.LIBCMA_FORCE_REAL === '1' || process.arch === 'riscv64') ? 1 : 0\")"
7
+ },
8
+ "targets": [
9
+ {
10
+ "target_name": "libcma_napi",
11
+ "sources": ["native/addon.cc"],
12
+ "include_dirs": [
13
+ "<!@(node -p \"require('node-addon-api').include_dir\")",
14
+ "<(libcma_include)",
15
+ "<(libcmt_include)",
16
+ "native"
17
+ ],
18
+ "defines": [
19
+ "NAPI_VERSION=8",
20
+ "NAPI_DISABLE_CPP_EXCEPTIONS",
21
+ "NODE_ADDON_API_DISABLE_DEPRECATED"
22
+ ],
23
+ "cflags!": ["-fno-exceptions"],
24
+ "cflags_cc!": ["-fno-exceptions"],
25
+ "cflags": ["-O2", "-fno-strict-aliasing", "-fno-strict-overflow"],
26
+ "cflags_cc": ["-std=c++20"],
27
+ "xcode_settings": {
28
+ "CLANG_CXX_LANGUAGE_STANDARD": "c++20",
29
+ "MACOSX_DEPLOYMENT_TARGET": "11.0",
30
+ "GCC_ENABLE_CPP_EXCEPTIONS": "YES"
31
+ },
32
+ "conditions": [
33
+ [
34
+ "libcma_use_real==1",
35
+ {
36
+ "defines": ["LIBCMA_USE_REAL=1"],
37
+ "sources": ["native/real/ledger_real.cc"],
38
+ "libraries": [
39
+ "-L<(module_root_dir)/<(libcma_lib_dir)",
40
+ "-lcma",
41
+ "-lstdc++"
42
+ ]
43
+ },
44
+ {
45
+ "defines": ["LIBCMA_USE_MOCK=1"],
46
+ "sources": ["native/mock/ledger_mock.cc"]
47
+ }
48
+ ]
49
+ ]
50
+ }
51
+ ]
52
+ }