@totemsdk/core 1.0.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 (175) hide show
  1. package/dist/Streamable.d.ts +268 -0
  2. package/dist/Streamable.js +416 -0
  3. package/dist/adapters/index.d.ts +190 -0
  4. package/dist/adapters/index.js +107 -0
  5. package/dist/adapters/types.d.ts +149 -0
  6. package/dist/adapters/types.js +67 -0
  7. package/dist/binio.d.ts +9 -0
  8. package/dist/binio.js +30 -0
  9. package/dist/bip39.d.ts +91 -0
  10. package/dist/bip39.js +417 -0
  11. package/dist/derive.d.ts +2 -0
  12. package/dist/derive.js +9 -0
  13. package/dist/index.d.ts +30 -0
  14. package/dist/index.js +53 -0
  15. package/dist/javaStreamables.d.ts +233 -0
  16. package/dist/javaStreamables.js +332 -0
  17. package/dist/lease/LeaseMonitor.d.ts +44 -0
  18. package/dist/lease/LeaseMonitor.js +107 -0
  19. package/dist/lease/LeaseStore.d.ts +57 -0
  20. package/dist/lease/LeaseStore.js +144 -0
  21. package/dist/lease/WatermarkStore.d.ts +61 -0
  22. package/dist/lease/WatermarkStore.js +202 -0
  23. package/dist/lease/index.d.ts +14 -0
  24. package/dist/lease/index.js +13 -0
  25. package/dist/lease-client.d.ts +31 -0
  26. package/dist/lease-client.js +39 -0
  27. package/dist/minima32.d.ts +18 -0
  28. package/dist/minima32.js +112 -0
  29. package/dist/minimaWireSerializer.d.ts +60 -0
  30. package/dist/minimaWireSerializer.js +71 -0
  31. package/dist/mmr.d.ts +156 -0
  32. package/dist/mmr.js +342 -0
  33. package/dist/mx.d.ts +1 -0
  34. package/dist/mx.js +1 -0
  35. package/dist/params.d.ts +29 -0
  36. package/dist/params.js +16 -0
  37. package/dist/script.d.ts +7 -0
  38. package/dist/script.js +22 -0
  39. package/dist/scripts/contract-helpers.d.ts +252 -0
  40. package/dist/scripts/contract-helpers.js +394 -0
  41. package/dist/scripts/dapp-types.d.ts +119 -0
  42. package/dist/scripts/dapp-types.js +72 -0
  43. package/dist/scripts/index.d.ts +4 -0
  44. package/dist/scripts/index.js +4 -0
  45. package/dist/scripts/types.d.ts +81 -0
  46. package/dist/scripts/types.js +145 -0
  47. package/dist/scripts/witness-serializer.d.ts +29 -0
  48. package/dist/scripts/witness-serializer.js +288 -0
  49. package/dist/transaction.d.ts +106 -0
  50. package/dist/transaction.js +284 -0
  51. package/dist/treekey.d.ts +383 -0
  52. package/dist/treekey.js +762 -0
  53. package/dist/tx/TransactionLifecycle.d.ts +55 -0
  54. package/dist/tx/TransactionLifecycle.js +189 -0
  55. package/dist/tx/TransactionReceiptStore.d.ts +36 -0
  56. package/dist/tx/TransactionReceiptStore.js +85 -0
  57. package/dist/tx/TransactionService.d.ts +50 -0
  58. package/dist/tx/TransactionService.js +178 -0
  59. package/dist/tx/index.d.ts +13 -0
  60. package/dist/tx/index.js +12 -0
  61. package/dist/tx/types.d.ts +114 -0
  62. package/dist/tx/types.js +5 -0
  63. package/dist/util.d.ts +1 -0
  64. package/dist/util.js +1 -0
  65. package/dist/utils.d.ts +8 -0
  66. package/dist/utils.js +35 -0
  67. package/dist/verify.d.ts +18 -0
  68. package/dist/verify.js +162 -0
  69. package/dist/version.d.ts +12 -0
  70. package/dist/version.js +12 -0
  71. package/dist/wots.d.ts +232 -0
  72. package/dist/wots.js +538 -0
  73. package/package.json +65 -0
  74. package/src/Streamable.d.ts +265 -0
  75. package/src/Streamable.js +431 -0
  76. package/src/Streamable.ts +567 -0
  77. package/src/__tests__/Streamable.parity.test.ts +422 -0
  78. package/src/__tests__/perAddressDerivation.parity.test.ts +152 -0
  79. package/src/__tests__/wots-parity.test.ts +289 -0
  80. package/src/adapters/index.d.ts +190 -0
  81. package/src/adapters/index.js +117 -0
  82. package/src/adapters/index.ts +301 -0
  83. package/src/adapters/types.ts +235 -0
  84. package/src/addr.oracle.test.ts +25 -0
  85. package/src/address.test.ts +55 -0
  86. package/src/binio.ts +21 -0
  87. package/src/bip39.d.ts +91 -0
  88. package/src/bip39.js +427 -0
  89. package/src/bip39.ts +432 -0
  90. package/src/derive.d.ts +2 -0
  91. package/src/derive.js +13 -0
  92. package/src/derive.ts +11 -0
  93. package/src/index.d.ts +26 -0
  94. package/src/index.js +128 -0
  95. package/src/index.test.ts +5 -0
  96. package/src/index.ts +206 -0
  97. package/src/javaStreamables.d.ts +233 -0
  98. package/src/javaStreamables.js +328 -0
  99. package/src/javaStreamables.ts +403 -0
  100. package/src/lease/LeaseMonitor.d.ts +44 -0
  101. package/src/lease/LeaseMonitor.js +111 -0
  102. package/src/lease/LeaseMonitor.ts +157 -0
  103. package/src/lease/LeaseStore.d.ts +57 -0
  104. package/src/lease/LeaseStore.js +148 -0
  105. package/src/lease/LeaseStore.ts +203 -0
  106. package/src/lease/WatermarkStore.d.ts +61 -0
  107. package/src/lease/WatermarkStore.js +206 -0
  108. package/src/lease/WatermarkStore.ts +270 -0
  109. package/src/lease/index.d.ts +14 -0
  110. package/src/lease/index.js +22 -0
  111. package/src/lease/index.ts +41 -0
  112. package/src/lease-client.d.ts +31 -0
  113. package/src/lease-client.js +44 -0
  114. package/src/lease-client.ts +69 -0
  115. package/src/minima32.d.ts +10 -0
  116. package/src/minima32.js +113 -0
  117. package/src/minima32.test.ts +11 -0
  118. package/src/minima32.ts +127 -0
  119. package/src/minimaWireSerializer.d.ts +189 -0
  120. package/src/minimaWireSerializer.js +311 -0
  121. package/src/minimaWireSerializer.test.ts +466 -0
  122. package/src/minimaWireSerializer.ts +117 -0
  123. package/src/mmr.d.ts +153 -0
  124. package/src/mmr.js +351 -0
  125. package/src/mmr.oracle.test.ts +28 -0
  126. package/src/mmr.ts +429 -0
  127. package/src/mx.test.ts +25 -0
  128. package/src/mx.ts +1 -0
  129. package/src/params.d.ts +29 -0
  130. package/src/params.d.ts.map +1 -0
  131. package/src/params.js +20 -0
  132. package/src/params.js.map +1 -0
  133. package/src/params.ts +44 -0
  134. package/src/script.d.ts +7 -0
  135. package/src/script.js +27 -0
  136. package/src/script.ts +24 -0
  137. package/src/scripts/contract-helpers.ts +609 -0
  138. package/src/scripts/dapp-types.ts +240 -0
  139. package/src/scripts/index.ts +22 -0
  140. package/src/scripts/types.ts +247 -0
  141. package/src/scripts/witness-serializer.ts +384 -0
  142. package/src/transaction.ts +430 -0
  143. package/src/treekey.d.ts +383 -0
  144. package/src/treekey.js +778 -0
  145. package/src/treekey.parity.test.ts +459 -0
  146. package/src/treekey.ts +979 -0
  147. package/src/tx/TransactionLifecycle.d.ts +55 -0
  148. package/src/tx/TransactionLifecycle.js +188 -0
  149. package/src/tx/TransactionLifecycle.ts +280 -0
  150. package/src/tx/TransactionReceiptStore.d.ts +36 -0
  151. package/src/tx/TransactionReceiptStore.js +89 -0
  152. package/src/tx/TransactionReceiptStore.ts +112 -0
  153. package/src/tx/TransactionService.d.ts +31 -0
  154. package/src/tx/TransactionService.js +140 -0
  155. package/src/tx/TransactionService.ts +250 -0
  156. package/src/tx/index.d.ts +13 -0
  157. package/src/tx/index.js +20 -0
  158. package/src/tx/index.ts +44 -0
  159. package/src/tx/types.d.ts +80 -0
  160. package/src/tx/types.js +6 -0
  161. package/src/tx/types.ts +127 -0
  162. package/src/util.d.ts +1 -0
  163. package/src/util.js +5 -0
  164. package/src/util.ts +1 -0
  165. package/src/utils.d.ts +8 -0
  166. package/src/utils.js +42 -0
  167. package/src/utils.ts +38 -0
  168. package/src/verify.ts +209 -0
  169. package/src/version.ts +13 -0
  170. package/src/wots.d.ts +224 -0
  171. package/src/wots.d.ts.map +1 -0
  172. package/src/wots.js +559 -0
  173. package/src/wots.js.map +1 -0
  174. package/src/wots.ts +636 -0
  175. package/test-vectors.json +45 -0
package/dist/mmr.js ADDED
@@ -0,0 +1,342 @@
1
+ // packages/totem-sdk/packages/core/src/mmr.ts
2
+ // Full MMR implementation matching Minima's MMR.java, MMRData.java, and TreeKeyNode.java
3
+ import { sha3_256 as nobleSha3 } from '@noble/hashes/sha3';
4
+ import { serializeMiniNumber, serializeMiniData, javaHashAllObjects } from "./javaStreamables.js";
5
+ // Import canonical wire serialization from Streamable.ts (single source of truth)
6
+ import { writeMMRProof } from "./Streamable.js";
7
+ // Re-export for API compatibility (existing code imports from mmr.ts)
8
+ // Using a wrapper function for better compatibility with dynamic imports
9
+ export function serializeMMRProof(proof, blockTime = 0n) {
10
+ // Convert to Streamable format and serialize
11
+ const streamableProof = {
12
+ blockTime: blockTime,
13
+ chunks: proof.chunks.map(c => ({
14
+ isLeft: c.isLeft,
15
+ mmrData: { data: c.mmrData.data, value: c.mmrData.value }
16
+ }))
17
+ };
18
+ return writeMMRProof(streamableProof);
19
+ }
20
+ export const serializeRealMMRProof = serializeMMRProof;
21
+ /** SHA3-256 helper returning 32 bytes */
22
+ function sha3(data) {
23
+ return nobleSha3(data);
24
+ }
25
+ /** concat utility */
26
+ function concat(...parts) {
27
+ const total = parts.reduce((n, p) => n + p.length, 0);
28
+ const out = new Uint8Array(total);
29
+ let off = 0;
30
+ for (const p of parts) {
31
+ out.set(p, off);
32
+ off += p.length;
33
+ }
34
+ return out;
35
+ }
36
+ /** big-endian u32 */
37
+ const u32be = (n) => new Uint8Array([(n >>> 24) & 0xff, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff]);
38
+ /**
39
+ * EXACT MiniNumber.ZERO wire format from Java:
40
+ * scale (1 byte) = 0x00
41
+ * length (1 byte) = 0x01
42
+ * unscaled bytes (length=1) = 0x00
43
+ * => 00 01 00
44
+ */
45
+ function encodeMiniNumberZERO() {
46
+ return new Uint8Array([0x00, 0x01, 0x00]);
47
+ }
48
+ /**
49
+ * EXACT MiniString wire format (MiniData of UTF-8):
50
+ * 4-byte big-endian length
51
+ * raw UTF-8 bytes
52
+ */
53
+ function encodeMiniStringUTF8(text) {
54
+ const utf8 = new TextEncoder().encode(text);
55
+ const len = u32be(utf8.length);
56
+ return concat(len, utf8);
57
+ }
58
+ /**
59
+ * Byte-exact one-leaf MMR leaf used by Minima Address.java path:
60
+ * sha3( MiniNumber.ZERO || MiniString(script) || MiniNumber.ZERO )
61
+ */
62
+ export function mmrLeafExact(script) {
63
+ const zero = encodeMiniNumberZERO();
64
+ const mstr = encodeMiniStringUTF8(script);
65
+ const all = concat(zero, mstr, zero);
66
+ return sha3(all); // 32-byte leaf hash
67
+ }
68
+ /** In a single-leaf MMR the root equals the leaf commitment. */
69
+ export function mmrRootFromSingleLeaf(script) {
70
+ return mmrLeafExact(script);
71
+ }
72
+ /**
73
+ * Create MMRData leaf node matching Minima's MMRData.CreateMMRDataLeafNode
74
+ *
75
+ * From MMRData.java:
76
+ * MiniData hash = Crypto.getInstance().hashAllObjects(MiniNumber.ZERO, zData, zSumValue);
77
+ *
78
+ * CRITICAL: Crypto.hashAllObjects uses writeDataStream for Streamables:
79
+ * - MiniNumber: scale + len + data (see serializeMiniNumber)
80
+ * - MiniData: 4-byte length + data (see serializeMiniData)
81
+ *
82
+ * For TreeKeyNode, zData is the Winternitz public key (MiniData) and zSumValue is ZERO
83
+ *
84
+ * Serialization order:
85
+ * 1. MiniNumber.ZERO: [0x00, 0x01, 0x00]
86
+ * 2. MiniData (pubkey): [4-byte length] + [bytes] (writeDataStream, NOT writeHashToStream)
87
+ * 3. MiniNumber.ZERO: [0x00, 0x01, 0x00]
88
+ */
89
+ export function createMMRDataLeafNode(pubkey, sumValue = 0n) {
90
+ // Use cached ZERO serialization for efficiency
91
+ const zero = new Uint8Array([0x00, 0x01, 0x00]); // MiniNumber.ZERO
92
+ // IMPORTANT: hashAllObjects uses writeDataStream which is 4-byte length prefixed
93
+ const pubkeySerialized = serializeMiniData(pubkey);
94
+ // For sumValue, serialize as MiniNumber
95
+ let sumSerialized;
96
+ if (sumValue === 0n) {
97
+ sumSerialized = new Uint8Array([0x00, 0x01, 0x00]); // MiniNumber.ZERO
98
+ }
99
+ else {
100
+ sumSerialized = serializeMiniNumber(Number(sumValue));
101
+ }
102
+ const hash = javaHashAllObjects(zero, pubkeySerialized, sumSerialized);
103
+ return { data: hash, value: sumValue };
104
+ }
105
+ /**
106
+ * Create MMRData parent node matching Minima's MMRData.CreateMMRDataParentNode
107
+ *
108
+ * From MMRData.java:
109
+ * MiniNumber sumvalue = zLeft.getValue().add(zRight.getValue());
110
+ * MiniData combinedhash = Crypto.getInstance().hashAllObjects(
111
+ * MiniNumber.ONE, zLeft.getData(), zRight.getData(), sumvalue);
112
+ *
113
+ * CRITICAL: The getData() returns MiniData (the hash), which is serialized
114
+ * with writeDataStream (4-byte length) in hashAllObjects.
115
+ *
116
+ * Serialization order:
117
+ * 1. MiniNumber.ONE: [0x00, 0x01, 0x01]
118
+ * 2. MiniData (left.data): [4-byte length] + [bytes]
119
+ * 3. MiniData (right.data): [4-byte length] + [bytes]
120
+ * 4. MiniNumber (sumvalue): serialized MiniNumber
121
+ */
122
+ export function createMMRDataParentNode(left, right) {
123
+ const sumValue = left.value + right.value;
124
+ // MiniNumber.ONE: [0x00, 0x01, 0x01]
125
+ const one = new Uint8Array([0x00, 0x01, 0x01]);
126
+ // Serialize left and right data as MiniData (4-byte length-prefixed)
127
+ const leftDataSerialized = serializeMiniData(left.data);
128
+ const rightDataSerialized = serializeMiniData(right.data);
129
+ // Serialize sum value
130
+ let sumSerialized;
131
+ if (sumValue === 0n) {
132
+ sumSerialized = new Uint8Array([0x00, 0x01, 0x00]); // MiniNumber.ZERO
133
+ }
134
+ else {
135
+ sumSerialized = serializeMiniNumber(Number(sumValue));
136
+ }
137
+ const hash = javaHashAllObjects(one, leftDataSerialized, rightDataSerialized, sumSerialized);
138
+ return { data: hash, value: sumValue };
139
+ }
140
+ /**
141
+ * Simple MMR Tree for TreeKeyNode
142
+ * Builds a perfect binary tree from N entries (N must be power of 2 for simplicity)
143
+ *
144
+ * This matches TreeKeyNode.java which always uses 64 leaves (2^6)
145
+ */
146
+ export class MMRTree {
147
+ constructor() {
148
+ this.entries = new Map();
149
+ this.leafCount = 0;
150
+ this.maxRow = 0;
151
+ }
152
+ getKey(row, entryNumber) {
153
+ return `${row}:${entryNumber}`;
154
+ }
155
+ setEntry(row, entryNumber, data) {
156
+ const entry = { row, entryNumber, mmrData: data };
157
+ this.entries.set(this.getKey(row, entryNumber), entry);
158
+ if (row > this.maxRow)
159
+ this.maxRow = row;
160
+ return entry;
161
+ }
162
+ getEntry(row, entryNumber) {
163
+ return this.entries.get(this.getKey(row, entryNumber));
164
+ }
165
+ /**
166
+ * Add a leaf entry to the MMR
167
+ * Matches MMR.java addEntry() but simplified for power-of-2 trees
168
+ */
169
+ addLeaf(data) {
170
+ const entryNumber = BigInt(this.leafCount);
171
+ const entry = this.setEntry(0, entryNumber, data);
172
+ this.leafCount++;
173
+ // Propagate up the tree
174
+ let current = entry;
175
+ while (current.entryNumber % 2n === 1n) { // Is right child
176
+ const siblingNumber = current.entryNumber - 1n;
177
+ const sibling = this.getEntry(current.row, siblingNumber);
178
+ if (!sibling)
179
+ break;
180
+ // Create parent node
181
+ const parentData = createMMRDataParentNode(sibling.mmrData, current.mmrData);
182
+ const parentRow = current.row + 1;
183
+ const parentEntry = current.entryNumber / 2n;
184
+ current = this.setEntry(parentRow, parentEntry, parentData);
185
+ }
186
+ return entry;
187
+ }
188
+ /**
189
+ * Build tree from array of Winternitz public keys
190
+ * Used by TreeKeyNode to compute wallet public key
191
+ */
192
+ static fromPublicKeys(pubkeys) {
193
+ const tree = new MMRTree();
194
+ for (const pk of pubkeys) {
195
+ const leafData = createMMRDataLeafNode(pk, 0n);
196
+ tree.addLeaf(leafData);
197
+ }
198
+ return tree;
199
+ }
200
+ /**
201
+ * Get the root of the tree
202
+ * For a perfect binary tree with N leaves, root is at row log2(N), entry 0
203
+ */
204
+ getRoot() {
205
+ if (this.leafCount === 0)
206
+ return null;
207
+ // For power of 2 leaves, there's exactly one peak at the top
208
+ const topRow = Math.floor(Math.log2(this.leafCount));
209
+ const root = this.getEntry(topRow, 0n);
210
+ return root?.mmrData || null;
211
+ }
212
+ /**
213
+ * Get proof for a leaf at given index
214
+ * Matches MMR.java getProofToPeak()
215
+ */
216
+ getProof(leafIndex) {
217
+ const chunks = [];
218
+ let row = 0;
219
+ let entryNumber = BigInt(leafIndex);
220
+ // Walk up the tree collecting siblings
221
+ while (row < this.maxRow) {
222
+ const siblingNumber = entryNumber % 2n === 0n
223
+ ? entryNumber + 1n // Current is left, sibling is right
224
+ : entryNumber - 1n; // Current is right, sibling is left
225
+ const sibling = this.getEntry(row, siblingNumber);
226
+ if (!sibling)
227
+ break;
228
+ const isLeft = siblingNumber < entryNumber;
229
+ chunks.push({ isLeft, mmrData: sibling.mmrData });
230
+ // Move to parent
231
+ row++;
232
+ entryNumber = entryNumber / 2n;
233
+ }
234
+ return { chunks };
235
+ }
236
+ /**
237
+ * Get the leaf MMRData at a specific index
238
+ */
239
+ getLeaf(index) {
240
+ const entry = this.getEntry(0, BigInt(index));
241
+ return entry?.mmrData || null;
242
+ }
243
+ }
244
+ /**
245
+ * Calculate root from leaf data and proof
246
+ * Matches SignatureProof.getRootPublicKey() in Java
247
+ *
248
+ * From SignatureProof.java:
249
+ * MMRData pubentry = MMRData.CreateMMRDataLeafNode(mPublicKey, MiniNumber.ZERO);
250
+ * return mProof.calculateProof(pubentry).getData();
251
+ */
252
+ export function calculateProofRoot(leafData, proof) {
253
+ let current = leafData;
254
+ for (const chunk of proof.chunks) {
255
+ if (chunk.isLeft) {
256
+ // Sibling is on the left, current is on the right
257
+ current = createMMRDataParentNode(chunk.mmrData, current);
258
+ }
259
+ else {
260
+ // Sibling is on the right, current is on the left
261
+ current = createMMRDataParentNode(current, chunk.mmrData);
262
+ }
263
+ }
264
+ return current.data;
265
+ }
266
+ /**
267
+ * Verify a proof: check that leaf + proof computes to expected root
268
+ */
269
+ export function verifyMMRProof(leafPubkey, proof, expectedRoot) {
270
+ const leafData = createMMRDataLeafNode(leafPubkey, 0n);
271
+ const computedRoot = calculateProofRoot(leafData, proof);
272
+ if (computedRoot.length !== expectedRoot.length)
273
+ return false;
274
+ for (let i = 0; i < computedRoot.length; i++) {
275
+ if (computedRoot[i] !== expectedRoot[i])
276
+ return false;
277
+ }
278
+ return true;
279
+ }
280
+ // NOTE: serializeMMRProof is now imported from minimaWireSerializer.ts and re-exported above
281
+ // This consolidates wire format serialization into a single source of truth.
282
+ /**
283
+ * Deserialize MMRProof from bytes matching Minima's MMRProof.readDataStream()
284
+ *
285
+ * Format:
286
+ * 1. blockTime (MiniNumber)
287
+ * 2. chain length (MiniNumber)
288
+ * 3. Each chunk: isLeft (1 byte) + MMRData (hash with 4-byte length prefix + value MiniNumber)
289
+ *
290
+ * CRITICAL: Java MMRData.readDataStream uses mData.readHashFromStream() which reads
291
+ * a 4-byte big-endian length prefix followed by the hash bytes.
292
+ *
293
+ * @returns { proof: MMRProof, blockTime: bigint }
294
+ */
295
+ export function parseMMRProofFromHex(data) {
296
+ let offset = 0;
297
+ // Read blockTime as MiniNumber
298
+ const { value: blockTime, bytesRead: btRead } = readMiniNumber(data, offset);
299
+ offset += btRead;
300
+ // Read chain length as MiniNumber
301
+ const { value: numChunks, bytesRead: ncRead } = readMiniNumber(data, offset);
302
+ offset += ncRead;
303
+ const chunks = [];
304
+ for (let i = 0; i < Number(numChunks); i++) {
305
+ // isLeft flag (1 byte)
306
+ const isLeft = data[offset] === 1;
307
+ offset += 1;
308
+ // MMRData: hash (4-byte length prefix + hash bytes) + value (MiniNumber)
309
+ // Read 4-byte big-endian length
310
+ const hashLength = (data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3];
311
+ offset += 4;
312
+ const hashData = data.slice(offset, offset + hashLength);
313
+ offset += hashLength;
314
+ const { value: chunkValue, bytesRead: cvRead } = readMiniNumber(data, offset);
315
+ offset += cvRead;
316
+ chunks.push({ isLeft, mmrData: { data: hashData, value: chunkValue } });
317
+ }
318
+ return { proof: { chunks }, blockTime };
319
+ }
320
+ /**
321
+ * Read a MiniNumber from bytes at the given offset
322
+ * Format: [scale: 1 byte] [length: 1 byte] [data: N bytes]
323
+ */
324
+ function readMiniNumber(data, offset) {
325
+ const scale = data[offset];
326
+ const length = data[offset + 1];
327
+ if (length === 0) {
328
+ // Zero value (shouldn't happen with proper serialization)
329
+ return { value: 0n, bytesRead: 2 };
330
+ }
331
+ const dataBytes = data.slice(offset + 2, offset + 2 + length);
332
+ // Convert bytes to bigint
333
+ let value = 0n;
334
+ for (let i = 0; i < dataBytes.length; i++) {
335
+ value = (value << 8n) | BigInt(dataBytes[i]);
336
+ }
337
+ // Apply scale if non-zero (for decimal numbers)
338
+ // For TreeKey MMR, scale is always 0
339
+ return { value, bytesRead: 2 + length };
340
+ }
341
+ /** @deprecated Use parseMMRProofFromHex */
342
+ export const deserializeMMRProof = parseMMRProofFromHex;
package/dist/mx.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { hexToMx, mxToHex, makeMinimaAddress, convertMinimaAddress, encodeMx, decodeMx } from './minima32.js';
package/dist/mx.js ADDED
@@ -0,0 +1 @@
1
+ export { hexToMx, mxToHex, makeMinimaAddress, convertMinimaAddress, encodeMx, decodeMx } from './minima32.js';
@@ -0,0 +1,29 @@
1
+ /**
2
+ * WOTS Parameter Set - BouncyCastle Compatible (w=8)
3
+ *
4
+ * Matches Minima Java implementation which uses BouncyCastle:
5
+ * - Winternitz.java: WINTERNITZ_VALUE = 8
6
+ * - WinternitzOTSignature.java: w=8 means 8 BITS per digit (not base-8)
7
+ * - SHA3-256 hash function (mdsize = 32 bytes)
8
+ *
9
+ * Chain count calculation (from WinternitzOTSignature constructor):
10
+ * messagesize = ((mdsize << 3) + w - 1) / w = (256 + 7) / 8 = 32
11
+ * checksumsize = getLog((messagesize << w) + 1) = getLog(8193) = 14 bits
12
+ * keysize = messagesize + (checksumsize + w - 1) / w = 32 + (14 + 7) / 8 = 34
13
+ *
14
+ * So L = 34 chains total, each chain value is 0-255 (8-bit digit)
15
+ */
16
+ export type ParamSet = {
17
+ name: 'minima';
18
+ n: 256;
19
+ w: 8;
20
+ L: 34;
21
+ messageSize: 32;
22
+ checksumSize: 14;
23
+ checksumDigits: 2;
24
+ maxDigit: 255;
25
+ };
26
+ export declare const WOTS_MINIMA: ParamSet;
27
+ export declare const WOTS_V1_DEV: ParamSet;
28
+ export declare const WOTS_V2_SPEC: ParamSet;
29
+ export declare function getParamSet(_env?: string): ParamSet;
package/dist/params.js ADDED
@@ -0,0 +1,16 @@
1
+ export const WOTS_MINIMA = {
2
+ name: 'minima',
3
+ n: 256,
4
+ w: 8,
5
+ L: 34,
6
+ messageSize: 32,
7
+ checksumSize: 14,
8
+ checksumDigits: 2,
9
+ maxDigit: 255,
10
+ };
11
+ // Legacy aliases for backwards compatibility during migration
12
+ export const WOTS_V1_DEV = WOTS_MINIMA;
13
+ export const WOTS_V2_SPEC = WOTS_MINIMA;
14
+ export function getParamSet(_env) {
15
+ return WOTS_MINIMA;
16
+ }
@@ -0,0 +1,7 @@
1
+ import type { WotsKeypair } from "./wots.js";
2
+ /** Produce KISSVM script that authorizes with a WOTS PK digest (32 bytes). */
3
+ export declare function scriptFromWotsPk(pkDigest32: Uint8Array): string;
4
+ /** Address from WOTS keypair (client-only): script -> MMR leaf -> Mx */
5
+ export declare function wotsAddressFromKeypair(kp: WotsKeypair): string;
6
+ /** tiny utils */
7
+ export declare function hexToBytes(hex: string): Uint8Array;
package/dist/script.js ADDED
@@ -0,0 +1,22 @@
1
+ import { bytesToHex } from "./util.js";
2
+ import { scriptToAddress } from "./derive.js";
3
+ /** Produce KISSVM script that authorizes with a WOTS PK digest (32 bytes). */
4
+ export function scriptFromWotsPk(pkDigest32) {
5
+ // Minima uses SHA3-256 in SIGNEDBY paths; here we embed the digest as hex.
6
+ return `RETURN SIGNEDBY(${bytesToHex(pkDigest32)})`;
7
+ }
8
+ /** Address from WOTS keypair (client-only): script -> MMR leaf -> Mx */
9
+ export function wotsAddressFromKeypair(kp) {
10
+ const script = scriptFromWotsPk(kp.pk);
11
+ return scriptToAddress(script);
12
+ }
13
+ /** tiny utils */
14
+ export function hexToBytes(hex) {
15
+ let h = hex.startsWith("0x") ? hex.slice(2) : hex;
16
+ if (h.length % 2)
17
+ h = "0" + h;
18
+ const out = new Uint8Array(h.length / 2);
19
+ for (let i = 0; i < out.length; i++)
20
+ out[i] = parseInt(h.slice(i * 2, i * 2 + 2), 16);
21
+ return out;
22
+ }
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Contract Helpers
3
+ *
4
+ * Provides high-level helpers for building specific contract types:
5
+ * - Timelock contracts
6
+ * - HTLC (Hashed Timelock Contracts)
7
+ * - MAST (Merkelized Abstract Syntax Trees)
8
+ * - Exchange contracts
9
+ * - Vault/covenant contracts
10
+ * - Flash/slow cash
11
+ * - Stateful game contracts
12
+ *
13
+ * Each helper validates inputs and builds the appropriate ScriptDescriptor
14
+ * for use with the EnhancedTransactionBuilder.
15
+ */
16
+ import type { ScriptDescriptor, StateValue } from './types.js';
17
+ /**
18
+ * Timelock Helper
19
+ *
20
+ * Creates timelocked scripts that can only be spent after a certain block.
21
+ */
22
+ export declare class TimelockHelper {
23
+ /**
24
+ * Create a timelock script that unlocks at a specific block.
25
+ */
26
+ static createBlockTimelock(publicKey: string, unlockBlock: bigint): {
27
+ script: string;
28
+ address: string;
29
+ };
30
+ /**
31
+ * Create a timelock script based on coin age.
32
+ */
33
+ static createCoinageTimelock(publicKey: string, minCoinAge: bigint): {
34
+ script: string;
35
+ address: string;
36
+ };
37
+ /**
38
+ * Check if a timelock is satisfied given current block.
39
+ */
40
+ static isUnlocked(unlockBlock: bigint, currentBlock: bigint): boolean;
41
+ /**
42
+ * Build ScriptDescriptor for a timelock spend.
43
+ */
44
+ static buildDescriptor(address: string, publicKey: string, unlockBlock: bigint): ScriptDescriptor;
45
+ }
46
+ /**
47
+ * HTLC Helper
48
+ *
49
+ * Creates Hashed Timelock Contracts for atomic swaps and lightning-style payments.
50
+ */
51
+ export declare class HTLCHelper {
52
+ /**
53
+ * Generate a random preimage and its hash.
54
+ */
55
+ static generateSecret(): {
56
+ preimage: string;
57
+ hash: string;
58
+ };
59
+ /**
60
+ * Hash a preimage using SHA3 (default) or SHA2.
61
+ */
62
+ static hashPreimage(preimage: string, algorithm?: 'sha3' | 'sha2'): string;
63
+ /**
64
+ * Verify a preimage matches a hash.
65
+ */
66
+ static verifyPreimage(preimage: string, expectedHash: string, algorithm?: 'sha3' | 'sha2'): boolean;
67
+ /**
68
+ * Create an HTLC script.
69
+ *
70
+ * The script allows:
71
+ * - Recipient to claim with preimage before timeout
72
+ * - Sender to refund after timeout
73
+ */
74
+ static createHTLC(senderPublicKey: string, recipientPublicKey: string, hashLock: string, timeoutBlock: bigint, algorithm?: 'sha3' | 'sha2'): {
75
+ script: string;
76
+ address: string;
77
+ };
78
+ /**
79
+ * Build ScriptDescriptor to claim HTLC with preimage.
80
+ */
81
+ static buildClaimDescriptor(address: string, senderPublicKey: string, recipientPublicKey: string, hashLock: string, timeoutBlock: bigint, preimage: string): ScriptDescriptor;
82
+ /**
83
+ * Build ScriptDescriptor to refund HTLC after timeout.
84
+ */
85
+ static buildRefundDescriptor(address: string, senderPublicKey: string, recipientPublicKey: string, hashLock: string, timeoutBlock: bigint): ScriptDescriptor;
86
+ }
87
+ /**
88
+ * MAST Helper
89
+ *
90
+ * Creates Merkelized Abstract Syntax Tree contracts for privacy and scalability.
91
+ */
92
+ export declare class MASTHelper {
93
+ /**
94
+ * Compute hash of a script for MAST leaf.
95
+ */
96
+ static hashScript(script: string): string;
97
+ /**
98
+ * Build a simple MAST tree from multiple scripts.
99
+ * Returns the root hash and proofs for each script.
100
+ *
101
+ * For a proper implementation, this should call the mmrcreate RPC.
102
+ * This is a simplified local version for 2 scripts.
103
+ */
104
+ static buildSimpleTree(scripts: string[]): {
105
+ root: string;
106
+ proofs: Map<string, {
107
+ proof: string;
108
+ index: number;
109
+ }>;
110
+ };
111
+ /**
112
+ * Create a MAST script with the given root hash.
113
+ */
114
+ static createMASTScript(rootHash: string): {
115
+ script: string;
116
+ address: string;
117
+ };
118
+ /**
119
+ * Build ScriptDescriptor for spending a MAST branch.
120
+ */
121
+ static buildDescriptor(address: string, rootHash: string, branchScript: string, branchProof: string, wotsPublicKey?: string): ScriptDescriptor;
122
+ }
123
+ /**
124
+ * Exchange Contract Helper
125
+ *
126
+ * Creates DEX-style exchange contracts using VERIFYOUT.
127
+ */
128
+ export declare class ExchangeHelper {
129
+ /**
130
+ * Create an exchange offer script.
131
+ *
132
+ * Owner can cancel, or anyone can take the offer by providing
133
+ * the specified output.
134
+ */
135
+ static createOffer(ownerPublicKey: string, desiredAddress: string, desiredAmount: string, desiredTokenId: string): {
136
+ script: string;
137
+ address: string;
138
+ };
139
+ /**
140
+ * Build state variables for an exchange offer.
141
+ */
142
+ static buildOfferState(ownerPublicKey: string, desiredAddress: string, desiredAmount: string, desiredTokenId: string): StateValue[];
143
+ /**
144
+ * Build ScriptDescriptor for taking an exchange offer.
145
+ */
146
+ static buildTakeOfferDescriptor(address: string, ownerPublicKey: string, desiredAddress: string, desiredAmount: string, desiredTokenId: string): ScriptDescriptor;
147
+ /**
148
+ * Validate VERIFYOUT for an exchange transaction.
149
+ */
150
+ static validateExchange(outputs: Array<{
151
+ address: string;
152
+ amount: string;
153
+ tokenId: string;
154
+ }>, expectedAddress: string, expectedAmount: string, expectedTokenId: string, inputIndex: number): {
155
+ valid: boolean;
156
+ error?: string;
157
+ };
158
+ }
159
+ /**
160
+ * Vault Helper
161
+ *
162
+ * Creates vault/covenant contracts with safe house enforcement.
163
+ */
164
+ export declare class VaultHelper {
165
+ /**
166
+ * Generate safe house script from vault parameters.
167
+ */
168
+ static generateSafeHouseScript(coldKey: string, hotKey: string, cooldownBlocks?: bigint): string;
169
+ /**
170
+ * Create a vault script.
171
+ */
172
+ static createVault(coldKey: string, hotKey: string, cooldownBlocks?: bigint): {
173
+ vaultScript: string;
174
+ vaultAddress: string;
175
+ safeHouseScript: string;
176
+ safeHouseAddress: string;
177
+ };
178
+ /**
179
+ * Build state for vault withdrawal.
180
+ */
181
+ static buildWithdrawalState(amount: string, recipientAddress: string): StateValue[];
182
+ }
183
+ /**
184
+ * Flash Cash Helper
185
+ *
186
+ * Creates flash loan contracts for single-transaction borrowing.
187
+ */
188
+ export declare class FlashCashHelper {
189
+ /**
190
+ * Create a flash cash contract.
191
+ */
192
+ static createFlashCash(ownerPublicKey: string, interestMultiplier?: string): {
193
+ script: string;
194
+ address: string;
195
+ };
196
+ /**
197
+ * Calculate return amount with interest.
198
+ */
199
+ static calculateReturn(borrowAmount: bigint, interestMultiplier: number): bigint;
200
+ /**
201
+ * Build ScriptDescriptor for borrowing flash cash.
202
+ */
203
+ static buildBorrowDescriptor(address: string, ownerPublicKey: string, interestMultiplier?: string): ScriptDescriptor;
204
+ }
205
+ /**
206
+ * Slow Cash Helper
207
+ *
208
+ * Creates rate-limited withdrawal contracts.
209
+ */
210
+ export declare class SlowCashHelper {
211
+ /**
212
+ * Create a slow cash contract.
213
+ */
214
+ static createSlowCash(ownerPublicKey: string, withdrawalPercent?: string, cooldownBlocks?: bigint): {
215
+ script: string;
216
+ address: string;
217
+ };
218
+ /**
219
+ * Calculate withdrawal amount.
220
+ */
221
+ static calculateWithdrawal(currentAmount: bigint, withdrawalPercent: number): {
222
+ withdrawal: bigint;
223
+ remaining: bigint;
224
+ };
225
+ /**
226
+ * Check if withdrawal is allowed based on coin age.
227
+ */
228
+ static canWithdraw(coinAge: bigint, cooldownBlocks: bigint): boolean;
229
+ /**
230
+ * Build ScriptDescriptor for slow cash withdrawal.
231
+ */
232
+ static buildWithdrawalDescriptor(address: string, ownerPublicKey: string, withdrawalPercent?: string, cooldownBlocks?: bigint): ScriptDescriptor;
233
+ }
234
+ /**
235
+ * Stateful Game Helper
236
+ *
237
+ * Creates multi-round stateful contracts (like coin flip).
238
+ */
239
+ export declare class StatefulGameHelper {
240
+ /**
241
+ * Create a round increment assertion.
242
+ */
243
+ static createRoundCheck(): string;
244
+ /**
245
+ * Build state for next round.
246
+ */
247
+ static buildNextRoundState(currentRound: number, preservedPorts: number[], newStates: StateValue[]): StateValue[];
248
+ /**
249
+ * Validate round progression.
250
+ */
251
+ static validateRound(previousRound: number, currentRound: number): boolean;
252
+ }