@dynamic-labs-wallet/midnight 0.0.0 → 0.0.347

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.
package/index.cjs.js ADDED
@@ -0,0 +1,3242 @@
1
+ 'use strict';
2
+
3
+ var browser = require('@dynamic-labs-wallet/browser');
4
+ var ledger = require('@midnight-ntwrk/ledger-v8');
5
+ var walletSdkAddressFormat = require('@midnight-ntwrk/wallet-sdk-address-format');
6
+ var walletSdkDustWallet = require('@midnight-ntwrk/wallet-sdk-dust-wallet');
7
+ var walletSdkFacade = require('@midnight-ntwrk/wallet-sdk-facade');
8
+ var walletSdkShielded = require('@midnight-ntwrk/wallet-sdk-shielded');
9
+ var walletSdkUnshieldedWallet = require('@midnight-ntwrk/wallet-sdk-unshielded-wallet');
10
+ var bip32 = require('@scure/bip32');
11
+ var bs58 = require('bs58');
12
+ var bech32 = require('bech32');
13
+ var sdkApiCore = require('@dynamic-labs/sdk-api-core');
14
+
15
+ function _interopNamespaceDefault(e) {
16
+ var n = Object.create(null);
17
+ if (e) {
18
+ Object.keys(e).forEach(function (k) {
19
+ if (k !== 'default') {
20
+ var d = Object.getOwnPropertyDescriptor(e, k);
21
+ Object.defineProperty(n, k, d.get ? d : {
22
+ enumerable: true,
23
+ get: function () { return e[k]; }
24
+ });
25
+ }
26
+ });
27
+ }
28
+ n.default = e;
29
+ return Object.freeze(n);
30
+ }
31
+
32
+ var ledger__namespace = /*#__PURE__*/_interopNamespaceDefault(ledger);
33
+ var sdkApiCore__namespace = /*#__PURE__*/_interopNamespaceDefault(sdkApiCore);
34
+
35
+ // Midnight network identifiers.
36
+ // 0 = non-mainnet, 1 = Mainnet — baked into the transaction hash to prevent
37
+ // cross-network replay. Names match the Zswap NetworkId enum / the strings
38
+ // accepted by @midnight-ntwrk/midnight-js-network-id's setNetworkId().
39
+ var MIDNIGHT_NETWORK_IDS = {
40
+ mainnet: 1,
41
+ preview: 0,
42
+ preprod: 0,
43
+ undeployed: 0
44
+ };
45
+ // Error messages
46
+ var ERROR_ACCOUNT_ADDRESS_REQUIRED = 'Account address is required';
47
+ var ERROR_NETWORK_ID_REQUIRED = 'Network ID is required for Midnight transactions';
48
+ var ERROR_UNKNOWN_NETWORK = 'Unknown Midnight network';
49
+ var ERROR_CREATE_WALLET_ACCOUNT = 'Failed to create Midnight wallet account';
50
+ var ERROR_EXPORT_PRIVATE_KEY = 'Failed to export Midnight private key';
51
+ var ERROR_IMPORT_PRIVATE_KEY = 'Failed to import Midnight private key';
52
+ var ERROR_KEYGEN_FAILED = 'Key generation failed for Midnight wallet';
53
+ var ERROR_SIGN_MESSAGE = 'Failed to sign Midnight message';
54
+ var ERROR_SIGN_TRANSACTION = 'Failed to sign Midnight transaction';
55
+ /**
56
+ * Resolves a Midnight network name (or `"midnight:<network>"` chainId) to its
57
+ * numeric network ID (0 for non-mainnet, 1 for mainnet).
58
+ *
59
+ * Throws on unrecognized input rather than defaulting — silently falling back
60
+ * to mainnet would bake the wrong network ID into the transaction hash and
61
+ * break the replay-protection guarantee. Fail-loud is correct here.
62
+ *
63
+ * @param networkOrChainId `mainnet` | `preview` | `preprod` | `undeployed`,
64
+ * or the `midnight:<network>` chainId form.
65
+ * @throws {Error} ERROR_UNKNOWN_NETWORK when the input doesn't match any
66
+ * recognized network.
67
+ */ var getNetworkIdFromChainId = function(networkOrChainId) {
68
+ if (networkOrChainId in MIDNIGHT_NETWORK_IDS) {
69
+ return MIDNIGHT_NETWORK_IDS[networkOrChainId];
70
+ }
71
+ if (networkOrChainId.includes(':')) {
72
+ var network = networkOrChainId.split(':')[1];
73
+ if (network && network in MIDNIGHT_NETWORK_IDS) {
74
+ return MIDNIGHT_NETWORK_IDS[network];
75
+ }
76
+ }
77
+ var known = Object.keys(MIDNIGHT_NETWORK_IDS).join(', ');
78
+ throw new Error("".concat(ERROR_UNKNOWN_NETWORK, ': "').concat(networkOrChainId, '". Expected one of: ').concat(known, ', or "midnight:<network>".'));
79
+ };
80
+
81
+ /**
82
+ * IndexedDB-backed persistence for Midnight sub-wallet sync state.
83
+ *
84
+ * Shielded and Dust sub-wallets support serialize/restore — we cache the
85
+ * serialized state per accountAddress so re-initializing a wallet (either
86
+ * after switching away and back, or after a page reload) resumes sync from
87
+ * the last checkpoint instead of re-scanning the entire chain.
88
+ *
89
+ * Storage shape (object store "state", keyed by accountAddress):
90
+ * { accountAddress, shielded, dust, updatedAt }
91
+ *
92
+ * Security: blobs are stored plaintext, matching Dynamic's existing policy
93
+ * for locally-cached key material (see the role-keys entries in
94
+ * localStorage). Protection comes from the iframe's origin isolation, not
95
+ * from at-rest encryption. If Dynamic decides to tighten the local-storage
96
+ * policy product-wide (password-derived encryption with AES-GCM), this
97
+ * module should be upgraded alongside the localStorage role-keys flow as a
98
+ * single consistent hardening pass.
99
+ */ function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
100
+ try {
101
+ var info = gen[key](arg);
102
+ var value = info.value;
103
+ } catch (error) {
104
+ reject(error);
105
+ return;
106
+ }
107
+ if (info.done) {
108
+ resolve(value);
109
+ } else {
110
+ Promise.resolve(value).then(_next, _throw);
111
+ }
112
+ }
113
+ function _async_to_generator$1(fn) {
114
+ return function() {
115
+ var self = this, args = arguments;
116
+ return new Promise(function(resolve, reject) {
117
+ var gen = fn.apply(self, args);
118
+ function _next(value) {
119
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "next", value);
120
+ }
121
+ function _throw(err) {
122
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "throw", err);
123
+ }
124
+ _next(undefined);
125
+ });
126
+ };
127
+ }
128
+ function _instanceof$1(left, right) {
129
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
130
+ return !!right[Symbol.hasInstance](left);
131
+ } else {
132
+ return left instanceof right;
133
+ }
134
+ }
135
+ function _type_of$1(obj) {
136
+ "@swc/helpers - typeof";
137
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
138
+ }
139
+ function _ts_generator$1(thisArg, body) {
140
+ var f, y, t, g, _ = {
141
+ label: 0,
142
+ sent: function() {
143
+ if (t[0] & 1) throw t[1];
144
+ return t[1];
145
+ },
146
+ trys: [],
147
+ ops: []
148
+ };
149
+ return g = {
150
+ next: verb(0),
151
+ "throw": verb(1),
152
+ "return": verb(2)
153
+ }, typeof Symbol === "function" && (g[Symbol.iterator] = function() {
154
+ return this;
155
+ }), g;
156
+ function verb(n) {
157
+ return function(v) {
158
+ return step([
159
+ n,
160
+ v
161
+ ]);
162
+ };
163
+ }
164
+ function step(op) {
165
+ if (f) throw new TypeError("Generator is already executing.");
166
+ while(_)try {
167
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
168
+ if (y = 0, t) op = [
169
+ op[0] & 2,
170
+ t.value
171
+ ];
172
+ switch(op[0]){
173
+ case 0:
174
+ case 1:
175
+ t = op;
176
+ break;
177
+ case 4:
178
+ _.label++;
179
+ return {
180
+ value: op[1],
181
+ done: false
182
+ };
183
+ case 5:
184
+ _.label++;
185
+ y = op[1];
186
+ op = [
187
+ 0
188
+ ];
189
+ continue;
190
+ case 7:
191
+ op = _.ops.pop();
192
+ _.trys.pop();
193
+ continue;
194
+ default:
195
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
196
+ _ = 0;
197
+ continue;
198
+ }
199
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
200
+ _.label = op[1];
201
+ break;
202
+ }
203
+ if (op[0] === 6 && _.label < t[1]) {
204
+ _.label = t[1];
205
+ t = op;
206
+ break;
207
+ }
208
+ if (t && _.label < t[2]) {
209
+ _.label = t[2];
210
+ _.ops.push(op);
211
+ break;
212
+ }
213
+ if (t[2]) _.ops.pop();
214
+ _.trys.pop();
215
+ continue;
216
+ }
217
+ op = body.call(thisArg, _);
218
+ } catch (e) {
219
+ op = [
220
+ 6,
221
+ e
222
+ ];
223
+ y = 0;
224
+ } finally{
225
+ f = t = 0;
226
+ }
227
+ if (op[0] & 5) throw op[1];
228
+ return {
229
+ value: op[0] ? op[1] : void 0,
230
+ done: true
231
+ };
232
+ }
233
+ }
234
+ var DB_NAME = 'dynamic-midnight-wallet-state';
235
+ var DB_VERSION = 1;
236
+ var STORE_NAME = 'state';
237
+ // Normalizes a DOMException | unknown into an Error so promise rejections
238
+ // always carry an Error instance. Object-shaped errors (DOMException, plain
239
+ // objects) are looked up for a `.message` string first so we don't stringify
240
+ // them via Object.prototype.toString (which yields the useless '[object Object]').
241
+ // Exported for direct unit testing of the fallback chain.
242
+ function toError(err, fallbackMessage) {
243
+ if (_instanceof$1(err, Error)) return err;
244
+ if (err == null) return new Error(fallbackMessage);
245
+ if (typeof err === 'string') return new Error(err);
246
+ if (typeof err === 'number' || typeof err === 'boolean' || (typeof err === "undefined" ? "undefined" : _type_of$1(err)) === 'bigint') {
247
+ return new Error(String(err));
248
+ }
249
+ var message = err.message;
250
+ if (typeof message === 'string' && message.length > 0) return new Error(message);
251
+ try {
252
+ return new Error(JSON.stringify(err));
253
+ } catch (e) {
254
+ return new Error(fallbackMessage);
255
+ }
256
+ }
257
+ var dbPromise = null;
258
+ function openDb() {
259
+ if (dbPromise) return dbPromise;
260
+ // On rejection, null the module-level cache so the next caller retries
261
+ // the open instead of receiving the same rejected promise for the rest of
262
+ // the session (private-browsing bootup, transient quota errors, etc).
263
+ // Re-throw so the original caller still sees the rejection.
264
+ dbPromise = new Promise(function(resolve, reject) {
265
+ var req = indexedDB.open(DB_NAME, DB_VERSION);
266
+ req.onupgradeneeded = function() {
267
+ var db = req.result;
268
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
269
+ db.createObjectStore(STORE_NAME, {
270
+ keyPath: 'accountAddress'
271
+ });
272
+ }
273
+ };
274
+ req.onsuccess = function() {
275
+ return resolve(req.result);
276
+ };
277
+ req.onerror = function() {
278
+ return reject(toError(req.error, 'IndexedDB open failed'));
279
+ };
280
+ }).catch(function(err) {
281
+ dbPromise = null;
282
+ throw err;
283
+ });
284
+ return dbPromise;
285
+ }
286
+ function runTransaction(mode, fn) {
287
+ return _runTransaction.apply(this, arguments);
288
+ }
289
+ function _runTransaction() {
290
+ _runTransaction = _async_to_generator$1(function(mode, fn) {
291
+ var db;
292
+ return _ts_generator$1(this, function(_state) {
293
+ switch(_state.label){
294
+ case 0:
295
+ return [
296
+ 4,
297
+ openDb()
298
+ ];
299
+ case 1:
300
+ db = _state.sent();
301
+ return [
302
+ 2,
303
+ new Promise(function(resolve, reject) {
304
+ var tx = db.transaction(STORE_NAME, mode);
305
+ var store = tx.objectStore(STORE_NAME);
306
+ var req = fn(store);
307
+ req.onsuccess = function() {
308
+ return resolve(req.result);
309
+ };
310
+ req.onerror = function() {
311
+ return reject(toError(req.error, 'IndexedDB request failed'));
312
+ };
313
+ })
314
+ ];
315
+ }
316
+ });
317
+ });
318
+ return _runTransaction.apply(this, arguments);
319
+ }
320
+ function getWalletState(accountAddress) {
321
+ return _getWalletState.apply(this, arguments);
322
+ }
323
+ function _getWalletState() {
324
+ _getWalletState = _async_to_generator$1(function(accountAddress) {
325
+ var result;
326
+ return _ts_generator$1(this, function(_state) {
327
+ switch(_state.label){
328
+ case 0:
329
+ _state.trys.push([
330
+ 0,
331
+ 2,
332
+ ,
333
+ 3
334
+ ]);
335
+ return [
336
+ 4,
337
+ runTransaction('readonly', function(store) {
338
+ return store.get(accountAddress);
339
+ })
340
+ ];
341
+ case 1:
342
+ result = _state.sent();
343
+ return [
344
+ 2,
345
+ result !== null && result !== void 0 ? result : null
346
+ ];
347
+ case 2:
348
+ _state.sent();
349
+ // IndexedDB unavailable (private mode, corrupt DB, etc.) — behave as if empty.
350
+ return [
351
+ 2,
352
+ null
353
+ ];
354
+ case 3:
355
+ return [
356
+ 2
357
+ ];
358
+ }
359
+ });
360
+ });
361
+ return _getWalletState.apply(this, arguments);
362
+ }
363
+ function putWalletState(accountAddress, state) {
364
+ return _putWalletState.apply(this, arguments);
365
+ }
366
+ function _putWalletState() {
367
+ _putWalletState = _async_to_generator$1(function(accountAddress, state) {
368
+ var record;
369
+ return _ts_generator$1(this, function(_state) {
370
+ switch(_state.label){
371
+ case 0:
372
+ record = {
373
+ accountAddress: accountAddress,
374
+ shielded: state.shielded,
375
+ dust: state.dust,
376
+ updatedAt: Date.now()
377
+ };
378
+ _state.label = 1;
379
+ case 1:
380
+ _state.trys.push([
381
+ 1,
382
+ 3,
383
+ ,
384
+ 4
385
+ ]);
386
+ return [
387
+ 4,
388
+ runTransaction('readwrite', function(store) {
389
+ return store.put(record);
390
+ })
391
+ ];
392
+ case 2:
393
+ _state.sent();
394
+ return [
395
+ 3,
396
+ 4
397
+ ];
398
+ case 3:
399
+ _state.sent();
400
+ return [
401
+ 3,
402
+ 4
403
+ ];
404
+ case 4:
405
+ return [
406
+ 2
407
+ ];
408
+ }
409
+ });
410
+ });
411
+ return _putWalletState.apply(this, arguments);
412
+ }
413
+ function deleteWalletState(accountAddress) {
414
+ return _deleteWalletState.apply(this, arguments);
415
+ }
416
+ function _deleteWalletState() {
417
+ _deleteWalletState = _async_to_generator$1(function(accountAddress) {
418
+ return _ts_generator$1(this, function(_state) {
419
+ switch(_state.label){
420
+ case 0:
421
+ _state.trys.push([
422
+ 0,
423
+ 2,
424
+ ,
425
+ 3
426
+ ]);
427
+ return [
428
+ 4,
429
+ runTransaction('readwrite', function(store) {
430
+ return store.delete(accountAddress);
431
+ })
432
+ ];
433
+ case 1:
434
+ _state.sent();
435
+ return [
436
+ 3,
437
+ 3
438
+ ];
439
+ case 2:
440
+ _state.sent();
441
+ return [
442
+ 3,
443
+ 3
444
+ ];
445
+ case 3:
446
+ return [
447
+ 2
448
+ ];
449
+ }
450
+ });
451
+ });
452
+ return _deleteWalletState.apply(this, arguments);
453
+ }
454
+
455
+ function _array_like_to_array(arr, len) {
456
+ if (len == null || len > arr.length) len = arr.length;
457
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
458
+ return arr2;
459
+ }
460
+ function _array_with_holes(arr) {
461
+ if (Array.isArray(arr)) return arr;
462
+ }
463
+ function _assert_this_initialized(self) {
464
+ if (self === void 0) {
465
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
466
+ }
467
+ return self;
468
+ }
469
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
470
+ try {
471
+ var info = gen[key](arg);
472
+ var value = info.value;
473
+ } catch (error) {
474
+ reject(error);
475
+ return;
476
+ }
477
+ if (info.done) {
478
+ resolve(value);
479
+ } else {
480
+ Promise.resolve(value).then(_next, _throw);
481
+ }
482
+ }
483
+ function _async_to_generator(fn) {
484
+ return function() {
485
+ var self = this, args = arguments;
486
+ return new Promise(function(resolve, reject) {
487
+ var gen = fn.apply(self, args);
488
+ function _next(value) {
489
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
490
+ }
491
+ function _throw(err) {
492
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
493
+ }
494
+ _next(undefined);
495
+ });
496
+ };
497
+ }
498
+ function _call_super(_this, derived, args) {
499
+ derived = _get_prototype_of(derived);
500
+ return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
501
+ }
502
+ function _class_call_check(instance, Constructor) {
503
+ if (!(instance instanceof Constructor)) {
504
+ throw new TypeError("Cannot call a class as a function");
505
+ }
506
+ }
507
+ function _defineProperties(target, props) {
508
+ for(var i = 0; i < props.length; i++){
509
+ var descriptor = props[i];
510
+ descriptor.enumerable = descriptor.enumerable || false;
511
+ descriptor.configurable = true;
512
+ if ("value" in descriptor) descriptor.writable = true;
513
+ Object.defineProperty(target, descriptor.key, descriptor);
514
+ }
515
+ }
516
+ function _create_class(Constructor, protoProps, staticProps) {
517
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
518
+ if (staticProps) _defineProperties(Constructor, staticProps);
519
+ return Constructor;
520
+ }
521
+ function _define_property(obj, key, value) {
522
+ if (key in obj) {
523
+ Object.defineProperty(obj, key, {
524
+ value: value,
525
+ enumerable: true,
526
+ configurable: true,
527
+ writable: true
528
+ });
529
+ } else {
530
+ obj[key] = value;
531
+ }
532
+ return obj;
533
+ }
534
+ function _get_prototype_of(o) {
535
+ _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
536
+ return o.__proto__ || Object.getPrototypeOf(o);
537
+ };
538
+ return _get_prototype_of(o);
539
+ }
540
+ function _inherits(subClass, superClass) {
541
+ if (typeof superClass !== "function" && superClass !== null) {
542
+ throw new TypeError("Super expression must either be null or a function");
543
+ }
544
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
545
+ constructor: {
546
+ value: subClass,
547
+ writable: true,
548
+ configurable: true
549
+ }
550
+ });
551
+ if (superClass) _set_prototype_of(subClass, superClass);
552
+ }
553
+ function _instanceof(left, right) {
554
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
555
+ return !!right[Symbol.hasInstance](left);
556
+ } else {
557
+ return left instanceof right;
558
+ }
559
+ }
560
+ function _iterable_to_array_limit(arr, i) {
561
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
562
+ if (_i == null) return;
563
+ var _arr = [];
564
+ var _n = true;
565
+ var _d = false;
566
+ var _s, _e;
567
+ try {
568
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
569
+ _arr.push(_s.value);
570
+ if (i && _arr.length === i) break;
571
+ }
572
+ } catch (err) {
573
+ _d = true;
574
+ _e = err;
575
+ } finally{
576
+ try {
577
+ if (!_n && _i["return"] != null) _i["return"]();
578
+ } finally{
579
+ if (_d) throw _e;
580
+ }
581
+ }
582
+ return _arr;
583
+ }
584
+ function _non_iterable_rest() {
585
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
586
+ }
587
+ function _object_spread(target) {
588
+ for(var i = 1; i < arguments.length; i++){
589
+ var source = arguments[i] != null ? arguments[i] : {};
590
+ var ownKeys = Object.keys(source);
591
+ if (typeof Object.getOwnPropertySymbols === "function") {
592
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
593
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
594
+ }));
595
+ }
596
+ ownKeys.forEach(function(key) {
597
+ _define_property(target, key, source[key]);
598
+ });
599
+ }
600
+ return target;
601
+ }
602
+ function ownKeys(object, enumerableOnly) {
603
+ var keys = Object.keys(object);
604
+ if (Object.getOwnPropertySymbols) {
605
+ var symbols = Object.getOwnPropertySymbols(object);
606
+ keys.push.apply(keys, symbols);
607
+ }
608
+ return keys;
609
+ }
610
+ function _object_spread_props(target, source) {
611
+ source = source != null ? source : {};
612
+ if (Object.getOwnPropertyDescriptors) {
613
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
614
+ } else {
615
+ ownKeys(Object(source)).forEach(function(key) {
616
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
617
+ });
618
+ }
619
+ return target;
620
+ }
621
+ function _possible_constructor_return(self, call) {
622
+ if (call && (_type_of(call) === "object" || typeof call === "function")) {
623
+ return call;
624
+ }
625
+ return _assert_this_initialized(self);
626
+ }
627
+ function _set_prototype_of(o, p) {
628
+ _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
629
+ o.__proto__ = p;
630
+ return o;
631
+ };
632
+ return _set_prototype_of(o, p);
633
+ }
634
+ function _sliced_to_array(arr, i) {
635
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
636
+ }
637
+ function _type_of(obj) {
638
+ "@swc/helpers - typeof";
639
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
640
+ }
641
+ function _unsupported_iterable_to_array(o, minLen) {
642
+ if (!o) return;
643
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
644
+ var n = Object.prototype.toString.call(o).slice(8, -1);
645
+ if (n === "Object" && o.constructor) n = o.constructor.name;
646
+ if (n === "Map" || n === "Set") return Array.from(n);
647
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
648
+ }
649
+ function _is_native_reflect_construct() {
650
+ try {
651
+ var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
652
+ } catch (_) {}
653
+ return (_is_native_reflect_construct = function() {
654
+ return !!result;
655
+ })();
656
+ }
657
+ function _ts_generator(thisArg, body) {
658
+ var f, y, t, g, _ = {
659
+ label: 0,
660
+ sent: function() {
661
+ if (t[0] & 1) throw t[1];
662
+ return t[1];
663
+ },
664
+ trys: [],
665
+ ops: []
666
+ };
667
+ return g = {
668
+ next: verb(0),
669
+ "throw": verb(1),
670
+ "return": verb(2)
671
+ }, typeof Symbol === "function" && (g[Symbol.iterator] = function() {
672
+ return this;
673
+ }), g;
674
+ function verb(n) {
675
+ return function(v) {
676
+ return step([
677
+ n,
678
+ v
679
+ ]);
680
+ };
681
+ }
682
+ function step(op) {
683
+ if (f) throw new TypeError("Generator is already executing.");
684
+ while(_)try {
685
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
686
+ if (y = 0, t) op = [
687
+ op[0] & 2,
688
+ t.value
689
+ ];
690
+ switch(op[0]){
691
+ case 0:
692
+ case 1:
693
+ t = op;
694
+ break;
695
+ case 4:
696
+ _.label++;
697
+ return {
698
+ value: op[1],
699
+ done: false
700
+ };
701
+ case 5:
702
+ _.label++;
703
+ y = op[1];
704
+ op = [
705
+ 0
706
+ ];
707
+ continue;
708
+ case 7:
709
+ op = _.ops.pop();
710
+ _.trys.pop();
711
+ continue;
712
+ default:
713
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
714
+ _ = 0;
715
+ continue;
716
+ }
717
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
718
+ _.label = op[1];
719
+ break;
720
+ }
721
+ if (op[0] === 6 && _.label < t[1]) {
722
+ _.label = t[1];
723
+ t = op;
724
+ break;
725
+ }
726
+ if (t && _.label < t[2]) {
727
+ _.label = t[2];
728
+ _.ops.push(op);
729
+ break;
730
+ }
731
+ if (t[2]) _.ops.pop();
732
+ _.trys.pop();
733
+ continue;
734
+ }
735
+ op = body.call(thisArg, _);
736
+ } catch (e) {
737
+ op = [
738
+ 6,
739
+ e
740
+ ];
741
+ y = 0;
742
+ } finally{
743
+ f = t = 0;
744
+ }
745
+ if (op[0] & 5) throw op[1];
746
+ return {
747
+ value: op[0] ? op[1] : void 0,
748
+ done: true
749
+ };
750
+ }
751
+ }
752
+ function _ts_values(o) {
753
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
754
+ if (m) return m.call(o);
755
+ if (o && typeof o.length === "number") return {
756
+ next: function() {
757
+ if (o && i >= o.length) o = void 0;
758
+ return {
759
+ value: o && o[i++],
760
+ done: !o
761
+ };
762
+ }
763
+ };
764
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
765
+ }
766
+ var DynamicMidnightWalletClient = /*#__PURE__*/ function(DynamicWalletClient) {
767
+ _inherits(DynamicMidnightWalletClient, DynamicWalletClient);
768
+ function DynamicMidnightWalletClient(param, internalOptions) {
769
+ var environmentId = param.environmentId, authToken = param.authToken, baseApiUrl = param.baseApiUrl, baseMPCRelayApiUrl = param.baseMPCRelayApiUrl, storageKey = param.storageKey, debug = param.debug, featureFlags = param.featureFlags, _param_authMode = param.authMode, authMode = _param_authMode === void 0 ? browser.AuthMode.HEADER : _param_authMode, sdkVersion = param.sdkVersion, forwardMPCClient = param.forwardMPCClient, logger = param.logger;
770
+ _class_call_check(this, DynamicMidnightWalletClient);
771
+ var _this;
772
+ _this = _call_super(this, DynamicMidnightWalletClient, [
773
+ {
774
+ environmentId: environmentId,
775
+ authToken: authToken,
776
+ baseApiUrl: baseApiUrl,
777
+ baseMPCRelayApiUrl: baseMPCRelayApiUrl,
778
+ storageKey: storageKey,
779
+ debug: debug,
780
+ featureFlags: featureFlags,
781
+ authMode: authMode,
782
+ sdkVersion: sdkVersion,
783
+ forwardMPCClient: forwardMPCClient,
784
+ logger: logger
785
+ },
786
+ internalOptions
787
+ ]), _define_property(_this, "chainName", 'MIDNIGHT'), // Keep wallet alive between calls — avoids 90s re-sync per operation.
788
+ // `diagnosticSub` is the long-lived pending-tx log subscription attached
789
+ // at init time; we hold onto its handle so account-switch / resetCache
790
+ // paths can unsubscribe it and release the closure.
791
+ _define_property(_this, "cachedWallet", null), // Dedup concurrent init calls for the same account. Without this, two
792
+ // public methods invoked back-to-back (e.g. getPrivateBalance +
793
+ // submitTransaction) would both miss the cache, both run WalletFacade.init,
794
+ // and the first wallet's WebSocket + sync threads + diagnostic subscription
795
+ // would be leaked when the second overwrote `cachedWallet`.
796
+ _define_property(_this, "pendingInits", new Map());
797
+ return _this;
798
+ }
799
+ _create_class(DynamicMidnightWalletClient, [
800
+ {
801
+ key: "persistCachedWalletState",
802
+ value: /**
803
+ * Snapshot the current shielded + dust state to IndexedDB so the next
804
+ * init on this account resumes from this checkpoint. Fire-and-forget —
805
+ * callers shouldn't await this to avoid adding latency to user actions.
806
+ *
807
+ * Option A: ONLY persist when the wallet is in a clean resting state
808
+ * (no pending-tx entries, no pending UTXOs on any side). If the wallet
809
+ * has in-flight work, skip the write — we don't want dirty state to
810
+ * get baked into IndexedDB and trap the user on next reload.
811
+ *
812
+ * "Clean" == whatever's persisted can be restored without dragging
813
+ * stale pending entries forward. If a tx fails or a draft is abandoned,
814
+ * sync will reconcile on the next load based on what the chain actually
815
+ * shows, which is always authoritative.
816
+ */ function persistCachedWalletState() {
817
+ var _this = this;
818
+ return _async_to_generator(function() {
819
+ var cached, _snapshot_pending_all, _snapshot_pending, _snapshot_unshielded, _snapshot_shielded, _snapshot_dust, snapshot, _snapshot_pending_all_length, pendingTxCount, _snapshot_unshielded_pendingCoins, _length, unshieldedPending, _snapshot_shielded_pendingCoins, _length1, shieldedPending, _snapshot_dust_pendingCoins, _length2, dustPending, isDirty, _ref, shielded, dust, err;
820
+ return _ts_generator(this, function(_state) {
821
+ switch(_state.label){
822
+ case 0:
823
+ // Capture a local reference up-front: the three `await` sites below yield
824
+ // to the event loop, during which a concurrent resetCache or account
825
+ // switch could null `this.cachedWallet`. Using the local snapshot avoids
826
+ // a TypeError-then-warn on every concurrent access, and the final
827
+ // identity check prevents writing a stopped wallet's state to IndexedDB
828
+ // (which would effectively undo the reset on the next init).
829
+ cached = _this.cachedWallet;
830
+ if (!cached) return [
831
+ 2
832
+ ];
833
+ _state.label = 1;
834
+ case 1:
835
+ _state.trys.push([
836
+ 1,
837
+ 5,
838
+ ,
839
+ 6
840
+ ]);
841
+ return [
842
+ 4,
843
+ new Promise(function(resolve, reject) {
844
+ // `let` is required: the setTimeout closure references `sub` before the
845
+ // `.subscribe()` call returns, and the callback itself can fire
846
+ // synchronously (TDZ hazard with const).
847
+ // eslint-disable-next-line prefer-const
848
+ var sub;
849
+ var tid = setTimeout(function() {
850
+ sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
851
+ reject(new Error('persist snapshot timeout'));
852
+ }, 5000);
853
+ sub = cached.wallet.state().subscribe(function(s) {
854
+ clearTimeout(tid);
855
+ queueMicrotask(function() {
856
+ return sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
857
+ });
858
+ resolve(s);
859
+ });
860
+ })
861
+ ];
862
+ case 2:
863
+ snapshot = _state.sent();
864
+ pendingTxCount = (_snapshot_pending_all_length = snapshot === null || snapshot === void 0 ? void 0 : (_snapshot_pending = snapshot.pending) === null || _snapshot_pending === void 0 ? void 0 : (_snapshot_pending_all = _snapshot_pending.all) === null || _snapshot_pending_all === void 0 ? void 0 : _snapshot_pending_all.length) !== null && _snapshot_pending_all_length !== void 0 ? _snapshot_pending_all_length : 0;
865
+ unshieldedPending = (_length = ((_snapshot_unshielded_pendingCoins = snapshot === null || snapshot === void 0 ? void 0 : (_snapshot_unshielded = snapshot.unshielded) === null || _snapshot_unshielded === void 0 ? void 0 : _snapshot_unshielded.pendingCoins) !== null && _snapshot_unshielded_pendingCoins !== void 0 ? _snapshot_unshielded_pendingCoins : []).length) !== null && _length !== void 0 ? _length : 0;
866
+ shieldedPending = (_length1 = ((_snapshot_shielded_pendingCoins = snapshot === null || snapshot === void 0 ? void 0 : (_snapshot_shielded = snapshot.shielded) === null || _snapshot_shielded === void 0 ? void 0 : _snapshot_shielded.pendingCoins) !== null && _snapshot_shielded_pendingCoins !== void 0 ? _snapshot_shielded_pendingCoins : []).length) !== null && _length1 !== void 0 ? _length1 : 0;
867
+ dustPending = (_length2 = ((_snapshot_dust_pendingCoins = snapshot === null || snapshot === void 0 ? void 0 : (_snapshot_dust = snapshot.dust) === null || _snapshot_dust === void 0 ? void 0 : _snapshot_dust.pendingCoins) !== null && _snapshot_dust_pendingCoins !== void 0 ? _snapshot_dust_pendingCoins : []).length) !== null && _length2 !== void 0 ? _length2 : 0;
868
+ isDirty = pendingTxCount > 0 || unshieldedPending > 0 || shieldedPending > 0 || dustPending > 0;
869
+ if (isDirty) {
870
+ _this.logger.debug("[Midnight] persist skipped — state is dirty \xb7 " + "pendingTxs=".concat(pendingTxCount, " \xb7 unshieldedPending=").concat(unshieldedPending, " \xb7 ") + "shieldedPending=".concat(shieldedPending, " \xb7 dustPending=").concat(dustPending, ". ") + "IndexedDB retains last clean snapshot.");
871
+ return [
872
+ 2
873
+ ];
874
+ }
875
+ return [
876
+ 4,
877
+ Promise.all([
878
+ cached.wallet.shielded.serializeState(),
879
+ cached.wallet.dust.serializeState()
880
+ ])
881
+ ];
882
+ case 3:
883
+ _ref = _sliced_to_array.apply(void 0, [
884
+ _state.sent(),
885
+ 2
886
+ ]), shielded = _ref[0], dust = _ref[1];
887
+ // If the cache was swapped or cleared while we were serializing, skip
888
+ // the write — otherwise we'd persist the old wallet's snapshot under
889
+ // its accountAddress after resetCache (which just deleted that entry)
890
+ // or under a newly-stopped account.
891
+ if (_this.cachedWallet !== cached) {
892
+ _this.logger.debug('[Midnight] persist skipped — cache changed during serialize');
893
+ return [
894
+ 2
895
+ ];
896
+ }
897
+ return [
898
+ 4,
899
+ putWalletState(cached.accountAddress, {
900
+ shielded: shielded,
901
+ dust: dust
902
+ })
903
+ ];
904
+ case 4:
905
+ _state.sent();
906
+ _this.logger.debug('[Midnight] persisted clean wallet state to IndexedDB');
907
+ return [
908
+ 3,
909
+ 6
910
+ ];
911
+ case 5:
912
+ err = _state.sent();
913
+ _this.logger.warn('[Midnight] Failed to persist wallet state:', err);
914
+ return [
915
+ 3,
916
+ 6
917
+ ];
918
+ case 6:
919
+ return [
920
+ 2
921
+ ];
922
+ }
923
+ });
924
+ })();
925
+ }
926
+ },
927
+ {
928
+ key: "createWalletAccount",
929
+ value: function createWalletAccount(param) {
930
+ var thresholdSignatureScheme = param.thresholdSignatureScheme, _param_password = param.password, password = _param_password === void 0 ? undefined : _param_password, onError = param.onError, signedSessionId = param.signedSessionId;
931
+ var _this = this;
932
+ return _async_to_generator(function() {
933
+ var ceremonyCeremonyCompleteResolver, serverAccountAddress, ceremonyCompletePromise, _ref, publicKeyHex, clientKeyShares, accountAddress, pubKeyBytes, roleKeys, shieldedSecretKeys, shieldedAddr, shieldedBech32m, dustBech32m, dustSecretKey, dustAddr, toHex, correctAddresses, wallet, addrError, error;
934
+ return _ts_generator(this, function(_state) {
935
+ switch(_state.label){
936
+ case 0:
937
+ _state.trys.push([
938
+ 0,
939
+ 11,
940
+ ,
941
+ 12
942
+ ]);
943
+ ceremonyCompletePromise = new Promise(function(resolve) {
944
+ ceremonyCeremonyCompleteResolver = resolve;
945
+ });
946
+ return [
947
+ 4,
948
+ _this.keyGen({
949
+ chainName: _this.chainName,
950
+ thresholdSignatureScheme: thresholdSignatureScheme,
951
+ onError: onError,
952
+ onCeremonyComplete: function(accountAddress, walletId) {
953
+ var chainConfig = browser.getMPCChainConfig(_this.chainName);
954
+ serverAccountAddress = accountAddress;
955
+ _this.initializeWalletMapEntry({
956
+ accountAddress: accountAddress,
957
+ walletId: walletId,
958
+ chainName: _this.chainName,
959
+ thresholdSignatureScheme: thresholdSignatureScheme,
960
+ derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map(function(value, index) {
961
+ return [
962
+ index,
963
+ value
964
+ ];
965
+ })))
966
+ });
967
+ ceremonyCeremonyCompleteResolver(undefined);
968
+ },
969
+ password: password,
970
+ signedSessionId: signedSessionId
971
+ })
972
+ ];
973
+ case 1:
974
+ _ref = _state.sent(), publicKeyHex = _ref.rawPublicKey, clientKeyShares = _ref.clientKeyShares;
975
+ return [
976
+ 4,
977
+ ceremonyCompletePromise
978
+ ];
979
+ case 2:
980
+ _state.sent();
981
+ if (!publicKeyHex || !clientKeyShares) {
982
+ throw new Error(ERROR_KEYGEN_FAILED);
983
+ }
984
+ // Server uses ledger.addressFromKey() (Poseidon hash of public key) —
985
+ // we can't run it in the browser because the hashing is WASM-only.
986
+ accountAddress = serverAccountAddress;
987
+ return [
988
+ 4,
989
+ _this.setClientKeySharesToStorage({
990
+ accountAddress: accountAddress,
991
+ clientKeyShares: clientKeyShares
992
+ })
993
+ ];
994
+ case 3:
995
+ _state.sent();
996
+ return [
997
+ 4,
998
+ _this.storeEncryptedBackupByWallet({
999
+ accountAddress: accountAddress,
1000
+ clientKeyShares: clientKeyShares,
1001
+ password: password,
1002
+ signedSessionId: signedSessionId
1003
+ })
1004
+ ];
1005
+ case 4:
1006
+ _state.sent();
1007
+ pubKeyBytes = Buffer.from(publicKeyHex, 'hex');
1008
+ _state.label = 5;
1009
+ case 5:
1010
+ _state.trys.push([
1011
+ 5,
1012
+ 9,
1013
+ ,
1014
+ 10
1015
+ ]);
1016
+ _this.logger.info('[Midnight] Computing shielded and dust addresses client-side');
1017
+ return [
1018
+ 4,
1019
+ _this.getRoleKeys(accountAddress, {
1020
+ password: password,
1021
+ signedSessionId: signedSessionId
1022
+ })
1023
+ ];
1024
+ case 6:
1025
+ roleKeys = _state.sent();
1026
+ shieldedSecretKeys = ledger__namespace.ZswapSecretKeys.fromSeed(new Uint8Array(Buffer.from(roleKeys.shielded, 'hex')));
1027
+ shieldedAddr = new walletSdkAddressFormat.ShieldedAddress(new walletSdkAddressFormat.ShieldedCoinPublicKey(Buffer.from(shieldedSecretKeys.coinPublicKey, 'hex')), new walletSdkAddressFormat.ShieldedEncryptionPublicKey(Buffer.from(shieldedSecretKeys.encryptionPublicKey, 'hex')));
1028
+ shieldedBech32m = walletSdkAddressFormat.MidnightBech32m.encode('preview', shieldedAddr).toString();
1029
+ try {
1030
+ dustSecretKey = ledger__namespace.DustSecretKey.fromSeed(new Uint8Array(Buffer.from(roleKeys.dust, 'hex')));
1031
+ dustAddr = new walletSdkAddressFormat.DustAddress(dustSecretKey.publicKey);
1032
+ dustBech32m = walletSdkAddressFormat.MidnightBech32m.encode('preview', dustAddr).toString();
1033
+ } catch (dustErr) {
1034
+ _this.logger.warn('[Midnight] Dust address encoding failed (skipping):', dustErr);
1035
+ }
1036
+ toHex = function(val) {
1037
+ if (typeof val === 'string') return val;
1038
+ if (_instanceof(val, Uint8Array)) return Buffer.from(val).toString('hex');
1039
+ if ((typeof val === "undefined" ? "undefined" : _type_of(val)) === 'bigint') return val.toString(16);
1040
+ return String(val);
1041
+ };
1042
+ correctAddresses = [
1043
+ {
1044
+ address: accountAddress,
1045
+ type: 'midnight_unshielded',
1046
+ publicKey: toHex(publicKeyHex)
1047
+ },
1048
+ {
1049
+ address: shieldedBech32m,
1050
+ type: 'midnight_shielded',
1051
+ publicKey: toHex(shieldedSecretKeys.coinPublicKey)
1052
+ }
1053
+ ];
1054
+ if (dustBech32m && dustSecretKey) {
1055
+ correctAddresses.push({
1056
+ address: dustBech32m,
1057
+ type: 'midnight_dust',
1058
+ publicKey: toHex(dustSecretKey.publicKey)
1059
+ });
1060
+ }
1061
+ _this.logger.info('[Midnight] Updating additional addresses with correct derivation');
1062
+ return [
1063
+ 4,
1064
+ _this.getWallet({
1065
+ accountAddress: accountAddress,
1066
+ password: password,
1067
+ signedSessionId: signedSessionId
1068
+ })
1069
+ ];
1070
+ case 7:
1071
+ wallet = _state.sent();
1072
+ return [
1073
+ 4,
1074
+ _this.apiClient.updateAdditionalAddresses({
1075
+ walletId: wallet.walletId,
1076
+ additionalAddresses: correctAddresses
1077
+ })
1078
+ ];
1079
+ case 8:
1080
+ _state.sent();
1081
+ _this.logger.info('[Midnight] Additional addresses updated');
1082
+ return [
1083
+ 3,
1084
+ 10
1085
+ ];
1086
+ case 9:
1087
+ addrError = _state.sent();
1088
+ // Non-fatal — wallet works without correct addresses, just display is wrong
1089
+ _this.logger.error('[Midnight] FAILED TO COMPUTE/UPDATE ADDRESSES:', addrError);
1090
+ _this.logger.warn('[Midnight] Failed to update additional addresses (non-fatal)', addrError);
1091
+ return [
1092
+ 3,
1093
+ 10
1094
+ ];
1095
+ case 10:
1096
+ return [
1097
+ 2,
1098
+ {
1099
+ accountAddress: accountAddress,
1100
+ publicKeyHex: publicKeyHex,
1101
+ rawPublicKey: new Uint8Array(pubKeyBytes)
1102
+ }
1103
+ ];
1104
+ case 11:
1105
+ error = _state.sent();
1106
+ // Re-throw password mismatch errors without wrapping
1107
+ if (_instanceof(error, Error) && error.message === browser.ERROR_PASSWORD_MISMATCH) {
1108
+ throw error;
1109
+ }
1110
+ _this.logger.error(ERROR_CREATE_WALLET_ACCOUNT, error);
1111
+ throw new Error(ERROR_CREATE_WALLET_ACCOUNT);
1112
+ case 12:
1113
+ return [
1114
+ 2
1115
+ ];
1116
+ }
1117
+ });
1118
+ })();
1119
+ }
1120
+ },
1121
+ {
1122
+ key: "signMessage",
1123
+ value: function signMessage(param) {
1124
+ var message = param.message, accountAddress = param.accountAddress, _param_password = param.password, password = _param_password === void 0 ? undefined : _param_password, signedSessionId = param.signedSessionId, mfaToken = param.mfaToken, context = param.context, onError = param.onError;
1125
+ var _this = this;
1126
+ return _async_to_generator(function() {
1127
+ var messageHex, resolvedContext, signature, error;
1128
+ return _ts_generator(this, function(_state) {
1129
+ switch(_state.label){
1130
+ case 0:
1131
+ if (!accountAddress) {
1132
+ throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
1133
+ }
1134
+ return [
1135
+ 4,
1136
+ _this.verifyPassword({
1137
+ accountAddress: accountAddress,
1138
+ password: password,
1139
+ signedSessionId: signedSessionId
1140
+ })
1141
+ ];
1142
+ case 1:
1143
+ _state.sent();
1144
+ // The signing API expects hex; policy validation needs the original
1145
+ // bytes. Send hex on the wire, keep the original on the context.
1146
+ messageHex = Buffer.from(message).toString('hex');
1147
+ // Cast: SignMessageContext doesn't declare chain-specific fields.
1148
+ resolvedContext = _object_spread_props(_object_spread({}, context), {
1149
+ midnightMessage: message
1150
+ });
1151
+ _state.label = 2;
1152
+ case 2:
1153
+ _state.trys.push([
1154
+ 2,
1155
+ 4,
1156
+ ,
1157
+ 5
1158
+ ]);
1159
+ return [
1160
+ 4,
1161
+ _this.sign({
1162
+ message: messageHex,
1163
+ accountAddress: accountAddress,
1164
+ chainName: _this.chainName,
1165
+ password: password,
1166
+ signedSessionId: signedSessionId,
1167
+ mfaToken: mfaToken,
1168
+ context: resolvedContext,
1169
+ onError: onError
1170
+ })
1171
+ ];
1172
+ case 3:
1173
+ signature = _state.sent();
1174
+ return [
1175
+ 2,
1176
+ Buffer.from(signature).toString('base64')
1177
+ ];
1178
+ case 4:
1179
+ error = _state.sent();
1180
+ _this.logger.error(ERROR_SIGN_MESSAGE, error);
1181
+ throw new Error(ERROR_SIGN_MESSAGE);
1182
+ case 5:
1183
+ return [
1184
+ 2
1185
+ ];
1186
+ }
1187
+ });
1188
+ })();
1189
+ }
1190
+ },
1191
+ {
1192
+ key: "signTransaction",
1193
+ value: /**
1194
+ * Sign + finalize (prove) an unsigned Midnight transaction. Unshielded
1195
+ * segments are MPC-signed via BIP-340; shielded/dust proving is delegated
1196
+ * to the facade's proof server.
1197
+ *
1198
+ * Side effect: finalizeRecipe mutates wallet state (adds a pending-tx
1199
+ * entry). If the caller never calls submitTransaction, that entry sits
1200
+ * until the next re-sync drops it.
1201
+ */ function signTransaction(param) {
1202
+ var senderAddress = param.senderAddress, transaction = param.transaction, _param_password = param.password, password = _param_password === void 0 ? undefined : _param_password, signedSessionId = param.signedSessionId, mfaToken = param.mfaToken, elevatedAccessToken = param.elevatedAccessToken, networkId = param.networkId, context = param.context, onError = param.onError;
1203
+ var _this = this;
1204
+ return _async_to_generator(function() {
1205
+ var resolvedNetworkId, wallet, txBytes, unsignedTx, signedRecipe, finalized, error;
1206
+ return _ts_generator(this, function(_state) {
1207
+ switch(_state.label){
1208
+ case 0:
1209
+ if (!senderAddress) {
1210
+ throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
1211
+ }
1212
+ return [
1213
+ 4,
1214
+ _this.verifyPassword({
1215
+ accountAddress: senderAddress,
1216
+ password: password,
1217
+ signedSessionId: signedSessionId
1218
+ })
1219
+ ];
1220
+ case 1:
1221
+ _state.sent();
1222
+ if (networkId === undefined) {
1223
+ throw new Error(ERROR_NETWORK_ID_REQUIRED);
1224
+ }
1225
+ resolvedNetworkId = typeof networkId === 'number' ? networkId : getNetworkIdFromChainId(networkId);
1226
+ _state.label = 2;
1227
+ case 2:
1228
+ _state.trys.push([
1229
+ 2,
1230
+ 6,
1231
+ ,
1232
+ 7
1233
+ ]);
1234
+ return [
1235
+ 4,
1236
+ _this.initMidnightWallet('signTransaction', {
1237
+ accountAddress: senderAddress,
1238
+ password: password,
1239
+ signedSessionId: signedSessionId,
1240
+ mfaToken: mfaToken,
1241
+ elevatedAccessToken: elevatedAccessToken
1242
+ })
1243
+ ];
1244
+ case 3:
1245
+ wallet = _state.sent().wallet;
1246
+ txBytes = Buffer.from(transaction, 'base64');
1247
+ unsignedTx = ledger__namespace.Transaction.deserialize('signature', 'pre-proof', 'pre-binding', new Uint8Array(txBytes));
1248
+ // Context carries the full unsigned tx so wallet-service policy can
1249
+ // validate against the whole transaction on each per-segment signature
1250
+ // (same pattern as BTC PSBT per-input context).
1251
+ return [
1252
+ 4,
1253
+ _this.mpcSignIntents(unsignedTx, {
1254
+ accountAddress: senderAddress,
1255
+ password: password,
1256
+ signedSessionId: signedSessionId,
1257
+ mfaToken: mfaToken,
1258
+ elevatedAccessToken: elevatedAccessToken,
1259
+ fullTxBase64: transaction,
1260
+ networkId: resolvedNetworkId,
1261
+ baseContext: context,
1262
+ proofMarker: 'pre-proof'
1263
+ })
1264
+ ];
1265
+ case 4:
1266
+ _state.sent();
1267
+ signedRecipe = {
1268
+ type: 'UNPROVEN_TRANSACTION',
1269
+ transaction: unsignedTx
1270
+ };
1271
+ _this.logger.info('[Midnight] signTransaction: finalizing (ZK prove)...');
1272
+ return [
1273
+ 4,
1274
+ wallet.finalizeRecipe(signedRecipe)
1275
+ ];
1276
+ case 5:
1277
+ finalized = _state.sent();
1278
+ return [
1279
+ 2,
1280
+ Buffer.from(finalized.serialize()).toString('base64')
1281
+ ];
1282
+ case 6:
1283
+ error = _state.sent();
1284
+ _this.logger.error(ERROR_SIGN_TRANSACTION, error);
1285
+ onError === null || onError === void 0 ? void 0 : onError(error);
1286
+ throw _instanceof(error, Error) ? error : new Error(ERROR_SIGN_TRANSACTION);
1287
+ case 7:
1288
+ return [
1289
+ 2
1290
+ ];
1291
+ }
1292
+ });
1293
+ })();
1294
+ }
1295
+ },
1296
+ {
1297
+ key: "exportPrivateKey",
1298
+ value: function exportPrivateKey(param) {
1299
+ var accountAddress = param.accountAddress, _param_password = param.password, password = _param_password === void 0 ? undefined : _param_password, signedSessionId = param.signedSessionId, mfaToken = param.mfaToken, elevatedAccessToken = param.elevatedAccessToken;
1300
+ var _this = this;
1301
+ return _async_to_generator(function() {
1302
+ var mpcSigner, wallet, reconstructedKeyShare, exportId, data, keyExportRaw, exportStr, xprvBytes, error;
1303
+ return _ts_generator(this, function(_state) {
1304
+ switch(_state.label){
1305
+ case 0:
1306
+ // Matches the EVM/BTC exportPrivateKey pattern: verify the password OUTSIDE
1307
+ // the try-catch so a password-protected wallet can't be exported without
1308
+ // the right one AND the specific ERROR_PASSWORD_MISMATCH propagates to the
1309
+ // UI — wrapping it as ERROR_EXPORT_PRIVATE_KEY would hide which prompt to
1310
+ // show the user.
1311
+ return [
1312
+ 4,
1313
+ _this.verifyPassword({
1314
+ accountAddress: accountAddress,
1315
+ password: password,
1316
+ signedSessionId: signedSessionId
1317
+ })
1318
+ ];
1319
+ case 1:
1320
+ _state.sent();
1321
+ _state.label = 2;
1322
+ case 2:
1323
+ _state.trys.push([
1324
+ 2,
1325
+ 8,
1326
+ ,
1327
+ 9
1328
+ ]);
1329
+ // Fetch the master xprv (not the wallet-path-derived key) so derivations
1330
+ // here match what the iframe's HDWallet produces from the same root.
1331
+ mpcSigner = browser.getMPCSigner({
1332
+ chainName: _this.chainName,
1333
+ baseRelayUrl: _this.baseMPCRelayApiUrl
1334
+ });
1335
+ return [
1336
+ 4,
1337
+ _this.getWallet({
1338
+ accountAddress: accountAddress,
1339
+ password: password,
1340
+ walletOperation: browser.WalletOperation.EXPORT_PRIVATE_KEY,
1341
+ signedSessionId: signedSessionId
1342
+ })
1343
+ ];
1344
+ case 3:
1345
+ wallet = _state.sent();
1346
+ return [
1347
+ 4,
1348
+ _this.getReconstructedKeyShare(accountAddress, mpcSigner)
1349
+ ];
1350
+ case 4:
1351
+ reconstructedKeyShare = _state.sent();
1352
+ return [
1353
+ 4,
1354
+ _this.getExportId({
1355
+ chainName: _this.chainName,
1356
+ clientKeyShare: reconstructedKeyShare
1357
+ })
1358
+ ];
1359
+ case 5:
1360
+ exportId = _state.sent();
1361
+ return [
1362
+ 4,
1363
+ _this.apiClient.exportKey({
1364
+ walletId: wallet.walletId,
1365
+ exportId: exportId,
1366
+ mfaToken: mfaToken,
1367
+ elevatedAccessToken: elevatedAccessToken
1368
+ })
1369
+ ];
1370
+ case 6:
1371
+ data = _state.sent();
1372
+ return [
1373
+ 4,
1374
+ _this.performMPCExport(mpcSigner, reconstructedKeyShare, data.roomId, exportId, accountAddress, _this.chainName)
1375
+ ];
1376
+ case 7:
1377
+ keyExportRaw = _state.sent();
1378
+ if (!keyExportRaw) {
1379
+ throw new Error('MPC export returned no key');
1380
+ }
1381
+ // keyExportRaw is a BIP32 xprv in base58; bytes 46-78 are the 32-byte
1382
+ // master private key per the xprv serialization format.
1383
+ exportStr = typeof keyExportRaw === 'string' ? keyExportRaw : String(keyExportRaw);
1384
+ xprvBytes = bs58.decode(exportStr);
1385
+ return [
1386
+ 2,
1387
+ Buffer.from(xprvBytes.slice(46, 78)).toString('hex')
1388
+ ];
1389
+ case 8:
1390
+ error = _state.sent();
1391
+ _this.logger.error(ERROR_EXPORT_PRIVATE_KEY, error);
1392
+ throw new Error(ERROR_EXPORT_PRIVATE_KEY);
1393
+ case 9:
1394
+ return [
1395
+ 2
1396
+ ];
1397
+ }
1398
+ });
1399
+ })();
1400
+ }
1401
+ },
1402
+ {
1403
+ key: "importPrivateKey",
1404
+ value: function importPrivateKey(param) {
1405
+ var privateKey = param.privateKey, chainName = param.chainName, thresholdSignatureScheme = param.thresholdSignatureScheme, _param_password = param.password, password = _param_password === void 0 ? undefined : _param_password, signedSessionId = param.signedSessionId, onError = param.onError; param.publicAddressCheck; var legacyWalletId = param.legacyWalletId;
1406
+ var _this = this;
1407
+ return _async_to_generator(function() {
1408
+ var ceremonyCeremonyCompleteResolver, serverAccountAddress, ceremonyCompletePromise, formattedPrivateKey, _ref, rawPublicKey, clientKeyShares, accountAddress, pubKeyBytes, error;
1409
+ return _ts_generator(this, function(_state) {
1410
+ switch(_state.label){
1411
+ case 0:
1412
+ _state.trys.push([
1413
+ 0,
1414
+ 5,
1415
+ ,
1416
+ 6
1417
+ ]);
1418
+ ceremonyCompletePromise = new Promise(function(resolve) {
1419
+ ceremonyCeremonyCompleteResolver = resolve;
1420
+ });
1421
+ formattedPrivateKey = privateKey.startsWith('0x') ? privateKey.slice(2) : privateKey;
1422
+ return [
1423
+ 4,
1424
+ _this.importRawPrivateKey({
1425
+ chainName: chainName,
1426
+ thresholdSignatureScheme: thresholdSignatureScheme,
1427
+ privateKey: formattedPrivateKey,
1428
+ onCeremonyComplete: function(accountAddress, walletId) {
1429
+ serverAccountAddress = accountAddress;
1430
+ _this.initializeWalletMapEntry({
1431
+ accountAddress: accountAddress,
1432
+ walletId: walletId,
1433
+ chainName: _this.chainName,
1434
+ thresholdSignatureScheme: thresholdSignatureScheme
1435
+ });
1436
+ ceremonyCeremonyCompleteResolver(undefined);
1437
+ },
1438
+ onError: onError,
1439
+ legacyWalletId: legacyWalletId,
1440
+ password: password,
1441
+ signedSessionId: signedSessionId
1442
+ })
1443
+ ];
1444
+ case 1:
1445
+ _ref = _state.sent(), rawPublicKey = _ref.rawPublicKey, clientKeyShares = _ref.clientKeyShares;
1446
+ return [
1447
+ 4,
1448
+ ceremonyCompletePromise
1449
+ ];
1450
+ case 2:
1451
+ _state.sent();
1452
+ if (!rawPublicKey || !clientKeyShares) {
1453
+ throw new Error(ERROR_IMPORT_PRIVATE_KEY);
1454
+ }
1455
+ accountAddress = serverAccountAddress;
1456
+ return [
1457
+ 4,
1458
+ _this.setClientKeySharesToStorage({
1459
+ accountAddress: accountAddress,
1460
+ clientKeyShares: clientKeyShares
1461
+ })
1462
+ ];
1463
+ case 3:
1464
+ _state.sent();
1465
+ return [
1466
+ 4,
1467
+ _this.storeEncryptedBackupByWallet({
1468
+ accountAddress: accountAddress,
1469
+ clientKeyShares: clientKeyShares,
1470
+ password: password,
1471
+ signedSessionId: signedSessionId
1472
+ })
1473
+ ];
1474
+ case 4:
1475
+ _state.sent();
1476
+ pubKeyBytes = Buffer.from(rawPublicKey, 'hex');
1477
+ return [
1478
+ 2,
1479
+ {
1480
+ accountAddress: accountAddress,
1481
+ publicKeyHex: rawPublicKey,
1482
+ rawPublicKey: new Uint8Array(pubKeyBytes),
1483
+ clientKeyShares: clientKeyShares
1484
+ }
1485
+ ];
1486
+ case 5:
1487
+ error = _state.sent();
1488
+ // Password mismatch must propagate so the UI can re-prompt — wrapping it
1489
+ // as ERROR_IMPORT_PRIVATE_KEY would hide which error the UI is meant to
1490
+ // recover from. Same pattern as createWalletAccount.
1491
+ if (_instanceof(error, Error) && error.message === browser.ERROR_PASSWORD_MISMATCH) {
1492
+ throw error;
1493
+ }
1494
+ _this.logger.error(ERROR_IMPORT_PRIVATE_KEY, error);
1495
+ onError === null || onError === void 0 ? void 0 : onError(error);
1496
+ throw new Error(ERROR_IMPORT_PRIVATE_KEY);
1497
+ case 6:
1498
+ return [
1499
+ 2
1500
+ ];
1501
+ }
1502
+ });
1503
+ })();
1504
+ }
1505
+ },
1506
+ {
1507
+ key: "getPublicKeyFromPrivateKey",
1508
+ value: function getPublicKeyFromPrivateKey(privateKeyHex) {
1509
+ try {
1510
+ var privateKeyBytes = Buffer.from(privateKeyHex, 'hex');
1511
+ if (privateKeyBytes.length !== 32) {
1512
+ throw new Error("Invalid private key length: ".concat(privateKeyBytes.length, ", expected 32"));
1513
+ }
1514
+ return ledger__namespace.signatureVerifyingKey(privateKeyHex);
1515
+ } catch (error) {
1516
+ // Debug-level only: this is a caller-input validation failure, not a
1517
+ // system error. The full error is re-thrown, so callers can surface or
1518
+ // inspect it themselves — no need to duplicate it at a higher level
1519
+ // where it could land in production logs.
1520
+ this.logger.debug('[Midnight] getPublicKeyFromPrivateKey failed', error);
1521
+ throw error;
1522
+ }
1523
+ }
1524
+ },
1525
+ {
1526
+ key: "getMidnightWallets",
1527
+ value: function getMidnightWallets() {
1528
+ var _this = this;
1529
+ return _async_to_generator(function() {
1530
+ var wallets, midnightWallets;
1531
+ return _ts_generator(this, function(_state) {
1532
+ switch(_state.label){
1533
+ case 0:
1534
+ return [
1535
+ 4,
1536
+ _this.getWallets()
1537
+ ];
1538
+ case 1:
1539
+ wallets = _state.sent();
1540
+ // chainName on the wallet-map entry is uppercase (matches this.chainName
1541
+ // and all other chain clients: 'EVM', 'SVM', 'BTC', …). Filtering on
1542
+ // lowercase 'midnight' here always returned an empty array.
1543
+ midnightWallets = wallets.filter(function(wallet) {
1544
+ return wallet.chainName === _this.chainName;
1545
+ });
1546
+ return [
1547
+ 2,
1548
+ midnightWallets
1549
+ ];
1550
+ }
1551
+ });
1552
+ })();
1553
+ }
1554
+ },
1555
+ {
1556
+ key: "getRoleKeys",
1557
+ value: /**
1558
+ * Get or derive Midnight role keys (cached in storage).
1559
+ * Calls existing exportKey internally - no new MPC flow.
1560
+ * Keys: unshielded (NightExternal), shielded (Zswap), dust.
1561
+ */ function getRoleKeys(accountAddress, param) {
1562
+ var password = param.password, signedSessionId = param.signedSessionId, mfaToken = param.mfaToken, elevatedAccessToken = param.elevatedAccessToken;
1563
+ var _this = this;
1564
+ return _async_to_generator(function() {
1565
+ var _this_cachedWallet, mpcSigner, wallet, reconstructedKeyShare, exportId, data, keyExportRaw, exportStr, master, unshieldedNode, shieldedNode, dustNode, roleKeys;
1566
+ return _ts_generator(this, function(_state) {
1567
+ switch(_state.label){
1568
+ case 0:
1569
+ // In-memory cache: reuse role keys if the caller already booted this wallet
1570
+ // in the current session. initMidnightWallet sets this.cachedWallet after
1571
+ // its first call to getRoleKeys, so subsequent fresh-inits for the same
1572
+ // account can skip the expensive MPC export.
1573
+ if (((_this_cachedWallet = _this.cachedWallet) === null || _this_cachedWallet === void 0 ? void 0 : _this_cachedWallet.accountAddress) === accountAddress) {
1574
+ return [
1575
+ 2,
1576
+ _this.cachedWallet.roleKeys
1577
+ ];
1578
+ }
1579
+ // We deliberately do NOT persist role keys (private BIP32-derived keys
1580
+ // for shielded/dust/unshielded roles) to localStorage. Plaintext browser
1581
+ // storage of secret key material is a known exfiltration risk (XSS,
1582
+ // malicious extensions). The cost of MPC-re-exporting on each session
1583
+ // start (~few seconds) is acceptable vs. leaking the key material to
1584
+ // disk. A future hardening pass could add a password-derived AES-GCM
1585
+ // encryption layer to persist them securely across reloads.
1586
+ _this.logger.info('[Midnight] Exporting root key for role derivation', {
1587
+ accountAddress: accountAddress
1588
+ });
1589
+ mpcSigner = browser.getMPCSigner({
1590
+ chainName: _this.chainName,
1591
+ baseRelayUrl: _this.baseMPCRelayApiUrl
1592
+ });
1593
+ return [
1594
+ 4,
1595
+ _this.getWallet({
1596
+ accountAddress: accountAddress,
1597
+ password: password,
1598
+ walletOperation: browser.WalletOperation.EXPORT_PRIVATE_KEY,
1599
+ signedSessionId: signedSessionId
1600
+ })
1601
+ ];
1602
+ case 1:
1603
+ wallet = _state.sent();
1604
+ return [
1605
+ 4,
1606
+ _this.getReconstructedKeyShare(accountAddress, mpcSigner)
1607
+ ];
1608
+ case 2:
1609
+ reconstructedKeyShare = _state.sent();
1610
+ return [
1611
+ 4,
1612
+ _this.getExportId({
1613
+ chainName: _this.chainName,
1614
+ clientKeyShare: reconstructedKeyShare
1615
+ })
1616
+ ];
1617
+ case 3:
1618
+ exportId = _state.sent();
1619
+ return [
1620
+ 4,
1621
+ _this.apiClient.exportKey({
1622
+ walletId: wallet.walletId,
1623
+ exportId: exportId,
1624
+ mfaToken: mfaToken,
1625
+ elevatedAccessToken: elevatedAccessToken
1626
+ })
1627
+ ];
1628
+ case 4:
1629
+ data = _state.sent();
1630
+ return [
1631
+ 4,
1632
+ _this.performMPCExport(mpcSigner, reconstructedKeyShare, data.roomId, exportId, accountAddress, _this.chainName)
1633
+ ];
1634
+ case 5:
1635
+ keyExportRaw = _state.sent();
1636
+ if (!keyExportRaw) {
1637
+ throw new Error('MPC export returned no key');
1638
+ }
1639
+ // keyExportRaw is a base58 BIP32 xprv (e.g., xprv9s21ZrQH143K3...) — the MPC master xprv.
1640
+ // We derive role keys via BIP32 directly on this master so our derivations match what the
1641
+ // server does (BIP340.derivePrivateKeyFromXpriv) and what `verify-from-xprv.js` produces.
1642
+ exportStr = typeof keyExportRaw === 'string' ? keyExportRaw : String(keyExportRaw);
1643
+ master = bip32.HDKey.fromExtendedKey(exportStr);
1644
+ // Unshielded: NON-hardened to match the server's MPC signing path (Sodot's
1645
+ // derivePrivateKeyFromXpriv is non-hardened-only). If we used the hardened
1646
+ // Midnight-canonical path here, the UnshieldedWallet facade would track a
1647
+ // different address than the one the server signs for, and balances/txns
1648
+ // would silently diverge.
1649
+ // Shielded + Dust: hardened Midnight-canonical paths (m/44'/2400'/0'/role/0),
1650
+ // matching @midnight-ntwrk/wallet-sdk-hd. Those roles are signed entirely
1651
+ // client-side, so Sodot's non-hardened constraint doesn't apply.
1652
+ unshieldedNode = master.derive('m/44/2400/0/0/0');
1653
+ shieldedNode = master.derive("m/44'/2400'/0'/3/0");
1654
+ dustNode = master.derive("m/44'/2400'/0'/2/0");
1655
+ if (!unshieldedNode.privateKey || !shieldedNode.privateKey || !dustNode.privateKey) {
1656
+ throw new Error('BIP32 derivation returned null privateKey');
1657
+ }
1658
+ roleKeys = {
1659
+ unshielded: Buffer.from(unshieldedNode.privateKey).toString('hex'),
1660
+ shielded: Buffer.from(shieldedNode.privateKey).toString('hex'),
1661
+ dust: Buffer.from(dustNode.privateKey).toString('hex')
1662
+ };
1663
+ _this.logger.info('[Midnight] Role keys derived (in-memory only)', {
1664
+ accountAddress: accountAddress
1665
+ });
1666
+ return [
1667
+ 2,
1668
+ roleKeys
1669
+ ];
1670
+ }
1671
+ });
1672
+ })();
1673
+ }
1674
+ },
1675
+ {
1676
+ key: "initMidnightWallet",
1677
+ value: function initMidnightWallet(label, mpcParams) {
1678
+ var _this = this;
1679
+ return _async_to_generator(function() {
1680
+ var accountAddress, inFlight, initPromise;
1681
+ return _ts_generator(this, function(_state) {
1682
+ switch(_state.label){
1683
+ case 0:
1684
+ accountAddress = mpcParams.accountAddress;
1685
+ // If another init for this same account is in flight, return its promise
1686
+ // instead of kicking off a second, redundant WalletFacade.init.
1687
+ inFlight = _this.pendingInits.get(accountAddress);
1688
+ if (inFlight) {
1689
+ _this.logger.info("[Midnight] ".concat(label, ": joining in-flight init for ").concat(accountAddress));
1690
+ return [
1691
+ 2,
1692
+ inFlight
1693
+ ];
1694
+ }
1695
+ initPromise = _this.runMidnightWalletInit(label, mpcParams);
1696
+ _this.pendingInits.set(accountAddress, initPromise);
1697
+ _state.label = 1;
1698
+ case 1:
1699
+ _state.trys.push([
1700
+ 1,
1701
+ ,
1702
+ 3,
1703
+ 4
1704
+ ]);
1705
+ return [
1706
+ 4,
1707
+ initPromise
1708
+ ];
1709
+ case 2:
1710
+ return [
1711
+ 2,
1712
+ _state.sent()
1713
+ ];
1714
+ case 3:
1715
+ _this.pendingInits.delete(accountAddress);
1716
+ return [
1717
+ 7
1718
+ ];
1719
+ case 4:
1720
+ return [
1721
+ 2
1722
+ ];
1723
+ }
1724
+ });
1725
+ })();
1726
+ }
1727
+ },
1728
+ {
1729
+ key: "runMidnightWalletInit",
1730
+ value: function runMidnightWalletInit(label, mpcParams) {
1731
+ var _this = this;
1732
+ return _async_to_generator(function() {
1733
+ var _this_cachedWallet, roleKeys, accountAddress, state, _this_cachedWallet_diagnosticSub, shieldedSecretKeys, dustSecretKey, unshieldedKeystore, config, savedState, wallet, syncStart, lastLogTime, fmtSide, state1, err, lastPendingCount, lastPendingSig, diagnosticSub;
1734
+ return _ts_generator(this, function(_state) {
1735
+ switch(_state.label){
1736
+ case 0:
1737
+ return [
1738
+ 4,
1739
+ _this.getRoleKeys(mpcParams.accountAddress, mpcParams)
1740
+ ];
1741
+ case 1:
1742
+ roleKeys = _state.sent();
1743
+ accountAddress = mpcParams.accountAddress;
1744
+ if (!(((_this_cachedWallet = _this.cachedWallet) === null || _this_cachedWallet === void 0 ? void 0 : _this_cachedWallet.accountAddress) === accountAddress)) return [
1745
+ 3,
1746
+ 3
1747
+ ];
1748
+ _this.logger.info("[Midnight] ".concat(label, ": reusing cached wallet (background sync active)"));
1749
+ return [
1750
+ 4,
1751
+ new Promise(function(resolve, reject) {
1752
+ // `sub` must be declared as `let` because the callback can fire
1753
+ // synchronously during `.subscribe()` (the cached wallet is already
1754
+ // synced, so the state observable emits immediately on subscription).
1755
+ // If we used `const sub = ...subscribe(...)`, the callback would hit
1756
+ // `sub` before the binding was initialized (TDZ error).
1757
+ // eslint-disable-next-line prefer-const
1758
+ var sub;
1759
+ var tid = setTimeout(function() {
1760
+ sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
1761
+ reject(new Error('Wallet re-sync timeout'));
1762
+ }, 30000);
1763
+ sub = _this.cachedWallet.wallet.state().subscribe(function(s) {
1764
+ if (s.isSynced) {
1765
+ clearTimeout(tid);
1766
+ // Defer to a microtask so `sub` is definitely assigned whether the
1767
+ // emission is synchronous or async.
1768
+ queueMicrotask(function() {
1769
+ return sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
1770
+ });
1771
+ resolve(s);
1772
+ }
1773
+ });
1774
+ })
1775
+ ];
1776
+ case 2:
1777
+ state = _state.sent();
1778
+ return [
1779
+ 2,
1780
+ _object_spread_props(_object_spread({}, _this.cachedWallet), {
1781
+ state: state
1782
+ })
1783
+ ];
1784
+ case 3:
1785
+ if (!_this.cachedWallet) return [
1786
+ 3,
1787
+ 8
1788
+ ];
1789
+ _this.logger.info("[Midnight] ".concat(label, ": stopping previous wallet (account changed)"));
1790
+ try {
1791
+ ;
1792
+ (_this_cachedWallet_diagnosticSub = _this.cachedWallet.diagnosticSub) === null || _this_cachedWallet_diagnosticSub === void 0 ? void 0 : _this_cachedWallet_diagnosticSub.unsubscribe();
1793
+ } catch (e) {
1794
+ /* ignore */ }
1795
+ _state.label = 4;
1796
+ case 4:
1797
+ _state.trys.push([
1798
+ 4,
1799
+ 6,
1800
+ ,
1801
+ 7
1802
+ ]);
1803
+ return [
1804
+ 4,
1805
+ _this.cachedWallet.wallet.stop()
1806
+ ];
1807
+ case 5:
1808
+ _state.sent();
1809
+ return [
1810
+ 3,
1811
+ 7
1812
+ ];
1813
+ case 6:
1814
+ _state.sent();
1815
+ return [
1816
+ 3,
1817
+ 7
1818
+ ];
1819
+ case 7:
1820
+ _this.cachedWallet = null;
1821
+ _state.label = 8;
1822
+ case 8:
1823
+ shieldedSecretKeys = ledger__namespace.ZswapSecretKeys.fromSeed(new Uint8Array(Buffer.from(roleKeys.shielded, 'hex')));
1824
+ dustSecretKey = ledger__namespace.DustSecretKey.fromSeed(new Uint8Array(Buffer.from(roleKeys.dust, 'hex')));
1825
+ unshieldedKeystore = walletSdkUnshieldedWallet.createKeystore(new Uint8Array(Buffer.from(roleKeys.unshielded, 'hex')), 'preview');
1826
+ config = {
1827
+ networkId: 'preview',
1828
+ costParameters: {
1829
+ feeBlocksMargin: 5
1830
+ },
1831
+ relayURL: new URL('wss://rpc.preview.midnight.network'),
1832
+ provingServerUrl: new URL('http://localhost:6300'),
1833
+ indexerClientConnection: {
1834
+ indexerHttpUrl: 'https://indexer.preview.midnight.network/api/v4/graphql',
1835
+ indexerWsUrl: 'wss://indexer.preview.midnight.network/api/v4/graphql/ws'
1836
+ },
1837
+ txHistoryStorage: new walletSdkUnshieldedWallet.NoOpTransactionHistoryStorage()
1838
+ };
1839
+ return [
1840
+ 4,
1841
+ getWalletState(accountAddress)
1842
+ ];
1843
+ case 9:
1844
+ savedState = _state.sent();
1845
+ if (savedState) {
1846
+ _this.logger.info("[Midnight] ".concat(label, ": found persisted state — resuming sync from checkpoint"));
1847
+ } else {
1848
+ _this.logger.info("[Midnight] ".concat(label, ": no persisted state — cold sync from genesis"));
1849
+ }
1850
+ _this.logger.info("[Midnight] ".concat(label, ": initializing wallet..."));
1851
+ return [
1852
+ 4,
1853
+ walletSdkFacade.WalletFacade.init({
1854
+ configuration: config,
1855
+ shielded: function(cfg) {
1856
+ return savedState ? walletSdkShielded.ShieldedWallet(cfg).restore(savedState.shielded) : walletSdkShielded.ShieldedWallet(cfg).startWithSecretKeys(shieldedSecretKeys);
1857
+ },
1858
+ unshielded: function(cfg) {
1859
+ return walletSdkUnshieldedWallet.UnshieldedWallet(cfg).startWithPublicKey(walletSdkUnshieldedWallet.PublicKey.fromKeyStore(unshieldedKeystore));
1860
+ },
1861
+ dust: function(cfg) {
1862
+ return savedState ? walletSdkDustWallet.DustWallet(cfg).restore(savedState.dust) : walletSdkDustWallet.DustWallet(cfg).startWithSecretKey(dustSecretKey, ledger__namespace.LedgerParameters.initialParameters().dust);
1863
+ }
1864
+ })
1865
+ ];
1866
+ case 10:
1867
+ wallet = _state.sent();
1868
+ return [
1869
+ 4,
1870
+ wallet.start(shieldedSecretKeys, dustSecretKey)
1871
+ ];
1872
+ case 11:
1873
+ _state.sent();
1874
+ _this.logger.debug("[Midnight] ".concat(label, ": syncing..."));
1875
+ syncStart = Date.now();
1876
+ lastLogTime = 0;
1877
+ // Per-side sync-progress summary. Fields are bigints; `gap` is how many
1878
+ // updates still need to be applied to reach the latest relevant index
1879
+ // (not the chain tip — `highestRelevantIndex` is what matters for balance).
1880
+ // Read the progress object the SDK itself uses for isSynced. For shielded
1881
+ // and dust it lives at `side.state.progress`; for unshielded it's
1882
+ // `side.progress`. Fall back across both to be safe.
1883
+ fmtSide = function(side) {
1884
+ var _side_state;
1885
+ var _side_state_progress;
1886
+ var p = (_side_state_progress = side === null || side === void 0 ? void 0 : (_side_state = side.state) === null || _side_state === void 0 ? void 0 : _side_state.progress) !== null && _side_state_progress !== void 0 ? _side_state_progress : side === null || side === void 0 ? void 0 : side.progress;
1887
+ if (!p) return 'n/a';
1888
+ var _p_appliedIndex;
1889
+ var applied = (_p_appliedIndex = p.appliedIndex) !== null && _p_appliedIndex !== void 0 ? _p_appliedIndex : 0n;
1890
+ var _p_highestRelevantIndex;
1891
+ var highestRelevant = (_p_highestRelevantIndex = p.highestRelevantIndex) !== null && _p_highestRelevantIndex !== void 0 ? _p_highestRelevantIndex : 0n;
1892
+ var _p_highestRelevantWalletIndex;
1893
+ var highestRelevantWallet = (_p_highestRelevantWalletIndex = p.highestRelevantWalletIndex) !== null && _p_highestRelevantWalletIndex !== void 0 ? _p_highestRelevantWalletIndex : 0n;
1894
+ var _p_highestIndex;
1895
+ var highest = (_p_highestIndex = p.highestIndex) !== null && _p_highestIndex !== void 0 ? _p_highestIndex : 0n;
1896
+ var connected = p.isConnected ? '✓' : '✗';
1897
+ var done = '?';
1898
+ if (typeof p.isStrictlyComplete === 'function') {
1899
+ done = p.isStrictlyComplete() ? '✓' : '✗';
1900
+ }
1901
+ return "done=".concat(done, " \xb7 applied=").concat(applied, " \xb7 hrw=").concat(highestRelevantWallet, " \xb7 hr=").concat(highestRelevant, " \xb7 tip=").concat(highest, " \xb7 ws=").concat(connected);
1902
+ };
1903
+ _state.label = 12;
1904
+ case 12:
1905
+ _state.trys.push([
1906
+ 12,
1907
+ 14,
1908
+ ,
1909
+ 19
1910
+ ]);
1911
+ return [
1912
+ 4,
1913
+ new Promise(function(resolve, reject) {
1914
+ // `let` + optional chaining + queueMicrotask — same TDZ-safe pattern used
1915
+ // in the cached-wallet, persist, and snapshot paths. Restoring from a
1916
+ // checkpoint that's already at chain tip makes `.subscribe(...)` fire the
1917
+ // callback synchronously before the `sub` binding initializes.
1918
+ // eslint-disable-next-line prefer-const
1919
+ var sub;
1920
+ var timeoutId = setTimeout(function() {
1921
+ sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
1922
+ reject(new Error('Wallet sync timeout'));
1923
+ }, 300000);
1924
+ sub = wallet.state().subscribe(function(s) {
1925
+ var now = Date.now();
1926
+ if (now - lastLogTime > 5000) {
1927
+ lastLogTime = now;
1928
+ _this.logger.debug("[Midnight] ".concat(label, ": sync @ ").concat(((now - syncStart) / 1000).toFixed(1), "s \xb7 ") + "isSynced=".concat(s.isSynced, " \xb7 ") + "shielded=".concat(fmtSide(s.shielded), " \xb7 ") + "unshielded=".concat(fmtSide(s.unshielded), " \xb7 ") + "dust=".concat(fmtSide(s.dust)));
1929
+ }
1930
+ if (s.isSynced) {
1931
+ clearTimeout(timeoutId);
1932
+ queueMicrotask(function() {
1933
+ return sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
1934
+ });
1935
+ _this.logger.debug("[Midnight] ".concat(label, ": synced in ").concat(((Date.now() - syncStart) / 1000).toFixed(1), "s \xb7 ") + "shielded=".concat(fmtSide(s.shielded), " \xb7 ") + "unshielded=".concat(fmtSide(s.unshielded), " \xb7 ") + "dust=".concat(fmtSide(s.dust)));
1936
+ resolve(s);
1937
+ }
1938
+ });
1939
+ })
1940
+ ];
1941
+ case 13:
1942
+ state1 = _state.sent();
1943
+ return [
1944
+ 3,
1945
+ 19
1946
+ ];
1947
+ case 14:
1948
+ err = _state.sent();
1949
+ _state.label = 15;
1950
+ case 15:
1951
+ _state.trys.push([
1952
+ 15,
1953
+ 17,
1954
+ ,
1955
+ 18
1956
+ ]);
1957
+ return [
1958
+ 4,
1959
+ wallet.stop()
1960
+ ];
1961
+ case 16:
1962
+ _state.sent();
1963
+ return [
1964
+ 3,
1965
+ 18
1966
+ ];
1967
+ case 17:
1968
+ _state.sent();
1969
+ return [
1970
+ 3,
1971
+ 18
1972
+ ];
1973
+ case 18:
1974
+ throw err;
1975
+ case 19:
1976
+ // Diagnostic: track pending-tx transitions so we can observe TTL
1977
+ // auto-revert (entry flips from result=undefined → result.status='FAILURE'
1978
+ // then disappears on the next tick). Subscription handle is kept on the
1979
+ // cachedWallet so cleanup paths (account-switch, resetCache) can
1980
+ // unsubscribe it — otherwise its closure pins `this`, `wallet`, and the
1981
+ // full log-format state for the lifetime of the client.
1982
+ lastPendingCount = -1;
1983
+ lastPendingSig = '';
1984
+ diagnosticSub = wallet.state().subscribe(function(s) {
1985
+ var _s_pending;
1986
+ var _s_pending_all;
1987
+ var pending = (_s_pending_all = s === null || s === void 0 ? void 0 : (_s_pending = s.pending) === null || _s_pending === void 0 ? void 0 : _s_pending.all) !== null && _s_pending_all !== void 0 ? _s_pending_all : [];
1988
+ var sig = JSON.stringify(pending.map(function(p) {
1989
+ var _p_result;
1990
+ var _p_result_status;
1991
+ return {
1992
+ id: function() {
1993
+ try {
1994
+ var _p_tx_identifiers__slice, _p_tx_identifiers_;
1995
+ var _p_tx_identifiers__slice1;
1996
+ return (_p_tx_identifiers__slice1 = (_p_tx_identifiers_ = p.tx.identifiers()[0]) === null || _p_tx_identifiers_ === void 0 ? void 0 : (_p_tx_identifiers__slice = _p_tx_identifiers_.slice) === null || _p_tx_identifiers__slice === void 0 ? void 0 : _p_tx_identifiers__slice.call(_p_tx_identifiers_, 0, 12)) !== null && _p_tx_identifiers__slice1 !== void 0 ? _p_tx_identifiers__slice1 : '?';
1997
+ } catch (e) {
1998
+ return '?';
1999
+ }
2000
+ }(),
2001
+ resultStatus: (_p_result_status = (_p_result = p.result) === null || _p_result === void 0 ? void 0 : _p_result.status) !== null && _p_result_status !== void 0 ? _p_result_status : 'pending'
2002
+ };
2003
+ }));
2004
+ if (sig === lastPendingSig) return;
2005
+ lastPendingSig = sig;
2006
+ if (pending.length === 0 && lastPendingCount === 0) return;
2007
+ lastPendingCount = pending.length;
2008
+ _this.logger.debug("[Midnight] pending-tx list (".concat(pending.length, "):"), pending.map(function(p) {
2009
+ var _p_result;
2010
+ // Guard every date/serialize call — `p.creationTime` may be an
2011
+ // Effect DateTime (not a JS Date), `i.ttl` may be a bigint or
2012
+ // something else that new Date() can't handle. Fall back to
2013
+ // raw string representation if conversion fails.
2014
+ var safeDate = function(v) {
2015
+ try {
2016
+ var d = new Date(v);
2017
+ if (Number.isFinite(d.getTime())) return d.toISOString();
2018
+ return String(v);
2019
+ } catch (e) {
2020
+ return String(v);
2021
+ }
2022
+ };
2023
+ var intentTtls = [];
2024
+ try {
2025
+ var _p_tx_intents;
2026
+ var _p_tx_intents_values_toArray;
2027
+ intentTtls = ((_p_tx_intents_values_toArray = (_p_tx_intents = p.tx.intents) === null || _p_tx_intents === void 0 ? void 0 : _p_tx_intents.values().toArray()) !== null && _p_tx_intents_values_toArray !== void 0 ? _p_tx_intents_values_toArray : []).map(function(i) {
2028
+ if ((i === null || i === void 0 ? void 0 : i.ttl) == null) return 'none';
2029
+ // Midnight intent TTLs are typically seconds since epoch (may
2030
+ // also arrive as bigint or Date). Multiply to ms only if the
2031
+ // value is clearly in the seconds range (< 1e12).
2032
+ var asNumber = _type_of(i.ttl) === 'bigint' ? Number(i.ttl) : i.ttl;
2033
+ var ms = typeof asNumber === 'number' && asNumber < 1e12 ? asNumber * 1000 : asNumber;
2034
+ return safeDate(ms);
2035
+ });
2036
+ } catch (e) {
2037
+ /* ignore */ }
2038
+ var idShort = '?';
2039
+ try {
2040
+ var _p_tx_identifiers__slice, _p_tx_identifiers_;
2041
+ var _p_tx_identifiers__slice1;
2042
+ idShort = (_p_tx_identifiers__slice1 = (_p_tx_identifiers_ = p.tx.identifiers()[0]) === null || _p_tx_identifiers_ === void 0 ? void 0 : (_p_tx_identifiers__slice = _p_tx_identifiers_.slice) === null || _p_tx_identifiers__slice === void 0 ? void 0 : _p_tx_identifiers__slice.call(_p_tx_identifiers_, 0, 16)) !== null && _p_tx_identifiers__slice1 !== void 0 ? _p_tx_identifiers__slice1 : '?';
2043
+ } catch (e) {
2044
+ /* ignore */ }
2045
+ var _p_result_status;
2046
+ return {
2047
+ id: idShort,
2048
+ creationTime: p.creationTime == null ? 'n/a' : safeDate(p.creationTime),
2049
+ result: (_p_result_status = (_p_result = p.result) === null || _p_result === void 0 ? void 0 : _p_result.status) !== null && _p_result_status !== void 0 ? _p_result_status : 'pending',
2050
+ intentTtls: intentTtls
2051
+ };
2052
+ }));
2053
+ });
2054
+ _this.cachedWallet = {
2055
+ wallet: wallet,
2056
+ ledger: ledger__namespace,
2057
+ roleKeys: roleKeys,
2058
+ accountAddress: accountAddress,
2059
+ shieldedSecretKeys: shieldedSecretKeys,
2060
+ dustSecretKey: dustSecretKey,
2061
+ diagnosticSub: diagnosticSub
2062
+ };
2063
+ _this.logger.info("[Midnight] ".concat(label, ": wallet cached for future calls"));
2064
+ // Persist the freshly-synced state to IndexedDB so the next init can
2065
+ // resume. Routed through persistCachedWalletState so the same "clean
2066
+ // only" guard (Option A) applies — if this fresh sync somehow restored
2067
+ // dirty state (e.g., a lingering pending-tx entry from an earlier
2068
+ // session), we skip the write and keep IndexedDB at its last known-good.
2069
+ void _async_to_generator(function() {
2070
+ var err;
2071
+ return _ts_generator(this, function(_state) {
2072
+ switch(_state.label){
2073
+ case 0:
2074
+ _state.trys.push([
2075
+ 0,
2076
+ 2,
2077
+ ,
2078
+ 3
2079
+ ]);
2080
+ return [
2081
+ 4,
2082
+ _this.persistCachedWalletState()
2083
+ ];
2084
+ case 1:
2085
+ _state.sent();
2086
+ return [
2087
+ 3,
2088
+ 3
2089
+ ];
2090
+ case 2:
2091
+ err = _state.sent();
2092
+ _this.logger.warn('[Midnight] Failed to persist wallet state:', err);
2093
+ return [
2094
+ 3,
2095
+ 3
2096
+ ];
2097
+ case 3:
2098
+ return [
2099
+ 2
2100
+ ];
2101
+ }
2102
+ });
2103
+ })();
2104
+ return [
2105
+ 2,
2106
+ {
2107
+ wallet: wallet,
2108
+ state: state1,
2109
+ ledger: ledger__namespace,
2110
+ roleKeys: roleKeys,
2111
+ accountAddress: accountAddress,
2112
+ shieldedSecretKeys: shieldedSecretKeys,
2113
+ dustSecretKey: dustSecretKey
2114
+ }
2115
+ ];
2116
+ }
2117
+ });
2118
+ })();
2119
+ }
2120
+ },
2121
+ {
2122
+ key: "getPrivateBalance",
2123
+ value: function getPrivateBalance(param) {
2124
+ var accountAddress = param.accountAddress, password = param.password, signedSessionId = param.signedSessionId, mfaToken = param.mfaToken, elevatedAccessToken = param.elevatedAccessToken;
2125
+ var _this = this;
2126
+ return _async_to_generator(function() {
2127
+ var _state_unshielded, _state_shielded, _state_dust_balance, _state_dust, _ref, state, addr, unshieldedByToken, _state_unshielded_balances, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _step_value, tokenType, value, shieldedByToken, _state_shielded_balances, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, _step_value1, tokenType1, value1, _state_dust_balance1, result;
2128
+ return _ts_generator(this, function(_state) {
2129
+ switch(_state.label){
2130
+ case 0:
2131
+ return [
2132
+ 4,
2133
+ _this.initMidnightWallet('getPrivateBalance', {
2134
+ accountAddress: accountAddress,
2135
+ password: password,
2136
+ signedSessionId: signedSessionId,
2137
+ mfaToken: mfaToken,
2138
+ elevatedAccessToken: elevatedAccessToken
2139
+ })
2140
+ ];
2141
+ case 1:
2142
+ _ref = _state.sent(), state = _ref.state, addr = _ref.accountAddress;
2143
+ unshieldedByToken = {};
2144
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2145
+ try {
2146
+ for(_iterator = Object.entries((_state_unshielded_balances = (_state_unshielded = state.unshielded) === null || _state_unshielded === void 0 ? void 0 : _state_unshielded.balances) !== null && _state_unshielded_balances !== void 0 ? _state_unshielded_balances : {})[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2147
+ _step_value = _sliced_to_array(_step.value, 2), tokenType = _step_value[0], value = _step_value[1];
2148
+ unshieldedByToken[tokenType] = value.toString();
2149
+ }
2150
+ } catch (err) {
2151
+ _didIteratorError = true;
2152
+ _iteratorError = err;
2153
+ } finally{
2154
+ try {
2155
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2156
+ _iterator.return();
2157
+ }
2158
+ } finally{
2159
+ if (_didIteratorError) {
2160
+ throw _iteratorError;
2161
+ }
2162
+ }
2163
+ }
2164
+ shieldedByToken = {};
2165
+ _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
2166
+ try {
2167
+ for(_iterator1 = Object.entries((_state_shielded_balances = (_state_shielded = state.shielded) === null || _state_shielded === void 0 ? void 0 : _state_shielded.balances) !== null && _state_shielded_balances !== void 0 ? _state_shielded_balances : {})[Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
2168
+ _step_value1 = _sliced_to_array(_step1.value, 2), tokenType1 = _step_value1[0], value1 = _step_value1[1];
2169
+ shieldedByToken[tokenType1] = value1.toString();
2170
+ }
2171
+ } catch (err) {
2172
+ _didIteratorError1 = true;
2173
+ _iteratorError1 = err;
2174
+ } finally{
2175
+ try {
2176
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
2177
+ _iterator1.return();
2178
+ }
2179
+ } finally{
2180
+ if (_didIteratorError1) {
2181
+ throw _iteratorError1;
2182
+ }
2183
+ }
2184
+ }
2185
+ result = {
2186
+ unshielded: unshieldedByToken,
2187
+ shielded: shieldedByToken,
2188
+ dust: ((_state_dust_balance1 = (_state_dust = state.dust) === null || _state_dust === void 0 ? void 0 : (_state_dust_balance = _state_dust.balance) === null || _state_dust_balance === void 0 ? void 0 : _state_dust_balance.call(_state_dust, new Date())) !== null && _state_dust_balance1 !== void 0 ? _state_dust_balance1 : 0n).toString(),
2189
+ address: addr
2190
+ };
2191
+ // Fire-and-forget snapshot so the next init resumes from here instead
2192
+ // of cold-syncing from genesis.
2193
+ void _this.persistCachedWalletState();
2194
+ return [
2195
+ 2,
2196
+ result
2197
+ ];
2198
+ }
2199
+ });
2200
+ })();
2201
+ }
2202
+ },
2203
+ {
2204
+ key: "registerDust",
2205
+ value: function registerDust(param) {
2206
+ var accountAddress = param.accountAddress, password = param.password, signedSessionId = param.signedSessionId, mfaToken = param.mfaToken, elevatedAccessToken = param.elevatedAccessToken;
2207
+ var _this = this;
2208
+ return _async_to_generator(function() {
2209
+ var _state_dust_balance, _state_dust, _state_unshielded, _state_dust_balance1, _state_dust1, _ref, wallet, state, ledger, roleKeys, _state_dust_balance2, existingDust, _state_unshielded_availableCoins, allUtxos, nightUtxos, _state_dust_balance3, _state_dust2, _state_dust_balance4, dustBalance, verifyingKey, recipe, finalized, submitId, submitIdStr, _state_dust_balance5;
2210
+ return _ts_generator(this, function(_state) {
2211
+ switch(_state.label){
2212
+ case 0:
2213
+ return [
2214
+ 4,
2215
+ _this.initMidnightWallet('registerDust', {
2216
+ accountAddress: accountAddress,
2217
+ password: password,
2218
+ signedSessionId: signedSessionId,
2219
+ mfaToken: mfaToken,
2220
+ elevatedAccessToken: elevatedAccessToken
2221
+ })
2222
+ ];
2223
+ case 1:
2224
+ _ref = _state.sent(), wallet = _ref.wallet, state = _ref.state, ledger = _ref.ledger, roleKeys = _ref.roleKeys;
2225
+ existingDust = (_state_dust_balance2 = (_state_dust = state.dust) === null || _state_dust === void 0 ? void 0 : (_state_dust_balance = _state_dust.balance) === null || _state_dust_balance === void 0 ? void 0 : _state_dust_balance.call(_state_dust, new Date())) !== null && _state_dust_balance2 !== void 0 ? _state_dust_balance2 : 0n;
2226
+ if (existingDust > 0n) {
2227
+ return [
2228
+ 2,
2229
+ {
2230
+ dustBalance: existingDust.toString(),
2231
+ status: 'already_has_dust',
2232
+ message: "Wallet already has ".concat(existingDust.toString(), " dust. No action needed."),
2233
+ registeredCount: 0
2234
+ }
2235
+ ];
2236
+ }
2237
+ allUtxos = (_state_unshielded_availableCoins = (_state_unshielded = state.unshielded) === null || _state_unshielded === void 0 ? void 0 : _state_unshielded.availableCoins) !== null && _state_unshielded_availableCoins !== void 0 ? _state_unshielded_availableCoins : [];
2238
+ nightUtxos = allUtxos.filter(function(coin) {
2239
+ var _coin_meta;
2240
+ return ((_coin_meta = coin.meta) === null || _coin_meta === void 0 ? void 0 : _coin_meta.registeredForDustGeneration) !== true;
2241
+ });
2242
+ _this.logger.info('[Midnight] registerDust: UTXOs total:', allUtxos.length, 'unregistered:', nightUtxos.length);
2243
+ if (nightUtxos.length === 0 && allUtxos.length > 0) {
2244
+ dustBalance = ((_state_dust_balance4 = (_state_dust2 = state.dust) === null || _state_dust2 === void 0 ? void 0 : (_state_dust_balance3 = _state_dust2.balance) === null || _state_dust_balance3 === void 0 ? void 0 : _state_dust_balance3.call(_state_dust2, new Date())) !== null && _state_dust_balance4 !== void 0 ? _state_dust_balance4 : 0n).toString();
2245
+ return [
2246
+ 2,
2247
+ {
2248
+ dustBalance: dustBalance,
2249
+ status: 'already_registered',
2250
+ message: "All ".concat(allUtxos.length, " NIGHT UTXO(s) are already registered for dust generation. ") + "Current dust balance is ".concat(dustBalance, ". Dust generation runs continuously on-chain — ") + "poll getPrivateBalance periodically to see it accumulate. If it stays at 0 for a long " + "time past the grace period (3h on preview), the NIGHT UTXO may be generating too " + "slowly to show up — fund the wallet with more NIGHT to increase the rate.",
2251
+ registeredCount: 0
2252
+ }
2253
+ ];
2254
+ }
2255
+ if (nightUtxos.length === 0) {
2256
+ return [
2257
+ 2,
2258
+ {
2259
+ dustBalance: '0',
2260
+ status: 'no_utxos',
2261
+ message: 'No NIGHT UTXOs in wallet. Fund the wallet with NIGHT from the preview faucet before registering for dust.',
2262
+ registeredCount: 0
2263
+ }
2264
+ ];
2265
+ }
2266
+ _this.logger.debug("[Midnight] registerDust: registering ".concat(nightUtxos.length, " NIGHT UTXO(s) for dust generation..."));
2267
+ verifyingKey = ledger.signatureVerifyingKey(roleKeys.unshielded);
2268
+ _this.logger.debug('[Midnight] registerDust: building registration recipe...');
2269
+ return [
2270
+ 4,
2271
+ wallet.registerNightUtxosForDustGeneration(nightUtxos, verifyingKey, function(payload) {
2272
+ return ledger.signData(roleKeys.unshielded, payload);
2273
+ })
2274
+ ];
2275
+ case 2:
2276
+ recipe = _state.sent();
2277
+ _this.logger.debug('[Midnight] registerDust: proving + finalizing (proof server)...');
2278
+ return [
2279
+ 4,
2280
+ wallet.finalizeRecipe(recipe)
2281
+ ];
2282
+ case 3:
2283
+ finalized = _state.sent();
2284
+ _this.logger.debug('[Midnight] registerDust: broadcasting registration tx...');
2285
+ return [
2286
+ 4,
2287
+ wallet.submitTransaction(finalized)
2288
+ ];
2289
+ case 4:
2290
+ submitId = _state.sent();
2291
+ submitIdStr = DynamicMidnightWalletClient.toTxHashString(submitId);
2292
+ _this.logger.debug("[Midnight] registerDust: broadcast, txId=".concat(submitIdStr));
2293
+ // Do NOT block here waiting for dust. Dust generation is a continuous
2294
+ // on-chain process — it can take minutes to hours depending on NIGHT
2295
+ // value, grace period, and decay rate. Return immediately so the UI can
2296
+ // show "registration submitted" and the caller polls getPrivateBalance
2297
+ // to observe dust when it eventually appears.
2298
+ void _this.persistCachedWalletState();
2299
+ return [
2300
+ 2,
2301
+ {
2302
+ dustBalance: ((_state_dust_balance5 = (_state_dust1 = state.dust) === null || _state_dust1 === void 0 ? void 0 : (_state_dust_balance1 = _state_dust1.balance) === null || _state_dust_balance1 === void 0 ? void 0 : _state_dust_balance1.call(_state_dust1, new Date())) !== null && _state_dust_balance5 !== void 0 ? _state_dust_balance5 : 0n).toString(),
2303
+ txId: submitIdStr,
2304
+ status: 'registered',
2305
+ message: "Registered ".concat(nightUtxos.length, " NIGHT UTXO(s) for dust generation (txId ").concat(submitIdStr.slice(0, 16), "…). ") + "Dust will accumulate continuously on-chain. Poll getPrivateBalance to see it arrive " + "(usually a few minutes after the registration tx confirms, depending on network parameters).",
2306
+ registeredCount: nightUtxos.length
2307
+ }
2308
+ ];
2309
+ }
2310
+ });
2311
+ })();
2312
+ }
2313
+ },
2314
+ {
2315
+ key: "createTransferTransaction",
2316
+ value: /**
2317
+ * Build an unsigned Midnight transfer (unshielded, shielded, or mixed).
2318
+ * No MPC, no proof server, no broadcast — pair with signTransaction and
2319
+ * submitTransaction.
2320
+ */ function createTransferTransaction(param) {
2321
+ var accountAddress = param.accountAddress, transfers = param.transfers, ttlMinutes = param.ttlMinutes, password = param.password, signedSessionId = param.signedSessionId, mfaToken = param.mfaToken, elevatedAccessToken = param.elevatedAccessToken;
2322
+ var _this = this;
2323
+ return _async_to_generator(function() {
2324
+ var _state_dust_balance, _state_dust, _ref, wallet, state, shieldedSecretKeys, dustSecretKey, _state_dust_balance1, dustBalance, nativeToken, requiredByKey, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, t, _t_tokenType, token, key, existing, _existing_required, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, _step_value, side, token1, required, _state_unshielded, _state_shielded, balances, _balances_token, have, sdkTransfers, ttlMs, recipe;
2325
+ return _ts_generator(this, function(_state) {
2326
+ switch(_state.label){
2327
+ case 0:
2328
+ if (!transfers || transfers.length === 0) {
2329
+ throw new Error('At least one transfer is required');
2330
+ }
2331
+ return [
2332
+ 4,
2333
+ _this.initMidnightWallet('createTransferTransaction', {
2334
+ accountAddress: accountAddress,
2335
+ password: password,
2336
+ signedSessionId: signedSessionId,
2337
+ mfaToken: mfaToken,
2338
+ elevatedAccessToken: elevatedAccessToken
2339
+ })
2340
+ ];
2341
+ case 1:
2342
+ _ref = _state.sent(), wallet = _ref.wallet, state = _ref.state, shieldedSecretKeys = _ref.shieldedSecretKeys, dustSecretKey = _ref.dustSecretKey;
2343
+ // Dust fee is required for every Midnight transaction regardless of the transfer type.
2344
+ dustBalance = (_state_dust_balance1 = (_state_dust = state.dust) === null || _state_dust === void 0 ? void 0 : (_state_dust_balance = _state_dust.balance) === null || _state_dust_balance === void 0 ? void 0 : _state_dust_balance.call(_state_dust, new Date())) !== null && _state_dust_balance1 !== void 0 ? _state_dust_balance1 : 0n;
2345
+ if (dustBalance === 0n) {
2346
+ throw new Error('No dust balance — register dust first');
2347
+ }
2348
+ nativeToken = ledger__namespace.nativeToken().raw;
2349
+ // Aggregate per-(side, token) amounts so a single tx spending the same token
2350
+ // across multiple outputs gets checked against one combined total. The Map
2351
+ // value keeps the parsed components so we don't have to round-trip the key
2352
+ // through string-splitting — a token identifier containing `:` (Midnight
2353
+ // contract tokens can) would truncate if we split on ':' to recover it.
2354
+ requiredByKey = new Map();
2355
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2356
+ try {
2357
+ for(_iterator = transfers[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2358
+ t = _step.value;
2359
+ ;
2360
+ token = (_t_tokenType = t.tokenType) !== null && _t_tokenType !== void 0 ? _t_tokenType : nativeToken;
2361
+ // NUL-separated dedup key. The NUL byte cannot appear in a JS string
2362
+ // literal produced by any Midnight address/token encoder, so collisions
2363
+ // between (side, token) pairs are impossible regardless of token shape.
2364
+ key = "".concat(t.type, "\0").concat(token);
2365
+ existing = requiredByKey.get(key);
2366
+ ;
2367
+ requiredByKey.set(key, {
2368
+ side: t.type,
2369
+ token: token,
2370
+ required: ((_existing_required = existing === null || existing === void 0 ? void 0 : existing.required) !== null && _existing_required !== void 0 ? _existing_required : 0n) + BigInt(t.amount)
2371
+ });
2372
+ }
2373
+ } catch (err) {
2374
+ _didIteratorError = true;
2375
+ _iteratorError = err;
2376
+ } finally{
2377
+ try {
2378
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2379
+ _iterator.return();
2380
+ }
2381
+ } finally{
2382
+ if (_didIteratorError) {
2383
+ throw _iteratorError;
2384
+ }
2385
+ }
2386
+ }
2387
+ _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
2388
+ try {
2389
+ for(_iterator1 = requiredByKey.values()[Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
2390
+ _step_value = _step1.value, side = _step_value.side, token1 = _step_value.token, required = _step_value.required;
2391
+ ;
2392
+ balances = side === 'unshielded' ? (_state_unshielded = state.unshielded) === null || _state_unshielded === void 0 ? void 0 : _state_unshielded.balances : (_state_shielded = state.shielded) === null || _state_shielded === void 0 ? void 0 : _state_shielded.balances;
2393
+ ;
2394
+ have = (_balances_token = balances === null || balances === void 0 ? void 0 : balances[token1]) !== null && _balances_token !== void 0 ? _balances_token : 0n;
2395
+ if (have < required) {
2396
+ throw new Error("Insufficient ".concat(side, " balance for token ").concat(token1, ": ").concat(have, " < ").concat(required));
2397
+ }
2398
+ }
2399
+ } catch (err) {
2400
+ _didIteratorError1 = true;
2401
+ _iteratorError1 = err;
2402
+ } finally{
2403
+ try {
2404
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
2405
+ _iterator1.return();
2406
+ }
2407
+ } finally{
2408
+ if (_didIteratorError1) {
2409
+ throw _iteratorError1;
2410
+ }
2411
+ }
2412
+ }
2413
+ sdkTransfers = transfers.map(function(t) {
2414
+ var _t_tokenType;
2415
+ var token = (_t_tokenType = t.tokenType) !== null && _t_tokenType !== void 0 ? _t_tokenType : nativeToken;
2416
+ var receiverAddress;
2417
+ try {
2418
+ var parsed = walletSdkAddressFormat.MidnightBech32m.parse(t.recipientAddress);
2419
+ receiverAddress = t.type === 'unshielded' ? parsed.decode(walletSdkAddressFormat.UnshieldedAddress, 'preview') : parsed.decode(walletSdkAddressFormat.ShieldedAddress, 'preview');
2420
+ } catch (err) {
2421
+ throw new Error("Invalid ".concat(t.type, " recipient address ").concat(t.recipientAddress, ": ").concat(err.message));
2422
+ }
2423
+ _this.logger.info("[Midnight] createTransferTransaction: ".concat(t.type, " ").concat(t.amount, " of token ").concat(token.slice(0, 8), "… → ").concat(t.recipientAddress.slice(0, 20), "…"));
2424
+ return {
2425
+ type: t.type,
2426
+ outputs: [
2427
+ {
2428
+ amount: BigInt(t.amount),
2429
+ receiverAddress: receiverAddress,
2430
+ type: token
2431
+ }
2432
+ ]
2433
+ };
2434
+ });
2435
+ // TTL defaults to 5 min. If the caller doesn't submit within this window,
2436
+ // the SDK's PendingTransactions.allFailed stream picks up the expired tx
2437
+ // and auto-reverts the reserved UTXOs back to available. Short enough
2438
+ // that abandoned drafts recover quickly; long enough for a normal
2439
+ // craft → sign (ZK prove) → submit path to complete comfortably.
2440
+ // Callers can override via ttlMinutes for relayer/batched-submit flows.
2441
+ ttlMs = (ttlMinutes !== null && ttlMinutes !== void 0 ? ttlMinutes : 5) * 60 * 1000;
2442
+ return [
2443
+ 4,
2444
+ wallet.transferTransaction(sdkTransfers, {
2445
+ shieldedSecretKeys: shieldedSecretKeys,
2446
+ dustSecretKey: dustSecretKey
2447
+ }, {
2448
+ ttl: new Date(Date.now() + ttlMs)
2449
+ })
2450
+ ];
2451
+ case 2:
2452
+ recipe = _state.sent();
2453
+ if (recipe.type !== 'UNPROVEN_TRANSACTION') {
2454
+ throw new Error("Unexpected recipe type from transferTransaction: ".concat(recipe.type));
2455
+ }
2456
+ return [
2457
+ 2,
2458
+ {
2459
+ serializedTransaction: Buffer.from(recipe.transaction.serialize()).toString('base64')
2460
+ }
2461
+ ];
2462
+ }
2463
+ });
2464
+ })();
2465
+ }
2466
+ },
2467
+ {
2468
+ key: "submitTransaction",
2469
+ value: /**
2470
+ * Broadcast a finalized Midnight transaction. Pure RPC — no MPC, no proof
2471
+ * server; reuses the cached wallet's node connection. Optionally blocks
2472
+ * until the unshielded balance for tokenType stabilizes.
2473
+ */ function submitTransaction(param) {
2474
+ var accountAddress = param.accountAddress, transaction = param.transaction, _param_waitForBalance = param.waitForBalance, waitForBalance = _param_waitForBalance === void 0 ? false : _param_waitForBalance, tokenType = param.tokenType, balanceBefore = param.balanceBefore, password = param.password, signedSessionId = param.signedSessionId, mfaToken = param.mfaToken, elevatedAccessToken = param.elevatedAccessToken;
2475
+ var _this = this;
2476
+ return _async_to_generator(function() {
2477
+ var _updatedState_unshielded_balances, _updatedState_unshielded, wallet, txBytes, finalized, txIdentifier, txHash, balanceBeforeBig, updatedState, _updatedState_unshielded_balances_tokenType, balanceAfter;
2478
+ return _ts_generator(this, function(_state) {
2479
+ switch(_state.label){
2480
+ case 0:
2481
+ return [
2482
+ 4,
2483
+ _this.initMidnightWallet('submitTransaction', {
2484
+ accountAddress: accountAddress,
2485
+ password: password,
2486
+ signedSessionId: signedSessionId,
2487
+ mfaToken: mfaToken,
2488
+ elevatedAccessToken: elevatedAccessToken
2489
+ })
2490
+ ];
2491
+ case 1:
2492
+ wallet = _state.sent().wallet;
2493
+ txBytes = Buffer.from(transaction, 'base64');
2494
+ finalized = ledger__namespace.Transaction.deserialize('signature', 'proof', 'binding', new Uint8Array(txBytes));
2495
+ _this.logger.info('[Midnight] submitTransaction: broadcasting...');
2496
+ return [
2497
+ 4,
2498
+ wallet.submitTransaction(finalized)
2499
+ ];
2500
+ case 2:
2501
+ txIdentifier = _state.sent();
2502
+ txHash = DynamicMidnightWalletClient.toTxHashString(txIdentifier);
2503
+ _this.logger.info('[Midnight] submitTransaction: broadcast, txHash=', txHash);
2504
+ if (!waitForBalance) {
2505
+ void _this.persistCachedWalletState();
2506
+ return [
2507
+ 2,
2508
+ {
2509
+ txHash: txHash
2510
+ }
2511
+ ];
2512
+ }
2513
+ if (!tokenType || balanceBefore === undefined) {
2514
+ throw new Error('tokenType and balanceBefore are required when waitForBalance is true');
2515
+ }
2516
+ balanceBeforeBig = BigInt(balanceBefore);
2517
+ _this.logger.info('[Midnight] submitTransaction: waiting for balance to stabilize...');
2518
+ return [
2519
+ 4,
2520
+ new Promise(function(resolve, reject) {
2521
+ // Same TDZ-safe pattern used at every other subscribe site in the
2522
+ // file: `let sub` + optional chaining so if `.subscribe()` throws
2523
+ // synchronously (before `sub` is initialized) the hardTimeout and
2524
+ // stable-timer closures don't hit a TDZ ReferenceError.
2525
+ // eslint-disable-next-line prefer-const
2526
+ var sub;
2527
+ var hardTimeout = setTimeout(function() {
2528
+ sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
2529
+ reject(new Error('Balance update timeout'));
2530
+ }, 120000);
2531
+ var lastState = null;
2532
+ var lastValue = null;
2533
+ var stableTimer = null;
2534
+ sub = wallet.state().subscribe(function(s) {
2535
+ var _s_unshielded_balances, _s_unshielded;
2536
+ var _s_unshielded_balances_tokenType;
2537
+ var current = (_s_unshielded_balances_tokenType = (_s_unshielded = s.unshielded) === null || _s_unshielded === void 0 ? void 0 : (_s_unshielded_balances = _s_unshielded.balances) === null || _s_unshielded_balances === void 0 ? void 0 : _s_unshielded_balances[tokenType]) !== null && _s_unshielded_balances_tokenType !== void 0 ? _s_unshielded_balances_tokenType : 0n;
2538
+ if (current === balanceBeforeBig) return;
2539
+ lastState = s;
2540
+ if (lastValue !== current) {
2541
+ lastValue = current;
2542
+ if (stableTimer) clearTimeout(stableTimer);
2543
+ stableTimer = setTimeout(function() {
2544
+ clearTimeout(hardTimeout);
2545
+ sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
2546
+ resolve(lastState);
2547
+ }, 3000);
2548
+ }
2549
+ });
2550
+ })
2551
+ ];
2552
+ case 3:
2553
+ updatedState = _state.sent();
2554
+ balanceAfter = (_updatedState_unshielded_balances_tokenType = (_updatedState_unshielded = updatedState.unshielded) === null || _updatedState_unshielded === void 0 ? void 0 : (_updatedState_unshielded_balances = _updatedState_unshielded.balances) === null || _updatedState_unshielded_balances === void 0 ? void 0 : _updatedState_unshielded_balances[tokenType]) !== null && _updatedState_unshielded_balances_tokenType !== void 0 ? _updatedState_unshielded_balances_tokenType : 0n;
2555
+ void _this.persistCachedWalletState();
2556
+ return [
2557
+ 2,
2558
+ {
2559
+ txHash: txHash,
2560
+ balanceAfter: balanceAfter.toString()
2561
+ }
2562
+ ];
2563
+ }
2564
+ });
2565
+ })();
2566
+ }
2567
+ },
2568
+ {
2569
+ key: "revertTransaction",
2570
+ value: /**
2571
+ * Release UTXOs reserved by drafted or signed-but-never-submitted Midnight
2572
+ * transactions. Three mutually exclusive modes, resolved by priority below.
2573
+ *
2574
+ * Priority order:
2575
+ * 1. `resetCache` — nuclear: stops cached wallet, deletes the account's
2576
+ * persisted state from IndexedDB, forces next operation to cold-sync.
2577
+ * Use this when reference to specific pending txs is lost, or state
2578
+ * got into a stuck configuration that can't be reverted otherwise.
2579
+ * This is Midnight's documented workaround for "pending coins not
2580
+ * cleared after failed shielded transaction".
2581
+ * 2. `transaction` — revert one specific tx by its base64 serialization.
2582
+ * Accepts either UnprovenTransaction (step 1 output) or
2583
+ * FinalizedTransaction (step 2 output).
2584
+ * 3. `all` — iterate `state.pending.all` and revert each. Covers every
2585
+ * finalized tx the SDK knows about. Does NOT cover Step-1-only drafts
2586
+ * (those are never registered with the pending-tx service — by design
2587
+ * per Midnight, because unproven transactions hold secret-key material).
2588
+ *
2589
+ * Exactly one of the three must be truthy; otherwise this throws.
2590
+ */ function revertTransaction(params) {
2591
+ var _this = this;
2592
+ return _async_to_generator(function() {
2593
+ return _ts_generator(this, function(_state) {
2594
+ if (params.resetCache) {
2595
+ return [
2596
+ 2,
2597
+ _this.revertModeResetCache(params.accountAddress)
2598
+ ];
2599
+ }
2600
+ if (params.transaction) {
2601
+ return [
2602
+ 2,
2603
+ _this.revertModeSingleTransaction(params)
2604
+ ];
2605
+ }
2606
+ if (params.all) {
2607
+ return [
2608
+ 2,
2609
+ _this.revertModeAllPending(params)
2610
+ ];
2611
+ }
2612
+ throw new Error('revertTransaction requires one of: transaction, all, resetCache');
2613
+ });
2614
+ })();
2615
+ }
2616
+ },
2617
+ {
2618
+ key: "revertModeResetCache",
2619
+ value: function revertModeResetCache(accountAddress) {
2620
+ var _this = this;
2621
+ return _async_to_generator(function() {
2622
+ var _this_cachedWallet, _this_cachedWallet_diagnosticSub, err;
2623
+ return _ts_generator(this, function(_state) {
2624
+ switch(_state.label){
2625
+ case 0:
2626
+ _this.logger.info('[Midnight] revertTransaction[resetCache]: stopping cached wallet and clearing persisted state...');
2627
+ _state.label = 1;
2628
+ case 1:
2629
+ _state.trys.push([
2630
+ 1,
2631
+ 8,
2632
+ ,
2633
+ 9
2634
+ ]);
2635
+ if (!(((_this_cachedWallet = _this.cachedWallet) === null || _this_cachedWallet === void 0 ? void 0 : _this_cachedWallet.accountAddress) === accountAddress)) return [
2636
+ 3,
2637
+ 6
2638
+ ];
2639
+ try {
2640
+ ;
2641
+ (_this_cachedWallet_diagnosticSub = _this.cachedWallet.diagnosticSub) === null || _this_cachedWallet_diagnosticSub === void 0 ? void 0 : _this_cachedWallet_diagnosticSub.unsubscribe();
2642
+ } catch (e) {
2643
+ /* ignore */ }
2644
+ _state.label = 2;
2645
+ case 2:
2646
+ _state.trys.push([
2647
+ 2,
2648
+ 4,
2649
+ ,
2650
+ 5
2651
+ ]);
2652
+ return [
2653
+ 4,
2654
+ _this.cachedWallet.wallet.stop()
2655
+ ];
2656
+ case 3:
2657
+ _state.sent();
2658
+ return [
2659
+ 3,
2660
+ 5
2661
+ ];
2662
+ case 4:
2663
+ _state.sent();
2664
+ return [
2665
+ 3,
2666
+ 5
2667
+ ];
2668
+ case 5:
2669
+ _this.cachedWallet = null;
2670
+ _state.label = 6;
2671
+ case 6:
2672
+ return [
2673
+ 4,
2674
+ deleteWalletState(accountAddress)
2675
+ ];
2676
+ case 7:
2677
+ _state.sent();
2678
+ return [
2679
+ 3,
2680
+ 9
2681
+ ];
2682
+ case 8:
2683
+ err = _state.sent();
2684
+ throw new Error("resetCache failed: ".concat(err.message));
2685
+ case 9:
2686
+ _this.logger.info('[Midnight] revertTransaction[resetCache]: cache cleared');
2687
+ return [
2688
+ 2,
2689
+ {
2690
+ reverted: true,
2691
+ count: 0,
2692
+ cacheCleared: true,
2693
+ message: 'Wallet cache reset. The cached wallet instance was stopped, the persisted IndexedDB entry for this account was deleted, and the next operation will cold-sync from chain.'
2694
+ }
2695
+ ];
2696
+ }
2697
+ });
2698
+ })();
2699
+ }
2700
+ },
2701
+ {
2702
+ key: "revertModeSingleTransaction",
2703
+ value: function revertModeSingleTransaction(params) {
2704
+ var _this = this;
2705
+ return _async_to_generator(function() {
2706
+ var wallet, txBytes, tx;
2707
+ return _ts_generator(this, function(_state) {
2708
+ switch(_state.label){
2709
+ case 0:
2710
+ return [
2711
+ 4,
2712
+ _this.initMidnightWallet('revertTransaction', {
2713
+ accountAddress: params.accountAddress,
2714
+ password: params.password,
2715
+ signedSessionId: params.signedSessionId,
2716
+ mfaToken: params.mfaToken,
2717
+ elevatedAccessToken: params.elevatedAccessToken
2718
+ })
2719
+ ];
2720
+ case 1:
2721
+ wallet = _state.sent().wallet;
2722
+ txBytes = new Uint8Array(Buffer.from(params.transaction, 'base64'));
2723
+ tx = _this.deserializeAnyMidnightTx(txBytes);
2724
+ _this.logger.info('[Midnight] revertTransaction[single]: reverting specific tx...');
2725
+ return [
2726
+ 4,
2727
+ wallet.revert(tx)
2728
+ ];
2729
+ case 2:
2730
+ _state.sent();
2731
+ void _this.persistCachedWalletState();
2732
+ return [
2733
+ 2,
2734
+ {
2735
+ reverted: true,
2736
+ count: 1,
2737
+ cacheCleared: false,
2738
+ message: 'Transaction reverted. Reserved UTXOs have been returned to the available set.'
2739
+ }
2740
+ ];
2741
+ }
2742
+ });
2743
+ })();
2744
+ }
2745
+ },
2746
+ {
2747
+ key: "revertModeAllPending",
2748
+ value: function revertModeAllPending(params) {
2749
+ var _this = this;
2750
+ return _async_to_generator(function() {
2751
+ var _snapshot_pending, wallet, snapshot, _snapshot_pending_all, pending, reverted, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, item, err1, err;
2752
+ return _ts_generator(this, function(_state) {
2753
+ switch(_state.label){
2754
+ case 0:
2755
+ return [
2756
+ 4,
2757
+ _this.initMidnightWallet('revertTransaction', {
2758
+ accountAddress: params.accountAddress,
2759
+ password: params.password,
2760
+ signedSessionId: params.signedSessionId,
2761
+ mfaToken: params.mfaToken,
2762
+ elevatedAccessToken: params.elevatedAccessToken
2763
+ })
2764
+ ];
2765
+ case 1:
2766
+ wallet = _state.sent().wallet;
2767
+ _this.logger.info('[Midnight] revertTransaction[all]: reading pending-tx list...');
2768
+ return [
2769
+ 4,
2770
+ _this.snapshotWalletState(wallet)
2771
+ ];
2772
+ case 2:
2773
+ snapshot = _state.sent();
2774
+ pending = (_snapshot_pending_all = snapshot === null || snapshot === void 0 ? void 0 : (_snapshot_pending = snapshot.pending) === null || _snapshot_pending === void 0 ? void 0 : _snapshot_pending.all) !== null && _snapshot_pending_all !== void 0 ? _snapshot_pending_all : [];
2775
+ _this.logger.info("[Midnight] revertTransaction[all]: reverting ".concat(pending.length, " pending tx(s)..."));
2776
+ reverted = 0;
2777
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2778
+ _state.label = 3;
2779
+ case 3:
2780
+ _state.trys.push([
2781
+ 3,
2782
+ 10,
2783
+ 11,
2784
+ 12
2785
+ ]);
2786
+ _iterator = pending[Symbol.iterator]();
2787
+ _state.label = 4;
2788
+ case 4:
2789
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
2790
+ 3,
2791
+ 9
2792
+ ];
2793
+ item = _step.value;
2794
+ _state.label = 5;
2795
+ case 5:
2796
+ _state.trys.push([
2797
+ 5,
2798
+ 7,
2799
+ ,
2800
+ 8
2801
+ ]);
2802
+ return [
2803
+ 4,
2804
+ wallet.revert(item.tx)
2805
+ ];
2806
+ case 6:
2807
+ _state.sent();
2808
+ reverted += 1;
2809
+ return [
2810
+ 3,
2811
+ 8
2812
+ ];
2813
+ case 7:
2814
+ err1 = _state.sent();
2815
+ _this.logger.warn('[Midnight] revertTransaction[all]: revert failed for one tx, continuing:', err1);
2816
+ return [
2817
+ 3,
2818
+ 8
2819
+ ];
2820
+ case 8:
2821
+ _iteratorNormalCompletion = true;
2822
+ return [
2823
+ 3,
2824
+ 4
2825
+ ];
2826
+ case 9:
2827
+ return [
2828
+ 3,
2829
+ 12
2830
+ ];
2831
+ case 10:
2832
+ err = _state.sent();
2833
+ _didIteratorError = true;
2834
+ _iteratorError = err;
2835
+ return [
2836
+ 3,
2837
+ 12
2838
+ ];
2839
+ case 11:
2840
+ try {
2841
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2842
+ _iterator.return();
2843
+ }
2844
+ } finally{
2845
+ if (_didIteratorError) {
2846
+ throw _iteratorError;
2847
+ }
2848
+ }
2849
+ return [
2850
+ 7
2851
+ ];
2852
+ case 12:
2853
+ void _this.persistCachedWalletState();
2854
+ return [
2855
+ 2,
2856
+ {
2857
+ reverted: true,
2858
+ count: reverted,
2859
+ cacheCleared: false,
2860
+ message: reverted > 0 ? "Reverted ".concat(reverted, " pending transaction(s). Step-1-only drafts are not covered — use resetCache if UTXOs are still stuck.") : 'No pending transactions to revert. If UTXOs are still stuck, the tx was likely an unfinalized draft — use resetCache to clear local state.'
2861
+ }
2862
+ ];
2863
+ }
2864
+ });
2865
+ })();
2866
+ }
2867
+ },
2868
+ {
2869
+ key: "deserializeAnyMidnightTx",
2870
+ value: // Try unproven first (more common abandonment point), fall back to finalized.
2871
+ function deserializeAnyMidnightTx(txBytes) {
2872
+ try {
2873
+ return ledger__namespace.Transaction.deserialize('signature', 'pre-proof', 'pre-binding', txBytes);
2874
+ } catch (e) {
2875
+ try {
2876
+ return ledger__namespace.Transaction.deserialize('signature', 'proof', 'binding', txBytes);
2877
+ } catch (err) {
2878
+ throw new Error("Could not deserialize transaction as either UnprovenTransaction or FinalizedTransaction: ".concat(err.message));
2879
+ }
2880
+ }
2881
+ }
2882
+ },
2883
+ {
2884
+ key: "snapshotWalletState",
2885
+ value: // Take a single snapshot of wallet state via the observable. Same
2886
+ // subscribe-once pattern we use elsewhere — no rxjs dependency needed.
2887
+ function snapshotWalletState(wallet) {
2888
+ return _async_to_generator(function() {
2889
+ return _ts_generator(this, function(_state) {
2890
+ return [
2891
+ 2,
2892
+ new Promise(function(resolve, reject) {
2893
+ // eslint-disable-next-line prefer-const
2894
+ var sub;
2895
+ var tid = setTimeout(function() {
2896
+ sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
2897
+ reject(new Error('Timed out waiting for wallet state snapshot'));
2898
+ }, 10000);
2899
+ sub = wallet.state().subscribe(function(s) {
2900
+ clearTimeout(tid);
2901
+ queueMicrotask(function() {
2902
+ return sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
2903
+ });
2904
+ resolve(s);
2905
+ });
2906
+ })
2907
+ ];
2908
+ });
2909
+ })();
2910
+ }
2911
+ },
2912
+ {
2913
+ key: "mpcSignIntents",
2914
+ value: /**
2915
+ * Sign all unshielded intents in a transaction via MPC.
2916
+ * Mutates tx.intents in place with signatures attached.
2917
+ * No-op for pure shielded transactions (0 unshielded segments).
2918
+ *
2919
+ * Each per-segment sign call carries the full unsigned tx in context so
2920
+ * wallet-service policy sees the whole transaction once per signature
2921
+ * (same pattern as BTC's PSBT in per-input context).
2922
+ */ function mpcSignIntents(tx, options) {
2923
+ var _this = this;
2924
+ return _async_to_generator(function() {
2925
+ var _tx_intents, accountAddress, password, signedSessionId, mfaToken, elevatedAccessToken, fullTxBase64, networkId, baseContext, _options_proofMarker, proofMarker, _tx_intents_keys_toArray, segments, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _loop, _iterator, _step, err;
2926
+ return _ts_generator(this, function(_state) {
2927
+ switch(_state.label){
2928
+ case 0:
2929
+ accountAddress = options.accountAddress, password = options.password, signedSessionId = options.signedSessionId, mfaToken = options.mfaToken, elevatedAccessToken = options.elevatedAccessToken, fullTxBase64 = options.fullTxBase64, networkId = options.networkId, baseContext = options.baseContext, _options_proofMarker = options.proofMarker, proofMarker = _options_proofMarker === void 0 ? 'pre-proof' : _options_proofMarker;
2930
+ segments = (_tx_intents_keys_toArray = (_tx_intents = tx.intents) === null || _tx_intents === void 0 ? void 0 : _tx_intents.keys().toArray()) !== null && _tx_intents_keys_toArray !== void 0 ? _tx_intents_keys_toArray : [];
2931
+ if (segments.length === 0) return [
2932
+ 2
2933
+ ];
2934
+ _this.logger.info("[Midnight] MPC signing ".concat(segments.length, " segment(s)..."));
2935
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2936
+ _state.label = 1;
2937
+ case 1:
2938
+ _state.trys.push([
2939
+ 1,
2940
+ 6,
2941
+ 7,
2942
+ 8
2943
+ ]);
2944
+ _loop = function() {
2945
+ var segment, intent, cloned, sigData, hashBuffer, hash, signature, sigBytes, ledgerSig, sigs, sigs1;
2946
+ return _ts_generator(this, function(_state) {
2947
+ switch(_state.label){
2948
+ case 0:
2949
+ segment = _step.value;
2950
+ intent = tx.intents.get(segment);
2951
+ if (!intent) return [
2952
+ 2,
2953
+ "continue"
2954
+ ];
2955
+ cloned = ledger__namespace.Intent.deserialize('signature', proofMarker, 'pre-binding', intent.serialize());
2956
+ sigData = cloned.signatureData(segment);
2957
+ return [
2958
+ 4,
2959
+ crypto.subtle.digest('SHA-256', sigData)
2960
+ ];
2961
+ case 1:
2962
+ hashBuffer = _state.sent();
2963
+ hash = Array.from(new Uint8Array(hashBuffer)).map(function(b) {
2964
+ return b.toString(16).padStart(2, '0');
2965
+ }).join('');
2966
+ return [
2967
+ 4,
2968
+ _this.sign({
2969
+ message: hash,
2970
+ accountAddress: accountAddress,
2971
+ chainName: _this.chainName,
2972
+ password: password,
2973
+ signedSessionId: signedSessionId,
2974
+ mfaToken: mfaToken,
2975
+ elevatedAccessToken: elevatedAccessToken,
2976
+ context: _object_spread_props(_object_spread({}, baseContext), {
2977
+ midnightTransaction: {
2978
+ serializedTransaction: fullTxBase64,
2979
+ networkId: networkId
2980
+ }
2981
+ })
2982
+ })
2983
+ ];
2984
+ case 2:
2985
+ signature = _state.sent();
2986
+ sigBytes = _instanceof(signature, Uint8Array) ? signature : Buffer.from(signature, 'base64');
2987
+ ledgerSig = Buffer.from(sigBytes).toString('hex');
2988
+ if (cloned.fallibleUnshieldedOffer) {
2989
+ sigs = cloned.fallibleUnshieldedOffer.inputs.map(function(_, i) {
2990
+ var _cloned_fallibleUnshieldedOffer_signatures_at;
2991
+ return (_cloned_fallibleUnshieldedOffer_signatures_at = cloned.fallibleUnshieldedOffer.signatures.at(i)) !== null && _cloned_fallibleUnshieldedOffer_signatures_at !== void 0 ? _cloned_fallibleUnshieldedOffer_signatures_at : ledgerSig;
2992
+ });
2993
+ cloned.fallibleUnshieldedOffer = cloned.fallibleUnshieldedOffer.addSignatures(sigs);
2994
+ }
2995
+ if (cloned.guaranteedUnshieldedOffer) {
2996
+ sigs1 = cloned.guaranteedUnshieldedOffer.inputs.map(function(_, i) {
2997
+ var _cloned_guaranteedUnshieldedOffer_signatures_at;
2998
+ return (_cloned_guaranteedUnshieldedOffer_signatures_at = cloned.guaranteedUnshieldedOffer.signatures.at(i)) !== null && _cloned_guaranteedUnshieldedOffer_signatures_at !== void 0 ? _cloned_guaranteedUnshieldedOffer_signatures_at : ledgerSig;
2999
+ });
3000
+ cloned.guaranteedUnshieldedOffer = cloned.guaranteedUnshieldedOffer.addSignatures(sigs1);
3001
+ }
3002
+ tx.intents = tx.intents.set(segment, cloned);
3003
+ return [
3004
+ 2
3005
+ ];
3006
+ }
3007
+ });
3008
+ };
3009
+ _iterator = segments[Symbol.iterator]();
3010
+ _state.label = 2;
3011
+ case 2:
3012
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
3013
+ 3,
3014
+ 5
3015
+ ];
3016
+ return [
3017
+ 5,
3018
+ _ts_values(_loop())
3019
+ ];
3020
+ case 3:
3021
+ _state.sent();
3022
+ _state.label = 4;
3023
+ case 4:
3024
+ _iteratorNormalCompletion = true;
3025
+ return [
3026
+ 3,
3027
+ 2
3028
+ ];
3029
+ case 5:
3030
+ return [
3031
+ 3,
3032
+ 8
3033
+ ];
3034
+ case 6:
3035
+ err = _state.sent();
3036
+ _didIteratorError = true;
3037
+ _iteratorError = err;
3038
+ return [
3039
+ 3,
3040
+ 8
3041
+ ];
3042
+ case 7:
3043
+ try {
3044
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
3045
+ _iterator.return();
3046
+ }
3047
+ } finally{
3048
+ if (_didIteratorError) {
3049
+ throw _iteratorError;
3050
+ }
3051
+ }
3052
+ return [
3053
+ 7
3054
+ ];
3055
+ case 8:
3056
+ return [
3057
+ 2
3058
+ ];
3059
+ }
3060
+ });
3061
+ })();
3062
+ }
3063
+ },
3064
+ {
3065
+ key: "getWalletProvider",
3066
+ value: /**
3067
+ * Returns a Midnight.js-compatible WalletProvider for use with
3068
+ * midnight-js-contracts. Signing goes through MPC — no private key exposed.
3069
+ */ function getWalletProvider(param) {
3070
+ var accountAddress = param.accountAddress, password = param.password, signedSessionId = param.signedSessionId, mfaToken = param.mfaToken, elevatedAccessToken = param.elevatedAccessToken;
3071
+ var _this = this;
3072
+ return _async_to_generator(function() {
3073
+ var _ref, wallet, state, shieldedSecretKeys, dustSecretKey, walletProvider;
3074
+ return _ts_generator(this, function(_state) {
3075
+ switch(_state.label){
3076
+ case 0:
3077
+ return [
3078
+ 4,
3079
+ _this.initMidnightWallet('walletProvider', {
3080
+ accountAddress: accountAddress,
3081
+ password: password,
3082
+ signedSessionId: signedSessionId,
3083
+ mfaToken: mfaToken,
3084
+ elevatedAccessToken: elevatedAccessToken
3085
+ })
3086
+ ];
3087
+ case 1:
3088
+ _ref = _state.sent(), wallet = _ref.wallet, state = _ref.state, shieldedSecretKeys = _ref.shieldedSecretKeys, dustSecretKey = _ref.dustSecretKey;
3089
+ walletProvider = {
3090
+ getCoinPublicKey: function() {
3091
+ return state.shielded.coinPublicKey.toHexString();
3092
+ },
3093
+ getEncryptionPublicKey: function() {
3094
+ return state.shielded.encryptionPublicKey.toHexString();
3095
+ },
3096
+ balanceTx: /*#__PURE__*/ function() {
3097
+ var _ref = _async_to_generator(function(tx, ttl) {
3098
+ var recipe, baseTxB64, balancingTxB64;
3099
+ return _ts_generator(this, function(_state) {
3100
+ switch(_state.label){
3101
+ case 0:
3102
+ _this.logger.info('[Midnight] walletProvider.balanceTx: balancing transaction...');
3103
+ return [
3104
+ 4,
3105
+ wallet.balanceUnboundTransaction(tx, {
3106
+ shieldedSecretKeys: shieldedSecretKeys,
3107
+ dustSecretKey: dustSecretKey
3108
+ }, {
3109
+ ttl: ttl !== null && ttl !== void 0 ? ttl : new Date(Date.now() + 30 * 60 * 1000)
3110
+ })
3111
+ ];
3112
+ case 1:
3113
+ recipe = _state.sent();
3114
+ // The proven base tx uses the 'proof' marker. networkId 0 matches
3115
+ // the 'preview' facade network this provider is configured for.
3116
+ baseTxB64 = Buffer.from(recipe.baseTransaction.serialize()).toString('base64');
3117
+ return [
3118
+ 4,
3119
+ _this.mpcSignIntents(recipe.baseTransaction, {
3120
+ accountAddress: accountAddress,
3121
+ password: password,
3122
+ signedSessionId: signedSessionId,
3123
+ mfaToken: mfaToken,
3124
+ elevatedAccessToken: elevatedAccessToken,
3125
+ fullTxBase64: baseTxB64,
3126
+ networkId: 0,
3127
+ proofMarker: 'proof'
3128
+ })
3129
+ ];
3130
+ case 2:
3131
+ _state.sent();
3132
+ if (!recipe.balancingTransaction) return [
3133
+ 3,
3134
+ 4
3135
+ ];
3136
+ balancingTxB64 = Buffer.from(recipe.balancingTransaction.serialize()).toString('base64');
3137
+ return [
3138
+ 4,
3139
+ _this.mpcSignIntents(recipe.balancingTransaction, {
3140
+ accountAddress: accountAddress,
3141
+ password: password,
3142
+ signedSessionId: signedSessionId,
3143
+ mfaToken: mfaToken,
3144
+ elevatedAccessToken: elevatedAccessToken,
3145
+ fullTxBase64: balancingTxB64,
3146
+ networkId: 0,
3147
+ proofMarker: 'pre-proof'
3148
+ })
3149
+ ];
3150
+ case 3:
3151
+ _state.sent();
3152
+ _state.label = 4;
3153
+ case 4:
3154
+ _this.logger.info('[Midnight] walletProvider.balanceTx: finalizing...');
3155
+ return [
3156
+ 2,
3157
+ wallet.finalizeRecipe(recipe)
3158
+ ];
3159
+ }
3160
+ });
3161
+ });
3162
+ return function(tx, ttl) {
3163
+ return _ref.apply(this, arguments);
3164
+ };
3165
+ }(),
3166
+ submitTx: function(tx) {
3167
+ _this.logger.info('[Midnight] walletProvider.submitTx: submitting...');
3168
+ return wallet.submitTransaction(tx);
3169
+ }
3170
+ };
3171
+ return [
3172
+ 2,
3173
+ {
3174
+ walletProvider: walletProvider,
3175
+ wallet: wallet,
3176
+ state: state,
3177
+ shieldedSecretKeys: shieldedSecretKeys,
3178
+ dustSecretKey: dustSecretKey
3179
+ }
3180
+ ];
3181
+ }
3182
+ });
3183
+ })();
3184
+ }
3185
+ }
3186
+ ], [
3187
+ {
3188
+ key: "toTxHashString",
3189
+ value: /**
3190
+ * Coerce the value returned by `wallet.submitTransaction(...)` to a string.
3191
+ * Midnight's facade returns either a string txId, or a TransactionIdentifier
3192
+ * object with a `.toHex()` method. We normalize so callers always see a
3193
+ * string, and fall back to `String(...)` if neither shape matches.
3194
+ */ function toTxHashString(txIdentifier) {
3195
+ if (typeof txIdentifier === 'string') return txIdentifier;
3196
+ var maybeHex = txIdentifier === null || txIdentifier === void 0 ? void 0 : txIdentifier.toHex;
3197
+ if (typeof maybeHex === 'function') return txIdentifier.toHex();
3198
+ return String(txIdentifier);
3199
+ }
3200
+ }
3201
+ ]);
3202
+ return DynamicMidnightWalletClient;
3203
+ }(browser.DynamicWalletClient);
3204
+
3205
+ /**
3206
+ * Address prefixes for Bech32m encoding (BIP-0350)
3207
+ */ var ADDRESS_PREFIXES = {
3208
+ mainnet: 'mn_addr',
3209
+ preview: 'mn_addr_preview',
3210
+ preprod: 'mn_addr_preprod',
3211
+ undeployed: 'mn_addr_undeployed'
3212
+ };
3213
+ /**
3214
+ * Derives a Midnight unshielded address from a 32-byte address hash.
3215
+ * NOTE: Midnight addresses are Poseidon hashes of the public key, not the raw key.
3216
+ * The address hash should be computed server-side using ledger.addressFromKey().
3217
+ * If publicKeyHex is passed, it's assumed to already be the address hash.
3218
+ *
3219
+ * @param publicKeyHex - The 32-byte address hash (from addressFromKey) as hex string
3220
+ * @param network - The network. Defaults to preview
3221
+ * @returns Bech32m encoded address (e.g., mn_addr_preview1...)
3222
+ */ var deriveMidnightAddress = function(param) {
3223
+ var publicKeyHex = param.publicKeyHex, _param_network = param.network, network = _param_network === void 0 ? 'preview' : _param_network;
3224
+ var bytes = Buffer.from(publicKeyHex, 'hex');
3225
+ if (bytes.length !== 32) {
3226
+ throw new Error("Invalid key length: ".concat(bytes.length, ", expected 32"));
3227
+ }
3228
+ var prefix = ADDRESS_PREFIXES[network];
3229
+ var words = bech32.bech32m.toWords(bytes);
3230
+ return bech32.bech32m.encode(prefix, words);
3231
+ };
3232
+ // `'mn_addr'` is a strict prefix of every other value in ADDRESS_PREFIXES,
3233
+ // so naive `startsWith` checks hit `mainnet` for any Midnight address. Always
3234
+ // check longest prefix first (descending).
3235
+ Object.entries(ADDRESS_PREFIXES).slice().sort(function(a, b) {
3236
+ return b[1].length - a[1].length;
3237
+ });
3238
+
3239
+ exports.sdkApiCore = sdkApiCore__namespace;
3240
+ exports.DynamicMidnightWalletClient = DynamicMidnightWalletClient;
3241
+ exports.MIDNIGHT_NETWORK_IDS = MIDNIGHT_NETWORK_IDS;
3242
+ exports.deriveMidnightAddress = deriveMidnightAddress;