@geeqdev/geeq-sdk 0.1.0 → 0.2.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 (392) hide show
  1. package/.idea/geeq_sdk.iml +12 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/vcs.xml +6 -0
  4. package/.nvmrc +1 -0
  5. package/CONTRIBUTING.md +20 -0
  6. package/dist/src/address/record-type.d.ts +10 -0
  7. package/dist/src/address/record-type.js +59 -0
  8. package/dist/src/address/record-type.js.map +1 -0
  9. package/dist/src/address/wallet-address.d.ts +34 -0
  10. package/dist/src/address/wallet-address.js +90 -0
  11. package/dist/src/address/wallet-address.js.map +1 -0
  12. package/dist/src/amount.d.ts +43 -0
  13. package/dist/src/amount.js +105 -0
  14. package/dist/src/amount.js.map +1 -0
  15. package/dist/src/assert.d.ts +12 -0
  16. package/dist/src/assert.js +24 -0
  17. package/dist/src/assert.js.map +1 -0
  18. package/dist/src/capnp/adminNetTx.capnp.d.ts +75 -0
  19. package/dist/src/capnp/adminNetTx.capnp.js +66 -0
  20. package/dist/src/capnp/adminNetTx.capnp.js.map +1 -0
  21. package/dist/src/capnp/appLayBlock.capnp.d.ts +26 -0
  22. package/dist/src/capnp/appLayBlock.capnp.js +24 -0
  23. package/dist/src/capnp/appLayBlock.capnp.js.map +1 -0
  24. package/dist/src/capnp/appLayLedger.capnp.d.ts +34 -0
  25. package/dist/src/capnp/appLayLedger.capnp.js +32 -0
  26. package/dist/src/capnp/appLayLedger.capnp.js.map +1 -0
  27. package/dist/src/capnp/appLayRec.capnp.d.ts +129 -0
  28. package/dist/src/capnp/appLayRec.capnp.js +156 -0
  29. package/dist/src/capnp/appLayRec.capnp.js.map +1 -0
  30. package/dist/src/capnp/chainStateView.capnp.d.ts +50 -0
  31. package/dist/src/capnp/chainStateView.capnp.js +48 -0
  32. package/dist/src/capnp/chainStateView.capnp.js.map +1 -0
  33. package/dist/src/capnp/coinAcctRec.capnp.d.ts +178 -0
  34. package/dist/src/capnp/coinAcctRec.capnp.js +189 -0
  35. package/dist/src/capnp/coinAcctRec.capnp.js.map +1 -0
  36. package/dist/src/capnp/genesisBlock.capnp.d.ts +61 -0
  37. package/dist/src/capnp/genesisBlock.capnp.js +55 -0
  38. package/dist/src/capnp/genesisBlock.capnp.js.map +1 -0
  39. package/dist/src/capnp/hubContentStmt.capnp.d.ts +63 -0
  40. package/dist/src/capnp/hubContentStmt.capnp.js +57 -0
  41. package/dist/src/capnp/hubContentStmt.capnp.js.map +1 -0
  42. package/dist/src/capnp/misc.capnp.d.ts +20 -0
  43. package/dist/src/capnp/misc.capnp.js +18 -0
  44. package/dist/src/capnp/misc.capnp.js.map +1 -0
  45. package/dist/src/capnp/netActorRec.capnp.d.ts +65 -0
  46. package/dist/src/capnp/netActorRec.capnp.js +65 -0
  47. package/dist/src/capnp/netActorRec.capnp.js.map +1 -0
  48. package/dist/src/capnp/nodeContentStmt.capnp.d.ts +67 -0
  49. package/dist/src/capnp/nodeContentStmt.capnp.js +61 -0
  50. package/dist/src/capnp/nodeContentStmt.capnp.js.map +1 -0
  51. package/dist/src/capnp/nodePayloadList.capnp.d.ts +28 -0
  52. package/dist/src/capnp/nodePayloadList.capnp.js +26 -0
  53. package/dist/src/capnp/nodePayloadList.capnp.js.map +1 -0
  54. package/dist/src/capnp/nodeTxList.capnp.d.ts +36 -0
  55. package/dist/src/capnp/nodeTxList.capnp.js +34 -0
  56. package/dist/src/capnp/nodeTxList.capnp.js.map +1 -0
  57. package/dist/src/capnp/paramAcctRec.capnp.d.ts +338 -0
  58. package/dist/src/capnp/paramAcctRec.capnp.js +669 -0
  59. package/dist/src/capnp/paramAcctRec.capnp.js.map +1 -0
  60. package/dist/src/capnp/payload.capnp.d.ts +237 -0
  61. package/dist/src/capnp/payload.capnp.js +260 -0
  62. package/dist/src/capnp/payload.capnp.js.map +1 -0
  63. package/dist/src/capnp/proxyAcctRec.capnp.d.ts +223 -0
  64. package/dist/src/capnp/proxyAcctRec.capnp.js +255 -0
  65. package/dist/src/capnp/proxyAcctRec.capnp.js.map +1 -0
  66. package/dist/src/capnp/relayContentStmt.capnp.d.ts +82 -0
  67. package/dist/src/capnp/relayContentStmt.capnp.js +85 -0
  68. package/dist/src/capnp/relayContentStmt.capnp.js.map +1 -0
  69. package/dist/src/capnp/sysAcctRec.capnp.d.ts +48 -0
  70. package/dist/src/capnp/sysAcctRec.capnp.js +46 -0
  71. package/dist/src/capnp/sysAcctRec.capnp.js.map +1 -0
  72. package/dist/src/capnp/userAppTx.capnp.d.ts +230 -0
  73. package/dist/src/capnp/userAppTx.capnp.js +270 -0
  74. package/dist/src/capnp/userAppTx.capnp.js.map +1 -0
  75. package/dist/src/capnp/userValTx.capnp.d.ts +1575 -0
  76. package/dist/src/capnp/userValTx.capnp.js +2004 -0
  77. package/dist/src/capnp/userValTx.capnp.js.map +1 -0
  78. package/dist/src/capnp/valLayBlock.capnp.d.ts +88 -0
  79. package/dist/src/capnp/valLayBlock.capnp.js +86 -0
  80. package/dist/src/capnp/valLayBlock.capnp.js.map +1 -0
  81. package/dist/src/capnp/valLayLedger.capnp.d.ts +85 -0
  82. package/dist/src/capnp/valLayLedger.capnp.js +75 -0
  83. package/dist/src/capnp/valLayLedger.capnp.js.map +1 -0
  84. package/dist/src/chain/geeq-chain.d.ts +474 -0
  85. package/dist/src/chain/geeq-chain.js +721 -0
  86. package/dist/src/chain/geeq-chain.js.map +1 -0
  87. package/dist/src/chain/geeq-node.d.ts +57 -0
  88. package/dist/src/chain/geeq-node.js +62 -0
  89. package/dist/src/chain/geeq-node.js.map +1 -0
  90. package/dist/src/chain/nonce-guard.d.ts +42 -0
  91. package/dist/src/chain/nonce-guard.js +68 -0
  92. package/dist/src/chain/nonce-guard.js.map +1 -0
  93. package/dist/src/chain/select.d.ts +40 -0
  94. package/dist/src/chain/select.js +114 -0
  95. package/dist/src/chain/select.js.map +1 -0
  96. package/dist/src/crypto/account-id.d.ts +35 -0
  97. package/dist/src/crypto/account-id.js +58 -0
  98. package/dist/src/crypto/account-id.js.map +1 -0
  99. package/dist/src/crypto/keypair.d.ts +24 -0
  100. package/dist/src/crypto/keypair.js +158 -0
  101. package/dist/src/crypto/keypair.js.map +1 -0
  102. package/dist/src/crypto/mnemonic.d.ts +34 -0
  103. package/dist/src/crypto/mnemonic.js +57 -0
  104. package/dist/src/crypto/mnemonic.js.map +1 -0
  105. package/dist/src/encoding/base64.d.ts +8 -0
  106. package/dist/src/encoding/base64.js +53 -0
  107. package/dist/src/encoding/base64.js.map +1 -0
  108. package/dist/src/encoding/hex.d.ts +2 -0
  109. package/dist/src/encoding/hex.js +35 -0
  110. package/dist/src/encoding/hex.js.map +1 -0
  111. package/dist/src/errors.d.ts +83 -0
  112. package/dist/src/errors.js +49 -0
  113. package/dist/src/errors.js.map +1 -0
  114. package/dist/src/index.d.ts +59 -0
  115. package/dist/src/index.js +53 -0
  116. package/dist/src/index.js.map +1 -0
  117. package/dist/src/ledger/coin-accounts.d.ts +42 -0
  118. package/dist/src/ledger/coin-accounts.js +37 -0
  119. package/dist/src/ledger/coin-accounts.js.map +1 -0
  120. package/dist/src/ledger/decode.d.ts +18 -0
  121. package/dist/src/ledger/decode.js +113 -0
  122. package/dist/src/ledger/decode.js.map +1 -0
  123. package/dist/src/ledger/geeq-ledger.d.ts +99 -0
  124. package/dist/src/ledger/geeq-ledger.js +125 -0
  125. package/dist/src/ledger/geeq-ledger.js.map +1 -0
  126. package/dist/src/ledger/net-actors.d.ts +65 -0
  127. package/dist/src/ledger/net-actors.js +53 -0
  128. package/dist/src/ledger/net-actors.js.map +1 -0
  129. package/dist/src/ledger/nft-records.d.ts +13 -0
  130. package/dist/src/ledger/nft-records.js +41 -0
  131. package/dist/src/ledger/nft-records.js.map +1 -0
  132. package/dist/src/ledger/params.d.ts +34 -0
  133. package/dist/src/ledger/params.js +71 -0
  134. package/dist/src/ledger/params.js.map +1 -0
  135. package/dist/src/ledger/proxy-accounts.d.ts +26 -0
  136. package/dist/src/ledger/proxy-accounts.js +27 -0
  137. package/dist/src/ledger/proxy-accounts.js.map +1 -0
  138. package/dist/src/net/discovery.d.ts +62 -0
  139. package/dist/src/net/discovery.js +136 -0
  140. package/dist/src/net/discovery.js.map +1 -0
  141. package/dist/src/net/explorer.d.ts +57 -0
  142. package/dist/src/net/explorer.js +64 -0
  143. package/dist/src/net/explorer.js.map +1 -0
  144. package/dist/src/net/read-ledger.d.ts +7 -0
  145. package/dist/src/net/read-ledger.js +39 -0
  146. package/dist/src/net/read-ledger.js.map +1 -0
  147. package/dist/src/net/routes.d.ts +49 -0
  148. package/dist/src/net/routes.js +70 -0
  149. package/dist/src/net/routes.js.map +1 -0
  150. package/dist/src/net/transport.d.ts +55 -0
  151. package/dist/src/net/transport.js +168 -0
  152. package/dist/src/net/transport.js.map +1 -0
  153. package/dist/src/net/websocket.d.ts +49 -0
  154. package/dist/src/net/websocket.js +54 -0
  155. package/dist/src/net/websocket.js.map +1 -0
  156. package/dist/src/runtime/bindings.d.ts +9 -0
  157. package/dist/src/runtime/bindings.js +27 -0
  158. package/dist/src/runtime/bindings.js.map +1 -0
  159. package/dist/src/runtime/init.d.ts +13 -0
  160. package/dist/src/runtime/init.js +40 -0
  161. package/dist/src/runtime/init.js.map +1 -0
  162. package/dist/src/runtime/wasm-loader.browser.d.ts +14 -0
  163. package/dist/src/runtime/wasm-loader.browser.js +20 -0
  164. package/dist/src/runtime/wasm-loader.browser.js.map +1 -0
  165. package/dist/src/runtime/wasm-loader.node.d.ts +7 -0
  166. package/dist/src/runtime/wasm-loader.node.js +14 -0
  167. package/dist/src/runtime/wasm-loader.node.js.map +1 -0
  168. package/dist/src/socket/geeq-socket.d.ts +232 -0
  169. package/dist/src/socket/geeq-socket.js +634 -0
  170. package/dist/src/socket/geeq-socket.js.map +1 -0
  171. package/dist/src/socket/tracked-tx.d.ts +148 -0
  172. package/dist/src/socket/tracked-tx.js +212 -0
  173. package/dist/src/socket/tracked-tx.js.map +1 -0
  174. package/dist/src/socket/tx-status.d.ts +69 -0
  175. package/dist/src/socket/tx-status.js +72 -0
  176. package/dist/src/socket/tx-status.js.map +1 -0
  177. package/dist/src/tx/attestation.d.ts +60 -0
  178. package/dist/src/tx/attestation.js +163 -0
  179. package/dist/src/tx/attestation.js.map +1 -0
  180. package/dist/src/tx/content.d.ts +27 -0
  181. package/dist/src/tx/content.js +62 -0
  182. package/dist/src/tx/content.js.map +1 -0
  183. package/dist/src/tx/encode.d.ts +60 -0
  184. package/dist/src/tx/encode.js +82 -0
  185. package/dist/src/tx/encode.js.map +1 -0
  186. package/dist/src/tx/expiry.d.ts +11 -0
  187. package/dist/src/tx/expiry.js +12 -0
  188. package/dist/src/tx/expiry.js.map +1 -0
  189. package/dist/src/tx/fee.d.ts +16 -0
  190. package/dist/src/tx/fee.js +29 -0
  191. package/dist/src/tx/fee.js.map +1 -0
  192. package/dist/src/tx/metadata.d.ts +39 -0
  193. package/dist/src/tx/metadata.js +66 -0
  194. package/dist/src/tx/metadata.js.map +1 -0
  195. package/dist/src/tx/nft.d.ts +16 -0
  196. package/dist/src/tx/nft.js +98 -0
  197. package/dist/src/tx/nft.js.map +1 -0
  198. package/dist/src/tx/proxy.d.ts +37 -0
  199. package/dist/src/tx/proxy.js +134 -0
  200. package/dist/src/tx/proxy.js.map +1 -0
  201. package/dist/src/tx/transfer.d.ts +31 -0
  202. package/dist/src/tx/transfer.js +123 -0
  203. package/dist/src/tx/transfer.js.map +1 -0
  204. package/dist/src/types.d.ts +448 -0
  205. package/dist/src/types.js +2 -0
  206. package/dist/src/types.js.map +1 -0
  207. package/dist/tests/account-id.test.d.ts +1 -0
  208. package/dist/tests/account-id.test.js +27 -0
  209. package/dist/tests/account-id.test.js.map +1 -0
  210. package/dist/tests/amount.test.d.ts +1 -0
  211. package/dist/tests/amount.test.js +113 -0
  212. package/dist/tests/amount.test.js.map +1 -0
  213. package/dist/tests/attestation.test.d.ts +1 -0
  214. package/dist/tests/attestation.test.js +182 -0
  215. package/dist/tests/attestation.test.js.map +1 -0
  216. package/dist/tests/chain.test.d.ts +1 -0
  217. package/dist/tests/chain.test.js +647 -0
  218. package/dist/tests/chain.test.js.map +1 -0
  219. package/dist/tests/content.test.d.ts +1 -0
  220. package/dist/tests/content.test.js +90 -0
  221. package/dist/tests/content.test.js.map +1 -0
  222. package/dist/tests/documented-api.test.d.ts +1 -0
  223. package/dist/tests/documented-api.test.js +229 -0
  224. package/dist/tests/documented-api.test.js.map +1 -0
  225. package/dist/tests/explorer.test.d.ts +1 -0
  226. package/dist/tests/explorer.test.js +95 -0
  227. package/dist/tests/explorer.test.js.map +1 -0
  228. package/dist/tests/fee.test.d.ts +1 -0
  229. package/dist/tests/fee.test.js +179 -0
  230. package/dist/tests/fee.test.js.map +1 -0
  231. package/dist/tests/fixtures/build-vll.d.ts +71 -0
  232. package/dist/tests/fixtures/build-vll.js +141 -0
  233. package/dist/tests/fixtures/build-vll.js.map +1 -0
  234. package/dist/tests/fixtures/fake-socket.d.ts +44 -0
  235. package/dist/tests/fixtures/fake-socket.js +93 -0
  236. package/dist/tests/fixtures/fake-socket.js.map +1 -0
  237. package/dist/tests/fixtures/fake-transport.d.ts +24 -0
  238. package/dist/tests/fixtures/fake-transport.js +30 -0
  239. package/dist/tests/fixtures/fake-transport.js.map +1 -0
  240. package/dist/tests/keypair.test.d.ts +1 -0
  241. package/dist/tests/keypair.test.js +163 -0
  242. package/dist/tests/keypair.test.js.map +1 -0
  243. package/dist/tests/ledger.test.d.ts +1 -0
  244. package/dist/tests/ledger.test.js +234 -0
  245. package/dist/tests/ledger.test.js.map +1 -0
  246. package/dist/tests/mnemonic.test.d.ts +1 -0
  247. package/dist/tests/mnemonic.test.js +97 -0
  248. package/dist/tests/mnemonic.test.js.map +1 -0
  249. package/dist/tests/nft-transfer.test.d.ts +1 -0
  250. package/dist/tests/nft-transfer.test.js +170 -0
  251. package/dist/tests/nft-transfer.test.js.map +1 -0
  252. package/dist/tests/nft.test.d.ts +1 -0
  253. package/dist/tests/nft.test.js +180 -0
  254. package/dist/tests/nft.test.js.map +1 -0
  255. package/dist/tests/offline.test.d.ts +1 -0
  256. package/dist/tests/offline.test.js +95 -0
  257. package/dist/tests/offline.test.js.map +1 -0
  258. package/dist/tests/proxy.test.d.ts +1 -0
  259. package/dist/tests/proxy.test.js +183 -0
  260. package/dist/tests/proxy.test.js.map +1 -0
  261. package/dist/tests/select.test.d.ts +1 -0
  262. package/dist/tests/select.test.js +200 -0
  263. package/dist/tests/select.test.js.map +1 -0
  264. package/dist/tests/socket.test.d.ts +1 -0
  265. package/dist/tests/socket.test.js +607 -0
  266. package/dist/tests/socket.test.js.map +1 -0
  267. package/dist/tests/transfer.test.d.ts +1 -0
  268. package/dist/tests/transfer.test.js +225 -0
  269. package/dist/tests/transfer.test.js.map +1 -0
  270. package/dist/tests/wallet-address.test.d.ts +1 -0
  271. package/dist/tests/wallet-address.test.js +101 -0
  272. package/dist/tests/wallet-address.test.js.map +1 -0
  273. package/dist/tests/wasm-loader.jest.d.ts +13 -0
  274. package/dist/tests/wasm-loader.jest.js +15 -0
  275. package/dist/tests/wasm-loader.jest.js.map +1 -0
  276. package/example/.env.example +4 -0
  277. package/example/README.md +304 -0
  278. package/example/USAGE.md +74 -0
  279. package/example/index.html +12 -0
  280. package/example/package-lock.json +1557 -0
  281. package/example/package.json +25 -0
  282. package/example/scripts/browser-check.mjs +1421 -0
  283. package/example/scripts/match-derivation.mjs +65 -0
  284. package/example/src/App.vue +138 -0
  285. package/example/src/components/AuthorityPanel.vue +277 -0
  286. package/example/src/components/ChainPanel.vue +267 -0
  287. package/example/src/components/ChainState.vue +59 -0
  288. package/example/src/components/CopyButton.vue +25 -0
  289. package/example/src/components/CreateAssetPanel.vue +313 -0
  290. package/example/src/components/DigitalAssetsPanel.vue +68 -0
  291. package/example/src/components/EvidencePanel.vue +396 -0
  292. package/example/src/components/ExplorerPanel.vue +119 -0
  293. package/example/src/components/KeypairPanel.vue +182 -0
  294. package/example/src/components/PhrasePanel.vue +105 -0
  295. package/example/src/components/SocketWarning.vue +18 -0
  296. package/example/src/components/StepGate.vue +24 -0
  297. package/example/src/components/TransferPanel.vue +416 -0
  298. package/example/src/components/TxDeadline.vue +19 -0
  299. package/example/src/components/TxFee.vue +31 -0
  300. package/example/src/components/TxStatus.vue +105 -0
  301. package/example/src/composables/useSocketConnection.ts +80 -0
  302. package/example/src/env.d.ts +12 -0
  303. package/example/src/main.ts +5 -0
  304. package/example/src/pennies.ts +7 -0
  305. package/example/src/style.css +149 -0
  306. package/example/tsconfig.json +19 -0
  307. package/example/vite.config.ts +26 -0
  308. package/jest.config.js +18 -0
  309. package/package.json +2 -6
  310. package/scripts/copy-wasm.mjs +21 -0
  311. package/scripts/smoke.mjs +382 -0
  312. package/src/address/record-type.ts +77 -0
  313. package/src/address/wallet-address.ts +105 -0
  314. package/src/amount.ts +143 -0
  315. package/src/assert.ts +30 -0
  316. package/src/capnp/README.md +15 -0
  317. package/src/capnp/adminNetTx.capnp.ts +66 -0
  318. package/src/capnp/appLayBlock.capnp.ts +26 -0
  319. package/src/capnp/appLayLedger.capnp.ts +35 -0
  320. package/src/capnp/appLayRec.capnp.ts +159 -0
  321. package/src/capnp/chainStateView.capnp.ts +49 -0
  322. package/src/capnp/coinAcctRec.capnp.ts +193 -0
  323. package/src/capnp/genesisBlock.capnp.ts +56 -0
  324. package/src/capnp/hubContentStmt.capnp.ts +59 -0
  325. package/src/capnp/misc.capnp.ts +19 -0
  326. package/src/capnp/netActorRec.capnp.ts +64 -0
  327. package/src/capnp/nodeContentStmt.capnp.ts +62 -0
  328. package/src/capnp/nodePayloadList.capnp.ts +28 -0
  329. package/src/capnp/nodeTxList.capnp.ts +37 -0
  330. package/src/capnp/paramAcctRec.capnp.ts +669 -0
  331. package/src/capnp/payload.capnp.ts +261 -0
  332. package/src/capnp/proxyAcctRec.capnp.ts +259 -0
  333. package/src/capnp/relayContentStmt.capnp.ts +85 -0
  334. package/src/capnp/sysAcctRec.capnp.ts +47 -0
  335. package/src/capnp/userAppTx.capnp.ts +269 -0
  336. package/src/capnp/userValTx.capnp.ts +1999 -0
  337. package/src/capnp/valLayBlock.capnp.ts +93 -0
  338. package/src/capnp/valLayLedger.capnp.ts +80 -0
  339. package/src/chain/geeq-chain.ts +1094 -0
  340. package/src/chain/geeq-node.ts +105 -0
  341. package/src/chain/nonce-guard.ts +73 -0
  342. package/src/chain/select.ts +149 -0
  343. package/src/crypto/account-id.ts +83 -0
  344. package/src/crypto/keypair.ts +221 -0
  345. package/src/crypto/mnemonic.ts +69 -0
  346. package/src/encoding/base64.ts +58 -0
  347. package/src/encoding/hex.ts +42 -0
  348. package/src/errors.ts +122 -0
  349. package/src/index.ts +195 -0
  350. package/src/ledger/coin-accounts.ts +73 -0
  351. package/src/ledger/decode.ts +147 -0
  352. package/src/ledger/geeq-ledger.ts +184 -0
  353. package/src/ledger/net-actors.ts +129 -0
  354. package/src/ledger/nft-records.ts +49 -0
  355. package/src/ledger/params.ts +82 -0
  356. package/src/ledger/proxy-accounts.ts +51 -0
  357. package/src/net/discovery.ts +231 -0
  358. package/src/net/explorer.ts +123 -0
  359. package/src/net/read-ledger.ts +58 -0
  360. package/src/net/routes.ts +79 -0
  361. package/src/net/transport.ts +221 -0
  362. package/src/net/websocket.ts +94 -0
  363. package/src/runtime/bindings.ts +38 -0
  364. package/src/runtime/init.ts +49 -0
  365. package/src/runtime/wasm-loader.browser.ts +22 -0
  366. package/src/runtime/wasm-loader.node.ts +16 -0
  367. package/src/socket/geeq-socket.ts +827 -0
  368. package/src/socket/tracked-tx.ts +319 -0
  369. package/src/socket/tx-status.ts +131 -0
  370. package/src/tx/attestation.ts +222 -0
  371. package/src/tx/content.ts +82 -0
  372. package/src/tx/encode.ts +107 -0
  373. package/src/tx/expiry.ts +11 -0
  374. package/src/tx/fee.ts +31 -0
  375. package/src/tx/metadata.ts +100 -0
  376. package/src/tx/nft.ts +108 -0
  377. package/src/tx/proxy.ts +156 -0
  378. package/src/tx/transfer.ts +162 -0
  379. package/src/types.ts +503 -0
  380. package/src/wasm/README.md +22 -0
  381. package/src/wasm/browser/geeq_core.d.ts +1224 -0
  382. package/src/wasm/browser/geeq_core.js +6014 -0
  383. package/src/wasm/browser/geeq_core_bg.wasm +0 -0
  384. package/src/wasm/browser/geeq_core_bg.wasm.d.ts +447 -0
  385. package/src/wasm/nodejs/geeq_core.d.ts +753 -0
  386. package/src/wasm/nodejs/geeq_core.js +6016 -0
  387. package/src/wasm/nodejs/geeq_core_bg.wasm +0 -0
  388. package/src/wasm/nodejs/geeq_core_bg.wasm.d.ts +447 -0
  389. package/src/wasm/nodejs/package.json +3 -0
  390. package/tsconfig.build.json +8 -0
  391. package/tsconfig.json +21 -0
  392. package/tsup.config.ts +60 -0
@@ -0,0 +1,82 @@
1
+ import { blake3 } from '@noble/hashes/blake3'
2
+
3
+ import { invalidArgument } from '../errors'
4
+
5
+ /** The protocol attests a 32-byte BLAKE3 digest and rejects any other length. */
6
+ export const ATTEST_HASH_BYTES = 32
7
+
8
+ /**
9
+ * Anything that can be attested.
10
+ *
11
+ * A `File` from an `<input type="file">` is a `Blob`, so it can be passed straight in —
12
+ * there is no need to read it into a buffer first. A string is encoded as UTF-8.
13
+ */
14
+ export type GeeqContent = Uint8Array | ArrayBuffer | Blob | string
15
+
16
+ /** Read any accepted content into bytes. Async only because a `Blob` requires it. */
17
+ export async function readContent(content: GeeqContent): Promise<Uint8Array> {
18
+ if (content instanceof Uint8Array) return content
19
+ if (typeof content === 'string') return new TextEncoder().encode(content)
20
+ if (content instanceof ArrayBuffer) return new Uint8Array(content)
21
+ if (typeof Blob !== 'undefined' && content instanceof Blob) {
22
+ return new Uint8Array(await content.arrayBuffer())
23
+ }
24
+ throw invalidArgument(
25
+ 'content must be a string, a Uint8Array, an ArrayBuffer, or a Blob (which includes ' +
26
+ 'a File from a file input).',
27
+ )
28
+ }
29
+
30
+ /**
31
+ * The digest that goes on chain.
32
+ *
33
+ * The content itself never leaves the device; only this does. Pure BLAKE3, so it needs
34
+ * no engine and no network and works before {@link initGeeq} has resolved — which is
35
+ * what lets a UI show the digest as someone types.
36
+ *
37
+ * Use this rather than calling a hash library directly: the length and the algorithm are
38
+ * both fixed by the protocol, and a digest of any other width is rejected when the
39
+ * transaction is built.
40
+ */
41
+ export function attestHashOfSync(content: Uint8Array | ArrayBuffer | string): Uint8Array {
42
+ if (typeof Blob !== 'undefined' && content instanceof Blob) {
43
+ throw invalidArgument(
44
+ 'attestHashOfSync cannot read a Blob. Use attestHashOf, which awaits it.',
45
+ )
46
+ }
47
+ const bytes =
48
+ content instanceof Uint8Array
49
+ ? content
50
+ : typeof content === 'string'
51
+ ? new TextEncoder().encode(content)
52
+ : content instanceof ArrayBuffer
53
+ ? new Uint8Array(content)
54
+ : undefined
55
+
56
+ if (bytes === undefined) {
57
+ throw invalidArgument(
58
+ 'content must be a string, a Uint8Array or an ArrayBuffer. For a Blob or a File, ' +
59
+ 'use attestHashOf.',
60
+ )
61
+ }
62
+ return blake3(bytes, { dkLen: ATTEST_HASH_BYTES })
63
+ }
64
+
65
+ /** {@link attestHashOfSync}, also accepting a `Blob` or a `File`. */
66
+ export async function attestHashOf(content: GeeqContent): Promise<Uint8Array> {
67
+ return blake3(await readContent(content), { dkLen: ATTEST_HASH_BYTES })
68
+ }
69
+
70
+ /** Reject a digest the chain would refuse, naming what was wrong. */
71
+ export function assertAttestHash(attestHash: unknown): Uint8Array {
72
+ if (!(attestHash instanceof Uint8Array)) {
73
+ throw invalidArgument('attestHash must be a Uint8Array.')
74
+ }
75
+ if (attestHash.length !== ATTEST_HASH_BYTES) {
76
+ throw invalidArgument(
77
+ `attestHash must be ${ATTEST_HASH_BYTES} bytes, received ${attestHash.length}. ` +
78
+ 'Use attestHashOf() to produce one.',
79
+ )
80
+ }
81
+ return attestHash
82
+ }
@@ -0,0 +1,107 @@
1
+ import type { Message } from 'capnp-ts'
2
+
3
+ import { assertUint32 } from '../assert'
4
+ import { invalidArgument } from '../errors'
5
+ import type { ChainStateInput, GeeqKeypair } from '../types'
6
+ import { TARGET_BLOCK_SLACK } from './expiry'
7
+
8
+ /**
9
+ * What every transaction builder shares: the checks on its inputs, the Cap'n Proto
10
+ * packing, the engine's canonical flatten, and the fields every built transaction reports
11
+ * about what it is pinned to. One copy, so the four builders cannot drift apart.
12
+ *
13
+ * @internal
14
+ */
15
+
16
+ /** Every refHash the chain computes is a 32-byte BLAKE3. */
17
+ export const REF_HASH_BYTES = 32
18
+
19
+ /** @internal */
20
+ export function assertKeypair(keypair: GeeqKeypair): void {
21
+ if (keypair === null || typeof keypair !== 'object' || typeof keypair.sign !== 'function') {
22
+ throw invalidArgument('keypair must be a GeeqKeypair.')
23
+ }
24
+ }
25
+
26
+ /** @internal The four numbers a transaction carries are each a uint32 on the wire. */
27
+ export function assertChainState(chainState: ChainStateInput): void {
28
+ assertUint32(chainState.chainNumber, 'chainNumber')
29
+ assertUint32(chainState.blockNumber, 'blockNumber')
30
+ assertUint32(chainState.nodeNumber, 'nodeNumber')
31
+ assertUint32(chainState.nonce, 'nonce')
32
+ }
33
+
34
+ /** The two shapes a builder accepts chain state in: four numbers, or one object. */
35
+ type FlatOrStateInput =
36
+ | { readonly chainState: ChainStateInput }
37
+ | {
38
+ readonly chainState?: never
39
+ readonly chainNumber: number
40
+ readonly blockNumber: number
41
+ readonly nodeNumber: number
42
+ readonly nonce: number
43
+ }
44
+
45
+ /**
46
+ * Normalise the two input shapes into one chain state.
47
+ *
48
+ * The flat four-number form is kept for replay and offline signing; the object form is
49
+ * what a chain read produces. Everything after this sees only the object.
50
+ *
51
+ * @internal
52
+ */
53
+ export function resolveChainState(input: FlatOrStateInput): ChainStateInput {
54
+ if (input.chainState !== undefined) return input.chainState
55
+ return {
56
+ chainNumber: input.chainNumber,
57
+ blockNumber: input.blockNumber,
58
+ nodeNumber: input.nodeNumber,
59
+ nonce: input.nonce,
60
+ }
61
+ }
62
+
63
+ /**
64
+ * What a built transaction reports about what it is pinned to: the state itself, frozen,
65
+ * the last block a node takes it at, and the node it must go to when a chain read chose it.
66
+ *
67
+ * @internal
68
+ */
69
+ export function pinning(chainState: ChainStateInput): {
70
+ readonly chainState: ChainStateInput
71
+ readonly validUntilBlock: number
72
+ readonly nodeUrl?: string
73
+ } {
74
+ return {
75
+ chainState: Object.freeze({ ...chainState }),
76
+ validUntilBlock: chainState.blockNumber + TARGET_BLOCK_SLACK,
77
+ ...(chainState.nodeUrl === undefined ? {} : { nodeUrl: chainState.nodeUrl }),
78
+ }
79
+ }
80
+
81
+ /** @internal A message as it is submitted: Cap'n Proto packed. */
82
+ export function packed(message: Message): Uint8Array {
83
+ return new Uint8Array(message.toPackedArrayBuffer())
84
+ }
85
+
86
+ /**
87
+ * Flattening is what makes a signature verifiable by the chain: the engine turns a
88
+ * Cap'n Proto message into the one canonical byte sequence the protocol signs over.
89
+ * Signing the capnp bytes directly would produce a signature every node rejects,
90
+ * because packing is not canonical.
91
+ *
92
+ * @internal
93
+ */
94
+ export function flatten<T extends { flatten(): Uint8Array; free(): void }>(
95
+ parse: () => T,
96
+ what: string,
97
+ ): Uint8Array {
98
+ let handle: T | undefined
99
+ try {
100
+ handle = parse()
101
+ return handle.flatten()
102
+ } catch (cause) {
103
+ throw invalidArgument(`Could not encode the ${what} for signing.`, cause)
104
+ } finally {
105
+ handle?.free()
106
+ }
107
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * How many blocks the chain may move past a transaction's target block before nodes
3
+ * refuse it.
4
+ *
5
+ * A node accepts a target within `[N-8, N+1]` of its own last committed block N
6
+ * (geeq_node_core `indicator-function-worker.ts`, Block Target Consistency), and answers
7
+ * anything older with an HTTP 400 and a `nonsane` status.
8
+ *
9
+ * @internal
10
+ */
11
+ export const TARGET_BLOCK_SLACK = 8
package/src/tx/fee.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { invalidArgument } from '../errors'
2
+ import type { GeeqFee } from '../types'
3
+
4
+ /** The coin part of a fee never exceeds this many times `geeqNorm`, in pennies. */
5
+ const COIN_FEE_CAP = 10_000_000n
6
+
7
+ /**
8
+ * What the chain will charge for a transaction, worked out exactly as the node works it out
9
+ * (geeq_node_core `wrappers/base.ts`, `calculateTransactionFee`):
10
+ *
11
+ * - **data** — `geeqNorm` pennies for every byte of the signed, flattened transaction, and
12
+ * of its flattened payload when it has one;
13
+ * - **coin** — a quarter of a percent of the amount sent, rounded down, and never more than
14
+ * `geeqNorm × 10⁷` pennies. An attestation sends no amount, so it pays only for its data.
15
+ *
16
+ * `undefined` when the chain's `geeqNorm` is not known — the four numbers were supplied by
17
+ * hand, or the chain does not publish it.
18
+ *
19
+ * @internal
20
+ */
21
+ export function feeFor(bytes: number, amount: bigint, geeqNorm: bigint | undefined): GeeqFee | undefined {
22
+ if (geeqNorm === undefined) return undefined
23
+ if (typeof geeqNorm !== 'bigint' || geeqNorm < 0n) {
24
+ throw invalidArgument('geeqNorm must be a bigint of zero or more, as the ledger holds it.')
25
+ }
26
+
27
+ const data = BigInt(bytes) * geeqNorm
28
+ const cap = geeqNorm * COIN_FEE_CAP
29
+ const coin = amount / 400n < cap ? amount / 400n : cap
30
+ return Object.freeze({ total: data + coin, data, coin, bytes })
31
+ }
@@ -0,0 +1,100 @@
1
+ import { invalidArgument, metadataTooLarge } from '../errors'
2
+ import type { GeeqMetadataLimits } from '../types'
3
+
4
+ /** Labels are kept in the order given and encoded as UTF-8. */
5
+ export function encodeMetadata(
6
+ metadata: readonly (string | Uint8Array)[] | undefined,
7
+ ): Uint8Array[] {
8
+ if (metadata === undefined) return []
9
+ const encoder = new TextEncoder()
10
+ return metadata.map((item, index) => {
11
+ if (typeof item === 'string') return encoder.encode(item)
12
+ if (item instanceof Uint8Array) return item
13
+ throw invalidArgument(`metadata[${index}] must be a string or a Uint8Array.`)
14
+ })
15
+ }
16
+
17
+ /**
18
+ * Check encoded metadata against the limits the chain publishes in its ledger.
19
+ *
20
+ * The node enforces both of these at submit time, so catching them here turns an
21
+ * opaque HTTP 400 into a message naming the entry and the limit — and does it before
22
+ * anything is signed. Skipped entirely when the ledger carries no such parameters,
23
+ * because a missing parameter is a schema difference, not a caller error.
24
+ */
25
+ export function assertMetadataWithinLimits(
26
+ encoded: readonly Uint8Array[],
27
+ limits: GeeqMetadataLimits | undefined,
28
+ context: { readonly chainNumber: number; readonly blockNumber: number },
29
+ ): void {
30
+ if (limits === undefined) return
31
+
32
+ if (encoded.length > limits.maxEntries) {
33
+ throw metadataTooLarge(
34
+ `metadata has ${encoded.length} entries but chain ${context.chainNumber} allows at ` +
35
+ `most ${limits.maxEntries} (parameter metadataVarNum, read at block ` +
36
+ `${context.blockNumber}). Remove ${encoded.length - limits.maxEntries}.`,
37
+ )
38
+ }
39
+
40
+ for (let index = 0; index < encoded.length; index += 1) {
41
+ const entry = encoded[index] as Uint8Array
42
+ if (entry.length > limits.maxBytesPerEntry) {
43
+ throw metadataTooLarge(
44
+ `metadata[${index}] is ${entry.length} bytes but chain ${context.chainNumber} ` +
45
+ `allows at most ${limits.maxBytesPerEntry} bytes per entry (parameter ` +
46
+ `metadataVarBytes, read at block ${context.blockNumber}). Characters outside ` +
47
+ 'ASCII cost more than one byte each once encoded as UTF-8, so shorten it.',
48
+ )
49
+ }
50
+ }
51
+ }
52
+
53
+ /** What one metadata entry costs, and whether the chain would take it. */
54
+ export interface MetadataEntryReport {
55
+ readonly index: number
56
+ /** Length once encoded as UTF-8, which is what the limit is measured in. */
57
+ readonly bytes: number
58
+ readonly overLimit: boolean
59
+ }
60
+
61
+ export interface MetadataReport {
62
+ readonly entries: readonly MetadataEntryReport[]
63
+ readonly count: number
64
+ readonly tooManyEntries: boolean
65
+ readonly withinLimits: boolean
66
+ /** Undefined when the chain publishes no limits, in which case nothing is checked. */
67
+ readonly limits: GeeqMetadataLimits | undefined
68
+ }
69
+
70
+ /**
71
+ * Measure metadata against a chain's limits without throwing.
72
+ *
73
+ * The same rules {@link assertMetadataWithinLimits} enforces, reported rather than
74
+ * raised, so a UI can colour a field as someone types instead of waiting for a failed
75
+ * build. Byte lengths are UTF-8, which is the only measure that matters here — a label
76
+ * of ten emoji is forty bytes, and counting characters would call it short.
77
+ */
78
+ export function inspectMetadata(
79
+ metadata: readonly (string | Uint8Array)[] | undefined,
80
+ limits: GeeqMetadataLimits | undefined,
81
+ ): MetadataReport {
82
+ const encoded = encodeMetadata(metadata)
83
+ const maxBytes = limits?.maxBytesPerEntry
84
+ const entries = encoded.map((entry, index) =>
85
+ Object.freeze({
86
+ index,
87
+ bytes: entry.length,
88
+ overLimit: maxBytes !== undefined && entry.length > maxBytes,
89
+ }),
90
+ )
91
+ const tooManyEntries = limits !== undefined && encoded.length > limits.maxEntries
92
+
93
+ return Object.freeze({
94
+ entries: Object.freeze(entries),
95
+ count: encoded.length,
96
+ tooManyEntries,
97
+ withinLimits: !tooManyEntries && !entries.some((entry) => entry.overLimit),
98
+ limits,
99
+ })
100
+ }
package/src/tx/nft.ts ADDED
@@ -0,0 +1,108 @@
1
+ import { blake3 } from '@noble/hashes/blake3'
2
+ import { Message } from 'capnp-ts'
3
+ import { Payload as CapnpPayload } from '../capnp/payload.capnp'
4
+ import { UserAppTx as CapnpUserAppTx } from '../capnp/userAppTx.capnp'
5
+
6
+ import { penniesToUint64 } from '../amount'
7
+ import { ACCOUNT_ID_BYTES, PUBLIC_KEY_BYTES, resolveAccountId } from '../crypto/account-id'
8
+ import { invalidArgument } from '../errors'
9
+ import { assertReady, initGeeq } from '../runtime/init'
10
+ import type { NftMintTx, NftMintTxInput } from '../types'
11
+ import { packPayload, signAppTx, signAttestationSubgroup } from './attestation'
12
+ import { assertAttestHash } from './content'
13
+ import { assertChainState, assertKeypair, pinning } from './encode'
14
+ import { feeFor } from './fee'
15
+ import { assertMetadataWithinLimits, encodeMetadata } from './metadata'
16
+
17
+ /**
18
+ * Build and sign an NFT mint. Synchronous; requires a loaded engine.
19
+ *
20
+ * An NFT is minted through a proxy, and the proxy is the sender: it pays the fee and
21
+ * `amount`, which goes to the receiver with the NFT, and it spends its own nonce. Its
22
+ * admin — the signer here — is the only key the chain accepts for it. The NFT itself is an
23
+ * attestation subgroup, as an attestation carries: the content's hash and its labels,
24
+ * signed by the admin and naming the proxy.
25
+ *
26
+ * Offline: it cannot check that the proxy exists, is the signer's, or can pay.
27
+ * {@link GeeqChain.mintNft} does all three.
28
+ */
29
+ export function createNftMintTxSync(input: NftMintTxInput): NftMintTx {
30
+ assertReady('createNftMintTxSync')
31
+
32
+ const { keypair, attestHash, amount, chainState } = input
33
+ assertKeypair(keypair)
34
+ const proxyAccountId = resolveAccountId(input.proxyAccountId)
35
+ const to = resolveAccountId(input.to)
36
+ assertAttestHash(attestHash)
37
+ if (typeof amount !== 'bigint' || amount <= 0n) {
38
+ throw invalidArgument('amount must be a number of pennies greater than zero, as a bigint.')
39
+ }
40
+ assertChainState(chainState)
41
+ const { chainNumber, blockNumber, nodeNumber, nonce } = chainState
42
+
43
+ const metadata = encodeMetadata(input.metadata)
44
+ assertMetadataWithinLimits(metadata, chainState.metadataLimits, { chainNumber, blockNumber })
45
+
46
+ // 1. The NFT: what it stands for, signed by the admin and naming the proxy. Its id is the
47
+ // hash of the signature-excluded subgroup, as the Geeq wallet computes it.
48
+ const { subgroup, flattened } = signAttestationSubgroup({
49
+ keypair,
50
+ attestHash,
51
+ metadata,
52
+ chainNumber,
53
+ accountId: proxyAccountId,
54
+ })
55
+ const nftId = blake3(flattened, { dkLen: ACCOUNT_ID_BYTES })
56
+
57
+ // 2. The payload carries the subgroup and the id.
58
+ const payloadMessage = new Message()
59
+ const mintPayload = payloadMessage.initRoot(CapnpPayload).initTxType().initNftMint()
60
+ mintPayload.setAttestationSubgroup(subgroup)
61
+ mintPayload.initAcctNumApp(ACCOUNT_ID_BYTES)
62
+ mintPayload.getAcctNumApp().copyBuffer(nftId)
63
+ const { payload, refHashPayload, bytes: payloadBytes } = packPayload(payloadMessage)
64
+
65
+ // 3. The transaction: from the proxy, to the receiver. The nonce is the proxy's, and the
66
+ // key is the admin's, which the node checks against the admin the proxy names.
67
+ const txMessage = new Message()
68
+ const tx = txMessage.initRoot(CapnpUserAppTx)
69
+ const txData = tx.getData()
70
+ const mint = txData.initTxType().initNftMint()
71
+ mint.setAmtCoin(penniesToUint64(amount))
72
+ mint.initAcctNumApp(ACCOUNT_ID_BYTES)
73
+ mint.getAcctNumApp().copyBuffer(nftId)
74
+ mint.initAcctNumRcv(ACCOUNT_ID_BYTES)
75
+ mint.getAcctNumRcv().copyBuffer(to)
76
+ mint.initAcctNumVal(ACCOUNT_ID_BYTES)
77
+ mint.getAcctNumVal().copyBuffer(proxyAccountId)
78
+ txData.setChainNum(chainNumber)
79
+ txData.setBlockNum(blockNumber)
80
+ txData.setNodeNum(nodeNumber)
81
+ txData.setNonce(nonce)
82
+ txData.initRefHashPayload(refHashPayload.length)
83
+ txData.getRefHashPayload().copyBuffer(refHashPayload)
84
+ txData.initPubKey(PUBLIC_KEY_BYTES)
85
+ txData.getPubKey().copyBuffer(keypair.publicKey)
86
+
87
+ const { transaction, transactionHash, bytes } = signAppTx(txMessage, tx, keypair)
88
+
89
+ return Object.freeze({
90
+ transaction,
91
+ payload,
92
+ refHashPayload,
93
+ transactionHash,
94
+ publicKey: keypair.publicKey,
95
+ nftId,
96
+ proxyAccountId,
97
+ to,
98
+ amount,
99
+ fee: feeFor(bytes + payloadBytes, amount, chainState.geeqNorm),
100
+ ...pinning(chainState),
101
+ })
102
+ }
103
+
104
+ /** Build and sign an NFT mint, loading the engine if needed. */
105
+ export async function createNftMintTx(input: NftMintTxInput): Promise<NftMintTx> {
106
+ await initGeeq()
107
+ return createNftMintTxSync(input)
108
+ }
@@ -0,0 +1,156 @@
1
+ import { Message } from 'capnp-ts'
2
+ import { UserValTx as CapnpUserValTx } from '../capnp/userValTx.capnp'
3
+
4
+ import { createWalletAddressSync } from '../address/wallet-address'
5
+ import { penniesToUint64 } from '../amount'
6
+ import { assertUint32 } from '../assert'
7
+ import { ACCOUNT_ID_BYTES, PUBLIC_KEY_BYTES } from '../crypto/account-id'
8
+ import { toBase64 } from '../encoding/base64'
9
+ import { invalidArgument } from '../errors'
10
+ import type { GeeqLedger } from '../ledger/geeq-ledger'
11
+ import { WasmIrnRecordType, wasmGenerateIrn } from '../runtime/bindings'
12
+ import { assertReady, initGeeq } from '../runtime/init'
13
+ import type { GeeqNftMintProxies, NftMintProxyTx, NftMintProxyTxInput } from '../types'
14
+ import { assertChainState, assertKeypair, pinning } from './encode'
15
+ import { feeFor } from './fee'
16
+ import { signValidationTx } from './transfer'
17
+
18
+ /**
19
+ * How many indexes past the last one found the search keeps going before it decides an
20
+ * admin's remaining proxies were not derived from its key. Indexes are taken in order, so
21
+ * a gap is only ever creations that never landed.
22
+ */
23
+ const MAX_INDEX_GAP = 100
24
+
25
+ /**
26
+ * The id of an admin's `index`-th NFT mint proxy.
27
+ *
28
+ * Derived rather than random, exactly as the Geeq wallet derives it, so every proxy an
29
+ * account made can be found again from its key alone. Requires a loaded engine.
30
+ *
31
+ * @internal
32
+ */
33
+ export function nftMintProxyId(adminPublicKey: Uint8Array, index: number): Uint8Array {
34
+ return wasmGenerateIrn(WasmIrnRecordType.ProxyNftMint, adminPublicKey, index)
35
+ }
36
+
37
+ /**
38
+ * An admin's NFT mint proxies in `ledger`, each with its index, and the index the next
39
+ * one takes. Requires a loaded engine.
40
+ *
41
+ * The ledger knows a proxy's admin but not its index, so the index is found by deriving
42
+ * the admin's ids in order — 1, 2, 3… — until every proxy is matched.
43
+ *
44
+ * @internal
45
+ */
46
+ export function nftMintProxiesIn(
47
+ ledger: GeeqLedger,
48
+ admin: { readonly publicKey: Uint8Array },
49
+ ): GeeqNftMintProxies {
50
+ const owned = ledger.findProxyAccounts({ admin })
51
+ const ids = new Set(owned.map((proxy) => toBase64(proxy.accountId)))
52
+
53
+ const indexOf = new Map<string, number>()
54
+ let index = 0
55
+ let highest = 0
56
+ while (indexOf.size < ids.size && index - highest < MAX_INDEX_GAP) {
57
+ index += 1
58
+ const id = toBase64(nftMintProxyId(admin.publicKey, index))
59
+ if (ids.has(id)) {
60
+ indexOf.set(id, index)
61
+ highest = index
62
+ }
63
+ }
64
+
65
+ const proxies = owned
66
+ .map((proxy) =>
67
+ Object.freeze({
68
+ ...proxy,
69
+ index: indexOf.get(toBase64(proxy.accountId)),
70
+ address: createWalletAddressSync({
71
+ accountId: proxy.accountId,
72
+ chainNumber: ledger.chainNumber,
73
+ recordType: 'proxy-nft-mint',
74
+ }),
75
+ }),
76
+ )
77
+ .sort((a, b) => (a.index ?? Number.MAX_SAFE_INTEGER) - (b.index ?? Number.MAX_SAFE_INTEGER))
78
+
79
+ return Object.freeze({ proxies, nextIndex: highest + 1 })
80
+ }
81
+
82
+ /**
83
+ * Build and sign a transaction that creates an NFT mint proxy. Synchronous; requires a
84
+ * loaded engine.
85
+ *
86
+ * A proxy is a record of its own on the chain. It holds coin, carries its own nonce, and
87
+ * names one admin — the signer here — who is the only key that can mint NFTs through it.
88
+ * The signer pays `amount` onto it, plus the fee.
89
+ *
90
+ * Offline: it cannot check that the index is unused or that the signer can afford it.
91
+ * {@link GeeqChain.createNftMintProxy} does both.
92
+ */
93
+ export function createNftMintProxyTxSync(input: NftMintProxyTxInput): NftMintProxyTx {
94
+ assertReady('createNftMintProxyTxSync')
95
+
96
+ const { keypair, index, amount, chainState } = input
97
+ assertKeypair(keypair)
98
+ assertUint32(index, 'index')
99
+ if (index === 0) {
100
+ throw invalidArgument("index counts from 1, as the Geeq wallet counts an admin's proxies.")
101
+ }
102
+ if (typeof amount !== 'bigint' || amount <= 0n) {
103
+ throw invalidArgument('amount must be a number of pennies greater than zero, as a bigint.')
104
+ }
105
+ assertChainState(chainState)
106
+ const { chainNumber, blockNumber, nodeNumber, nonce } = chainState
107
+
108
+ const message = new Message()
109
+ const tx = message.initRoot(CapnpUserValTx)
110
+
111
+ const data = tx.initData()
112
+ data.setChainNum(chainNumber)
113
+ data.setBlockNum(blockNumber)
114
+ data.setNodeNum(nodeNumber)
115
+
116
+ // The nonce and the payer's key sit on the proxy creation itself, as they do on a coin
117
+ // transfer's asset arm. The new record's id goes in the receiver's slot.
118
+ const proxyAccountId = nftMintProxyId(keypair.publicKey, index)
119
+ const create = data.initTx().initProxyCreate()
120
+ create.setNonce(nonce)
121
+ create.setAmtCoin(penniesToUint64(amount))
122
+ create.initAcctNumRcv(ACCOUNT_ID_BYTES)
123
+ create.getAcctNumRcv().copyBuffer(proxyAccountId)
124
+ create.initPubKey(PUBLIC_KEY_BYTES)
125
+ create.getPubKey().copyBuffer(keypair.publicKey)
126
+
127
+ // The admin is named by account id. A mint through the proxy is checked against it.
128
+ const nftMint = create.initTxType().initNftMint()
129
+ nftMint.initAcctNumAdminUser(ACCOUNT_ID_BYTES)
130
+ nftMint.getAcctNumAdminUser().copyBuffer(keypair.accountId)
131
+
132
+ const { transaction, transactionHash, bytes } = signValidationTx(message, tx, keypair, 'proxy creation')
133
+
134
+ return Object.freeze({
135
+ transaction,
136
+ transactionHash,
137
+ publicKey: keypair.publicKey,
138
+ amount,
139
+ index,
140
+ proxyAccountId,
141
+ proxyAddress: createWalletAddressSync({
142
+ accountId: proxyAccountId,
143
+ chainNumber,
144
+ recordType: 'proxy-nft-mint',
145
+ }),
146
+ // The funding counts as the amount sent, so it carries the coin part of the fee too.
147
+ fee: feeFor(bytes, amount, chainState.geeqNorm),
148
+ ...pinning(chainState),
149
+ })
150
+ }
151
+
152
+ /** Build and sign a proxy creation, loading the engine if needed. */
153
+ export async function createNftMintProxyTx(input: NftMintProxyTxInput): Promise<NftMintProxyTx> {
154
+ await initGeeq()
155
+ return createNftMintProxyTxSync(input)
156
+ }