boing-sdk 0.3.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 (186) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +191 -0
  3. package/dist/accessList.d.ts +22 -0
  4. package/dist/accessList.d.ts.map +1 -0
  5. package/dist/accessList.js +45 -0
  6. package/dist/bincode.d.ts +92 -0
  7. package/dist/bincode.d.ts.map +1 -0
  8. package/dist/bincode.js +154 -0
  9. package/dist/callAbi.d.ts +119 -0
  10. package/dist/callAbi.d.ts.map +1 -0
  11. package/dist/callAbi.js +156 -0
  12. package/dist/calldata.d.ts +35 -0
  13. package/dist/calldata.d.ts.map +1 -0
  14. package/dist/calldata.js +93 -0
  15. package/dist/canonicalDeployArtifacts.d.ts +154 -0
  16. package/dist/canonicalDeployArtifacts.d.ts.map +1 -0
  17. package/dist/canonicalDeployArtifacts.js +271 -0
  18. package/dist/canonicalTestnet.d.ts +15 -0
  19. package/dist/canonicalTestnet.d.ts.map +1 -0
  20. package/dist/canonicalTestnet.js +15 -0
  21. package/dist/canonicalTestnetDex.d.ts +17 -0
  22. package/dist/canonicalTestnetDex.d.ts.map +1 -0
  23. package/dist/canonicalTestnetDex.js +17 -0
  24. package/dist/chainIds.d.ts +18 -0
  25. package/dist/chainIds.d.ts.map +1 -0
  26. package/dist/chainIds.js +56 -0
  27. package/dist/client.d.ts +223 -0
  28. package/dist/client.d.ts.map +1 -0
  29. package/dist/client.js +659 -0
  30. package/dist/connectionMonitor.d.ts +47 -0
  31. package/dist/connectionMonitor.d.ts.map +1 -0
  32. package/dist/connectionMonitor.js +93 -0
  33. package/dist/create2.d.ts +94 -0
  34. package/dist/create2.d.ts.map +1 -0
  35. package/dist/create2.js +225 -0
  36. package/dist/dappDeploy.d.ts +100 -0
  37. package/dist/dappDeploy.d.ts.map +1 -0
  38. package/dist/dappDeploy.js +140 -0
  39. package/dist/dappUiHelpers.d.ts +28 -0
  40. package/dist/dappUiHelpers.d.ts.map +1 -0
  41. package/dist/dappUiHelpers.js +69 -0
  42. package/dist/defaultReferenceFungibleSecuredRuntimeBytecodeHex.d.ts +6 -0
  43. package/dist/defaultReferenceFungibleSecuredRuntimeBytecodeHex.d.ts.map +1 -0
  44. package/dist/defaultReferenceFungibleSecuredRuntimeBytecodeHex.js +5 -0
  45. package/dist/defaultReferenceFungibleSecuredTemplateBytecodeHex.d.ts +6 -0
  46. package/dist/defaultReferenceFungibleSecuredTemplateBytecodeHex.d.ts.map +1 -0
  47. package/dist/defaultReferenceFungibleSecuredTemplateBytecodeHex.js +5 -0
  48. package/dist/defaultReferenceFungibleTemplateBytecodeHex.d.ts +6 -0
  49. package/dist/defaultReferenceFungibleTemplateBytecodeHex.d.ts.map +1 -0
  50. package/dist/defaultReferenceFungibleTemplateBytecodeHex.js +5 -0
  51. package/dist/defaultReferenceNftCollectionTemplateBytecodeHex.d.ts +7 -0
  52. package/dist/defaultReferenceNftCollectionTemplateBytecodeHex.d.ts.map +1 -0
  53. package/dist/defaultReferenceNftCollectionTemplateBytecodeHex.js +6 -0
  54. package/dist/dexIntegration.d.ts +61 -0
  55. package/dist/dexIntegration.d.ts.map +1 -0
  56. package/dist/dexIntegration.js +193 -0
  57. package/dist/erc721Logs.d.ts +21 -0
  58. package/dist/erc721Logs.d.ts.map +1 -0
  59. package/dist/erc721Logs.js +69 -0
  60. package/dist/errors.d.ts +60 -0
  61. package/dist/errors.d.ts.map +1 -0
  62. package/dist/errors.js +153 -0
  63. package/dist/hex.d.ts +27 -0
  64. package/dist/hex.d.ts.map +1 -0
  65. package/dist/hex.js +82 -0
  66. package/dist/index.d.ts +83 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +78 -0
  69. package/dist/indexerBatch.d.ts +111 -0
  70. package/dist/indexerBatch.d.ts.map +1 -0
  71. package/dist/indexerBatch.js +253 -0
  72. package/dist/indexerGaps.d.ts +50 -0
  73. package/dist/indexerGaps.d.ts.map +1 -0
  74. package/dist/indexerGaps.js +117 -0
  75. package/dist/indexerSync.d.ts +61 -0
  76. package/dist/indexerSync.d.ts.map +1 -0
  77. package/dist/indexerSync.js +100 -0
  78. package/dist/nativeAmm.d.ts +64 -0
  79. package/dist/nativeAmm.d.ts.map +1 -0
  80. package/dist/nativeAmm.js +174 -0
  81. package/dist/nativeAmmLogs.d.ts +48 -0
  82. package/dist/nativeAmmLogs.d.ts.map +1 -0
  83. package/dist/nativeAmmLogs.js +114 -0
  84. package/dist/nativeAmmLpVault.d.ts +94 -0
  85. package/dist/nativeAmmLpVault.d.ts.map +1 -0
  86. package/dist/nativeAmmLpVault.js +205 -0
  87. package/dist/nativeAmmPool.d.ts +124 -0
  88. package/dist/nativeAmmPool.d.ts.map +1 -0
  89. package/dist/nativeAmmPool.js +245 -0
  90. package/dist/nativeContractSubmit.d.ts +26 -0
  91. package/dist/nativeContractSubmit.d.ts.map +1 -0
  92. package/dist/nativeContractSubmit.js +23 -0
  93. package/dist/nativeDexDirectory.d.ts +83 -0
  94. package/dist/nativeDexDirectory.d.ts.map +1 -0
  95. package/dist/nativeDexDirectory.js +147 -0
  96. package/dist/nativeDexDirectoryApi.d.ts +121 -0
  97. package/dist/nativeDexDirectoryApi.d.ts.map +1 -0
  98. package/dist/nativeDexDirectoryApi.js +408 -0
  99. package/dist/nativeDexFactory.d.ts +25 -0
  100. package/dist/nativeDexFactory.d.ts.map +1 -0
  101. package/dist/nativeDexFactory.js +72 -0
  102. package/dist/nativeDexFactoryLogs.d.ts +19 -0
  103. package/dist/nativeDexFactoryLogs.d.ts.map +1 -0
  104. package/dist/nativeDexFactoryLogs.js +61 -0
  105. package/dist/nativeDexFactoryPool.d.ts +61 -0
  106. package/dist/nativeDexFactoryPool.d.ts.map +1 -0
  107. package/dist/nativeDexFactoryPool.js +120 -0
  108. package/dist/nativeDexIndexerStats.d.ts +96 -0
  109. package/dist/nativeDexIndexerStats.d.ts.map +1 -0
  110. package/dist/nativeDexIndexerStats.js +448 -0
  111. package/dist/nativeDexLedgerRouter.d.ts +67 -0
  112. package/dist/nativeDexLedgerRouter.d.ts.map +1 -0
  113. package/dist/nativeDexLedgerRouter.js +108 -0
  114. package/dist/nativeDexLpPositions.d.ts +39 -0
  115. package/dist/nativeDexLpPositions.d.ts.map +1 -0
  116. package/dist/nativeDexLpPositions.js +69 -0
  117. package/dist/nativeDexNftIndexer.d.ts +26 -0
  118. package/dist/nativeDexNftIndexer.d.ts.map +1 -0
  119. package/dist/nativeDexNftIndexer.js +50 -0
  120. package/dist/nativeDexPoolHistory.d.ts +40 -0
  121. package/dist/nativeDexPoolHistory.d.ts.map +1 -0
  122. package/dist/nativeDexPoolHistory.js +110 -0
  123. package/dist/nativeDexReceiptArchive.d.ts +25 -0
  124. package/dist/nativeDexReceiptArchive.d.ts.map +1 -0
  125. package/dist/nativeDexReceiptArchive.js +47 -0
  126. package/dist/nativeDexRouting.d.ts +160 -0
  127. package/dist/nativeDexRouting.d.ts.map +1 -0
  128. package/dist/nativeDexRouting.js +345 -0
  129. package/dist/nativeDexSeamless.d.ts +86 -0
  130. package/dist/nativeDexSeamless.d.ts.map +1 -0
  131. package/dist/nativeDexSeamless.js +131 -0
  132. package/dist/nativeDexSwap2Router.d.ts +45 -0
  133. package/dist/nativeDexSwap2Router.d.ts.map +1 -0
  134. package/dist/nativeDexSwap2Router.js +276 -0
  135. package/dist/nativeLpShareToken.d.ts +54 -0
  136. package/dist/nativeLpShareToken.d.ts.map +1 -0
  137. package/dist/nativeLpShareToken.js +135 -0
  138. package/dist/nativeTokenSecurity.d.ts +59 -0
  139. package/dist/nativeTokenSecurity.d.ts.map +1 -0
  140. package/dist/nativeTokenSecurity.js +59 -0
  141. package/dist/networkProfile.d.ts +8 -0
  142. package/dist/networkProfile.d.ts.map +1 -0
  143. package/dist/networkProfile.js +29 -0
  144. package/dist/newHeadsWs.d.ts +43 -0
  145. package/dist/newHeadsWs.d.ts.map +1 -0
  146. package/dist/newHeadsWs.js +139 -0
  147. package/dist/preflightGate.d.ts +16 -0
  148. package/dist/preflightGate.d.ts.map +1 -0
  149. package/dist/preflightGate.js +29 -0
  150. package/dist/receiptLogs.d.ts +29 -0
  151. package/dist/receiptLogs.d.ts.map +1 -0
  152. package/dist/receiptLogs.js +66 -0
  153. package/dist/referenceFungibleSecuredDeployBytecode.d.ts +54 -0
  154. package/dist/referenceFungibleSecuredDeployBytecode.d.ts.map +1 -0
  155. package/dist/referenceFungibleSecuredDeployBytecode.js +274 -0
  156. package/dist/referenceNft.d.ts +14 -0
  157. package/dist/referenceNft.d.ts.map +1 -0
  158. package/dist/referenceNft.js +34 -0
  159. package/dist/referenceToken.d.ts +14 -0
  160. package/dist/referenceToken.d.ts.map +1 -0
  161. package/dist/referenceToken.js +29 -0
  162. package/dist/retryAfter.d.ts +6 -0
  163. package/dist/retryAfter.d.ts.map +1 -0
  164. package/dist/retryAfter.js +24 -0
  165. package/dist/rpcCapabilities.d.ts +43 -0
  166. package/dist/rpcCapabilities.d.ts.map +1 -0
  167. package/dist/rpcCapabilities.js +159 -0
  168. package/dist/rpcDoctor.d.ts +27 -0
  169. package/dist/rpcDoctor.d.ts.map +1 -0
  170. package/dist/rpcDoctor.js +66 -0
  171. package/dist/rpcSurfaceUi.d.ts +32 -0
  172. package/dist/rpcSurfaceUi.d.ts.map +1 -0
  173. package/dist/rpcSurfaceUi.js +49 -0
  174. package/dist/submitFlow.d.ts +70 -0
  175. package/dist/submitFlow.d.ts.map +1 -0
  176. package/dist/submitFlow.js +121 -0
  177. package/dist/transactionBuilder.d.ts +55 -0
  178. package/dist/transactionBuilder.d.ts.map +1 -0
  179. package/dist/transactionBuilder.js +100 -0
  180. package/dist/types.d.ts +436 -0
  181. package/dist/types.d.ts.map +1 -0
  182. package/dist/types.js +4 -0
  183. package/dist/walletProvider.d.ts +46 -0
  184. package/dist/walletProvider.d.ts.map +1 -0
  185. package/dist/walletProvider.js +126 -0
  186. package/package.json +44 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) as applied before **1.0.0** (minor releases may include breaking TypeScript surface changes).
7
+
8
+ ## [0.3.0] - 2026-04-12
9
+
10
+ ### Added
11
+
12
+ - **DEX discovery JSON-RPC helpers** on `BoingClient`: `listDexPoolsPage`, `listDexTokensPage`, `getDexToken` (`boing_listDexPools`, `boing_listDexTokens`, `boing_getDexToken`), including optional `factory`, `light` / `enrich`, and `includeDiagnostics`.
13
+ - **Types** `DexPoolListRow`, `DexPoolListPage`, `DexTokenListRow`, `DexTokenListPage`, `DexDiscoveryPoolDiagnostics`, `DexDiscoveryTokenDiagnostics` (exported from package root).
14
+ - **`buildNativeDexIndexerStatsForClient`**: merges `createdAtHeight`, `tokenADecimals`, and `tokenBDecimals` from `boing_listDexPools` into `NativeDexIndexerPoolRow` when the node supports discovery RPC.
15
+
16
+ ### Changed
17
+
18
+ - **`DexPoolListRow`** now includes required **`tokenADecimals`** and **`tokenBDecimals`** (aligned with node; default **18** when the node has no decimals map).
19
+
20
+ ### Breaking (TypeScript)
21
+
22
+ - Code that **constructs** `DexPoolListRow` literals must supply **`tokenADecimals`** and **`tokenBDecimals`**. Consumers that only **parse** RPC JSON from a current node are unchanged.
23
+
24
+ ### Packaging
25
+
26
+ - **`package.json` `files`**: the published tarball includes **`dist/`**, **`README.md`**, and **`CHANGELOG.md`** only (smaller install; `prepublishOnly` still runs **`npm run build`**).
package/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # Boing SDK
2
+
3
+ TypeScript/JavaScript client for [Boing Network](https://github.com/Boing-Network/boing.network): typed RPC client, hex utilities, and structured errors (including QA rejection feedback).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install
9
+ npm run build
10
+ ```
11
+
12
+ Or from a parent repo (when published): `npm install boing-sdk`.
13
+
14
+ ### Consuming via `file:` (e.g. [boing.finance](https://github.com/Boing-Network/boing.finance))
15
+
16
+ The compiled output lives in **`dist/`**, which is **committed** in `Boing-Network/boing.network` (repo root `.gitignore` ignores generic `dist/` but not `boing-sdk/dist/`). Clones and CI siblings therefore get a usable `dist/index.js` without a separate SDK build step.
17
+
18
+ When you change SDK **source** (`src/`), run `npm run build` in `boing-sdk` and commit the updated **`dist/`**. The **`boing-sdk`** workflow fails if `dist/` drifts from the TypeScript build output.
19
+
20
+ **boing.finance** checks out `boing.network` only so the `file:` path resolves; it does not build the SDK first. **boing.finance**’s `frontend/scripts/postinstall-boing-sdk.mjs` only runs `npm run build` in the linked package when `dist/index.js` is missing (e.g. local SDK development or a broken checkout) and **fails the install** if that build does not succeed.
21
+
22
+ ## Tests
23
+
24
+ - **Unit / offline:** `npm test` — Vitest; does not require a running Boing node.
25
+ - **Optional RPC integration:** `tests/rpcIntegration.test.ts` runs only when **`BOING_INTEGRATION_RPC_URL`** is set (e.g. `http://127.0.0.1:8545`). If it is unset, Vitest **skips** that whole suite so default runs stay offline-friendly. Core cases: sync state (or **`getBlockByHeight`** fallback), blocks + receipts, **`getLogsChunked`**, **`fetchBlocksWithReceiptsForHeightRange`**, **`getTransactionReceipt`** (unknown tx → **`null`**). Endpoints that return **-32601** for **`boing_getSyncState`** or **`boing_getLogs`** still pass where noted. With **`BOING_EXPECT_FULL_RPC=1`** (see **`.github/workflows/boing-sdk-rpc-integration.yml`**), an extra test asserts **`boing_clientVersion`**, **`boing_rpcSupportedMethods`**, and **`probeBoingRpcCapabilities`** (6/6 core methods, including **`boing_getNetworkInfo`** / **`boing_getBlockByHeight`** / **`boing_getTransactionReceipt`**).
26
+ - **Operator / tutorial smoke (separate from Vitest):** in **`examples/native-boing-tutorial`**, **`npm run preflight-rpc`** (or **`check-testnet-rpc`** only) with **`BOING_RPC_URL`** — same scripts CI runs after starting a local node; see [PRE-VIBEMINER-NODE-COMMANDS.md](../docs/PRE-VIBEMINER-NODE-COMMANDS.md). From the **monorepo root**, the same **`npm run <script>`** names delegate to the tutorial package (see root **`package.json`**).
27
+ - **`npm run verify`** — same as `npm test`, then prints a short note explaining the skip when the env var is missing.
28
+
29
+ ## Quick start
30
+
31
+ ```ts
32
+ import { createClient, BoingRpcError } from 'boing-sdk';
33
+
34
+ const client = createClient('http://localhost:8545');
35
+
36
+ // Read chain and account state
37
+ const height = await client.chainHeight();
38
+ const account = await client.getAccount('0x' + '00'.repeat(32)); // 32-byte hex
39
+ console.log(account.balance, account.nonce, account.stake);
40
+
41
+ // Pre-flight QA check before deploying a contract
42
+ const qa = await client.qaCheck('0x600160005260206000f3'); // hex bytecode
43
+ if (qa.result === 'reject') {
44
+ console.error('QA rejected:', qa.rule_id, qa.message);
45
+ } else if (qa.result === 'allow') {
46
+ // Submit signed tx (hex from Rust CLI or future signer)
47
+ await client.submitTransaction(hexSignedTx);
48
+ }
49
+
50
+ // Handle structured QA errors on submit
51
+ try {
52
+ await client.submitTransaction(hexSignedTx);
53
+ } catch (e) {
54
+ if (e instanceof BoingRpcError && e.isQaRejected) {
55
+ const { rule_id, message } = e.qaData ?? {};
56
+ console.error('Deployment rejected:', rule_id, message);
57
+ }
58
+ throw e;
59
+ }
60
+ ```
61
+
62
+ ## API
63
+
64
+ - **createClient(config)** — `config` can be a URL string or `{ baseUrl, fetch?, timeoutMs? }`. Default timeout 30s; set `timeoutMs: 0` to disable.
65
+ - **BoingClient** — typed methods for all RPCs (32-byte account/hash params are validated locally before sending):
66
+ - **RPC probe** — **`probeBoingRpcCapabilities`** returns **`{ clientVersion, supportedMethods, methods }`** plus **`countAvailableBoingRpcMethods`**, **`explainBoingRpcProbeGaps`** (`rpcCapabilities.ts`): detect **-32601** missing methods; CLI: **`npm run build`** then **`npm run probe-rpc`** (or **`npm run probe-rpc`** from repo root); **`diagnosis`** in JSON explains stale node vs current repo; node discovery: **`boing_clientVersion`**, **`boing_rpcSupportedMethods`**
67
+ - `chainHeight()`, `getBalance(hexAccountId)`, `getAccount(hexAccountId)`
68
+ - `getBlockByHeight(height, includeReceipts?)`, `getBlockByHash(hexHash, includeReceipts?)`
69
+ - `getTransactionReceipt(hexTxId)`, `getLogs(filter)` — bounded log query ([RPC-API-SPEC.md](../docs/RPC-API-SPEC.md))
70
+ - Receipt/log helpers: `normalizeTopicWord`, `iterBlockReceiptLogs`, `filterReceiptLogsByTopic0`, … (`receiptLogs.ts`; see [INDEXER-RECEIPT-AND-LOG-INGESTION.md](../docs/INDEXER-RECEIPT-AND-LOG-INGESTION.md))
71
+ - `getAccountProof(hexAccountId)`, `verifyAccountProof(hexProof, hexStateRoot)`
72
+ - `simulateTransaction(hexSignedTx)`, `submitTransaction(hexSignedTx)`
73
+ - High-level flows: `submitTransferWithSimulationRetry`, `submitContractCallWithSimulationRetry`, `submitDeployWithPurposeFlow` (see **Simulate → access list → submit** below)
74
+ - **Pinned native deploy (Boing Express tx objects)** — `buildContractDeployMetaTx`, **`buildReferenceFungibleDeployMetaTx`** / **`buildReferenceFungibleSecuredDeployMetaTx`** / **`buildReferenceNftCollectionDeployMetaTx`** (wizard-friendly one-call builders), `resolveReferenceFungibleTemplateBytecodeHex`, **`resolveReferenceFungibleSecuredTemplateBytecodeHex`**, `resolveReferenceNftCollectionTemplateBytecodeHex`, `ensure0xHex`, `DEFAULT_REFERENCE_FUNGIBLE_SECURED_TEMPLATE_BYTECODE_HEX`, `REFERENCE_FUNGIBLE_TEMPLATE_VERSION`, **`REFERENCE_FUNGIBLE_SECURED_TEMPLATE_VERSION`**, `REFERENCE_NFT_COLLECTION_TEMPLATE_VERSION` (`canonicalDeployArtifacts.ts`; [BOING-CANONICAL-DEPLOY-ARTIFACTS.md](../docs/BOING-CANONICAL-DEPLOY-ARTIFACTS.md)); multi-network wizards: **`isBoingTestnetChainId`**, **`normalizeBoingChainIdHex`**, **`BOING_TESTNET_CHAIN_ID_*`** (`chainIds.ts`); review-step QA (`dappDeploy.ts`; [BOING-DAPP-INTEGRATION.md](../docs/BOING-DAPP-INTEGRATION.md) § **One wizard, two backends**): **`buildAndPreflightReferenceFungibleDeploy`**, **`buildAndPreflightReferenceNftCollectionDeployMeta`**, **`preflightContractDeployMetaWithUi`**, **`describeContractDeployMetaQaResponse`**, **`preflightContractDeployMetaQa`**, **`BOING_QA_PLACEHOLDER_DESCRIPTION_HASH_HEX`**
75
+ - **Generic calldata words** — `calldataSelectorLastByte`, `calldataU128BeWord`, `calldataAccountIdWord`, `calldataFixedWord32`, `concatCalldata` (same layout as reference token/NFT encoders; use for custom contracts)
76
+ - **Typed call builder** — `BoingCalldataWord`, `assertBoingCalldataWord`, `boingWordU128` / `boingWordAccount` / `boingWordFixed` / `boingWordSelector` (32-byte argument words), **`encodeBoingCall(selectorLowByte, args)`** (reference-style first word + argument words)
77
+ - **Minimal call ABI (Boing-native)** — `encodeBoingCallTyped(selector, ['u128','account',…], values)`, `encodeBoingCallFromAbiArgs`, **`BoingReferenceCallDescriptors`** (reference token / NFT / native AMM layouts) + **`encodeBoingCallFromDescriptor`** — not Solidity ABI / keccak4; matches `docs/BOING-REFERENCE-TOKEN.md`, `BOING-REFERENCE-NFT.md`, `NATIVE-AMM-CALLDATA.md`
78
+ - **Native CP pool (MVP)** — `buildNativeConstantProductPoolAccessList`, `buildNativeConstantProductContractCallTx`, `mergeNativePoolAccessListWithSimulation`; **`fetchNativeConstantProductReserves`**, **`fetchNativeConstantProductPoolSnapshot`** (batched reserves + total LP ± signer LP), **`fetchNativeConstantProductTotalLpSupply`**, **`fetchNativeConstantProductSwapFeeBps`** (v3/v4), **`fetchNativeAmmSignerLpBalance`**, **`decodeBoingStorageWordU128`**, **`decodeNativeAmmAddLiquidityReturnLpMinted`**, **`decodeNativeAmmLogDataU128Triple`**, reserve / total-LP / token / **swap-fee-bps** key helpers (`nativeAmmPool.ts`); **`tryParseNativeAmmLog2`**, **`filterMapNativeAmmRpcLogs`** (`nativeAmmLogs.ts`); **`constantProductAmountOut`** / **`constantProductAmountOutWithFeeBps`** / **`constantProductAmountOutNoFee`** / **`encodeNativeAmmSetTokensCalldata`** / **`encodeNativeAmmSetSwapFeeBpsCalldata`** / **`NATIVE_CP_SWAP_FEE_BPS`** / **`NATIVE_AMM_TOPIC_*_HEX`** / **`nativeAmmLogTopic0Utf8`** (`nativeAmm.ts`; [NATIVE-AMM-CALLDATA.md](../docs/NATIVE-AMM-CALLDATA.md)); **LP vault** — `encodeNativeAmmLpVaultConfigureCalldata`, `buildNativeAmmLpVaultDepositAddAccessList`, `buildNativeAmmLpVaultDepositAddContractCallTx`, merge helpers (`nativeAmmLpVault.ts`; [NATIVE-AMM-LP-VAULT.md](../docs/NATIVE-AMM-LP-VAULT.md)); **LP share token** — encoders + `buildLpShareTokenAccessList`, `buildLpShareTokenContractCallTx`, `mergeLpShareTokenAccessListWithSimulation` (`nativeLpShareToken.ts`; [NATIVE-LP-SHARE-TOKEN.md](../docs/NATIVE-LP-SHARE-TOKEN.md)); **`CANONICAL_BOING_TESTNET_NATIVE_CP_POOL_HEX`** (`canonicalTestnet.ts`) — convenience mirror of [RPC-API-SPEC.md](../docs/RPC-API-SPEC.md) § Native constant-product AMM (bump when the on-chain canonical pool changes)
79
+ - **Native DEX (pair directory + routers)** — [BOING-NATIVE-DEX-CAPABILITY.md](../docs/BOING-NATIVE-DEX-CAPABILITY.md): factory calldata + access lists (`nativeDexFactory.ts`), **`fetchNativeDexFactoryPairsCount`**, **`findNativeDexFactoryPoolByTokens`**, **`Log3`** parsers (`nativeDexFactoryPool.ts`, `nativeDexFactoryLogs.ts`; [NATIVE-DEX-FACTORY.md](../docs/NATIVE-DEX-FACTORY.md)); ledger-router forward calldata + tx builders **v1–v3** (`nativeDexLedgerRouter.ts`; [NATIVE-DEX-LEDGER-ROUTER.md](../docs/NATIVE-DEX-LEDGER-ROUTER.md)); **swap2** + **multihop** encoders (`nativeDexSwap2Router.ts`; [NATIVE-DEX-SWAP2-ROUTER.md](../docs/NATIVE-DEX-SWAP2-ROUTER.md), [NATIVE-DEX-MULTIHOP-SWAP-ROUTER.md](../docs/NATIVE-DEX-MULTIHOP-SWAP-ROUTER.md)); CREATE2 predictors + salts (`create2.ts`); tutorial **`deploy-native-dex-directory`** ([examples/native-boing-tutorial](../examples/native-boing-tutorial/) README §7c2)
80
+ - **Seamless defaults + wallet glue** — **`fetchNativeDexIntegrationDefaults`** / **`mergeNativeDexIntegrationDefaults`** (`dexIntegration.ts`): merge **`boing_getNetworkInfo`**.**`end_user`** (**`BOING_CANONICAL_NATIVE_CP_POOL`** / **`BOING_CANONICAL_NATIVE_DEX_FACTORY`**) with overrides and **6913** embedded pool fallback; **`fetchNativeDexFactoryRegisterLogs`** for chunked **`register_pair`** scans; **`getInjectedEip1193Provider`**, **`boingSendTransaction`**, **`requestAccounts`**, **`readChainIdHex`**, **`providerSupportsBoingNativeRpc`** (`walletProvider.ts`; [BOING-DAPP-INTEGRATION.md](../docs/BOING-DAPP-INTEGRATION.md))
81
+ - **Directory snapshot (Boing-only)** — **`fetchNativeDexDirectorySnapshot`** (defaults + **`pairs_count`** + optional log backfill), **`pickNativeDexPoolFromRegisterLogs`**, **`resolveNativeDexPoolForTokens`** (`logs` | `simulate` | `auto`), **`nativeDexPairKey`**, **`suggestNativeDexRegisterLogCatchUpRange`** (`nativeDexDirectory.ts`; no external chain RPC)
82
+ - **DEX onboarding + preflight** — **`formatBoingNativeDexNotEvmDisclaimer`**, **`describeNativeDexDefaultGaps`**, **`assertBoingNativeDexToolkitRpc`**, **`formatNativeDexToolkitPreflightForUi`**, **`buildNativeCpPoolSwapExpressTx`**, **`buildNativeDexMultihopSwapExpressTxFromRoute128`** / **`160`**, **`applyNativeDexMultihopSimulationToContractCallTx`** (`nativeDexSeamless.ts`); wallet copy **`BOING_WALLET_RPC_METHODS_NATIVE_DAPP`**, **`explainEthSendTransactionInsufficientForBoingNativeCall`**, **`connectInjectedBoingWallet`**, **`mapInjectedProviderErrorToUiMessage`** (`walletProvider.ts`)
83
+ - **CP routing + aggregation (off-chain)** — **`quoteCpPoolSwap`**, **`rankDirectCpPools`**, **`findBestCpRoutes`**, **`pickFirstMultihopCpRoute`**, **`uniqueSortedTokenHex32FromCpRoute`**, **`minOutFloorAfterSlippageBps`**, **`encodeNativeDexMultihopRouterCalldata*FromRoute`**, **`quoteCpEvenSplitAcrossDirectPools`**, **`hydrateCpPoolVenuesFromRpc`**, **`fetchCpRoutingFromDirectoryLogs`** (`nativeDexRouting.ts`); **`buildNativeDexMultihopRouterAccessList`**, **`mergeNativeDexMultihopRouterAccessListWithSimulation`** (`nativeAmmPool.ts`)
84
+ - **CREATE2 address prediction** — **`predictCreate2ContractAddress`**, **`predictNativeCpPoolCreate2Address`** … **`predictNativeCpPoolV5Create2Address`**, **`nativeCpPoolCreate2SaltV1Hex`** … **`nativeCpPoolCreate2SaltV5Hex`**, **`NATIVE_CP_POOL_CREATE2_SALT_V1`** … **`V5`** (`create2.ts`; matches `boing_primitives::create2_contract_address` / `native_amm.rs`; see [NATIVE-AMM-CALLDATA.md](../docs/NATIVE-AMM-CALLDATA.md) § CREATE2)
85
+ - **Indexer-scale reads** — **`getIndexerChainTips`** / **`clampIndexerHeightRange`** / **`planIndexerChainTipsWithFallback`** / **`planIndexerCatchUp`** (`indexerSync.ts`; fallback when **`boing_getSyncState`** is **-32601**); **`fetchBlocksWithReceiptsForHeightRange`** (replay path: full blocks + receipts; demos: [fetch-blocks-range.mjs](../examples/native-boing-tutorial/scripts/fetch-blocks-range.mjs), [indexer-ingest-tick.mjs](../examples/native-boing-tutorial/scripts/indexer-ingest-tick.mjs)); **`summarizeIndexerFetchGaps`**, **`mergeInclusiveHeightRanges`**, **`unionInclusiveHeightRanges`**, **`subtractInclusiveRangeFromRanges`**, **`blockHeightGapRowsForInsert`**, **`nextContiguousIndexedHeightAfterOmittedFetch`** (`indexerBatch.ts`, `indexerGaps.ts`; pruned gaps, D1 row shapes, archive backfill subtraction); `getLogsChunked` / `planLogBlockChunks` (≤128-block spans per [RPC-API-SPEC.md](../docs/RPC-API-SPEC.md)); optional **`maxConcurrent`** on chunked logs and height-range fetches; **`mapWithConcurrencyLimit`**; **`flattenReceiptsFromBundles`**; `fetchReceiptsForBlockHeight`; **`fetchReceiptsForHeightRange`** (optional `onMissingBlock: 'omit'`) — ingestion pseudo-flow: [INDEXER-RECEIPT-AND-LOG-INGESTION.md](../docs/INDEXER-RECEIPT-AND-LOG-INGESTION.md); example DDL: [tools/observer-indexer-schema.sql](../tools/observer-indexer-schema.sql); JSON + SQLite ingest: [examples/observer-ingest-reference](../examples/observer-ingest-reference/) (`ingest-tick`, **`ingest-sqlite-tick`** + **`BOING_SQLITE_PATH`**); D1 cron sample: [examples/observer-d1-worker](../examples/observer-d1-worker/); backlog: [NEXT-STEPS-FUTURE-WORK.md](../docs/NEXT-STEPS-FUTURE-WORK.md)
86
+ - **Fixed contract submitter** — `createNativeContractSubmitter({ client, secretKey32, senderHex, contractHex, accessList? })` → `.submitCalldata(bytes)`
87
+ - `registerDappMetrics(hexContract, hexOwner)`, `submitIntent(hexSignedIntent)`
88
+ - `qaCheck(hexBytecode, purposeCategory?, descriptionHash?, assetName?, assetSymbol?)` — pre-flight QA without submitting (same param order as node `boing_qaCheck`)
89
+ - `qaPoolList()`, `qaPoolConfig()`, `qaPoolVote(txHashHex, voterHex, vote)` — governance QA pool for Unsure deploys
90
+ - `faucetRequest(hexAccountId)` — testnet only
91
+ - **BoingRpcError** — `code`, `message`, `data`, `method`; `isQaRejected`, `isQaPendingPool`, `pendingPoolTxHash`, `isQaPoolDisabled`, `isQaPoolFull`, `isQaPoolDeployerCap`, `qaData`; `toString()` for logging.
92
+ - **Hex helpers** — `ensureHex`, `bytesToHex`, `hexToBytes`, `accountIdToHex`, `hexToAccountId`, `validateHex32`, **`isBoingNativeAccountIdHex`** (32-byte account id check for multi-wallet wizards).
93
+
94
+ All 32-byte IDs (account, hash) are hex strings with or without `0x` prefix. Invalid hex or wrong length throws before the request.
95
+
96
+ ## Submitting transactions
97
+
98
+ The node expects **hex-encoded bincode-serialized `SignedTransaction`**. Encoding matches Rust `boing-primitives` (bincode 1.3); see [BOING-SIGNED-TRANSACTION-ENCODING.md](../docs/BOING-SIGNED-TRANSACTION-ENCODING.md).
99
+
100
+ **Options:**
101
+
102
+ 1. **TypeScript (Node or bundler)** — build + sign with a 32-byte Ed25519 secret key:
103
+
104
+ ```ts
105
+ import {
106
+ createClient,
107
+ fetchNextNonce,
108
+ buildTransferTransaction,
109
+ signTransactionInput,
110
+ } from 'boing-sdk';
111
+
112
+ const client = createClient('http://localhost:8545');
113
+ const senderHex = '0x' + '<64-hex of public key>';
114
+ const secret32 = new Uint8Array(32); // your signing seed / secret key bytes
115
+ const nonce = await fetchNextNonce(client, senderHex);
116
+ const tx = buildTransferTransaction({
117
+ nonce,
118
+ senderHex,
119
+ toHex: '0x' + '<64-hex recipient>',
120
+ amount: 1n,
121
+ });
122
+ const signedHex = await signTransactionInput(tx, secret32);
123
+ await client.simulateTransaction(signedHex);
124
+ await client.submitTransaction(signedHex);
125
+ ```
126
+
127
+ 2. **Injected wallet** — `boing_sendTransaction` / `boing_signTransaction` in **Boing Express** ([BOING-EXPRESS-WALLET.md](../docs/BOING-EXPRESS-WALLET.md)).
128
+
129
+ 3. **Rust CLI** — `cargo run -p boing-cli -- …` for local dev.
130
+
131
+ 4. **Custom signer** — `signTransactionInputWithSigner(tx, async (hash) => …)` (must return 64-byte Ed25519 signature over `hash`).
132
+
133
+ **Protocol QA:** Contract deploys are checked in the mempool (`boing_qa`). Use `qaCheck` before submit and purpose-bearing deploy types from the wallet. See [QUALITY-ASSURANCE-NETWORK.md](../docs/QUALITY-ASSURANCE-NETWORK.md).
134
+
135
+ **dApp checklist:** [BOING-DAPP-INTEGRATION.md](../docs/BOING-DAPP-INTEGRATION.md).
136
+
137
+ See [RPC-API-SPEC.md](../docs/RPC-API-SPEC.md), [BUILD-ROADMAP.md](../docs/BUILD-ROADMAP.md), and [BOING-VM-CAPABILITY-PARITY-ROADMAP.md](../docs/BOING-VM-CAPABILITY-PARITY-ROADMAP.md).
138
+
139
+ ## Simulate → access list → submit (P4)
140
+
141
+ Use **`submitTransferWithSimulationRetry`**, **`submitContractCallWithSimulationRetry`**, or **`submitDeployWithPurposeFlow`** so the node can widen `access_list` when `boing_simulateTransaction` returns `access_list_covers_suggestion: false` (merges `suggested_access_list` via `mergeAccessListWithSimulation`).
142
+
143
+ ```ts
144
+ import {
145
+ createClient,
146
+ submitTransferWithSimulationRetry,
147
+ explainBoingRpcError,
148
+ senderHexFromSecretKey,
149
+ hexToBytes,
150
+ } from 'boing-sdk';
151
+
152
+ const client = createClient(process.env.BOING_RPC_URL ?? 'http://127.0.0.1:8545');
153
+ const secret = hexToBytes(process.env.BOING_SECRET_HEX!); // 0x + 64 hex
154
+ const senderHex = await senderHexFromSecretKey(secret);
155
+
156
+ try {
157
+ const { tx_hash, lastSimulation, attempts } = await submitTransferWithSimulationRetry({
158
+ client,
159
+ secretKey32: secret,
160
+ senderHex,
161
+ toHex: process.env.BOING_TO_HEX!,
162
+ amount: 10n,
163
+ });
164
+ console.log({ tx_hash, gas: lastSimulation.gas_used, attempts });
165
+ } catch (e) {
166
+ console.error(explainBoingRpcError(e));
167
+ }
168
+ ```
169
+
170
+ Deploy path runs **`boing_qaCheck`** first; **`reject`** throws `BoingRpcError` with `isQaRejected`. On **`submitTransaction`**, catch **`BoingRpcError`** for mempool QA (**-32050**), pool (**-32051**), and pool caps (**-32054..-32056**). Code reference: [BOING-RPC-ERROR-CODES-FOR-DAPPS.md](../docs/BOING-RPC-ERROR-CODES-FOR-DAPPS.md).
171
+
172
+ **Canonical scripts:** [examples/native-boing-tutorial](../examples/native-boing-tutorial/) (`transfer`, `contract-call`, `deploy-minimal`).
173
+
174
+ ## API additions (transaction flows)
175
+
176
+ - `senderHexFromSecretKey(secret32)` — derive `AccountId` hex from signing seed.
177
+ - `submitTransferWithSimulationRetry`, `submitContractCallWithSimulationRetry`, `submitDeployWithPurposeFlow` — see `submitFlow.ts`.
178
+ - `SimulationFailedError` — simulation failed without an access-list retry path.
179
+ - `explainBoingRpcError(e)` — human-readable string for `BoingRpcError` and QA pool codes.
180
+
181
+ ## Tests
182
+
183
+ ```bash
184
+ cd boing-sdk && npm install && npm test
185
+ ```
186
+
187
+ Golden vectors are tied to `cargo run -p boing-primitives --example dump_bincode`.
188
+
189
+ ## Planned
190
+
191
+ - CLI auto-completion, contract templates. See [DEVELOPMENT-AND-ENHANCEMENTS.md](../docs/DEVELOPMENT-AND-ENHANCEMENTS.md).
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Access list helpers — pair with `boing_simulateTransaction` hints (Track A).
3
+ */
4
+ import type { AccessListJson, SimulateResult } from './types.js';
5
+ /** Deduped sorted union of hex account ids (read ∪ write from suggestion). */
6
+ export declare function accountsFromSuggestedAccessList(s: AccessListJson): string[];
7
+ /**
8
+ * Merge explicit read/write lists with simulation `suggested_access_list` (union per side).
9
+ * Use after a successful or failed simulate to widen lists toward the heuristic minimum.
10
+ */
11
+ export declare function mergeAccessListWithSimulation(read: string[], write: string[], sim: SimulateResult): {
12
+ read: string[];
13
+ write: string[];
14
+ };
15
+ /** Build `AccessList`-shaped object from simulation only (both sides = union of suggested read+write). */
16
+ export declare function accessListFromSimulation(sim: SimulateResult): {
17
+ read: string[];
18
+ write: string[];
19
+ } | null;
20
+ /** True if simulation reports the signed tx’s access list covers the heuristic minimum. */
21
+ export declare function simulationCoversSuggestedAccessList(sim: SimulateResult): boolean;
22
+ //# sourceMappingURL=accessList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessList.d.ts","sourceRoot":"","sources":["../src/accessList.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAOjE,8EAA8E;AAC9E,wBAAgB,+BAA+B,CAAC,CAAC,EAAE,cAAc,GAAG,MAAM,EAAE,CAK3E;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,cAAc,GAClB;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAUrC;AAED,0GAA0G;AAC1G,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAKxG;AAED,2FAA2F;AAC3F,wBAAgB,mCAAmC,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAEhF"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Access list helpers — pair with `boing_simulateTransaction` hints (Track A).
3
+ */
4
+ import { validateHex32 } from './hex.js';
5
+ function normHex32(s) {
6
+ return validateHex32(s);
7
+ }
8
+ /** Deduped sorted union of hex account ids (read ∪ write from suggestion). */
9
+ export function accountsFromSuggestedAccessList(s) {
10
+ const set = new Set();
11
+ for (const x of s.read)
12
+ set.add(normHex32(x));
13
+ for (const x of s.write)
14
+ set.add(normHex32(x));
15
+ return [...set].sort();
16
+ }
17
+ /**
18
+ * Merge explicit read/write lists with simulation `suggested_access_list` (union per side).
19
+ * Use after a successful or failed simulate to widen lists toward the heuristic minimum.
20
+ */
21
+ export function mergeAccessListWithSimulation(read, write, sim) {
22
+ const sug = sim.suggested_access_list;
23
+ if (!sug) {
24
+ return { read: [...read], write: [...write] };
25
+ }
26
+ const r = new Set(read.map(normHex32));
27
+ const w = new Set(write.map(normHex32));
28
+ for (const x of sug.read)
29
+ r.add(normHex32(x));
30
+ for (const x of sug.write)
31
+ w.add(normHex32(x));
32
+ return { read: [...r], write: [...w] };
33
+ }
34
+ /** Build `AccessList`-shaped object from simulation only (both sides = union of suggested read+write). */
35
+ export function accessListFromSimulation(sim) {
36
+ const sug = sim.suggested_access_list;
37
+ if (!sug)
38
+ return null;
39
+ const ids = accountsFromSuggestedAccessList(sug);
40
+ return { read: ids, write: ids };
41
+ }
42
+ /** True if simulation reports the signed tx’s access list covers the heuristic minimum. */
43
+ export function simulationCoversSuggestedAccessList(sim) {
44
+ return sim.access_list_covers_suggestion === true;
45
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * bincode 1.3 layout matching `crates/boing-primitives` (serde derive).
3
+ * Used for `Transaction`, `SignedTransaction`, and signable hash preimage.
4
+ * @see docs/BOING-SIGNED-TRANSACTION-ENCODING.md
5
+ */
6
+ /** Payload variants — discriminant u32 LE must match Rust enum declaration order. */
7
+ export declare const PayloadVariant: {
8
+ readonly Transfer: 0;
9
+ readonly ContractCall: 1;
10
+ readonly ContractDeploy: 2;
11
+ readonly ContractDeployWithPurpose: 3;
12
+ readonly ContractDeployWithPurposeAndMetadata: 4;
13
+ readonly Bond: 5;
14
+ readonly Unbond: 6;
15
+ };
16
+ export declare function concatBytes(...parts: Uint8Array[]): Uint8Array;
17
+ export declare function writeU32Le(n: number): Uint8Array;
18
+ export declare function writeU64Le(n: bigint): Uint8Array;
19
+ export declare function writeU128Le(n: bigint): Uint8Array;
20
+ /** `AccessList` — two length-prefixed vectors of 32-byte accounts. */
21
+ export declare function encodeAccessList(read: Uint8Array[], write: Uint8Array[]): Uint8Array;
22
+ /** `Vec<u8>` — u64 LE length + raw bytes. */
23
+ export declare function encodeByteVec(data: Uint8Array): Uint8Array;
24
+ /** UTF-8 string: u64 LE byte length + UTF-8 payload. */
25
+ export declare function encodeBincodeString(s: string): Uint8Array;
26
+ /** `Option<[u8;32]>` — tag u8 + optional fixed 32 bytes. */
27
+ export declare function encodeOptionFixed32(salt: Uint8Array | null | undefined): Uint8Array;
28
+ /** `Option<Vec<u8>>` — tag u8 + optional vec. */
29
+ export declare function encodeOptionByteVec(opt: Uint8Array | null | undefined): Uint8Array;
30
+ /** `Option<String>` — tag u8 + optional string. */
31
+ export declare function encodeOptionString(opt: string | null | undefined): Uint8Array;
32
+ export type TransactionPayloadInput = {
33
+ kind: 'transfer';
34
+ to: Uint8Array;
35
+ amount: bigint;
36
+ } | {
37
+ kind: 'contractCall';
38
+ contract: Uint8Array;
39
+ calldata: Uint8Array;
40
+ } | {
41
+ kind: 'contractDeploy';
42
+ bytecode: Uint8Array;
43
+ create2Salt?: Uint8Array | null;
44
+ } | {
45
+ kind: 'contractDeployWithPurpose';
46
+ bytecode: Uint8Array;
47
+ purposeCategory: string;
48
+ descriptionHash?: Uint8Array | null;
49
+ create2Salt?: Uint8Array | null;
50
+ } | {
51
+ kind: 'contractDeployWithPurposeAndMetadata';
52
+ bytecode: Uint8Array;
53
+ purposeCategory: string;
54
+ descriptionHash?: Uint8Array | null;
55
+ assetName?: string | null;
56
+ assetSymbol?: string | null;
57
+ create2Salt?: Uint8Array | null;
58
+ } | {
59
+ kind: 'bond';
60
+ amount: bigint;
61
+ } | {
62
+ kind: 'unbond';
63
+ amount: bigint;
64
+ };
65
+ export declare function encodeTransactionPayload(payload: TransactionPayloadInput): Uint8Array;
66
+ export interface TransactionInput {
67
+ nonce: bigint;
68
+ sender: Uint8Array;
69
+ payload: TransactionPayloadInput;
70
+ accessList: {
71
+ read: Uint8Array[];
72
+ write: Uint8Array[];
73
+ };
74
+ }
75
+ export declare function encodeTransaction(tx: TransactionInput): Uint8Array;
76
+ /** `Signature` — serde `serialize_bytes` → u64 LE length + 64 raw bytes. */
77
+ export declare function encodeSignature(signature64: Uint8Array): Uint8Array;
78
+ export declare function encodeSignedTransaction(tx: TransactionInput, signature64: Uint8Array): Uint8Array;
79
+ /**
80
+ * BLAKE3 hash signed by the node for `SignedTransaction` verification.
81
+ * preimage = nonce_le || sender(32) || bincode(payload) || bincode(access_list)
82
+ */
83
+ export declare function signableTransactionHash(tx: TransactionInput): Uint8Array;
84
+ /**
85
+ * Derives the mempool / receipt **`tx_id`** (32-byte BLAKE3) from **`0x` + bincode(`SignedTransaction`)** hex
86
+ * returned by Boing Express after `boing_signTransaction`. Matches **`Transaction::id()`** / **`boing_getTransactionReceipt`** param
87
+ * per [RPC-API-SPEC.md](https://github.com/Boing-Network/boing.network/blob/main/docs/RPC-API-SPEC.md) (signable body excludes the trailing serde `Signature` block).
88
+ *
89
+ * @throws if hex is invalid or the trailing signature length field is not 64
90
+ */
91
+ export declare function transactionIdFromSignedTransactionHex(signedTxHex: string): string;
92
+ //# sourceMappingURL=bincode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bincode.d.ts","sourceRoot":"","sources":["../src/bincode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * bincode 1.3 layout matching `crates/boing-primitives` (serde derive).
3
+ * Used for `Transaction`, `SignedTransaction`, and signable hash preimage.
4
+ * @see docs/BOING-SIGNED-TRANSACTION-ENCODING.md
5
+ */
6
+ import { blake3 } from '@noble/hashes/blake3';
7
+ import { bytesToHex, ensureHex, hexToBytes } from './hex.js';
8
+ /** Payload variants — discriminant u32 LE must match Rust enum declaration order. */
9
+ export const PayloadVariant = {
10
+ Transfer: 0,
11
+ ContractCall: 1,
12
+ ContractDeploy: 2,
13
+ ContractDeployWithPurpose: 3,
14
+ ContractDeployWithPurposeAndMetadata: 4,
15
+ Bond: 5,
16
+ Unbond: 6,
17
+ };
18
+ export function concatBytes(...parts) {
19
+ const n = parts.reduce((a, p) => a + p.length, 0);
20
+ const out = new Uint8Array(n);
21
+ let o = 0;
22
+ for (const p of parts) {
23
+ out.set(p, o);
24
+ o += p.length;
25
+ }
26
+ return out;
27
+ }
28
+ export function writeU32Le(n) {
29
+ const b = new Uint8Array(4);
30
+ new DataView(b.buffer).setUint32(0, n >>> 0, true);
31
+ return b;
32
+ }
33
+ export function writeU64Le(n) {
34
+ const b = new Uint8Array(8);
35
+ new DataView(b.buffer).setBigUint64(0, n, true);
36
+ return b;
37
+ }
38
+ export function writeU128Le(n) {
39
+ const b = new Uint8Array(16);
40
+ let x = n;
41
+ for (let i = 0; i < 16; i++) {
42
+ b[i] = Number(x & 0xffn);
43
+ x >>= 8n;
44
+ }
45
+ return b;
46
+ }
47
+ function encodeVecAccountIds(ids) {
48
+ const parts = [writeU64Le(BigInt(ids.length))];
49
+ for (const id of ids) {
50
+ if (id.length !== 32)
51
+ throw new Error('Each AccountId must be exactly 32 bytes');
52
+ parts.push(id);
53
+ }
54
+ return concatBytes(...parts);
55
+ }
56
+ /** `AccessList` — two length-prefixed vectors of 32-byte accounts. */
57
+ export function encodeAccessList(read, write) {
58
+ return concatBytes(encodeVecAccountIds(read), encodeVecAccountIds(write));
59
+ }
60
+ /** `Vec<u8>` — u64 LE length + raw bytes. */
61
+ export function encodeByteVec(data) {
62
+ return concatBytes(writeU64Le(BigInt(data.length)), data);
63
+ }
64
+ /** UTF-8 string: u64 LE byte length + UTF-8 payload. */
65
+ export function encodeBincodeString(s) {
66
+ const utf8 = new TextEncoder().encode(s);
67
+ return concatBytes(writeU64Le(BigInt(utf8.length)), utf8);
68
+ }
69
+ /** `Option<[u8;32]>` — tag u8 + optional fixed 32 bytes. */
70
+ export function encodeOptionFixed32(salt) {
71
+ if (salt == null)
72
+ return new Uint8Array([0]);
73
+ if (salt.length !== 32)
74
+ throw new Error('create2_salt must be 32 bytes');
75
+ return concatBytes(new Uint8Array([1]), salt);
76
+ }
77
+ /** `Option<Vec<u8>>` — tag u8 + optional vec. */
78
+ export function encodeOptionByteVec(opt) {
79
+ if (opt == null)
80
+ return new Uint8Array([0]);
81
+ return concatBytes(new Uint8Array([1]), encodeByteVec(opt));
82
+ }
83
+ /** `Option<String>` — tag u8 + optional string. */
84
+ export function encodeOptionString(opt) {
85
+ if (opt == null)
86
+ return new Uint8Array([0]);
87
+ return concatBytes(new Uint8Array([1]), encodeBincodeString(opt));
88
+ }
89
+ export function encodeTransactionPayload(payload) {
90
+ switch (payload.kind) {
91
+ case 'transfer':
92
+ return concatBytes(writeU32Le(PayloadVariant.Transfer), payload.to, writeU128Le(payload.amount));
93
+ case 'contractCall':
94
+ return concatBytes(writeU32Le(PayloadVariant.ContractCall), payload.contract, encodeByteVec(payload.calldata));
95
+ case 'contractDeploy':
96
+ return concatBytes(writeU32Le(PayloadVariant.ContractDeploy), encodeByteVec(payload.bytecode), encodeOptionFixed32(payload.create2Salt ?? null));
97
+ case 'contractDeployWithPurpose':
98
+ return concatBytes(writeU32Le(PayloadVariant.ContractDeployWithPurpose), encodeByteVec(payload.bytecode), encodeBincodeString(payload.purposeCategory), encodeOptionByteVec(payload.descriptionHash ?? null), encodeOptionFixed32(payload.create2Salt ?? null));
99
+ case 'contractDeployWithPurposeAndMetadata':
100
+ return concatBytes(writeU32Le(PayloadVariant.ContractDeployWithPurposeAndMetadata), encodeByteVec(payload.bytecode), encodeBincodeString(payload.purposeCategory), encodeOptionByteVec(payload.descriptionHash ?? null), encodeOptionString(payload.assetName ?? null), encodeOptionString(payload.assetSymbol ?? null), encodeOptionFixed32(payload.create2Salt ?? null));
101
+ case 'bond':
102
+ return concatBytes(writeU32Le(PayloadVariant.Bond), writeU128Le(payload.amount));
103
+ case 'unbond':
104
+ return concatBytes(writeU32Le(PayloadVariant.Unbond), writeU128Le(payload.amount));
105
+ default: {
106
+ const _x = payload;
107
+ return _x;
108
+ }
109
+ }
110
+ }
111
+ export function encodeTransaction(tx) {
112
+ if (tx.sender.length !== 32)
113
+ throw new Error('sender must be 32 bytes');
114
+ return concatBytes(writeU64Le(tx.nonce), tx.sender, encodeTransactionPayload(tx.payload), encodeAccessList(tx.accessList.read, tx.accessList.write));
115
+ }
116
+ /** `Signature` — serde `serialize_bytes` → u64 LE length + 64 raw bytes. */
117
+ export function encodeSignature(signature64) {
118
+ if (signature64.length !== 64)
119
+ throw new Error('Ed25519 signature must be 64 bytes');
120
+ return concatBytes(writeU64Le(64n), signature64);
121
+ }
122
+ export function encodeSignedTransaction(tx, signature64) {
123
+ return concatBytes(encodeTransaction(tx), encodeSignature(signature64));
124
+ }
125
+ /**
126
+ * BLAKE3 hash signed by the node for `SignedTransaction` verification.
127
+ * preimage = nonce_le || sender(32) || bincode(payload) || bincode(access_list)
128
+ */
129
+ export function signableTransactionHash(tx) {
130
+ const preimage = concatBytes(writeU64Le(tx.nonce), tx.sender, encodeTransactionPayload(tx.payload), encodeAccessList(tx.accessList.read, tx.accessList.write));
131
+ return blake3(preimage);
132
+ }
133
+ const SIGNED_TX_SIGNATURE_TRAIL_BYTES = 8 + 64;
134
+ /**
135
+ * Derives the mempool / receipt **`tx_id`** (32-byte BLAKE3) from **`0x` + bincode(`SignedTransaction`)** hex
136
+ * returned by Boing Express after `boing_signTransaction`. Matches **`Transaction::id()`** / **`boing_getTransactionReceipt`** param
137
+ * per [RPC-API-SPEC.md](https://github.com/Boing-Network/boing.network/blob/main/docs/RPC-API-SPEC.md) (signable body excludes the trailing serde `Signature` block).
138
+ *
139
+ * @throws if hex is invalid or the trailing signature length field is not 64
140
+ */
141
+ export function transactionIdFromSignedTransactionHex(signedTxHex) {
142
+ const bytes = hexToBytes(ensureHex(signedTxHex));
143
+ if (bytes.length < SIGNED_TX_SIGNATURE_TRAIL_BYTES + 1) {
144
+ throw new Error('Signed transaction bytes too short to derive tx_id');
145
+ }
146
+ const sigLenOffset = bytes.length - SIGNED_TX_SIGNATURE_TRAIL_BYTES;
147
+ const dv = new DataView(bytes.buffer, bytes.byteOffset + sigLenOffset, 8);
148
+ const sigLen = dv.getBigUint64(0, true);
149
+ if (sigLen !== 64n) {
150
+ throw new Error(`Unexpected serde signature length field: ${sigLen} (expected 64)`);
151
+ }
152
+ const txBody = bytes.subarray(0, sigLenOffset);
153
+ return bytesToHex(blake3(txBody));
154
+ }