@dynamic-labs-wallet/node-midnight 1.1.4 → 1.1.5
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 +1660 -6
- package/index.esm.js +1662 -9
- package/package.json +7 -2
- package/src/client/client.d.ts +187 -1
- package/src/client/client.d.ts.map +1 -1
- package/src/client/constants.d.ts +36 -1
- package/src/client/constants.d.ts.map +1 -1
- package/src/client/index.d.ts +2 -1
- package/src/client/index.d.ts.map +1 -1
- package/src/client/walletState.d.ts +54 -0
- package/src/client/walletState.d.ts.map +1 -0
- package/src/index.d.ts +1 -1
- package/src/index.d.ts.map +1 -1
package/index.cjs
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var node_crypto = require('node:crypto');
|
|
4
|
+
var node_util = require('node:util');
|
|
3
5
|
var node = require('@dynamic-labs-wallet/node');
|
|
4
6
|
var ledger = require('@midnight-ntwrk/ledger-v8');
|
|
7
|
+
var walletSdkAbstractions = require('@midnight-ntwrk/wallet-sdk-abstractions');
|
|
5
8
|
var walletSdkAddressFormat = require('@midnight-ntwrk/wallet-sdk-address-format');
|
|
9
|
+
var walletSdkDustWallet = require('@midnight-ntwrk/wallet-sdk-dust-wallet');
|
|
10
|
+
var walletSdkFacade = require('@midnight-ntwrk/wallet-sdk-facade');
|
|
11
|
+
var walletSdkShielded = require('@midnight-ntwrk/wallet-sdk-shielded');
|
|
12
|
+
var walletSdkUnshieldedWallet = require('@midnight-ntwrk/wallet-sdk-unshielded-wallet');
|
|
6
13
|
var bip32 = require('@scure/bip32');
|
|
7
14
|
var bech32 = require('bech32');
|
|
8
15
|
|
|
@@ -37,14 +44,64 @@ var MIDNIGHT_NETWORK_IDS = {
|
|
|
37
44
|
preprod: 0,
|
|
38
45
|
undeployed: 0
|
|
39
46
|
};
|
|
47
|
+
var _process_env_MIDNIGHT_PROOF_SERVER_URL;
|
|
48
|
+
var MIDNIGHT_PROOF_SERVER_URL = (_process_env_MIDNIGHT_PROOF_SERVER_URL = process.env.MIDNIGHT_PROOF_SERVER_URL) !== null && _process_env_MIDNIGHT_PROOF_SERVER_URL !== void 0 ? _process_env_MIDNIGHT_PROOF_SERVER_URL : 'https://proof-server.us-east-1.dynamic-preprod.xyz';
|
|
49
|
+
/**
|
|
50
|
+
* Per-network wallet-facade infrastructure. There is no public mainnet proof
|
|
51
|
+
* server, so Dynamic's is shared across networks for now.
|
|
52
|
+
*/ var MIDNIGHT_INFRA = {
|
|
53
|
+
mainnet: {
|
|
54
|
+
relayUrl: 'wss://rpc.mainnet.midnight.network',
|
|
55
|
+
provingServerUrl: MIDNIGHT_PROOF_SERVER_URL,
|
|
56
|
+
indexerHttpUrl: 'https://indexer.mainnet.midnight.network/api/v4/graphql',
|
|
57
|
+
indexerWsUrl: 'wss://indexer.mainnet.midnight.network/api/v4/graphql/ws'
|
|
58
|
+
},
|
|
59
|
+
preview: {
|
|
60
|
+
relayUrl: 'wss://rpc.preview.midnight.network',
|
|
61
|
+
provingServerUrl: MIDNIGHT_PROOF_SERVER_URL,
|
|
62
|
+
indexerHttpUrl: 'https://indexer.preview.midnight.network/api/v4/graphql',
|
|
63
|
+
indexerWsUrl: 'wss://indexer.preview.midnight.network/api/v4/graphql/ws'
|
|
64
|
+
}
|
|
65
|
+
};
|
|
40
66
|
/**
|
|
41
67
|
* Resolves a caller-supplied network identifier (numeric 0/1, network name, or
|
|
42
|
-
* `midnight:<network>` chainId) to the facade network tag.
|
|
68
|
+
* `midnight:<network>` chainId) to the facade network tag. Omitting it defaults
|
|
69
|
+
* to 'preview'.
|
|
70
|
+
*
|
|
71
|
+
* Throws on anything else rather than falling back, for the same reason
|
|
72
|
+
* {@link getNetworkIdFromChainId} does: an unrecognized identifier that quietly
|
|
73
|
+
* became 'preview' would have the caller sync one network while signing with
|
|
74
|
+
* another network's replay-protection ID, with no error to show for it.
|
|
43
75
|
*/ var resolveMidnightNetworkTag = function(networkId) {
|
|
44
76
|
if (networkId === undefined || networkId === null) return 'preview';
|
|
45
|
-
if (typeof networkId === 'number')
|
|
77
|
+
if (typeof networkId === 'number') {
|
|
78
|
+
if (networkId === MIDNIGHT_NETWORK_IDS.mainnet) return 'mainnet';
|
|
79
|
+
if (networkId === MIDNIGHT_NETWORK_IDS.preview) return 'preview';
|
|
80
|
+
throw new Error("".concat(ERROR_UNKNOWN_NETWORK, ": ").concat(networkId));
|
|
81
|
+
}
|
|
46
82
|
var name = networkId.includes(':') ? networkId.split(':')[1] : networkId;
|
|
47
|
-
|
|
83
|
+
if (name === 'mainnet' || name === 'preview') return name;
|
|
84
|
+
throw new Error("".concat(ERROR_UNKNOWN_NETWORK, ": ").concat(networkId));
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Resolves a network name (or `midnight:<network>` chainId) to its numeric
|
|
88
|
+
* network ID.
|
|
89
|
+
*
|
|
90
|
+
* Throws on unrecognized input rather than defaulting — silently falling back to
|
|
91
|
+
* mainnet would bake the wrong network ID into the transaction hash and break
|
|
92
|
+
* replay protection.
|
|
93
|
+
*/ var getNetworkIdFromChainId = function(networkOrChainId) {
|
|
94
|
+
if (networkOrChainId in MIDNIGHT_NETWORK_IDS) {
|
|
95
|
+
return MIDNIGHT_NETWORK_IDS[networkOrChainId];
|
|
96
|
+
}
|
|
97
|
+
if (networkOrChainId.includes(':')) {
|
|
98
|
+
var network = networkOrChainId.split(':')[1];
|
|
99
|
+
if (network && network in MIDNIGHT_NETWORK_IDS) {
|
|
100
|
+
return MIDNIGHT_NETWORK_IDS[network];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
var known = Object.keys(MIDNIGHT_NETWORK_IDS).join(', ');
|
|
104
|
+
throw new Error("".concat(ERROR_UNKNOWN_NETWORK, ': "').concat(networkOrChainId, '". Expected one of: ').concat(known, ', or "midnight:<network>".'));
|
|
48
105
|
};
|
|
49
106
|
var ERROR_KEYGEN_FAILED = 'Error with keygen';
|
|
50
107
|
var ERROR_CREATE_WALLET_ACCOUNT = 'Error creating midnight wallet account';
|
|
@@ -52,6 +109,53 @@ var ERROR_IMPORT_PRIVATE_KEY = 'Error importing private key';
|
|
|
52
109
|
var ERROR_EXPORT_PRIVATE_KEY = 'Error exporting private key';
|
|
53
110
|
var ERROR_SIGN_MESSAGE = 'Error signing message';
|
|
54
111
|
var ERROR_ACCOUNT_ADDRESS_REQUIRED = 'Account address is required';
|
|
112
|
+
var ERROR_SIGN_TRANSACTION = 'Error signing transaction';
|
|
113
|
+
var ERROR_UNKNOWN_NETWORK = 'Unknown Midnight network';
|
|
114
|
+
var ERROR_NETWORK_ID_REQUIRED = 'Network ID is required for Midnight transactions';
|
|
115
|
+
var ERROR_NO_DUST = 'No dust balance — register dust first';
|
|
116
|
+
var ERROR_SUBMIT_TRANSACTION = 'Error submitting transaction';
|
|
117
|
+
var ERROR_CREATE_TRANSFER = 'Error creating transfer transaction';
|
|
118
|
+
var ERROR_GET_BALANCE = 'Error fetching balance';
|
|
119
|
+
var ERROR_REGISTER_DUST = 'Error registering dust';
|
|
120
|
+
var ERROR_BALANCE_TRANSACTION = 'Error balancing contract transaction';
|
|
121
|
+
|
|
122
|
+
/** Whether a sub-wallet side has finished syncing. `highestRelevantIndex` is 0
|
|
123
|
+
* during sync, so `isStrictlyComplete()` is the authoritative signal. */ var isSideSynced = function(side) {
|
|
124
|
+
var _side_state;
|
|
125
|
+
var _side_progress;
|
|
126
|
+
var p = (_side_progress = side === null || side === void 0 ? void 0 : side.progress) !== null && _side_progress !== void 0 ? _side_progress : side === null || side === void 0 ? void 0 : (_side_state = side.state) === null || _side_state === void 0 ? void 0 : _side_state.progress;
|
|
127
|
+
if (!p) return false;
|
|
128
|
+
if (typeof p.isStrictlyComplete === 'function') return p.isStrictlyComplete();
|
|
129
|
+
var _p_appliedIndex;
|
|
130
|
+
var applied = BigInt((_p_appliedIndex = p.appliedIndex) !== null && _p_appliedIndex !== void 0 ? _p_appliedIndex : 0n);
|
|
131
|
+
var _p_highestRelevantIndex;
|
|
132
|
+
var highestRelevant = BigInt((_p_highestRelevantIndex = p.highestRelevantIndex) !== null && _p_highestRelevantIndex !== void 0 ? _p_highestRelevantIndex : 0n);
|
|
133
|
+
return highestRelevant > 0n && applied >= highestRelevant;
|
|
134
|
+
};
|
|
135
|
+
var isSyncResolved = function(state, mode) {
|
|
136
|
+
return mode === 'full' ? Boolean(state.isSynced) : isSideSynced(state.shielded) && isSideSynced(state.unshielded);
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Whether a checkpoint may be restored into a facade for `network`.
|
|
140
|
+
*
|
|
141
|
+
* A checkpoint is only meaningful for the network it was taken on — sync
|
|
142
|
+
* indices do not carry across — so a mismatch is treated as no checkpoint at
|
|
143
|
+
* all rather than as an error, since the caller may legitimately hold state for
|
|
144
|
+
* several networks.
|
|
145
|
+
*/ var isRestorableState = function(state, network) {
|
|
146
|
+
return state !== undefined && typeof state.shielded === 'string' && typeof state.dust === 'string' && state.network === network;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Whether the wallet is at a clean resting point, with nothing in flight.
|
|
150
|
+
*
|
|
151
|
+
* Checkpointing mid-flight would bake pending entries into whatever the caller
|
|
152
|
+
* stores and carry them forward on every later restore, so a dirty wallet is
|
|
153
|
+
* skipped and the caller simply keeps its previous checkpoint.
|
|
154
|
+
*/ var isCleanForCheckpoint = function(state) {
|
|
155
|
+
var _state_pending_all, _state_pending, _state_unshielded_pendingCoins, _state_unshielded, _state_shielded_pendingCoins, _state_shielded, _state_dust_pendingCoins, _state_dust;
|
|
156
|
+
var _state_pending_all_length, _state_unshielded_pendingCoins_length, _state_shielded_pendingCoins_length, _state_dust_pendingCoins_length;
|
|
157
|
+
return ((_state_pending_all_length = state === null || state === void 0 ? void 0 : (_state_pending = state.pending) === null || _state_pending === void 0 ? void 0 : (_state_pending_all = _state_pending.all) === null || _state_pending_all === void 0 ? void 0 : _state_pending_all.length) !== null && _state_pending_all_length !== void 0 ? _state_pending_all_length : 0) === 0 && ((_state_unshielded_pendingCoins_length = state === null || state === void 0 ? void 0 : (_state_unshielded = state.unshielded) === null || _state_unshielded === void 0 ? void 0 : (_state_unshielded_pendingCoins = _state_unshielded.pendingCoins) === null || _state_unshielded_pendingCoins === void 0 ? void 0 : _state_unshielded_pendingCoins.length) !== null && _state_unshielded_pendingCoins_length !== void 0 ? _state_unshielded_pendingCoins_length : 0) === 0 && ((_state_shielded_pendingCoins_length = state === null || state === void 0 ? void 0 : (_state_shielded = state.shielded) === null || _state_shielded === void 0 ? void 0 : (_state_shielded_pendingCoins = _state_shielded.pendingCoins) === null || _state_shielded_pendingCoins === void 0 ? void 0 : _state_shielded_pendingCoins.length) !== null && _state_shielded_pendingCoins_length !== void 0 ? _state_shielded_pendingCoins_length : 0) === 0 && ((_state_dust_pendingCoins_length = state === null || state === void 0 ? void 0 : (_state_dust = state.dust) === null || _state_dust === void 0 ? void 0 : (_state_dust_pendingCoins = _state_dust.pendingCoins) === null || _state_dust_pendingCoins === void 0 ? void 0 : _state_dust_pendingCoins.length) !== null && _state_dust_pendingCoins_length !== void 0 ? _state_dust_pendingCoins_length : 0) === 0;
|
|
158
|
+
};
|
|
55
159
|
|
|
56
160
|
function _array_like_to_array$1(arr, len) {
|
|
57
161
|
if (len == null || len > arr.length) len = arr.length;
|
|
@@ -316,6 +420,40 @@ function _iterable_to_array_limit(arr, i) {
|
|
|
316
420
|
function _non_iterable_rest() {
|
|
317
421
|
throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
318
422
|
}
|
|
423
|
+
function _object_spread(target) {
|
|
424
|
+
for(var i = 1; i < arguments.length; i++){
|
|
425
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
426
|
+
var ownKeys = Object.keys(source);
|
|
427
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
428
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
429
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
430
|
+
}));
|
|
431
|
+
}
|
|
432
|
+
ownKeys.forEach(function(key) {
|
|
433
|
+
_define_property(target, key, source[key]);
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
return target;
|
|
437
|
+
}
|
|
438
|
+
function ownKeys(object, enumerableOnly) {
|
|
439
|
+
var keys = Object.keys(object);
|
|
440
|
+
if (Object.getOwnPropertySymbols) {
|
|
441
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
442
|
+
keys.push.apply(keys, symbols);
|
|
443
|
+
}
|
|
444
|
+
return keys;
|
|
445
|
+
}
|
|
446
|
+
function _object_spread_props(target, source) {
|
|
447
|
+
source = source != null ? source : {};
|
|
448
|
+
if (Object.getOwnPropertyDescriptors) {
|
|
449
|
+
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
450
|
+
} else {
|
|
451
|
+
ownKeys(Object(source)).forEach(function(key) {
|
|
452
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
return target;
|
|
456
|
+
}
|
|
319
457
|
function _possible_constructor_return(self, call) {
|
|
320
458
|
if (call && (_type_of(call) === "object" || typeof call === "function")) {
|
|
321
459
|
return call;
|
|
@@ -447,10 +585,117 @@ function _ts_generator(thisArg, body) {
|
|
|
447
585
|
};
|
|
448
586
|
}
|
|
449
587
|
}
|
|
588
|
+
function _ts_values(o) {
|
|
589
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
590
|
+
if (m) return m.call(o);
|
|
591
|
+
if (o && typeof o.length === "number") return {
|
|
592
|
+
next: function() {
|
|
593
|
+
if (o && i >= o.length) o = void 0;
|
|
594
|
+
return {
|
|
595
|
+
value: o && o[i++],
|
|
596
|
+
done: !o
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
601
|
+
}
|
|
450
602
|
var logError = node.createLogError('node-midnight');
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
603
|
+
/** Strict base64, optional padding — validated before host input reaches the
|
|
604
|
+
* WASM deserializer, which accepts silently-truncated garbage otherwise. */ var BASE64_PATTERN = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
605
|
+
/** Upper bound on a serialized transaction we will decode. Generous next to real
|
|
606
|
+
* transactions, small enough that a hostile payload is rejected before WASM. */ var MAX_SERIALIZED_TRANSACTION_BYTES = 4 * 1024 * 1024;
|
|
607
|
+
var SYNC_TIMEOUT_MS = 300000;
|
|
608
|
+
/** One retry is enough: the stale socket reports closed by the second attempt. */ var SUBMIT_ATTEMPTS = 2;
|
|
609
|
+
var SUBMIT_RETRY_DELAY_MS = 1000;
|
|
610
|
+
/**
|
|
611
|
+
* Whether an error is the node client's stale-connection failure rather than a
|
|
612
|
+
* ledger rejection.
|
|
613
|
+
*
|
|
614
|
+
* The websocket close reason sits several `cause` levels below the
|
|
615
|
+
* `SubmissionError` the facade surfaces, and Effect's `FiberFailure` exposes
|
|
616
|
+
* none of them as a readable `cause` property — the chain is only reachable
|
|
617
|
+
* through the rendered form, so that is what gets matched.
|
|
618
|
+
*/ var isStaleConnectionError = function(error) {
|
|
619
|
+
return /disconnected from|WebSocket is not connected|Normal Closure/i.test(node_util.inspect(error, {
|
|
620
|
+
depth: 8
|
|
621
|
+
}));
|
|
622
|
+
};
|
|
623
|
+
/**
|
|
624
|
+
* Parses a caller-supplied transfer amount.
|
|
625
|
+
*
|
|
626
|
+
* `BigInt()` is too lenient to use directly here: `BigInt('')` is `0n`, so an
|
|
627
|
+
* empty amount would silently become a zero-value transfer, and `BigInt('-5')`
|
|
628
|
+
* yields a negative that trivially passes the balance check. Decimals do throw,
|
|
629
|
+
* but with an opaque message.
|
|
630
|
+
*/ var parseTransferAmount = function(amount) {
|
|
631
|
+
if (typeof amount !== 'string' || !/^\d+$/.test(amount)) {
|
|
632
|
+
throw new Error("Invalid transfer amount ".concat(JSON.stringify(amount), ": expected a whole number in the token's smallest unit, as a string"));
|
|
633
|
+
}
|
|
634
|
+
var parsed = BigInt(amount);
|
|
635
|
+
if (parsed === 0n) {
|
|
636
|
+
throw new Error('Transfer amount must be greater than zero');
|
|
637
|
+
}
|
|
638
|
+
return parsed;
|
|
639
|
+
};
|
|
640
|
+
/**
|
|
641
|
+
* `submitTransaction` returns either a string txId or a TransactionIdentifier
|
|
642
|
+
* with `.toHex()`; normalize so callers always get a string.
|
|
643
|
+
*/ var toTxHashString = function(txIdentifier) {
|
|
644
|
+
if (typeof txIdentifier === 'string') return txIdentifier;
|
|
645
|
+
var maybeHex = txIdentifier === null || txIdentifier === void 0 ? void 0 : txIdentifier.toHex;
|
|
646
|
+
if (typeof maybeHex === 'function') return txIdentifier.toHex();
|
|
647
|
+
return String(txIdentifier);
|
|
648
|
+
};
|
|
649
|
+
/**
|
|
650
|
+
* Validates caller-supplied base64 before it reaches the WASM deserializer.
|
|
651
|
+
* `Buffer.from(x, 'base64')` silently drops invalid characters, so a malformed
|
|
652
|
+
* payload would otherwise arrive as truncated-but-plausible bytes and fail deep
|
|
653
|
+
* inside WASM with an opaque error.
|
|
654
|
+
*/ var decodeSerializedTransaction = function(transaction, label) {
|
|
655
|
+
if (!transaction || !BASE64_PATTERN.test(transaction)) {
|
|
656
|
+
throw new Error("".concat(label, ": transaction must be base64"));
|
|
657
|
+
}
|
|
658
|
+
var bytes = Buffer.from(transaction, 'base64');
|
|
659
|
+
if (bytes.length === 0 || bytes.length > MAX_SERIALIZED_TRANSACTION_BYTES) {
|
|
660
|
+
throw new Error("".concat(label, ": transaction must decode to 1..").concat(MAX_SERIALIZED_TRANSACTION_BYTES, " bytes, got ").concat(bytes.length));
|
|
661
|
+
}
|
|
662
|
+
return new Uint8Array(bytes);
|
|
663
|
+
};
|
|
664
|
+
/**
|
|
665
|
+
* Parses a caller-supplied ISO-8601 timestamp.
|
|
666
|
+
*
|
|
667
|
+
* `new Date()` alone is too lenient to enforce the contract: it accepts
|
|
668
|
+
* implementation-defined formats like `'March 5, 2026'`, and `'2026-13-45'`
|
|
669
|
+
* parses on some engines. A TTL misread by a few hours silently changes when
|
|
670
|
+
* the balanced transaction stops being valid, so the shape is checked first.
|
|
671
|
+
*/ /**
|
|
672
|
+
* Anchored at both ends: `new Date()` also understands worded formats such as
|
|
673
|
+
* `'2026-09-01 1:00 PM'` and `'2026-09-01 12:00 EST'`, which are V8 extensions
|
|
674
|
+
* rather than ISO-8601 and parse differently — or not at all — elsewhere.
|
|
675
|
+
* Matching only a prefix would let those through.
|
|
676
|
+
*
|
|
677
|
+
* Spelled `\d\d` rather than `\d{2}` because each counted repetition adds to
|
|
678
|
+
* the regex complexity budget, and the nesting here already uses most of it.
|
|
679
|
+
*/ var ISO_TIMESTAMP = /^(\d\d\d\d)-(\d\d)-(\d\d)([T ]\d\d:\d\d(:\d\d)?(\.\d+)?(Z|[+-]\d\d:?\d\d)?)?$/;
|
|
680
|
+
/** Whether the y/m/d the caller wrote is a date that exists. */ var isRealCalendarDate = function(year, month, day) {
|
|
681
|
+
var asUtc = new Date("".concat(year, "-").concat(month, "-").concat(day, "T00:00:00Z"));
|
|
682
|
+
return !Number.isNaN(asUtc.getTime()) && asUtc.getUTCDate() === Number(day);
|
|
683
|
+
};
|
|
684
|
+
var parseIsoTimestamp = function(value, label) {
|
|
685
|
+
// Date rolls impossible days forward instead of rejecting them, so
|
|
686
|
+
// '2026-02-29' becomes 1 March and the transaction outlives its stated ttl.
|
|
687
|
+
var match = ISO_TIMESTAMP.exec(value);
|
|
688
|
+
var parsed = match && isRealCalendarDate(match[1], match[2], match[3]) ? new Date(value) : new Date(Number.NaN);
|
|
689
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
690
|
+
throw new TypeError("".concat(label, ": ttl must be a valid ISO-8601 date, got ").concat(JSON.stringify(value)));
|
|
691
|
+
}
|
|
692
|
+
return parsed;
|
|
693
|
+
};
|
|
694
|
+
// Unshielded is NON-hardened to match Sodot's derivePrivateKeyFromXpriv, which
|
|
695
|
+
// is non-hardened-only. The hardened Midnight-canonical path would make the
|
|
696
|
+
// wallet track a different address than the server signs for — no error, just
|
|
697
|
+
// silently diverging balances. Shielded and dust use the hardened canonical
|
|
698
|
+
// paths; those roles are signed client-side, so the constraint does not apply.
|
|
454
699
|
var ROLE_DERIVATION_PATHS = {
|
|
455
700
|
unshielded: 'm/44/2400/0/0/0',
|
|
456
701
|
shielded: "m/44'/2400'/0'/3/0",
|
|
@@ -1043,6 +1288,1414 @@ var DynamicMidnightWalletClient = /*#__PURE__*/ function(DynamicWalletClient) {
|
|
|
1043
1288
|
})();
|
|
1044
1289
|
}
|
|
1045
1290
|
},
|
|
1291
|
+
{
|
|
1292
|
+
key: "withWallet",
|
|
1293
|
+
value: /**
|
|
1294
|
+
* Boots a synced wallet, runs `use` against it, and stops it afterwards.
|
|
1295
|
+
*
|
|
1296
|
+
* Nothing is retained between calls: the wallet is created here and torn down
|
|
1297
|
+
* in `finally`, so the client holds no state of its own. Callers who want to
|
|
1298
|
+
* avoid the ~150s genesis sync pass back the checkpoint from a previous call
|
|
1299
|
+
* (`access.walletState`) and receive an updated one alongside every result.
|
|
1300
|
+
*/ function withWallet(label, access, mode, use) {
|
|
1301
|
+
var _this = this;
|
|
1302
|
+
return _async_to_generator(function() {
|
|
1303
|
+
var network, booted, state, result, _ref, durable, session;
|
|
1304
|
+
return _ts_generator(this, function(_state) {
|
|
1305
|
+
switch(_state.label){
|
|
1306
|
+
case 0:
|
|
1307
|
+
network = resolveMidnightNetworkTag(access.networkId);
|
|
1308
|
+
return [
|
|
1309
|
+
4,
|
|
1310
|
+
_this.bootWallet(label, access, network)
|
|
1311
|
+
];
|
|
1312
|
+
case 1:
|
|
1313
|
+
booted = _state.sent();
|
|
1314
|
+
_state.label = 2;
|
|
1315
|
+
case 2:
|
|
1316
|
+
_state.trys.push([
|
|
1317
|
+
2,
|
|
1318
|
+
,
|
|
1319
|
+
6,
|
|
1320
|
+
10
|
|
1321
|
+
]);
|
|
1322
|
+
return [
|
|
1323
|
+
4,
|
|
1324
|
+
_this.waitForSync(booted.wallet, mode, label)
|
|
1325
|
+
];
|
|
1326
|
+
case 3:
|
|
1327
|
+
state = _state.sent();
|
|
1328
|
+
return [
|
|
1329
|
+
4,
|
|
1330
|
+
use(_object_spread_props(_object_spread({}, booted), {
|
|
1331
|
+
state: state
|
|
1332
|
+
}))
|
|
1333
|
+
];
|
|
1334
|
+
case 4:
|
|
1335
|
+
result = _state.sent();
|
|
1336
|
+
return [
|
|
1337
|
+
4,
|
|
1338
|
+
_this.checkpoint(booted.wallet, network, label)
|
|
1339
|
+
];
|
|
1340
|
+
case 5:
|
|
1341
|
+
_ref = _state.sent(), durable = _ref.durable, session = _ref.session;
|
|
1342
|
+
return [
|
|
1343
|
+
2,
|
|
1344
|
+
{
|
|
1345
|
+
result: result,
|
|
1346
|
+
walletState: durable,
|
|
1347
|
+
sessionState: session
|
|
1348
|
+
}
|
|
1349
|
+
];
|
|
1350
|
+
case 6:
|
|
1351
|
+
_state.trys.push([
|
|
1352
|
+
6,
|
|
1353
|
+
8,
|
|
1354
|
+
,
|
|
1355
|
+
9
|
|
1356
|
+
]);
|
|
1357
|
+
return [
|
|
1358
|
+
4,
|
|
1359
|
+
booted.wallet.stop()
|
|
1360
|
+
];
|
|
1361
|
+
case 7:
|
|
1362
|
+
_state.sent();
|
|
1363
|
+
return [
|
|
1364
|
+
3,
|
|
1365
|
+
9
|
|
1366
|
+
];
|
|
1367
|
+
case 8:
|
|
1368
|
+
_state.sent();
|
|
1369
|
+
return [
|
|
1370
|
+
3,
|
|
1371
|
+
9
|
|
1372
|
+
];
|
|
1373
|
+
case 9:
|
|
1374
|
+
return [
|
|
1375
|
+
7
|
|
1376
|
+
];
|
|
1377
|
+
case 10:
|
|
1378
|
+
return [
|
|
1379
|
+
2
|
|
1380
|
+
];
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
})();
|
|
1384
|
+
}
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
key: "checkpoint",
|
|
1388
|
+
value: /**
|
|
1389
|
+
* Serializes the wallet's shielded and dust state, or returns undefined when
|
|
1390
|
+
* the wallet has work in flight.
|
|
1391
|
+
*
|
|
1392
|
+
* Checkpointing a dirty wallet would carry pending entries forward into every
|
|
1393
|
+
* later restore, so the caller keeps its previous checkpoint instead — sync
|
|
1394
|
+
* reconciles against the chain either way.
|
|
1395
|
+
*/ function checkpoint(wallet, network, label) {
|
|
1396
|
+
var _this = this;
|
|
1397
|
+
return _async_to_generator(function() {
|
|
1398
|
+
var current, _ref, shielded, dust, state, error;
|
|
1399
|
+
return _ts_generator(this, function(_state) {
|
|
1400
|
+
switch(_state.label){
|
|
1401
|
+
case 0:
|
|
1402
|
+
_state.trys.push([
|
|
1403
|
+
0,
|
|
1404
|
+
3,
|
|
1405
|
+
,
|
|
1406
|
+
4
|
|
1407
|
+
]);
|
|
1408
|
+
return [
|
|
1409
|
+
4,
|
|
1410
|
+
_this.readState(wallet)
|
|
1411
|
+
];
|
|
1412
|
+
case 1:
|
|
1413
|
+
current = _state.sent();
|
|
1414
|
+
return [
|
|
1415
|
+
4,
|
|
1416
|
+
Promise.all([
|
|
1417
|
+
wallet.shielded.serializeState(),
|
|
1418
|
+
wallet.dust.serializeState()
|
|
1419
|
+
])
|
|
1420
|
+
];
|
|
1421
|
+
case 2:
|
|
1422
|
+
_ref = _sliced_to_array.apply(void 0, [
|
|
1423
|
+
_state.sent(),
|
|
1424
|
+
2
|
|
1425
|
+
]), shielded = _ref[0], dust = _ref[1];
|
|
1426
|
+
state = {
|
|
1427
|
+
shielded: shielded,
|
|
1428
|
+
dust: dust,
|
|
1429
|
+
network: network,
|
|
1430
|
+
savedAt: Date.now()
|
|
1431
|
+
};
|
|
1432
|
+
// A dirty snapshot is still the truth about what this wallet has spent,
|
|
1433
|
+
// so it is kept for the session; it is only withheld from the caller,
|
|
1434
|
+
// who would otherwise carry pending entries forward on every restore.
|
|
1435
|
+
if (!isCleanForCheckpoint(current)) {
|
|
1436
|
+
_this.logger.info("[Midnight] ".concat(label, ": skipping checkpoint, wallet has work in flight"));
|
|
1437
|
+
return [
|
|
1438
|
+
2,
|
|
1439
|
+
{
|
|
1440
|
+
session: state
|
|
1441
|
+
}
|
|
1442
|
+
];
|
|
1443
|
+
}
|
|
1444
|
+
return [
|
|
1445
|
+
2,
|
|
1446
|
+
{
|
|
1447
|
+
durable: state,
|
|
1448
|
+
session: state
|
|
1449
|
+
}
|
|
1450
|
+
];
|
|
1451
|
+
case 3:
|
|
1452
|
+
error = _state.sent();
|
|
1453
|
+
// A checkpoint is an optimisation; failing to take one must not fail the
|
|
1454
|
+
// operation the caller actually asked for.
|
|
1455
|
+
_this.logger.warn("[Midnight] ".concat(label, ": could not take checkpoint"), error);
|
|
1456
|
+
return [
|
|
1457
|
+
2,
|
|
1458
|
+
{}
|
|
1459
|
+
];
|
|
1460
|
+
case 4:
|
|
1461
|
+
return [
|
|
1462
|
+
2
|
|
1463
|
+
];
|
|
1464
|
+
}
|
|
1465
|
+
});
|
|
1466
|
+
})();
|
|
1467
|
+
}
|
|
1468
|
+
},
|
|
1469
|
+
{
|
|
1470
|
+
key: "submitWithReconnect",
|
|
1471
|
+
value: /**
|
|
1472
|
+
* Submits, retrying once past a stale-connection failure.
|
|
1473
|
+
*
|
|
1474
|
+
* The facade's node client calls `api.disconnect()` during startup, and that
|
|
1475
|
+
* promise resolves before the socket has actually closed. A submit issued in
|
|
1476
|
+
* that window sees `isConnected === true`, skips reconnecting, and is then
|
|
1477
|
+
* rejected by the close that lands a moment later. The retry reconnects for
|
|
1478
|
+
* real, because by then the socket reports closed. Resubmitting is safe: the
|
|
1479
|
+
* bytes never reached the node, and an identical transaction has an identical
|
|
1480
|
+
* hash, so a duplicate would be rejected rather than spent twice.
|
|
1481
|
+
*/ function submitWithReconnect(wallet, finalized) {
|
|
1482
|
+
var _this = this;
|
|
1483
|
+
return _async_to_generator(function() {
|
|
1484
|
+
var attempt, error;
|
|
1485
|
+
return _ts_generator(this, function(_state) {
|
|
1486
|
+
switch(_state.label){
|
|
1487
|
+
case 0:
|
|
1488
|
+
attempt = 1;
|
|
1489
|
+
_state.label = 1;
|
|
1490
|
+
case 1:
|
|
1491
|
+
_state.trys.push([
|
|
1492
|
+
1,
|
|
1493
|
+
3,
|
|
1494
|
+
,
|
|
1495
|
+
5
|
|
1496
|
+
]);
|
|
1497
|
+
return [
|
|
1498
|
+
4,
|
|
1499
|
+
wallet.submitTransaction(finalized)
|
|
1500
|
+
];
|
|
1501
|
+
case 2:
|
|
1502
|
+
return [
|
|
1503
|
+
2,
|
|
1504
|
+
_state.sent()
|
|
1505
|
+
];
|
|
1506
|
+
case 3:
|
|
1507
|
+
error = _state.sent();
|
|
1508
|
+
if (attempt >= SUBMIT_ATTEMPTS || !isStaleConnectionError(error)) throw error;
|
|
1509
|
+
_this.logger.warn("[Midnight] submitTransaction: node connection was stale, reconnecting and retrying");
|
|
1510
|
+
return [
|
|
1511
|
+
4,
|
|
1512
|
+
new Promise(function(resolve) {
|
|
1513
|
+
return setTimeout(resolve, SUBMIT_RETRY_DELAY_MS);
|
|
1514
|
+
})
|
|
1515
|
+
];
|
|
1516
|
+
case 4:
|
|
1517
|
+
_state.sent();
|
|
1518
|
+
return [
|
|
1519
|
+
3,
|
|
1520
|
+
5
|
|
1521
|
+
];
|
|
1522
|
+
case 5:
|
|
1523
|
+
attempt++;
|
|
1524
|
+
return [
|
|
1525
|
+
3,
|
|
1526
|
+
1
|
|
1527
|
+
];
|
|
1528
|
+
case 6:
|
|
1529
|
+
return [
|
|
1530
|
+
2
|
|
1531
|
+
];
|
|
1532
|
+
}
|
|
1533
|
+
});
|
|
1534
|
+
})();
|
|
1535
|
+
}
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
key: "readState",
|
|
1539
|
+
value: /** First emission from the wallet's state observable. */ function readState(wallet) {
|
|
1540
|
+
return _async_to_generator(function() {
|
|
1541
|
+
return _ts_generator(this, function(_state) {
|
|
1542
|
+
return [
|
|
1543
|
+
2,
|
|
1544
|
+
new Promise(function(resolve, reject) {
|
|
1545
|
+
// eslint-disable-next-line prefer-const
|
|
1546
|
+
var sub;
|
|
1547
|
+
var timeout = setTimeout(function() {
|
|
1548
|
+
sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
|
|
1549
|
+
reject(new Error('timed out reading wallet state'));
|
|
1550
|
+
}, 10000);
|
|
1551
|
+
sub = wallet.state().subscribe(function(state) {
|
|
1552
|
+
clearTimeout(timeout);
|
|
1553
|
+
queueMicrotask(function() {
|
|
1554
|
+
return sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
|
|
1555
|
+
});
|
|
1556
|
+
resolve(state);
|
|
1557
|
+
});
|
|
1558
|
+
})
|
|
1559
|
+
];
|
|
1560
|
+
});
|
|
1561
|
+
})();
|
|
1562
|
+
}
|
|
1563
|
+
},
|
|
1564
|
+
{
|
|
1565
|
+
key: "bootWallet",
|
|
1566
|
+
value: function bootWallet(label, access, network) {
|
|
1567
|
+
var _this = this;
|
|
1568
|
+
return _async_to_generator(function() {
|
|
1569
|
+
var roleKeys, shieldedSecretKeys, dustSecretKey, unshieldedKeystore, checkpoint, infra, wallet;
|
|
1570
|
+
return _ts_generator(this, function(_state) {
|
|
1571
|
+
switch(_state.label){
|
|
1572
|
+
case 0:
|
|
1573
|
+
return [
|
|
1574
|
+
4,
|
|
1575
|
+
_this.getRoleKeys(access)
|
|
1576
|
+
];
|
|
1577
|
+
case 1:
|
|
1578
|
+
roleKeys = _state.sent();
|
|
1579
|
+
shieldedSecretKeys = ledger__namespace.ZswapSecretKeys.fromSeed(new Uint8Array(Buffer.from(roleKeys.shielded, 'hex')));
|
|
1580
|
+
dustSecretKey = ledger__namespace.DustSecretKey.fromSeed(new Uint8Array(Buffer.from(roleKeys.dust, 'hex')));
|
|
1581
|
+
unshieldedKeystore = walletSdkUnshieldedWallet.createKeystore(new Uint8Array(Buffer.from(roleKeys.unshielded, 'hex')), network);
|
|
1582
|
+
// A checkpoint from another network would corrupt sync, so a mismatch is
|
|
1583
|
+
// treated as absent rather than as an error — callers may hold several.
|
|
1584
|
+
checkpoint = isRestorableState(access.walletState, network) ? access.walletState : undefined;
|
|
1585
|
+
infra = MIDNIGHT_INFRA[network];
|
|
1586
|
+
_this.logger.info("[Midnight] ".concat(label, ": initializing wallet facade (").concat(network, ", ").concat(checkpoint ? "resuming from checkpoint saved ".concat(new Date(checkpoint.savedAt).toISOString()) : 'syncing from genesis', ")"));
|
|
1587
|
+
return [
|
|
1588
|
+
4,
|
|
1589
|
+
walletSdkFacade.WalletFacade.init({
|
|
1590
|
+
configuration: {
|
|
1591
|
+
networkId: network,
|
|
1592
|
+
costParameters: {
|
|
1593
|
+
feeBlocksMargin: 5
|
|
1594
|
+
},
|
|
1595
|
+
relayURL: new URL(infra.relayUrl),
|
|
1596
|
+
provingServerUrl: new URL(infra.provingServerUrl),
|
|
1597
|
+
indexerClientConnection: {
|
|
1598
|
+
indexerHttpUrl: infra.indexerHttpUrl,
|
|
1599
|
+
indexerWsUrl: infra.indexerWsUrl
|
|
1600
|
+
},
|
|
1601
|
+
// Measured: 2000 and 20000 both sync in ~150s — the fold is apply-bound
|
|
1602
|
+
// (per-entry WASM compute), not fetch-bound, so batch size is not a lever.
|
|
1603
|
+
batchUpdates: {
|
|
1604
|
+
size: 2000
|
|
1605
|
+
},
|
|
1606
|
+
txHistoryStorage: new walletSdkAbstractions.NoOpTransactionHistoryStorage()
|
|
1607
|
+
},
|
|
1608
|
+
shielded: function(cfg) {
|
|
1609
|
+
return checkpoint ? walletSdkShielded.ShieldedWallet(cfg).restore(checkpoint.shielded) : walletSdkShielded.ShieldedWallet(cfg).startWithSecretKeys(shieldedSecretKeys);
|
|
1610
|
+
},
|
|
1611
|
+
unshielded: function(cfg) {
|
|
1612
|
+
return walletSdkUnshieldedWallet.UnshieldedWallet(cfg).startWithPublicKey(walletSdkUnshieldedWallet.PublicKey.fromKeyStore(unshieldedKeystore));
|
|
1613
|
+
},
|
|
1614
|
+
dust: function(cfg) {
|
|
1615
|
+
return checkpoint ? walletSdkDustWallet.DustWallet(cfg).restore(checkpoint.dust) : walletSdkDustWallet.DustWallet(cfg).startWithSecretKey(dustSecretKey, ledger__namespace.LedgerParameters.initialParameters().dust);
|
|
1616
|
+
}
|
|
1617
|
+
})
|
|
1618
|
+
];
|
|
1619
|
+
case 2:
|
|
1620
|
+
wallet = _state.sent();
|
|
1621
|
+
return [
|
|
1622
|
+
4,
|
|
1623
|
+
wallet.start(shieldedSecretKeys, dustSecretKey)
|
|
1624
|
+
];
|
|
1625
|
+
case 3:
|
|
1626
|
+
_state.sent();
|
|
1627
|
+
return [
|
|
1628
|
+
2,
|
|
1629
|
+
{
|
|
1630
|
+
wallet: wallet,
|
|
1631
|
+
roleKeys: roleKeys,
|
|
1632
|
+
shieldedSecretKeys: shieldedSecretKeys,
|
|
1633
|
+
dustSecretKey: dustSecretKey
|
|
1634
|
+
}
|
|
1635
|
+
];
|
|
1636
|
+
}
|
|
1637
|
+
});
|
|
1638
|
+
})();
|
|
1639
|
+
}
|
|
1640
|
+
},
|
|
1641
|
+
{
|
|
1642
|
+
key: "waitForSync",
|
|
1643
|
+
value: /**
|
|
1644
|
+
* Resolves once the requested sides report synced.
|
|
1645
|
+
*
|
|
1646
|
+
* Does not stop the wallet on failure — `withWallet` owns the wallet's
|
|
1647
|
+
* lifetime and tears it down in `finally`, whether this resolves or throws.
|
|
1648
|
+
*/ function waitForSync(wallet, mode, label) {
|
|
1649
|
+
var _this = this;
|
|
1650
|
+
return _async_to_generator(function() {
|
|
1651
|
+
var startedAt, lastLoggedAt;
|
|
1652
|
+
return _ts_generator(this, function(_state) {
|
|
1653
|
+
switch(_state.label){
|
|
1654
|
+
case 0:
|
|
1655
|
+
startedAt = Date.now();
|
|
1656
|
+
lastLoggedAt = 0;
|
|
1657
|
+
return [
|
|
1658
|
+
4,
|
|
1659
|
+
new Promise(function(resolve, reject) {
|
|
1660
|
+
// `let` + optional chaining: an already-synced wallet emits synchronously
|
|
1661
|
+
// during .subscribe(), so the callback can touch `sub` before assignment.
|
|
1662
|
+
// eslint-disable-next-line prefer-const
|
|
1663
|
+
var sub;
|
|
1664
|
+
var timeout = setTimeout(function() {
|
|
1665
|
+
sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
|
|
1666
|
+
reject(new Error("[Midnight] ".concat(label, ": wallet sync timeout after ").concat(SYNC_TIMEOUT_MS, "ms")));
|
|
1667
|
+
}, SYNC_TIMEOUT_MS);
|
|
1668
|
+
sub = wallet.state().subscribe(function(state) {
|
|
1669
|
+
var now = Date.now();
|
|
1670
|
+
if (now - lastLoggedAt > 15000) {
|
|
1671
|
+
lastLoggedAt = now;
|
|
1672
|
+
_this.logger.info("[Midnight] ".concat(label, ": syncing ").concat(((now - startedAt) / 1000).toFixed(0), "s \xb7 ") + "shielded=".concat(isSideSynced(state.shielded), " unshielded=").concat(isSideSynced(state.unshielded), " ") + "dust=".concat(isSideSynced(state.dust)));
|
|
1673
|
+
}
|
|
1674
|
+
if (isSyncResolved(state, mode)) {
|
|
1675
|
+
clearTimeout(timeout);
|
|
1676
|
+
queueMicrotask(function() {
|
|
1677
|
+
return sub === null || sub === void 0 ? void 0 : sub.unsubscribe();
|
|
1678
|
+
});
|
|
1679
|
+
_this.logger.info("[Midnight] ".concat(label, ": synced in ").concat(((now - startedAt) / 1000).toFixed(1), "s (").concat(mode, ")"));
|
|
1680
|
+
resolve(state);
|
|
1681
|
+
}
|
|
1682
|
+
});
|
|
1683
|
+
})
|
|
1684
|
+
];
|
|
1685
|
+
case 1:
|
|
1686
|
+
return [
|
|
1687
|
+
2,
|
|
1688
|
+
_state.sent()
|
|
1689
|
+
];
|
|
1690
|
+
}
|
|
1691
|
+
});
|
|
1692
|
+
})();
|
|
1693
|
+
}
|
|
1694
|
+
},
|
|
1695
|
+
{
|
|
1696
|
+
key: "getBalances",
|
|
1697
|
+
value: /**
|
|
1698
|
+
* Reads unshielded, shielded, and dust balances.
|
|
1699
|
+
*
|
|
1700
|
+
* Resolves as soon as shielded + unshielded are synced, leaving dust folding in
|
|
1701
|
+
* the background — `dustSynced` says whether the dust figure is final yet.
|
|
1702
|
+
*/ function getBalances(access) {
|
|
1703
|
+
var _this = this;
|
|
1704
|
+
return _async_to_generator(function() {
|
|
1705
|
+
var _ref, result, walletState, error;
|
|
1706
|
+
return _ts_generator(this, function(_state) {
|
|
1707
|
+
switch(_state.label){
|
|
1708
|
+
case 0:
|
|
1709
|
+
_state.trys.push([
|
|
1710
|
+
0,
|
|
1711
|
+
2,
|
|
1712
|
+
,
|
|
1713
|
+
3
|
|
1714
|
+
]);
|
|
1715
|
+
return [
|
|
1716
|
+
4,
|
|
1717
|
+
_this.withWallet('getBalances', access, 'shielded-unshielded', /*#__PURE__*/ function() {
|
|
1718
|
+
var _ref = _async_to_generator(function(param) {
|
|
1719
|
+
var state, _state_dust_balance, _state_dust, _state_dust1, _state_unshielded, _state_shielded, toStringMap, now, _state_dust_balance1, dustBalance, _state_dust_totalCoins, dustCap;
|
|
1720
|
+
return _ts_generator(this, function(_state) {
|
|
1721
|
+
state = param.state;
|
|
1722
|
+
toStringMap = function() {
|
|
1723
|
+
var balances = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
1724
|
+
return Object.fromEntries(Object.entries(balances).map(function(param) {
|
|
1725
|
+
var _param = _sliced_to_array(param, 2), token = _param[0], value = _param[1];
|
|
1726
|
+
return [
|
|
1727
|
+
token,
|
|
1728
|
+
value.toString()
|
|
1729
|
+
];
|
|
1730
|
+
}));
|
|
1731
|
+
};
|
|
1732
|
+
now = new Date();
|
|
1733
|
+
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, now)) !== null && _state_dust_balance1 !== void 0 ? _state_dust_balance1 : 0n;
|
|
1734
|
+
// v4 exposes the generation cap per coin; the wallet-level cap is their sum.
|
|
1735
|
+
dustCap = ((_state_dust_totalCoins = (_state_dust1 = state.dust) === null || _state_dust1 === void 0 ? void 0 : _state_dust1.totalCoins) !== null && _state_dust_totalCoins !== void 0 ? _state_dust_totalCoins : []).reduce(function(sum, coin) {
|
|
1736
|
+
var _coin_maxCap;
|
|
1737
|
+
return sum + ((_coin_maxCap = coin.maxCap) !== null && _coin_maxCap !== void 0 ? _coin_maxCap : 0n);
|
|
1738
|
+
}, 0n);
|
|
1739
|
+
return [
|
|
1740
|
+
2,
|
|
1741
|
+
{
|
|
1742
|
+
unshielded: toStringMap((_state_unshielded = state.unshielded) === null || _state_unshielded === void 0 ? void 0 : _state_unshielded.balances),
|
|
1743
|
+
shielded: toStringMap((_state_shielded = state.shielded) === null || _state_shielded === void 0 ? void 0 : _state_shielded.balances),
|
|
1744
|
+
dust: {
|
|
1745
|
+
balance: dustBalance.toString(),
|
|
1746
|
+
cap: dustCap.toString()
|
|
1747
|
+
},
|
|
1748
|
+
dustSynced: isSideSynced(state.dust),
|
|
1749
|
+
address: access.walletMetadata.accountAddress
|
|
1750
|
+
}
|
|
1751
|
+
];
|
|
1752
|
+
});
|
|
1753
|
+
});
|
|
1754
|
+
return function(_) {
|
|
1755
|
+
return _ref.apply(this, arguments);
|
|
1756
|
+
};
|
|
1757
|
+
}())
|
|
1758
|
+
];
|
|
1759
|
+
case 1:
|
|
1760
|
+
_ref = _state.sent(), result = _ref.result, walletState = _ref.walletState;
|
|
1761
|
+
return [
|
|
1762
|
+
2,
|
|
1763
|
+
_object_spread_props(_object_spread({}, result), {
|
|
1764
|
+
walletState: walletState
|
|
1765
|
+
})
|
|
1766
|
+
];
|
|
1767
|
+
case 2:
|
|
1768
|
+
error = _state.sent();
|
|
1769
|
+
logError({
|
|
1770
|
+
message: ERROR_GET_BALANCE,
|
|
1771
|
+
error: error,
|
|
1772
|
+
context: {
|
|
1773
|
+
accountAddress: access.walletMetadata.accountAddress
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1776
|
+
throw _instanceof(error, Error) ? error : new Error(ERROR_GET_BALANCE);
|
|
1777
|
+
case 3:
|
|
1778
|
+
return [
|
|
1779
|
+
2
|
|
1780
|
+
];
|
|
1781
|
+
}
|
|
1782
|
+
});
|
|
1783
|
+
})();
|
|
1784
|
+
}
|
|
1785
|
+
},
|
|
1786
|
+
{
|
|
1787
|
+
key: "registerDust",
|
|
1788
|
+
value: /**
|
|
1789
|
+
* Registers the wallet's NIGHT UTXOs for dust generation. Dust pays fees on
|
|
1790
|
+
* every Midnight transaction, so this is a prerequisite for transacting.
|
|
1791
|
+
*
|
|
1792
|
+
* Returns immediately after broadcast — dust accrues continuously on-chain and
|
|
1793
|
+
* can take minutes, so poll {@link getBalances} rather than blocking here.
|
|
1794
|
+
*/ function registerDust(access) {
|
|
1795
|
+
var _this = this;
|
|
1796
|
+
return _async_to_generator(function() {
|
|
1797
|
+
var _ref, result, walletState, error;
|
|
1798
|
+
return _ts_generator(this, function(_state) {
|
|
1799
|
+
switch(_state.label){
|
|
1800
|
+
case 0:
|
|
1801
|
+
_state.trys.push([
|
|
1802
|
+
0,
|
|
1803
|
+
2,
|
|
1804
|
+
,
|
|
1805
|
+
3
|
|
1806
|
+
]);
|
|
1807
|
+
return [
|
|
1808
|
+
4,
|
|
1809
|
+
_this.withWallet('registerDust', access, 'full', /*#__PURE__*/ function() {
|
|
1810
|
+
var _ref = _async_to_generator(function(param) {
|
|
1811
|
+
var wallet, roleKeys, state, _state_dust_balance, _state_dust, _state_unshielded, _state_dust_balance1, existingDust, _state_unshielded_availableCoins, allUtxos, unregistered, registered, verifyingKey, recipe, finalized, txId;
|
|
1812
|
+
return _ts_generator(this, function(_state) {
|
|
1813
|
+
switch(_state.label){
|
|
1814
|
+
case 0:
|
|
1815
|
+
wallet = param.wallet, roleKeys = param.roleKeys, state = param.state;
|
|
1816
|
+
existingDust = (_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;
|
|
1817
|
+
if (existingDust > 0n) {
|
|
1818
|
+
return [
|
|
1819
|
+
2,
|
|
1820
|
+
{
|
|
1821
|
+
status: 'already_has_dust',
|
|
1822
|
+
message: "Wallet already has ".concat(existingDust, " dust; no action needed."),
|
|
1823
|
+
registeredCount: 0,
|
|
1824
|
+
dustBalance: existingDust.toString()
|
|
1825
|
+
}
|
|
1826
|
+
];
|
|
1827
|
+
}
|
|
1828
|
+
// The flag lives under `.meta`, not on the coin itself — reading it one
|
|
1829
|
+
// level up is silently always undefined, which makes every UTXO look
|
|
1830
|
+
// unregistered and re-submits a registration tx on every call. Matches
|
|
1831
|
+
// packages/midnight (browser), which reads the same shape.
|
|
1832
|
+
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 : [];
|
|
1833
|
+
unregistered = allUtxos.filter(function(utxo) {
|
|
1834
|
+
var _utxo_meta;
|
|
1835
|
+
return ((_utxo_meta = utxo.meta) === null || _utxo_meta === void 0 ? void 0 : _utxo_meta.registeredForDustGeneration) !== true;
|
|
1836
|
+
});
|
|
1837
|
+
if (unregistered.length === 0) {
|
|
1838
|
+
registered = allUtxos.length > 0;
|
|
1839
|
+
return [
|
|
1840
|
+
2,
|
|
1841
|
+
{
|
|
1842
|
+
status: registered ? 'already_registered' : 'no_utxos',
|
|
1843
|
+
message: registered ? "All ".concat(allUtxos.length, " NIGHT UTXO(s) are already registered. Dust accrues on-chain — poll getBalances.") : 'No NIGHT UTXOs. Fund the wallet with NIGHT before registering for dust.',
|
|
1844
|
+
registeredCount: 0,
|
|
1845
|
+
dustBalance: '0'
|
|
1846
|
+
}
|
|
1847
|
+
];
|
|
1848
|
+
}
|
|
1849
|
+
verifyingKey = ledger__namespace.signatureVerifyingKey(roleKeys.unshielded);
|
|
1850
|
+
return [
|
|
1851
|
+
4,
|
|
1852
|
+
wallet.registerNightUtxosForDustGeneration(unregistered, verifyingKey, function(payload) {
|
|
1853
|
+
return ledger__namespace.signData(roleKeys.unshielded, payload);
|
|
1854
|
+
})
|
|
1855
|
+
];
|
|
1856
|
+
case 1:
|
|
1857
|
+
recipe = _state.sent();
|
|
1858
|
+
return [
|
|
1859
|
+
4,
|
|
1860
|
+
wallet.finalizeRecipe(recipe)
|
|
1861
|
+
];
|
|
1862
|
+
case 2:
|
|
1863
|
+
finalized = _state.sent();
|
|
1864
|
+
return [
|
|
1865
|
+
4,
|
|
1866
|
+
wallet.submitTransaction(finalized)
|
|
1867
|
+
];
|
|
1868
|
+
case 3:
|
|
1869
|
+
txId = toTxHashString.apply(void 0, [
|
|
1870
|
+
_state.sent()
|
|
1871
|
+
]);
|
|
1872
|
+
return [
|
|
1873
|
+
2,
|
|
1874
|
+
{
|
|
1875
|
+
status: 'registered',
|
|
1876
|
+
message: "Registered ".concat(unregistered.length, " NIGHT UTXO(s) for dust generation (tx ").concat(txId.slice(0, 16), "…). ") + 'Dust accrues continuously — poll getBalances to see it arrive.',
|
|
1877
|
+
registeredCount: unregistered.length,
|
|
1878
|
+
dustBalance: '0',
|
|
1879
|
+
txId: txId
|
|
1880
|
+
}
|
|
1881
|
+
];
|
|
1882
|
+
}
|
|
1883
|
+
});
|
|
1884
|
+
});
|
|
1885
|
+
return function(_) {
|
|
1886
|
+
return _ref.apply(this, arguments);
|
|
1887
|
+
};
|
|
1888
|
+
}())
|
|
1889
|
+
];
|
|
1890
|
+
case 1:
|
|
1891
|
+
_ref = _state.sent(), result = _ref.result, walletState = _ref.walletState;
|
|
1892
|
+
return [
|
|
1893
|
+
2,
|
|
1894
|
+
_object_spread_props(_object_spread({}, result), {
|
|
1895
|
+
walletState: walletState
|
|
1896
|
+
})
|
|
1897
|
+
];
|
|
1898
|
+
case 2:
|
|
1899
|
+
error = _state.sent();
|
|
1900
|
+
logError({
|
|
1901
|
+
message: ERROR_REGISTER_DUST,
|
|
1902
|
+
error: error,
|
|
1903
|
+
context: {
|
|
1904
|
+
accountAddress: access.walletMetadata.accountAddress
|
|
1905
|
+
}
|
|
1906
|
+
});
|
|
1907
|
+
throw _instanceof(error, Error) ? error : new Error(ERROR_REGISTER_DUST);
|
|
1908
|
+
case 3:
|
|
1909
|
+
return [
|
|
1910
|
+
2
|
|
1911
|
+
];
|
|
1912
|
+
}
|
|
1913
|
+
});
|
|
1914
|
+
})();
|
|
1915
|
+
}
|
|
1916
|
+
},
|
|
1917
|
+
{
|
|
1918
|
+
key: "createTransferTransaction",
|
|
1919
|
+
value: /**
|
|
1920
|
+
* Builds an unsigned transfer. No MPC, no proving, no broadcast — pair with
|
|
1921
|
+
* {@link signTransaction} then {@link submitTransaction}.
|
|
1922
|
+
*/ function createTransferTransaction(access) {
|
|
1923
|
+
var _this = this;
|
|
1924
|
+
return _async_to_generator(function() {
|
|
1925
|
+
var transfers, _access_ttlMinutes, ttlMinutes, _ref, result, walletState, error;
|
|
1926
|
+
return _ts_generator(this, function(_state) {
|
|
1927
|
+
switch(_state.label){
|
|
1928
|
+
case 0:
|
|
1929
|
+
transfers = access.transfers, _access_ttlMinutes = access.ttlMinutes, ttlMinutes = _access_ttlMinutes === void 0 ? 5 : _access_ttlMinutes;
|
|
1930
|
+
if (!(transfers === null || transfers === void 0 ? void 0 : transfers.length)) {
|
|
1931
|
+
throw new Error('At least one transfer is required');
|
|
1932
|
+
}
|
|
1933
|
+
_state.label = 1;
|
|
1934
|
+
case 1:
|
|
1935
|
+
_state.trys.push([
|
|
1936
|
+
1,
|
|
1937
|
+
3,
|
|
1938
|
+
,
|
|
1939
|
+
4
|
|
1940
|
+
]);
|
|
1941
|
+
return [
|
|
1942
|
+
4,
|
|
1943
|
+
_this.withWallet('createTransferTransaction', access, 'full', /*#__PURE__*/ function() {
|
|
1944
|
+
var _ref = _async_to_generator(function(param) {
|
|
1945
|
+
var wallet, state, shieldedSecretKeys, dustSecretKey, _state_dust_balance, _state_dust, _state_dust_balance1, nativeToken, network, requiredByKey, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, transfer, _transfer_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, recipe;
|
|
1946
|
+
return _ts_generator(this, function(_state) {
|
|
1947
|
+
switch(_state.label){
|
|
1948
|
+
case 0:
|
|
1949
|
+
wallet = param.wallet, state = param.state, shieldedSecretKeys = param.shieldedSecretKeys, dustSecretKey = param.dustSecretKey;
|
|
1950
|
+
// Dust pays the fee on every Midnight transaction regardless of transfer type.
|
|
1951
|
+
if (((_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) === 0n) {
|
|
1952
|
+
throw new Error(ERROR_NO_DUST);
|
|
1953
|
+
}
|
|
1954
|
+
nativeToken = ledger__namespace.nativeToken().raw;
|
|
1955
|
+
network = resolveMidnightNetworkTag(access.networkId);
|
|
1956
|
+
// Aggregate per (side, token) so multiple outputs spending the same token
|
|
1957
|
+
// are checked against one combined total. NUL separator: it cannot appear
|
|
1958
|
+
// in any Midnight address or token encoding, so keys never collide (a
|
|
1959
|
+
// token identifier may itself contain ':').
|
|
1960
|
+
requiredByKey = new Map();
|
|
1961
|
+
_iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
1962
|
+
try {
|
|
1963
|
+
for(_iterator = transfers[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
1964
|
+
transfer = _step.value;
|
|
1965
|
+
;
|
|
1966
|
+
token = (_transfer_tokenType = transfer.tokenType) !== null && _transfer_tokenType !== void 0 ? _transfer_tokenType : nativeToken;
|
|
1967
|
+
key = "".concat(transfer.type, "\0").concat(token);
|
|
1968
|
+
existing = requiredByKey.get(key);
|
|
1969
|
+
;
|
|
1970
|
+
requiredByKey.set(key, {
|
|
1971
|
+
side: transfer.type,
|
|
1972
|
+
token: token,
|
|
1973
|
+
required: ((_existing_required = existing === null || existing === void 0 ? void 0 : existing.required) !== null && _existing_required !== void 0 ? _existing_required : 0n) + parseTransferAmount(transfer.amount)
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1976
|
+
} catch (err) {
|
|
1977
|
+
_didIteratorError = true;
|
|
1978
|
+
_iteratorError = err;
|
|
1979
|
+
} finally{
|
|
1980
|
+
try {
|
|
1981
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
1982
|
+
_iterator.return();
|
|
1983
|
+
}
|
|
1984
|
+
} finally{
|
|
1985
|
+
if (_didIteratorError) {
|
|
1986
|
+
throw _iteratorError;
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
_iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
|
|
1991
|
+
try {
|
|
1992
|
+
for(_iterator1 = requiredByKey.values()[Symbol.iterator](); !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
|
|
1993
|
+
_step_value = _step1.value, side = _step_value.side, token1 = _step_value.token, required = _step_value.required;
|
|
1994
|
+
;
|
|
1995
|
+
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;
|
|
1996
|
+
;
|
|
1997
|
+
have = (_balances_token = balances === null || balances === void 0 ? void 0 : balances[token1]) !== null && _balances_token !== void 0 ? _balances_token : 0n;
|
|
1998
|
+
if (have < required) {
|
|
1999
|
+
throw new Error("Insufficient ".concat(side, " balance for token ").concat(token1, ": ").concat(have, " < ").concat(required));
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
} catch (err) {
|
|
2003
|
+
_didIteratorError1 = true;
|
|
2004
|
+
_iteratorError1 = err;
|
|
2005
|
+
} finally{
|
|
2006
|
+
try {
|
|
2007
|
+
if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
|
|
2008
|
+
_iterator1.return();
|
|
2009
|
+
}
|
|
2010
|
+
} finally{
|
|
2011
|
+
if (_didIteratorError1) {
|
|
2012
|
+
throw _iteratorError1;
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
sdkTransfers = transfers.map(function(transfer) {
|
|
2017
|
+
var _transfer_tokenType;
|
|
2018
|
+
var token = (_transfer_tokenType = transfer.tokenType) !== null && _transfer_tokenType !== void 0 ? _transfer_tokenType : nativeToken;
|
|
2019
|
+
// The SDK wants a decoded address object, not the bech32m string.
|
|
2020
|
+
var receiverAddress;
|
|
2021
|
+
try {
|
|
2022
|
+
var parsed = walletSdkAddressFormat.MidnightBech32m.parse(transfer.recipientAddress);
|
|
2023
|
+
receiverAddress = transfer.type === 'unshielded' ? parsed.decode(walletSdkAddressFormat.UnshieldedAddress, network) : parsed.decode(walletSdkAddressFormat.ShieldedAddress, network);
|
|
2024
|
+
} catch (err) {
|
|
2025
|
+
throw new Error("Invalid ".concat(transfer.type, " recipient address ").concat(transfer.recipientAddress, ": ").concat(err.message));
|
|
2026
|
+
}
|
|
2027
|
+
return {
|
|
2028
|
+
type: transfer.type,
|
|
2029
|
+
outputs: [
|
|
2030
|
+
{
|
|
2031
|
+
amount: parseTransferAmount(transfer.amount),
|
|
2032
|
+
receiverAddress: receiverAddress,
|
|
2033
|
+
type: token
|
|
2034
|
+
}
|
|
2035
|
+
]
|
|
2036
|
+
};
|
|
2037
|
+
});
|
|
2038
|
+
return [
|
|
2039
|
+
4,
|
|
2040
|
+
wallet.transferTransaction(sdkTransfers, {
|
|
2041
|
+
shieldedSecretKeys: shieldedSecretKeys,
|
|
2042
|
+
dustSecretKey: dustSecretKey
|
|
2043
|
+
}, {
|
|
2044
|
+
ttl: new Date(Date.now() + ttlMinutes * 60 * 1000)
|
|
2045
|
+
})
|
|
2046
|
+
];
|
|
2047
|
+
case 1:
|
|
2048
|
+
recipe = _state.sent();
|
|
2049
|
+
if (recipe.type !== 'UNPROVEN_TRANSACTION') {
|
|
2050
|
+
throw new Error("Unexpected recipe type from transferTransaction: ".concat(recipe.type));
|
|
2051
|
+
}
|
|
2052
|
+
return [
|
|
2053
|
+
2,
|
|
2054
|
+
{
|
|
2055
|
+
serializedTransaction: Buffer.from(recipe.transaction.serialize()).toString('base64')
|
|
2056
|
+
}
|
|
2057
|
+
];
|
|
2058
|
+
}
|
|
2059
|
+
});
|
|
2060
|
+
});
|
|
2061
|
+
return function(_) {
|
|
2062
|
+
return _ref.apply(this, arguments);
|
|
2063
|
+
};
|
|
2064
|
+
}())
|
|
2065
|
+
];
|
|
2066
|
+
case 2:
|
|
2067
|
+
_ref = _state.sent(), result = _ref.result, walletState = _ref.walletState;
|
|
2068
|
+
return [
|
|
2069
|
+
2,
|
|
2070
|
+
_object_spread_props(_object_spread({}, result), {
|
|
2071
|
+
walletState: walletState
|
|
2072
|
+
})
|
|
2073
|
+
];
|
|
2074
|
+
case 3:
|
|
2075
|
+
error = _state.sent();
|
|
2076
|
+
logError({
|
|
2077
|
+
message: ERROR_CREATE_TRANSFER,
|
|
2078
|
+
error: error,
|
|
2079
|
+
context: {
|
|
2080
|
+
accountAddress: access.walletMetadata.accountAddress
|
|
2081
|
+
}
|
|
2082
|
+
});
|
|
2083
|
+
throw _instanceof(error, Error) ? error : new Error(ERROR_CREATE_TRANSFER);
|
|
2084
|
+
case 4:
|
|
2085
|
+
return [
|
|
2086
|
+
2
|
|
2087
|
+
];
|
|
2088
|
+
}
|
|
2089
|
+
});
|
|
2090
|
+
})();
|
|
2091
|
+
}
|
|
2092
|
+
},
|
|
2093
|
+
{
|
|
2094
|
+
key: "submitTransaction",
|
|
2095
|
+
value: /**
|
|
2096
|
+
* Broadcasts a finalized transaction. Pure RPC — reuses the cached wallet's
|
|
2097
|
+
* node connection; no MPC and no proving.
|
|
2098
|
+
*
|
|
2099
|
+
* Returns both identifiers, because they are not interchangeable:
|
|
2100
|
+
* - `txHash` is the canonical ledger hash, and what the block explorer indexes.
|
|
2101
|
+
* - `txIdentifier` is the submission handle; midnight-js polls
|
|
2102
|
+
* `transactions(offset: { identifier })` to observe inclusion, so a caller
|
|
2103
|
+
* handed only the hash would wait forever on a transaction that succeeded.
|
|
2104
|
+
*/ function submitTransaction(access) {
|
|
2105
|
+
var _this = this;
|
|
2106
|
+
return _async_to_generator(function() {
|
|
2107
|
+
var bytes, _ref, result, walletState, error;
|
|
2108
|
+
return _ts_generator(this, function(_state) {
|
|
2109
|
+
switch(_state.label){
|
|
2110
|
+
case 0:
|
|
2111
|
+
// Validate before booting the facade — see signTransaction.
|
|
2112
|
+
bytes = decodeSerializedTransaction(access.transaction, 'submitTransaction');
|
|
2113
|
+
_state.label = 1;
|
|
2114
|
+
case 1:
|
|
2115
|
+
_state.trys.push([
|
|
2116
|
+
1,
|
|
2117
|
+
3,
|
|
2118
|
+
,
|
|
2119
|
+
4
|
|
2120
|
+
]);
|
|
2121
|
+
return [
|
|
2122
|
+
4,
|
|
2123
|
+
_this.withWallet('submitTransaction', access, 'full', /*#__PURE__*/ function() {
|
|
2124
|
+
var _ref = _async_to_generator(function(param) {
|
|
2125
|
+
var wallet, finalized, txIdentifier, txHash, canonical;
|
|
2126
|
+
return _ts_generator(this, function(_state) {
|
|
2127
|
+
switch(_state.label){
|
|
2128
|
+
case 0:
|
|
2129
|
+
wallet = param.wallet;
|
|
2130
|
+
finalized = ledger__namespace.Transaction.deserialize('signature', 'proof', 'binding', bytes);
|
|
2131
|
+
return [
|
|
2132
|
+
4,
|
|
2133
|
+
_this.submitWithReconnect(wallet, finalized)
|
|
2134
|
+
];
|
|
2135
|
+
case 1:
|
|
2136
|
+
txIdentifier = toTxHashString.apply(void 0, [
|
|
2137
|
+
_state.sent()
|
|
2138
|
+
]);
|
|
2139
|
+
txHash = txIdentifier;
|
|
2140
|
+
try {
|
|
2141
|
+
canonical = toTxHashString(finalized.transactionHash());
|
|
2142
|
+
if (canonical) txHash = canonical;
|
|
2143
|
+
} catch (err) {
|
|
2144
|
+
_this.logger.warn('[Midnight] submitTransaction: could not derive canonical hash, using identifier', err);
|
|
2145
|
+
}
|
|
2146
|
+
return [
|
|
2147
|
+
2,
|
|
2148
|
+
{
|
|
2149
|
+
txHash: txHash,
|
|
2150
|
+
txIdentifier: txIdentifier
|
|
2151
|
+
}
|
|
2152
|
+
];
|
|
2153
|
+
}
|
|
2154
|
+
});
|
|
2155
|
+
});
|
|
2156
|
+
return function(_) {
|
|
2157
|
+
return _ref.apply(this, arguments);
|
|
2158
|
+
};
|
|
2159
|
+
}())
|
|
2160
|
+
];
|
|
2161
|
+
case 2:
|
|
2162
|
+
_ref = _state.sent(), result = _ref.result, walletState = _ref.walletState;
|
|
2163
|
+
return [
|
|
2164
|
+
2,
|
|
2165
|
+
_object_spread_props(_object_spread({}, result), {
|
|
2166
|
+
walletState: walletState
|
|
2167
|
+
})
|
|
2168
|
+
];
|
|
2169
|
+
case 3:
|
|
2170
|
+
error = _state.sent();
|
|
2171
|
+
logError({
|
|
2172
|
+
message: ERROR_SUBMIT_TRANSACTION,
|
|
2173
|
+
error: error,
|
|
2174
|
+
context: {
|
|
2175
|
+
accountAddress: access.walletMetadata.accountAddress
|
|
2176
|
+
}
|
|
2177
|
+
});
|
|
2178
|
+
throw _instanceof(error, Error) ? error : new Error(ERROR_SUBMIT_TRANSACTION);
|
|
2179
|
+
case 4:
|
|
2180
|
+
return [
|
|
2181
|
+
2
|
|
2182
|
+
];
|
|
2183
|
+
}
|
|
2184
|
+
});
|
|
2185
|
+
})();
|
|
2186
|
+
}
|
|
2187
|
+
},
|
|
2188
|
+
{
|
|
2189
|
+
key: "signTransaction",
|
|
2190
|
+
value: /**
|
|
2191
|
+
* MPC-signs every unshielded intent segment, then finalizes (ZK-proves) the
|
|
2192
|
+
* transaction through the proof server.
|
|
2193
|
+
*
|
|
2194
|
+
* Side effect: finalizeRecipe mutates wallet state by adding a pending-tx
|
|
2195
|
+
* entry. If the caller never submits, that entry lingers until the next
|
|
2196
|
+
* re-sync reconciles against the chain.
|
|
2197
|
+
*/ function signTransaction(access) {
|
|
2198
|
+
var _this = this;
|
|
2199
|
+
return _async_to_generator(function() {
|
|
2200
|
+
var transaction, networkId, context, resolvedNetworkId, bytes, _ref, result, walletState, error;
|
|
2201
|
+
return _ts_generator(this, function(_state) {
|
|
2202
|
+
switch(_state.label){
|
|
2203
|
+
case 0:
|
|
2204
|
+
transaction = access.transaction, networkId = access.networkId, context = access.context;
|
|
2205
|
+
if (networkId === undefined) {
|
|
2206
|
+
// Never default: the network id is baked into the transaction hash for
|
|
2207
|
+
// replay protection, so guessing wrong is a correctness bug, not a nit.
|
|
2208
|
+
throw new Error(ERROR_NETWORK_ID_REQUIRED);
|
|
2209
|
+
}
|
|
2210
|
+
resolvedNetworkId = typeof networkId === 'number' ? networkId : getNetworkIdFromChainId(networkId);
|
|
2211
|
+
// Validate before booting the facade: a cold sync is ~150s and getRoleKeys
|
|
2212
|
+
// runs a full MPC export, neither of which a malformed payload should cost.
|
|
2213
|
+
bytes = decodeSerializedTransaction(transaction, 'signTransaction');
|
|
2214
|
+
_state.label = 1;
|
|
2215
|
+
case 1:
|
|
2216
|
+
_state.trys.push([
|
|
2217
|
+
1,
|
|
2218
|
+
3,
|
|
2219
|
+
,
|
|
2220
|
+
4
|
|
2221
|
+
]);
|
|
2222
|
+
return [
|
|
2223
|
+
4,
|
|
2224
|
+
_this.withWallet('signTransaction', access, 'full', /*#__PURE__*/ function() {
|
|
2225
|
+
var _ref = _async_to_generator(function(param) {
|
|
2226
|
+
var wallet, unsignedTx, finalized;
|
|
2227
|
+
return _ts_generator(this, function(_state) {
|
|
2228
|
+
switch(_state.label){
|
|
2229
|
+
case 0:
|
|
2230
|
+
wallet = param.wallet;
|
|
2231
|
+
unsignedTx = ledger__namespace.Transaction.deserialize('signature', 'pre-proof', 'pre-binding', bytes);
|
|
2232
|
+
return [
|
|
2233
|
+
4,
|
|
2234
|
+
_this.mpcSignIntents(unsignedTx, access, {
|
|
2235
|
+
fullTxBase64: transaction,
|
|
2236
|
+
networkId: resolvedNetworkId,
|
|
2237
|
+
baseContext: context
|
|
2238
|
+
})
|
|
2239
|
+
];
|
|
2240
|
+
case 1:
|
|
2241
|
+
_state.sent();
|
|
2242
|
+
_this.logger.info('[Midnight] signTransaction: finalizing (ZK prove)…');
|
|
2243
|
+
return [
|
|
2244
|
+
4,
|
|
2245
|
+
wallet.finalizeRecipe({
|
|
2246
|
+
type: 'UNPROVEN_TRANSACTION',
|
|
2247
|
+
transaction: unsignedTx
|
|
2248
|
+
})
|
|
2249
|
+
];
|
|
2250
|
+
case 2:
|
|
2251
|
+
finalized = _state.sent();
|
|
2252
|
+
return [
|
|
2253
|
+
2,
|
|
2254
|
+
Buffer.from(finalized.serialize()).toString('base64')
|
|
2255
|
+
];
|
|
2256
|
+
}
|
|
2257
|
+
});
|
|
2258
|
+
});
|
|
2259
|
+
return function(_) {
|
|
2260
|
+
return _ref.apply(this, arguments);
|
|
2261
|
+
};
|
|
2262
|
+
}())
|
|
2263
|
+
];
|
|
2264
|
+
case 2:
|
|
2265
|
+
_ref = _state.sent(), result = _ref.result, walletState = _ref.walletState;
|
|
2266
|
+
return [
|
|
2267
|
+
2,
|
|
2268
|
+
{
|
|
2269
|
+
transaction: result,
|
|
2270
|
+
walletState: walletState
|
|
2271
|
+
}
|
|
2272
|
+
];
|
|
2273
|
+
case 3:
|
|
2274
|
+
error = _state.sent();
|
|
2275
|
+
logError({
|
|
2276
|
+
message: ERROR_SIGN_TRANSACTION,
|
|
2277
|
+
error: error,
|
|
2278
|
+
context: {
|
|
2279
|
+
accountAddress: access.walletMetadata.accountAddress
|
|
2280
|
+
}
|
|
2281
|
+
});
|
|
2282
|
+
throw _instanceof(error, Error) ? error : new Error(ERROR_SIGN_TRANSACTION);
|
|
2283
|
+
case 4:
|
|
2284
|
+
return [
|
|
2285
|
+
2
|
|
2286
|
+
];
|
|
2287
|
+
}
|
|
2288
|
+
});
|
|
2289
|
+
})();
|
|
2290
|
+
}
|
|
2291
|
+
},
|
|
2292
|
+
{
|
|
2293
|
+
key: "getWalletProvider",
|
|
2294
|
+
value: /**
|
|
2295
|
+
* Returns a Midnight.js-compatible wallet provider for use with
|
|
2296
|
+
* midnight-js-contracts (deployment and contract calls). Signing goes through
|
|
2297
|
+
* MPC; no private key is handed to the caller.
|
|
2298
|
+
*
|
|
2299
|
+
* `balanceTx` and `submitTx` boot a wallet per call rather than closing over
|
|
2300
|
+
* one, so nothing is held open between the caller's contract operations. To
|
|
2301
|
+
* keep that from re-syncing from genesis every time, the provider carries the
|
|
2302
|
+
* checkpoint from one call into the next. That state lives in this closure
|
|
2303
|
+
* and dies with the provider — read it with `getWalletState()` to persist it
|
|
2304
|
+
* beyond that.
|
|
2305
|
+
*/ function getWalletProvider(access) {
|
|
2306
|
+
var _this = this;
|
|
2307
|
+
return _async_to_generator(function() {
|
|
2308
|
+
var network, numericNetworkId, resume, durable, queue, withLatest, _ref, coinPublicKey, encryptionPublicKey;
|
|
2309
|
+
return _ts_generator(this, function(_state) {
|
|
2310
|
+
switch(_state.label){
|
|
2311
|
+
case 0:
|
|
2312
|
+
network = resolveMidnightNetworkTag(access.networkId);
|
|
2313
|
+
numericNetworkId = MIDNIGHT_NETWORK_IDS[network];
|
|
2314
|
+
// Two views of the same wallet. `resume` is what the next call boots from
|
|
2315
|
+
// and includes work in flight, so a second balanceTx cannot re-spend coins
|
|
2316
|
+
// the first one already reserved. `durable` is the clean subset handed to
|
|
2317
|
+
// the caller, who must not persist pending entries.
|
|
2318
|
+
resume = access.walletState;
|
|
2319
|
+
durable = access.walletState;
|
|
2320
|
+
// Each operation reads `resume`, awaits, then writes it back, so two
|
|
2321
|
+
// overlapping calls would both start from the same state and the later
|
|
2322
|
+
// write would drop the earlier one's reservations. Chaining them means a
|
|
2323
|
+
// caller that fires several without awaiting still gets them in order.
|
|
2324
|
+
queue = Promise.resolve();
|
|
2325
|
+
withLatest = function(label, use) {
|
|
2326
|
+
var run = queue.then(/*#__PURE__*/ _async_to_generator(function() {
|
|
2327
|
+
var _ref, result, walletState, sessionState;
|
|
2328
|
+
return _ts_generator(this, function(_state) {
|
|
2329
|
+
switch(_state.label){
|
|
2330
|
+
case 0:
|
|
2331
|
+
return [
|
|
2332
|
+
4,
|
|
2333
|
+
_this.withWallet(label, _object_spread_props(_object_spread({}, access), {
|
|
2334
|
+
walletState: resume
|
|
2335
|
+
}), 'full', use)
|
|
2336
|
+
];
|
|
2337
|
+
case 1:
|
|
2338
|
+
_ref = _state.sent(), result = _ref.result, walletState = _ref.walletState, sessionState = _ref.sessionState;
|
|
2339
|
+
if (sessionState) resume = sessionState;
|
|
2340
|
+
if (walletState) durable = walletState;
|
|
2341
|
+
return [
|
|
2342
|
+
2,
|
|
2343
|
+
result
|
|
2344
|
+
];
|
|
2345
|
+
}
|
|
2346
|
+
});
|
|
2347
|
+
}));
|
|
2348
|
+
// Swallow only for the chain's own sake — `run` still rejects for the
|
|
2349
|
+
// caller, but one failure must not poison every later operation.
|
|
2350
|
+
queue = run.catch(function() {
|
|
2351
|
+
return undefined;
|
|
2352
|
+
});
|
|
2353
|
+
return run;
|
|
2354
|
+
};
|
|
2355
|
+
return [
|
|
2356
|
+
4,
|
|
2357
|
+
withLatest('walletProvider', /*#__PURE__*/ function() {
|
|
2358
|
+
var _ref = _async_to_generator(function(param) {
|
|
2359
|
+
var state;
|
|
2360
|
+
return _ts_generator(this, function(_state) {
|
|
2361
|
+
state = param.state;
|
|
2362
|
+
return [
|
|
2363
|
+
2,
|
|
2364
|
+
{
|
|
2365
|
+
coinPublicKey: state.shielded.coinPublicKey.toHexString(),
|
|
2366
|
+
encryptionPublicKey: state.shielded.encryptionPublicKey.toHexString()
|
|
2367
|
+
}
|
|
2368
|
+
];
|
|
2369
|
+
});
|
|
2370
|
+
});
|
|
2371
|
+
return function(_) {
|
|
2372
|
+
return _ref.apply(this, arguments);
|
|
2373
|
+
};
|
|
2374
|
+
}())
|
|
2375
|
+
];
|
|
2376
|
+
case 1:
|
|
2377
|
+
_ref = _state.sent(), coinPublicKey = _ref.coinPublicKey, encryptionPublicKey = _ref.encryptionPublicKey;
|
|
2378
|
+
return [
|
|
2379
|
+
2,
|
|
2380
|
+
{
|
|
2381
|
+
getCoinPublicKey: function() {
|
|
2382
|
+
return coinPublicKey;
|
|
2383
|
+
},
|
|
2384
|
+
getEncryptionPublicKey: function() {
|
|
2385
|
+
return encryptionPublicKey;
|
|
2386
|
+
},
|
|
2387
|
+
getWalletState: function() {
|
|
2388
|
+
return durable;
|
|
2389
|
+
},
|
|
2390
|
+
balanceTx: function(tx, ttl) {
|
|
2391
|
+
return withLatest('walletProvider.balanceTx', /*#__PURE__*/ function() {
|
|
2392
|
+
var _ref = _async_to_generator(function(param) {
|
|
2393
|
+
var wallet, shieldedSecretKeys, dustSecretKey, recipe;
|
|
2394
|
+
return _ts_generator(this, function(_state) {
|
|
2395
|
+
switch(_state.label){
|
|
2396
|
+
case 0:
|
|
2397
|
+
wallet = param.wallet, shieldedSecretKeys = param.shieldedSecretKeys, dustSecretKey = param.dustSecretKey;
|
|
2398
|
+
return [
|
|
2399
|
+
4,
|
|
2400
|
+
wallet.balanceUnboundTransaction(tx, {
|
|
2401
|
+
shieldedSecretKeys: shieldedSecretKeys,
|
|
2402
|
+
dustSecretKey: dustSecretKey
|
|
2403
|
+
}, {
|
|
2404
|
+
ttl: ttl !== null && ttl !== void 0 ? ttl : new Date(Date.now() + 30 * 60 * 1000)
|
|
2405
|
+
})
|
|
2406
|
+
];
|
|
2407
|
+
case 1:
|
|
2408
|
+
recipe = _state.sent();
|
|
2409
|
+
// The base transaction arrives already proven, so it deserializes and
|
|
2410
|
+
// signs under the 'proof' marker; the balancing transaction the SDK
|
|
2411
|
+
// adds has not been proven yet and uses 'pre-proof'.
|
|
2412
|
+
return [
|
|
2413
|
+
4,
|
|
2414
|
+
_this.mpcSignIntents(recipe.baseTransaction, access, {
|
|
2415
|
+
fullTxBase64: Buffer.from(recipe.baseTransaction.serialize()).toString('base64'),
|
|
2416
|
+
networkId: numericNetworkId,
|
|
2417
|
+
proofMarker: 'proof'
|
|
2418
|
+
})
|
|
2419
|
+
];
|
|
2420
|
+
case 2:
|
|
2421
|
+
_state.sent();
|
|
2422
|
+
if (!recipe.balancingTransaction) return [
|
|
2423
|
+
3,
|
|
2424
|
+
4
|
|
2425
|
+
];
|
|
2426
|
+
return [
|
|
2427
|
+
4,
|
|
2428
|
+
_this.mpcSignIntents(recipe.balancingTransaction, access, {
|
|
2429
|
+
fullTxBase64: Buffer.from(recipe.balancingTransaction.serialize()).toString('base64'),
|
|
2430
|
+
networkId: numericNetworkId,
|
|
2431
|
+
proofMarker: 'pre-proof'
|
|
2432
|
+
})
|
|
2433
|
+
];
|
|
2434
|
+
case 3:
|
|
2435
|
+
_state.sent();
|
|
2436
|
+
_state.label = 4;
|
|
2437
|
+
case 4:
|
|
2438
|
+
_this.logger.info('[Midnight] walletProvider.balanceTx: finalizing (ZK prove)…');
|
|
2439
|
+
return [
|
|
2440
|
+
2,
|
|
2441
|
+
wallet.finalizeRecipe(recipe)
|
|
2442
|
+
];
|
|
2443
|
+
}
|
|
2444
|
+
});
|
|
2445
|
+
});
|
|
2446
|
+
return function(_) {
|
|
2447
|
+
return _ref.apply(this, arguments);
|
|
2448
|
+
};
|
|
2449
|
+
}());
|
|
2450
|
+
},
|
|
2451
|
+
submitTx: function(tx) {
|
|
2452
|
+
return withLatest('walletProvider.submitTx', /*#__PURE__*/ function() {
|
|
2453
|
+
var _ref = _async_to_generator(function(param) {
|
|
2454
|
+
var wallet;
|
|
2455
|
+
return _ts_generator(this, function(_state) {
|
|
2456
|
+
switch(_state.label){
|
|
2457
|
+
case 0:
|
|
2458
|
+
wallet = param.wallet;
|
|
2459
|
+
return [
|
|
2460
|
+
4,
|
|
2461
|
+
_this.submitWithReconnect(wallet, tx)
|
|
2462
|
+
];
|
|
2463
|
+
case 1:
|
|
2464
|
+
return [
|
|
2465
|
+
2,
|
|
2466
|
+
toTxHashString.apply(void 0, [
|
|
2467
|
+
_state.sent()
|
|
2468
|
+
])
|
|
2469
|
+
];
|
|
2470
|
+
}
|
|
2471
|
+
});
|
|
2472
|
+
});
|
|
2473
|
+
return function(_) {
|
|
2474
|
+
return _ref.apply(this, arguments);
|
|
2475
|
+
};
|
|
2476
|
+
}());
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
];
|
|
2480
|
+
}
|
|
2481
|
+
});
|
|
2482
|
+
})();
|
|
2483
|
+
}
|
|
2484
|
+
},
|
|
2485
|
+
{
|
|
2486
|
+
key: "balanceContractTransaction",
|
|
2487
|
+
value: /**
|
|
2488
|
+
* Balances a serialized midnight-js UnboundTransaction and returns the
|
|
2489
|
+
* finalized transaction, base64-encoded. A transport-friendly wrapper over
|
|
2490
|
+
* {@link getWalletProvider}'s `balanceTx` for callers that pass transactions
|
|
2491
|
+
* across a process boundary rather than holding ledger objects.
|
|
2492
|
+
*/ function balanceContractTransaction(access) {
|
|
2493
|
+
var _this = this;
|
|
2494
|
+
return _async_to_generator(function() {
|
|
2495
|
+
var transaction, ttl, ttlDate, bytes, unbound, provider, finalized, error;
|
|
2496
|
+
return _ts_generator(this, function(_state) {
|
|
2497
|
+
switch(_state.label){
|
|
2498
|
+
case 0:
|
|
2499
|
+
transaction = access.transaction, ttl = access.ttl;
|
|
2500
|
+
// `ttl ? …` would treat '' as absent and quietly apply the default lifetime.
|
|
2501
|
+
ttlDate = ttl === undefined ? undefined : parseIsoTimestamp(ttl, 'balanceContractTransaction');
|
|
2502
|
+
// Validated before the facade boots — see signTransaction. An unbound
|
|
2503
|
+
// contract transaction arrives proven, hence the 'proof' marker.
|
|
2504
|
+
bytes = decodeSerializedTransaction(transaction, 'balanceContractTransaction');
|
|
2505
|
+
_state.label = 1;
|
|
2506
|
+
case 1:
|
|
2507
|
+
_state.trys.push([
|
|
2508
|
+
1,
|
|
2509
|
+
4,
|
|
2510
|
+
,
|
|
2511
|
+
5
|
|
2512
|
+
]);
|
|
2513
|
+
unbound = ledger__namespace.Transaction.deserialize('signature', 'proof', 'pre-binding', bytes);
|
|
2514
|
+
return [
|
|
2515
|
+
4,
|
|
2516
|
+
_this.getWalletProvider(access)
|
|
2517
|
+
];
|
|
2518
|
+
case 2:
|
|
2519
|
+
provider = _state.sent();
|
|
2520
|
+
return [
|
|
2521
|
+
4,
|
|
2522
|
+
provider.balanceTx(unbound, ttlDate)
|
|
2523
|
+
];
|
|
2524
|
+
case 3:
|
|
2525
|
+
finalized = _state.sent();
|
|
2526
|
+
// Booting the provider produces a clean checkpoint before any balancing
|
|
2527
|
+
// happens; dropping it would make the next call re-sync from genesis.
|
|
2528
|
+
return [
|
|
2529
|
+
2,
|
|
2530
|
+
{
|
|
2531
|
+
transaction: Buffer.from(finalized.serialize()).toString('base64'),
|
|
2532
|
+
walletState: provider.getWalletState()
|
|
2533
|
+
}
|
|
2534
|
+
];
|
|
2535
|
+
case 4:
|
|
2536
|
+
error = _state.sent();
|
|
2537
|
+
logError({
|
|
2538
|
+
message: ERROR_BALANCE_TRANSACTION,
|
|
2539
|
+
error: error,
|
|
2540
|
+
context: {
|
|
2541
|
+
accountAddress: access.walletMetadata.accountAddress
|
|
2542
|
+
}
|
|
2543
|
+
});
|
|
2544
|
+
throw _instanceof(error, Error) ? error : new Error(ERROR_BALANCE_TRANSACTION);
|
|
2545
|
+
case 5:
|
|
2546
|
+
return [
|
|
2547
|
+
2
|
|
2548
|
+
];
|
|
2549
|
+
}
|
|
2550
|
+
});
|
|
2551
|
+
})();
|
|
2552
|
+
}
|
|
2553
|
+
},
|
|
2554
|
+
{
|
|
2555
|
+
key: "mpcSignIntents",
|
|
2556
|
+
value: /**
|
|
2557
|
+
* Signs each intent segment via MPC and writes the signatures back onto the
|
|
2558
|
+
* transaction.
|
|
2559
|
+
*
|
|
2560
|
+
* Strictly serial. `tx.intents` is an immutable persistent map — `.set()`
|
|
2561
|
+
* returns a new map — so a Promise.all would have every iteration read the
|
|
2562
|
+
* same initial map and race to write back, silently dropping all but the last
|
|
2563
|
+
* segment's signature. Relay ceremonies serialize anyway, so little is lost.
|
|
2564
|
+
*/ function mpcSignIntents(tx, access, options) {
|
|
2565
|
+
var _this = this;
|
|
2566
|
+
return _async_to_generator(function() {
|
|
2567
|
+
var _tx_intents, _tx_intents_keys_toArray, segments, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _loop, _iterator, _step, err;
|
|
2568
|
+
return _ts_generator(this, function(_state) {
|
|
2569
|
+
switch(_state.label){
|
|
2570
|
+
case 0:
|
|
2571
|
+
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 : [];
|
|
2572
|
+
if (segments.length === 0) return [
|
|
2573
|
+
2
|
|
2574
|
+
];
|
|
2575
|
+
_this.logger.info("[Midnight] MPC signing ".concat(segments.length, " intent segment(s)…"));
|
|
2576
|
+
_iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
2577
|
+
_state.label = 1;
|
|
2578
|
+
case 1:
|
|
2579
|
+
_state.trys.push([
|
|
2580
|
+
1,
|
|
2581
|
+
6,
|
|
2582
|
+
7,
|
|
2583
|
+
8
|
|
2584
|
+
]);
|
|
2585
|
+
_loop = function() {
|
|
2586
|
+
var _loop, segment, intent, _options_proofMarker, cloned, sigData, hash, signature, sigBytes, ledgerSig, _i, _iter;
|
|
2587
|
+
return _ts_generator(this, function(_state) {
|
|
2588
|
+
switch(_state.label){
|
|
2589
|
+
case 0:
|
|
2590
|
+
_loop = function(_i, _iter) {
|
|
2591
|
+
var offerKey = _iter[_i];
|
|
2592
|
+
var offer = cloned[offerKey];
|
|
2593
|
+
if (!offer) return "continue";
|
|
2594
|
+
cloned[offerKey] = offer.addSignatures(offer.inputs.map(function(_, index) {
|
|
2595
|
+
var _offer_signatures_at;
|
|
2596
|
+
return (_offer_signatures_at = offer.signatures.at(index)) !== null && _offer_signatures_at !== void 0 ? _offer_signatures_at : ledgerSig;
|
|
2597
|
+
}));
|
|
2598
|
+
};
|
|
2599
|
+
segment = _step.value;
|
|
2600
|
+
intent = tx.intents.get(segment);
|
|
2601
|
+
if (!intent) return [
|
|
2602
|
+
2,
|
|
2603
|
+
"continue"
|
|
2604
|
+
];
|
|
2605
|
+
cloned = ledger__namespace.Intent.deserialize('signature', (_options_proofMarker = options.proofMarker) !== null && _options_proofMarker !== void 0 ? _options_proofMarker : 'pre-proof', 'pre-binding', intent.serialize());
|
|
2606
|
+
sigData = cloned.signatureData(segment);
|
|
2607
|
+
hash = node_crypto.createHash('sha256').update(Buffer.from(sigData)).digest('hex');
|
|
2608
|
+
return [
|
|
2609
|
+
4,
|
|
2610
|
+
_this.sign({
|
|
2611
|
+
message: hash,
|
|
2612
|
+
accountAddress: access.walletMetadata.accountAddress,
|
|
2613
|
+
chainName: _this.chainName,
|
|
2614
|
+
password: access.password,
|
|
2615
|
+
externalServerKeyShares: access.externalServerKeyShares,
|
|
2616
|
+
walletMetadata: access.walletMetadata,
|
|
2617
|
+
walletOperation: node.WalletOperation.SIGN_TRANSACTION,
|
|
2618
|
+
// Policy validation runs per signature, so every segment carries the
|
|
2619
|
+
// whole transaction — same shape as BTC's per-input PSBT context.
|
|
2620
|
+
context: _object_spread_props(_object_spread({}, options.baseContext), {
|
|
2621
|
+
midnightTransaction: {
|
|
2622
|
+
serializedTransaction: options.fullTxBase64,
|
|
2623
|
+
networkId: options.networkId
|
|
2624
|
+
}
|
|
2625
|
+
})
|
|
2626
|
+
})
|
|
2627
|
+
];
|
|
2628
|
+
case 1:
|
|
2629
|
+
signature = _state.sent();
|
|
2630
|
+
sigBytes = _instanceof(signature, Uint8Array) ? signature : Buffer.from(String(signature), 'base64');
|
|
2631
|
+
ledgerSig = Buffer.from(sigBytes).toString('hex');
|
|
2632
|
+
// Preserve any signature already present at an input index; only fill gaps.
|
|
2633
|
+
for(_i = 0, _iter = [
|
|
2634
|
+
'guaranteedUnshieldedOffer',
|
|
2635
|
+
'fallibleUnshieldedOffer'
|
|
2636
|
+
]; _i < _iter.length; _i++)_loop(_i, _iter);
|
|
2637
|
+
tx.intents = tx.intents.set(segment, cloned);
|
|
2638
|
+
return [
|
|
2639
|
+
2
|
|
2640
|
+
];
|
|
2641
|
+
}
|
|
2642
|
+
});
|
|
2643
|
+
};
|
|
2644
|
+
_iterator = segments[Symbol.iterator]();
|
|
2645
|
+
_state.label = 2;
|
|
2646
|
+
case 2:
|
|
2647
|
+
if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
|
|
2648
|
+
3,
|
|
2649
|
+
5
|
|
2650
|
+
];
|
|
2651
|
+
return [
|
|
2652
|
+
5,
|
|
2653
|
+
_ts_values(_loop())
|
|
2654
|
+
];
|
|
2655
|
+
case 3:
|
|
2656
|
+
_state.sent();
|
|
2657
|
+
_state.label = 4;
|
|
2658
|
+
case 4:
|
|
2659
|
+
_iteratorNormalCompletion = true;
|
|
2660
|
+
return [
|
|
2661
|
+
3,
|
|
2662
|
+
2
|
|
2663
|
+
];
|
|
2664
|
+
case 5:
|
|
2665
|
+
return [
|
|
2666
|
+
3,
|
|
2667
|
+
8
|
|
2668
|
+
];
|
|
2669
|
+
case 6:
|
|
2670
|
+
err = _state.sent();
|
|
2671
|
+
_didIteratorError = true;
|
|
2672
|
+
_iteratorError = err;
|
|
2673
|
+
return [
|
|
2674
|
+
3,
|
|
2675
|
+
8
|
|
2676
|
+
];
|
|
2677
|
+
case 7:
|
|
2678
|
+
try {
|
|
2679
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
2680
|
+
_iterator.return();
|
|
2681
|
+
}
|
|
2682
|
+
} finally{
|
|
2683
|
+
if (_didIteratorError) {
|
|
2684
|
+
throw _iteratorError;
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
return [
|
|
2688
|
+
7
|
|
2689
|
+
];
|
|
2690
|
+
case 8:
|
|
2691
|
+
return [
|
|
2692
|
+
2
|
|
2693
|
+
];
|
|
2694
|
+
}
|
|
2695
|
+
});
|
|
2696
|
+
})();
|
|
2697
|
+
}
|
|
2698
|
+
},
|
|
1046
2699
|
{
|
|
1047
2700
|
key: "getMidnightWallets",
|
|
1048
2701
|
value: /**
|
|
@@ -1078,6 +2731,7 @@ var DynamicMidnightWalletClient = /*#__PURE__*/ function(DynamicWalletClient) {
|
|
|
1078
2731
|
|
|
1079
2732
|
exports.DynamicMidnightWalletClient = DynamicMidnightWalletClient;
|
|
1080
2733
|
exports.ERROR_ACCOUNT_ADDRESS_REQUIRED = ERROR_ACCOUNT_ADDRESS_REQUIRED;
|
|
2734
|
+
exports.ERROR_BALANCE_TRANSACTION = ERROR_BALANCE_TRANSACTION;
|
|
1081
2735
|
exports.ERROR_CREATE_WALLET_ACCOUNT = ERROR_CREATE_WALLET_ACCOUNT;
|
|
1082
2736
|
exports.ERROR_EXPORT_PRIVATE_KEY = ERROR_EXPORT_PRIVATE_KEY;
|
|
1083
2737
|
exports.ERROR_IMPORT_PRIVATE_KEY = ERROR_IMPORT_PRIVATE_KEY;
|