@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
@@ -0,0 +1,301 @@
1
+ /**
2
+ * @module @totemsdk/core/adapters
3
+ * Platform-agnostic adapter interfaces for SDK portability
4
+ *
5
+ * These interfaces enable the SDK to work across multiple platforms:
6
+ * - Browser (Chrome Extensions, web apps)
7
+ * - Node.js (server-side, CLI tools)
8
+ * - React Native (mobile apps) - follow-up
9
+ *
10
+ * Each platform provides its own implementation of these adapters.
11
+ */
12
+
13
+ export interface StorageAdapter {
14
+ get<T>(key: string): Promise<T | null>;
15
+ set<T>(key: string, value: T): Promise<void>;
16
+ remove(key: string): Promise<boolean>;
17
+ clear(): Promise<void>;
18
+ keys(): Promise<string[]>;
19
+ has(key: string): Promise<boolean>;
20
+ }
21
+
22
+ export interface AuthTokenProvider {
23
+ getToken(): Promise<string | null>;
24
+ setToken(token: string): Promise<void>;
25
+ clearToken(): Promise<void>;
26
+ onTokenChange(callback: (token: string | null) => void): () => void;
27
+ isAuthenticated(): Promise<boolean>;
28
+ }
29
+
30
+ export type BinaryData = Uint8Array | ArrayBuffer;
31
+
32
+ export interface WebSocketFactoryOptions {
33
+ pingIntervalMs?: number;
34
+ pongTimeoutMs?: number;
35
+ maxPayloadBytes?: number;
36
+ }
37
+
38
+ export interface WebSocketOpenEvent {
39
+ type: 'open';
40
+ }
41
+
42
+ export interface WebSocketCloseEvent {
43
+ type: 'close';
44
+ code: number;
45
+ reason: string;
46
+ wasClean: boolean;
47
+ }
48
+
49
+ export interface WebSocketMessageEvent {
50
+ type: 'message';
51
+ data: string | BinaryData;
52
+ }
53
+
54
+ export interface WebSocketErrorEvent {
55
+ type: 'error';
56
+ message?: string;
57
+ error?: Error;
58
+ }
59
+
60
+ export type WebSocketEventMap = {
61
+ open: WebSocketOpenEvent;
62
+ close: WebSocketCloseEvent;
63
+ message: WebSocketMessageEvent;
64
+ error: WebSocketErrorEvent;
65
+ };
66
+
67
+ export interface WebSocketFactory {
68
+ create(url: string, protocols?: string[], options?: WebSocketFactoryOptions): WebSocketClient;
69
+ dispose(): void;
70
+ }
71
+
72
+ export interface WebSocketClient {
73
+ readonly readyState: number;
74
+ readonly url: string;
75
+
76
+ send(data: string | BinaryData): void;
77
+ close(code?: number, reason?: string): void;
78
+ terminate(): void;
79
+
80
+ addEventListener<K extends keyof WebSocketEventMap>(
81
+ event: K,
82
+ listener: (ev: WebSocketEventMap[K]) => void
83
+ ): void;
84
+
85
+ removeEventListener<K extends keyof WebSocketEventMap>(
86
+ event: K,
87
+ listener: (ev: WebSocketEventMap[K]) => void
88
+ ): void;
89
+
90
+ removeAllListeners(): void;
91
+
92
+ onopen: ((ev: WebSocketOpenEvent) => void) | null;
93
+ onclose: ((ev: WebSocketCloseEvent) => void) | null;
94
+ onmessage: ((ev: WebSocketMessageEvent) => void) | null;
95
+ onerror: ((ev: WebSocketErrorEvent) => void) | null;
96
+ }
97
+
98
+ export const WebSocketReadyState = {
99
+ CONNECTING: 0,
100
+ OPEN: 1,
101
+ CLOSING: 2,
102
+ CLOSED: 3,
103
+ } as const;
104
+
105
+ export interface CancellationToken {
106
+ readonly cancelled: boolean;
107
+ onCancel(callback: () => void): () => void;
108
+ }
109
+
110
+ export interface CancellationTokenSource {
111
+ readonly token: CancellationToken;
112
+ cancel(): void;
113
+ }
114
+
115
+ export function createCancellationToken(): CancellationTokenSource {
116
+ let cancelled = false;
117
+ const callbacks = new Set<() => void>();
118
+
119
+ const token: CancellationToken = {
120
+ get cancelled() { return cancelled; },
121
+ onCancel(callback: () => void): () => void {
122
+ if (cancelled) {
123
+ callback();
124
+ return () => {};
125
+ }
126
+ callbacks.add(callback);
127
+ return () => callbacks.delete(callback);
128
+ }
129
+ };
130
+
131
+ return {
132
+ token,
133
+ cancel() {
134
+ if (!cancelled) {
135
+ cancelled = true;
136
+ callbacks.forEach(cb => cb());
137
+ callbacks.clear();
138
+ }
139
+ }
140
+ };
141
+ }
142
+
143
+ export interface HttpClient {
144
+ get<T>(url: string, options?: HttpRequestOptions): Promise<HttpResponse<T>>;
145
+ post<T>(url: string, body?: unknown, options?: HttpRequestOptions): Promise<HttpResponse<T>>;
146
+ put<T>(url: string, body?: unknown, options?: HttpRequestOptions): Promise<HttpResponse<T>>;
147
+ delete<T>(url: string, options?: HttpRequestOptions): Promise<HttpResponse<T>>;
148
+ }
149
+
150
+ export interface HttpRequestOptions {
151
+ headers?: Record<string, string>;
152
+ timeout?: number;
153
+ cancellationToken?: CancellationToken;
154
+ }
155
+
156
+ export interface HttpResponse<T> {
157
+ ok: boolean;
158
+ status: number;
159
+ statusText: string;
160
+ headers: Record<string, string>;
161
+ data: T;
162
+ }
163
+
164
+ export interface ConfigProvider {
165
+ get<T>(key: string): T | undefined;
166
+ get<T>(key: string, defaultValue: T): T;
167
+ set<T>(key: string, value: T): void;
168
+ has(key: string): boolean;
169
+ getAll(): Record<string, unknown>;
170
+
171
+ readonly apiUrl: string;
172
+ readonly wsUrl: string;
173
+ readonly network: 'mainnet' | 'testnet' | 'devnet';
174
+ readonly apiKey?: string;
175
+ }
176
+
177
+ export interface LoggerAdapter {
178
+ debug(message: string, ...args: unknown[]): void;
179
+ info(message: string, ...args: unknown[]): void;
180
+ warn(message: string, ...args: unknown[]): void;
181
+ error(message: string, ...args: unknown[]): void;
182
+ }
183
+
184
+ export interface MetricsAdapter {
185
+ increment(name: string, value?: number, tags?: Record<string, string>): void;
186
+ gauge(name: string, value: number, tags?: Record<string, string>): void;
187
+ timing(name: string, durationMs: number, tags?: Record<string, string>): void;
188
+ histogram(name: string, value: number, tags?: Record<string, string>): void;
189
+ }
190
+
191
+ export interface TimerAdapter {
192
+ setTimeout(callback: () => void, ms: number): TimerHandle;
193
+ setInterval(callback: () => void, ms: number): TimerHandle;
194
+ clearTimeout(handle: TimerHandle): void;
195
+ clearInterval(handle: TimerHandle): void;
196
+ now(): number;
197
+ }
198
+
199
+ export type TimerHandle = ReturnType<typeof setTimeout>;
200
+
201
+ export interface CryptoAdapter {
202
+ randomBytes(length: number): Uint8Array;
203
+ sha256(data: Uint8Array): Uint8Array;
204
+ sha256Async(data: Uint8Array): Promise<Uint8Array>;
205
+ }
206
+
207
+ export interface AdapterRegistry {
208
+ storage: StorageAdapter;
209
+ auth: AuthTokenProvider;
210
+ websocket: WebSocketFactory;
211
+ http: HttpClient;
212
+ config: ConfigProvider;
213
+ logger: LoggerAdapter;
214
+ metrics?: MetricsAdapter;
215
+ timer: TimerAdapter;
216
+ crypto: CryptoAdapter;
217
+ }
218
+
219
+ export function createAdapterRegistry(adapters: Partial<AdapterRegistry>): AdapterRegistry {
220
+ const required: (keyof AdapterRegistry)[] = [
221
+ 'storage', 'auth', 'websocket', 'http', 'config', 'logger', 'timer', 'crypto'
222
+ ];
223
+
224
+ for (const key of required) {
225
+ if (!adapters[key]) {
226
+ throw new Error(`Missing required adapter: ${key}`);
227
+ }
228
+ }
229
+
230
+ return adapters as AdapterRegistry;
231
+ }
232
+
233
+ export class NoopLogger implements LoggerAdapter {
234
+ debug(_message: string, ..._args: unknown[]): void {}
235
+ info(_message: string, ..._args: unknown[]): void {}
236
+ warn(_message: string, ..._args: unknown[]): void {}
237
+ error(_message: string, ..._args: unknown[]): void {}
238
+ }
239
+
240
+ export class ConsoleLogger implements LoggerAdapter {
241
+ constructor(private prefix: string = '[SDK]') {}
242
+
243
+ debug(message: string, ...args: unknown[]): void {
244
+ console.debug(`${this.prefix} ${message}`, ...args);
245
+ }
246
+
247
+ info(message: string, ...args: unknown[]): void {
248
+ console.info(`${this.prefix} ${message}`, ...args);
249
+ }
250
+
251
+ warn(message: string, ...args: unknown[]): void {
252
+ console.warn(`${this.prefix} ${message}`, ...args);
253
+ }
254
+
255
+ error(message: string, ...args: unknown[]): void {
256
+ console.error(`${this.prefix} ${message}`, ...args);
257
+ }
258
+ }
259
+
260
+ export class NoopMetrics implements MetricsAdapter {
261
+ increment(_name: string, _value?: number, _tags?: Record<string, string>): void {}
262
+ gauge(_name: string, _value: number, _tags?: Record<string, string>): void {}
263
+ timing(_name: string, _durationMs: number, _tags?: Record<string, string>): void {}
264
+ histogram(_name: string, _value: number, _tags?: Record<string, string>): void {}
265
+ }
266
+
267
+ export class DefaultTimerAdapter implements TimerAdapter {
268
+ setTimeout(callback: () => void, ms: number): TimerHandle {
269
+ return setTimeout(callback, ms);
270
+ }
271
+
272
+ setInterval(callback: () => void, ms: number): TimerHandle {
273
+ return setInterval(callback, ms);
274
+ }
275
+
276
+ clearTimeout(handle: TimerHandle): void {
277
+ clearTimeout(handle);
278
+ }
279
+
280
+ clearInterval(handle: TimerHandle): void {
281
+ clearInterval(handle);
282
+ }
283
+
284
+ now(): number {
285
+ return Date.now();
286
+ }
287
+ }
288
+
289
+ export interface LifecycleAdapter {
290
+ onSuspend(callback: () => void): () => void;
291
+ onResume?(callback: () => void): () => void;
292
+ }
293
+
294
+ export class NoopLifecycleAdapter implements LifecycleAdapter {
295
+ onSuspend(_callback: () => void): () => void {
296
+ return () => {};
297
+ }
298
+ onResume(_callback: () => void): () => void {
299
+ return () => {};
300
+ }
301
+ }
@@ -0,0 +1,235 @@
1
+ /**
2
+ * @module @totemsdk/core/adapters/types
3
+ * Shared type definitions for SDK modules
4
+ */
5
+
6
+ export interface WotsIndices {
7
+ addressIndex: number;
8
+ l1: number;
9
+ l2: number;
10
+ }
11
+
12
+ export type LeaseStatus = 'pending' | 'active' | 'expired' | 'finalized' | 'cancelled';
13
+
14
+ export interface StoredLease {
15
+ leaseId: string;
16
+ leaseToken: string;
17
+ indices: WotsIndices;
18
+ expiresAt: number;
19
+ status: LeaseStatus;
20
+ createdAt: number;
21
+ txId?: string;
22
+ leaseTTL: number;
23
+ }
24
+
25
+ export interface WatermarkState {
26
+ next_addressIndex: number;
27
+ next_l1: number;
28
+ next_l2: number;
29
+ usedIndices: Array<[number, number, number]>;
30
+ lastSyncTimestamp?: number;
31
+ serverWatermark?: WotsIndices;
32
+ }
33
+
34
+ export interface SyncResult {
35
+ updated: boolean;
36
+ drift: number;
37
+ hasConflict: boolean;
38
+ }
39
+
40
+ export interface LeaseExpiryEvent {
41
+ leaseId: string;
42
+ expiresAt: number;
43
+ remainingMs: number;
44
+ }
45
+
46
+ export type LeaseExpiryCallback = (event: LeaseExpiryEvent) => void;
47
+
48
+ export interface TransactionPrepareParams {
49
+ txId: string;
50
+ rootPublicKey: string;
51
+ to: string;
52
+ amount: string;
53
+ tokenId?: string;
54
+ burn?: string | null;
55
+ digestL2?: string | null;
56
+ digestL3?: string | null;
57
+ ttlMs?: number;
58
+ }
59
+
60
+ export interface PreparedTransaction {
61
+ leaseToken: string;
62
+ lease: WotsIndices;
63
+ txId: string;
64
+ digestTx?: string | null;
65
+ }
66
+
67
+ export interface SignedTransaction {
68
+ txId: string;
69
+ signedHex: string;
70
+ leaseToken: string;
71
+ }
72
+
73
+ export interface FinalizedTransaction {
74
+ txId: string;
75
+ status: 'success' | 'failed';
76
+ blockHeight?: number;
77
+ confirmations?: number;
78
+ error?: string;
79
+ }
80
+
81
+ export type TransactionStatus =
82
+ | 'preparing'
83
+ | 'signing'
84
+ | 'submitting'
85
+ | 'pending'
86
+ | 'confirmed'
87
+ | 'failed';
88
+
89
+ export interface TransactionState {
90
+ txId: string;
91
+ status: TransactionStatus;
92
+ lease?: StoredLease;
93
+ signedHex?: string;
94
+ blockHeight?: number;
95
+ confirmations?: number;
96
+ error?: string;
97
+ createdAt: number;
98
+ updatedAt: number;
99
+ }
100
+
101
+ export interface BalanceSnapshot {
102
+ address: string;
103
+ confirmed: string;
104
+ unconfirmed: string;
105
+ total: string;
106
+ tokenId: string;
107
+ timestamp: number;
108
+ }
109
+
110
+ export interface BalanceUpdate {
111
+ type: 'snapshot' | 'delta';
112
+ address: string;
113
+ tokenId: string;
114
+ confirmed?: string;
115
+ unconfirmed?: string;
116
+ total?: string;
117
+ delta?: string;
118
+ timestamp: number;
119
+ }
120
+
121
+ export type ConnectionStatus =
122
+ | 'disconnected'
123
+ | 'connecting'
124
+ | 'connected'
125
+ | 'reconnecting'
126
+ | 'error';
127
+
128
+ export interface ConnectionState {
129
+ status: ConnectionStatus;
130
+ lastConnectedAt?: number;
131
+ lastDisconnectedAt?: number;
132
+ reconnectAttempts: number;
133
+ error?: string;
134
+ }
135
+
136
+ export interface QuotaInfo {
137
+ used: number;
138
+ limit: number;
139
+ remaining: number;
140
+ resetsAt: number;
141
+ windowMs: number;
142
+ }
143
+
144
+ export interface RpcError {
145
+ code: number;
146
+ message: string;
147
+ data?: unknown;
148
+ }
149
+
150
+ export class SdkError extends Error {
151
+ constructor(
152
+ message: string,
153
+ public readonly code: string,
154
+ public readonly cause?: Error
155
+ ) {
156
+ super(message);
157
+ this.name = 'SdkError';
158
+ }
159
+ }
160
+
161
+ export class StorageError extends SdkError {
162
+ constructor(message: string, cause?: Error) {
163
+ super(message, 'STORAGE_ERROR', cause);
164
+ this.name = 'StorageError';
165
+ }
166
+ }
167
+
168
+ export class NetworkError extends SdkError {
169
+ constructor(message: string, cause?: Error) {
170
+ super(message, 'NETWORK_ERROR', cause);
171
+ this.name = 'NetworkError';
172
+ }
173
+ }
174
+
175
+ export class AuthenticationError extends SdkError {
176
+ constructor(message: string, cause?: Error) {
177
+ super(message, 'AUTH_ERROR', cause);
178
+ this.name = 'AuthenticationError';
179
+ }
180
+ }
181
+
182
+ export class LeaseError extends SdkError {
183
+ constructor(message: string, cause?: Error) {
184
+ super(message, 'LEASE_ERROR', cause);
185
+ this.name = 'LeaseError';
186
+ }
187
+ }
188
+
189
+ export class TransactionError extends SdkError {
190
+ constructor(message: string, cause?: Error) {
191
+ super(message, 'TRANSACTION_ERROR', cause);
192
+ this.name = 'TransactionError';
193
+ }
194
+ }
195
+
196
+ export class QuotaExceededError extends SdkError {
197
+ constructor(
198
+ message: string,
199
+ public readonly quotaInfo: QuotaInfo,
200
+ cause?: Error
201
+ ) {
202
+ super(message, 'QUOTA_EXCEEDED', cause);
203
+ this.name = 'QuotaExceededError';
204
+ }
205
+ }
206
+
207
+ export type EventUnsubscribe = () => void;
208
+
209
+ export interface EventEmitter<Events extends Record<string, unknown>> {
210
+ on<K extends keyof Events>(event: K, listener: (data: Events[K]) => void): EventUnsubscribe;
211
+ off<K extends keyof Events>(event: K, listener: (data: Events[K]) => void): void;
212
+ emit<K extends keyof Events>(event: K, data: Events[K]): void;
213
+ }
214
+
215
+ export function createEventEmitter<Events extends Record<string, unknown>>(): EventEmitter<Events> {
216
+ const listeners = new Map<keyof Events, Set<(data: unknown) => void>>();
217
+
218
+ return {
219
+ on<K extends keyof Events>(event: K, listener: (data: Events[K]) => void): EventUnsubscribe {
220
+ if (!listeners.has(event)) {
221
+ listeners.set(event, new Set());
222
+ }
223
+ listeners.get(event)!.add(listener as (data: unknown) => void);
224
+ return () => listeners.get(event)?.delete(listener as (data: unknown) => void);
225
+ },
226
+
227
+ off<K extends keyof Events>(event: K, listener: (data: Events[K]) => void): void {
228
+ listeners.get(event)?.delete(listener as (data: unknown) => void);
229
+ },
230
+
231
+ emit<K extends keyof Events>(event: K, data: Events[K]): void {
232
+ listeners.get(event)?.forEach(listener => listener(data));
233
+ }
234
+ };
235
+ }
@@ -0,0 +1,25 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { scriptToAddress } from "./derive";
3
+ import { decodeMx } from "../../base32/src/minima32";
4
+ import { bytesToHex } from "@noble/hashes/utils";
5
+
6
+ describe("Script → Mx (Minima oracles)", () => {
7
+ it("RETURN TRUE", () => {
8
+ const mx = scriptToAddress("RETURN TRUE");
9
+ expect(mx).toBe("MxG082Z5AW0TACM86D3R2WT4Z1PKJKYGWRKDGM2DU30RB43EAVA8HBQURHCQE9V");
10
+ // payload should equal oracle root
11
+ expect(bytesToHex(decodeMx(mx)).toUpperCase()).toBe(
12
+ "582AA40EA996419A3D8A5D26039A4E9584B746C2C26F860DAC8372BEA4457AF6"
13
+ );
14
+ });
15
+
16
+ it("LET x 1 RETURN x == 1", () => {
17
+ const mx = scriptToAddress("LET x 1 RETURN x == 1");
18
+ expect(mx).toBe("MxG085JV8JAT8VVQGR7Z8UVVQQYZ5TUEMN4Y4HU98T9SU8CVRU5Y5NRWFVU5MEF");
19
+ });
20
+
21
+ it("RETURN SIGNEDBY(0xFFFF)", () => {
22
+ const mx = scriptToAddress("RETURN SIGNEDBY(0xFFFF)");
23
+ expect(mx).toBe("MxG0835THZEDNNJHWU8S5AM61FGCZRRV3BB1RQN371SR4S6J0EWA2SUWYS7MZVQ");
24
+ });
25
+ });
@@ -0,0 +1,55 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { makeMinimaAddress, convertMinimaAddress } from "./index";
3
+
4
+ describe("Address Tests (matching Java AddressTests)", () => {
5
+ it("testMakeMinimaAddress - should roundtrip various lengths", () => {
6
+ // Test cases from Java AddressTests.testMakeMinimaAddress()
7
+ const testCases = [
8
+ "0xFFFF",
9
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", // 19 bytes (38 hex chars)
10
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", // 66 bytes (132 hex chars)
11
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", // 34 bytes
12
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", // 20 bytes
13
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" // 38 bytes
14
+ ];
15
+
16
+ for (const hexInput of testCases) {
17
+ console.log(`Testing hex length ${(hexInput.length - 2) / 2} bytes`);
18
+
19
+ // Make Minima address
20
+ const mxAddress = makeMinimaAddress(hexInput);
21
+ console.log(` Input: ${hexInput.slice(0, 20)}...`);
22
+ console.log(` Output: ${mxAddress}`);
23
+
24
+ // Convert back
25
+ const converted = convertMinimaAddress(mxAddress);
26
+
27
+ // Should be equal (case-insensitive comparison since we uppercase on output)
28
+ expect(converted.toUpperCase()).toBe(hexInput.toUpperCase());
29
+ console.log(` ✓ Roundtrip successful\n`);
30
+ }
31
+ });
32
+
33
+ it("should handle MiniData constructor test cases", () => {
34
+ // Test cases from the Java constructor tests
35
+ const testCases = [
36
+ "0xF0F0",
37
+ "0xFFFF",
38
+ "0xFFF0F0"
39
+ ];
40
+
41
+ for (const hexInput of testCases) {
42
+ const mxAddress = makeMinimaAddress(hexInput);
43
+ const converted = convertMinimaAddress(mxAddress);
44
+ expect(converted.toUpperCase()).toBe(hexInput.toUpperCase());
45
+ }
46
+ });
47
+
48
+ it("should handle empty MiniData", () => {
49
+ // Java test includes new MiniData() which is empty
50
+ const empty = "0x";
51
+ const mxAddress = makeMinimaAddress(empty);
52
+ const converted = convertMinimaAddress(mxAddress);
53
+ expect(converted).toBe("0X");
54
+ });
55
+ });
package/src/binio.ts ADDED
@@ -0,0 +1,21 @@
1
+ export class BinWriter {
2
+ #buf: number[] = [];
3
+ get bytes(): Uint8Array { return new Uint8Array(this.#buf); }
4
+
5
+ writeU8(n: number) { this.#buf.push(n & 0xff); }
6
+ writeU16(n: number) { this.#buf.push((n >>> 8) & 0xff, n & 0xff); } // big-endian
7
+ writeU32(n: number) {
8
+ this.#buf.push((n>>>24)&0xff, (n>>>16)&0xff, (n>>>8)&0xff, n&0xff);
9
+ }
10
+ writeU64(bi: bigint) {
11
+ // big-endian 8 bytes
12
+ const out = new Uint8Array(8);
13
+ let x = bi;
14
+ for (let i = 7; i >= 0; i--) {
15
+ out[i] = Number(x & 0xffn);
16
+ x >>= 8n;
17
+ }
18
+ this.writeBytes(out);
19
+ }
20
+ writeBytes(b: Uint8Array) { for (const x of b) this.#buf.push(x); }
21
+ }