@unicitylabs/sphere-sdk 0.5.3 → 0.5.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/README.md +2 -0
- package/dist/connect/index.cjs +145 -23
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.d.cts +15 -2
- package/dist/connect/index.d.ts +15 -2
- package/dist/connect/index.js +145 -23
- package/dist/connect/index.js.map +1 -1
- package/dist/core/index.cjs +670 -473
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +123 -2
- package/dist/core/index.d.ts +123 -2
- package/dist/core/index.js +667 -473
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/connect/index.cjs +119 -1
- package/dist/impl/browser/connect/index.cjs.map +1 -1
- package/dist/impl/browser/connect/index.d.cts +53 -1
- package/dist/impl/browser/connect/index.d.ts +53 -1
- package/dist/impl/browser/connect/index.js +119 -1
- package/dist/impl/browser/connect/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +306 -193
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +306 -193
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/browser/ipfs.cjs +134 -19
- package/dist/impl/browser/ipfs.cjs.map +1 -1
- package/dist/impl/browser/ipfs.js +134 -19
- package/dist/impl/browser/ipfs.js.map +1 -1
- package/dist/impl/nodejs/connect/index.cjs +101 -6
- package/dist/impl/nodejs/connect/index.cjs.map +1 -1
- package/dist/impl/nodejs/connect/index.d.cts +2 -0
- package/dist/impl/nodejs/connect/index.d.ts +2 -0
- package/dist/impl/nodejs/connect/index.js +101 -6
- package/dist/impl/nodejs/connect/index.js.map +1 -1
- package/dist/impl/nodejs/index.cjs +267 -152
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +2 -1
- package/dist/impl/nodejs/index.d.ts +2 -1
- package/dist/impl/nodejs/index.js +267 -152
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +682 -493
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +124 -8
- package/dist/index.d.ts +124 -8
- package/dist/index.js +680 -493
- package/dist/index.js.map +1 -1
- package/dist/l1/index.cjs +139 -32
- package/dist/l1/index.cjs.map +1 -1
- package/dist/l1/index.js +139 -32
- package/dist/l1/index.js.map +1 -1
- package/package.json +1 -16
package/dist/core/index.js
CHANGED
|
@@ -14,6 +14,125 @@ var __export = (target, all) => {
|
|
|
14
14
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
// core/logger.ts
|
|
18
|
+
function getState() {
|
|
19
|
+
const g = globalThis;
|
|
20
|
+
if (!g[LOGGER_KEY]) {
|
|
21
|
+
g[LOGGER_KEY] = { debug: false, tags: {}, handler: null };
|
|
22
|
+
}
|
|
23
|
+
return g[LOGGER_KEY];
|
|
24
|
+
}
|
|
25
|
+
function isEnabled(tag) {
|
|
26
|
+
const state = getState();
|
|
27
|
+
if (tag in state.tags) return state.tags[tag];
|
|
28
|
+
return state.debug;
|
|
29
|
+
}
|
|
30
|
+
var LOGGER_KEY, logger;
|
|
31
|
+
var init_logger = __esm({
|
|
32
|
+
"core/logger.ts"() {
|
|
33
|
+
"use strict";
|
|
34
|
+
LOGGER_KEY = "__sphere_sdk_logger__";
|
|
35
|
+
logger = {
|
|
36
|
+
/**
|
|
37
|
+
* Configure the logger. Can be called multiple times (last write wins).
|
|
38
|
+
* Typically called by createBrowserProviders(), createNodeProviders(), or Sphere.init().
|
|
39
|
+
*/
|
|
40
|
+
configure(config) {
|
|
41
|
+
const state = getState();
|
|
42
|
+
if (config.debug !== void 0) state.debug = config.debug;
|
|
43
|
+
if (config.handler !== void 0) state.handler = config.handler;
|
|
44
|
+
},
|
|
45
|
+
/**
|
|
46
|
+
* Enable/disable debug logging for a specific tag.
|
|
47
|
+
* Per-tag setting overrides the global debug flag.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* logger.setTagDebug('Nostr', true); // enable only Nostr logs
|
|
52
|
+
* logger.setTagDebug('Nostr', false); // disable Nostr logs even if global debug=true
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
setTagDebug(tag, enabled) {
|
|
56
|
+
getState().tags[tag] = enabled;
|
|
57
|
+
},
|
|
58
|
+
/**
|
|
59
|
+
* Clear per-tag override, falling back to global debug flag.
|
|
60
|
+
*/
|
|
61
|
+
clearTagDebug(tag) {
|
|
62
|
+
delete getState().tags[tag];
|
|
63
|
+
},
|
|
64
|
+
/** Returns true if debug mode is enabled for the given tag (or globally). */
|
|
65
|
+
isDebugEnabled(tag) {
|
|
66
|
+
if (tag) return isEnabled(tag);
|
|
67
|
+
return getState().debug;
|
|
68
|
+
},
|
|
69
|
+
/**
|
|
70
|
+
* Debug-level log. Only shown when debug is enabled (globally or for this tag).
|
|
71
|
+
* Use for detailed operational information.
|
|
72
|
+
*/
|
|
73
|
+
debug(tag, message, ...args) {
|
|
74
|
+
if (!isEnabled(tag)) return;
|
|
75
|
+
const state = getState();
|
|
76
|
+
if (state.handler) {
|
|
77
|
+
state.handler("debug", tag, message, ...args);
|
|
78
|
+
} else {
|
|
79
|
+
console.log(`[${tag}]`, message, ...args);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
/**
|
|
83
|
+
* Warning-level log. ALWAYS shown regardless of debug flag.
|
|
84
|
+
* Use for important but non-critical issues (timeouts, retries, degraded state).
|
|
85
|
+
*/
|
|
86
|
+
warn(tag, message, ...args) {
|
|
87
|
+
const state = getState();
|
|
88
|
+
if (state.handler) {
|
|
89
|
+
state.handler("warn", tag, message, ...args);
|
|
90
|
+
} else {
|
|
91
|
+
console.warn(`[${tag}]`, message, ...args);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
/**
|
|
95
|
+
* Error-level log. ALWAYS shown regardless of debug flag.
|
|
96
|
+
* Use for critical failures that should never be silenced.
|
|
97
|
+
*/
|
|
98
|
+
error(tag, message, ...args) {
|
|
99
|
+
const state = getState();
|
|
100
|
+
if (state.handler) {
|
|
101
|
+
state.handler("error", tag, message, ...args);
|
|
102
|
+
} else {
|
|
103
|
+
console.error(`[${tag}]`, message, ...args);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
/** Reset all logger state (debug flag, tags, handler). Primarily for tests. */
|
|
107
|
+
reset() {
|
|
108
|
+
const g = globalThis;
|
|
109
|
+
delete g[LOGGER_KEY];
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// core/errors.ts
|
|
116
|
+
function isSphereError(err) {
|
|
117
|
+
return err instanceof SphereError;
|
|
118
|
+
}
|
|
119
|
+
var SphereError;
|
|
120
|
+
var init_errors = __esm({
|
|
121
|
+
"core/errors.ts"() {
|
|
122
|
+
"use strict";
|
|
123
|
+
SphereError = class extends Error {
|
|
124
|
+
code;
|
|
125
|
+
cause;
|
|
126
|
+
constructor(message, code, cause) {
|
|
127
|
+
super(message);
|
|
128
|
+
this.name = "SphereError";
|
|
129
|
+
this.code = code;
|
|
130
|
+
this.cause = cause;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
17
136
|
// constants.ts
|
|
18
137
|
function getAddressId(directAddress) {
|
|
19
138
|
let hash = directAddress;
|
|
@@ -241,11 +360,11 @@ function bech32Checksum(hrp, data) {
|
|
|
241
360
|
}
|
|
242
361
|
function encodeBech32(hrp, version, program) {
|
|
243
362
|
if (version < 0 || version > 16) {
|
|
244
|
-
throw new
|
|
363
|
+
throw new SphereError("Invalid witness version", "VALIDATION_ERROR");
|
|
245
364
|
}
|
|
246
365
|
const converted = convertBits(Array.from(program), 8, 5, true);
|
|
247
366
|
if (!converted) {
|
|
248
|
-
throw new
|
|
367
|
+
throw new SphereError("Failed to convert bits", "VALIDATION_ERROR");
|
|
249
368
|
}
|
|
250
369
|
const data = [version].concat(converted);
|
|
251
370
|
const checksum = bech32Checksum(hrp, data);
|
|
@@ -298,6 +417,7 @@ var CHARSET, GENERATOR, createBech32;
|
|
|
298
417
|
var init_bech32 = __esm({
|
|
299
418
|
"core/bech32.ts"() {
|
|
300
419
|
"use strict";
|
|
420
|
+
init_errors();
|
|
301
421
|
CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
302
422
|
GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
303
423
|
createBech32 = encodeBech32;
|
|
@@ -311,7 +431,7 @@ function bytesToHex(buf) {
|
|
|
311
431
|
}
|
|
312
432
|
function addressToScriptHash(address) {
|
|
313
433
|
const decoded = decodeBech32(address);
|
|
314
|
-
if (!decoded) throw new
|
|
434
|
+
if (!decoded) throw new SphereError("Invalid bech32 address: " + address, "VALIDATION_ERROR");
|
|
315
435
|
const scriptHex = "0014" + bytesToHex(decoded.data);
|
|
316
436
|
const sha = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(scriptHex)).toString();
|
|
317
437
|
return sha.match(/../g).reverse().join("");
|
|
@@ -320,6 +440,7 @@ var init_addressToScriptHash = __esm({
|
|
|
320
440
|
"l1/addressToScriptHash.ts"() {
|
|
321
441
|
"use strict";
|
|
322
442
|
init_bech32();
|
|
443
|
+
init_errors();
|
|
323
444
|
}
|
|
324
445
|
});
|
|
325
446
|
|
|
@@ -379,7 +500,7 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
|
|
|
379
500
|
try {
|
|
380
501
|
ws = new WebSocket(endpoint);
|
|
381
502
|
} catch (err) {
|
|
382
|
-
|
|
503
|
+
logger.error("L1", "WebSocket constructor threw exception:", err);
|
|
383
504
|
isConnecting = false;
|
|
384
505
|
reject(err);
|
|
385
506
|
return;
|
|
@@ -415,7 +536,7 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
|
|
|
415
536
|
return;
|
|
416
537
|
}
|
|
417
538
|
if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
|
418
|
-
|
|
539
|
+
logger.error("L1", "Max reconnect attempts reached. Giving up.");
|
|
419
540
|
isConnecting = false;
|
|
420
541
|
const error = new Error("Max reconnect attempts reached");
|
|
421
542
|
connectionCallbacks.forEach((cb) => {
|
|
@@ -431,8 +552,9 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
|
|
|
431
552
|
}
|
|
432
553
|
const delay = Math.min(BASE_DELAY * Math.pow(2, reconnectAttempts), MAX_DELAY);
|
|
433
554
|
reconnectAttempts++;
|
|
434
|
-
|
|
435
|
-
|
|
555
|
+
logger.warn(
|
|
556
|
+
"L1",
|
|
557
|
+
`WebSocket closed unexpectedly. Reconnecting in ${delay}ms (attempt ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`
|
|
436
558
|
);
|
|
437
559
|
setTimeout(() => {
|
|
438
560
|
connect(endpoint).then(() => {
|
|
@@ -449,7 +571,7 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
|
|
|
449
571
|
}, delay);
|
|
450
572
|
};
|
|
451
573
|
ws.onerror = (err) => {
|
|
452
|
-
|
|
574
|
+
logger.error("L1", "WebSocket error:", err);
|
|
453
575
|
};
|
|
454
576
|
ws.onmessage = (msg) => handleMessage(msg);
|
|
455
577
|
});
|
|
@@ -507,7 +629,7 @@ async function getUtxo(address) {
|
|
|
507
629
|
const scripthash = addressToScriptHash(address);
|
|
508
630
|
const result = await rpc("blockchain.scripthash.listunspent", [scripthash]);
|
|
509
631
|
if (!Array.isArray(result)) {
|
|
510
|
-
|
|
632
|
+
logger.warn("L1", "listunspent returned non-array:", result);
|
|
511
633
|
return [];
|
|
512
634
|
}
|
|
513
635
|
return result.map((u) => ({
|
|
@@ -559,7 +681,7 @@ async function getTransactionHistory(address) {
|
|
|
559
681
|
const scriptHash = addressToScriptHash(address);
|
|
560
682
|
const result = await rpc("blockchain.scripthash.get_history", [scriptHash]);
|
|
561
683
|
if (!Array.isArray(result)) {
|
|
562
|
-
|
|
684
|
+
logger.warn("L1", "get_history returned non-array:", result);
|
|
563
685
|
return [];
|
|
564
686
|
}
|
|
565
687
|
return result;
|
|
@@ -575,7 +697,7 @@ async function getCurrentBlockHeight() {
|
|
|
575
697
|
const header = await rpc("blockchain.headers.subscribe", []);
|
|
576
698
|
return header?.height || 0;
|
|
577
699
|
} catch (err) {
|
|
578
|
-
|
|
700
|
+
logger.error("L1", "Error getting current block height:", err);
|
|
579
701
|
return 0;
|
|
580
702
|
}
|
|
581
703
|
}
|
|
@@ -604,6 +726,7 @@ var DEFAULT_ENDPOINT, ws, isConnected, isConnecting, requestId, intentionalClose
|
|
|
604
726
|
var init_network = __esm({
|
|
605
727
|
"l1/network.ts"() {
|
|
606
728
|
"use strict";
|
|
729
|
+
init_logger();
|
|
607
730
|
init_addressToScriptHash();
|
|
608
731
|
init_constants();
|
|
609
732
|
DEFAULT_ENDPOINT = DEFAULT_ELECTRUM_URL;
|
|
@@ -626,7 +749,12 @@ var init_network = __esm({
|
|
|
626
749
|
}
|
|
627
750
|
});
|
|
628
751
|
|
|
752
|
+
// core/Sphere.ts
|
|
753
|
+
init_logger();
|
|
754
|
+
init_errors();
|
|
755
|
+
|
|
629
756
|
// modules/payments/L1PaymentsModule.ts
|
|
757
|
+
init_errors();
|
|
630
758
|
init_constants();
|
|
631
759
|
|
|
632
760
|
// l1/index.ts
|
|
@@ -635,6 +763,7 @@ init_addressToScriptHash();
|
|
|
635
763
|
|
|
636
764
|
// core/crypto.ts
|
|
637
765
|
init_bech32();
|
|
766
|
+
init_errors();
|
|
638
767
|
import * as bip39 from "bip39";
|
|
639
768
|
import CryptoJS2 from "crypto-js";
|
|
640
769
|
import elliptic from "elliptic";
|
|
@@ -672,7 +801,7 @@ function generateMasterKey(seedHex) {
|
|
|
672
801
|
const IR = I.substring(64);
|
|
673
802
|
const masterKeyBigInt = BigInt("0x" + IL);
|
|
674
803
|
if (masterKeyBigInt === 0n || masterKeyBigInt >= CURVE_ORDER) {
|
|
675
|
-
throw new
|
|
804
|
+
throw new SphereError("Invalid master key generated", "VALIDATION_ERROR");
|
|
676
805
|
}
|
|
677
806
|
return {
|
|
678
807
|
privateKey: IL,
|
|
@@ -700,11 +829,11 @@ function deriveChildKey(parentPrivKey, parentChainCode, index) {
|
|
|
700
829
|
const ilBigInt = BigInt("0x" + IL);
|
|
701
830
|
const parentKeyBigInt = BigInt("0x" + parentPrivKey);
|
|
702
831
|
if (ilBigInt >= CURVE_ORDER) {
|
|
703
|
-
throw new
|
|
832
|
+
throw new SphereError("Invalid key: IL >= curve order", "VALIDATION_ERROR");
|
|
704
833
|
}
|
|
705
834
|
const childKeyBigInt = (ilBigInt + parentKeyBigInt) % CURVE_ORDER;
|
|
706
835
|
if (childKeyBigInt === 0n) {
|
|
707
|
-
throw new
|
|
836
|
+
throw new SphereError("Invalid key: child key is zero", "VALIDATION_ERROR");
|
|
708
837
|
}
|
|
709
838
|
const childPrivKey = childKeyBigInt.toString(16).padStart(64, "0");
|
|
710
839
|
return {
|
|
@@ -790,14 +919,14 @@ function randomBytes(length) {
|
|
|
790
919
|
}
|
|
791
920
|
async function identityFromMnemonic(mnemonic, passphrase = "") {
|
|
792
921
|
if (!validateMnemonic2(mnemonic)) {
|
|
793
|
-
throw new
|
|
922
|
+
throw new SphereError("Invalid mnemonic phrase", "INVALID_IDENTITY");
|
|
794
923
|
}
|
|
795
924
|
const seedHex = await mnemonicToSeed2(mnemonic, passphrase);
|
|
796
925
|
return generateMasterKey(seedHex);
|
|
797
926
|
}
|
|
798
927
|
function identityFromMnemonicSync(mnemonic, passphrase = "") {
|
|
799
928
|
if (!validateMnemonic2(mnemonic)) {
|
|
800
|
-
throw new
|
|
929
|
+
throw new SphereError("Invalid mnemonic phrase", "INVALID_IDENTITY");
|
|
801
930
|
}
|
|
802
931
|
const seedHex = mnemonicToSeedSync2(mnemonic, passphrase);
|
|
803
932
|
return generateMasterKey(seedHex);
|
|
@@ -845,12 +974,19 @@ function generateAddressFromMasterKey(masterPrivateKey, index) {
|
|
|
845
974
|
init_network();
|
|
846
975
|
|
|
847
976
|
// l1/tx.ts
|
|
977
|
+
init_logger();
|
|
978
|
+
init_errors();
|
|
848
979
|
init_network();
|
|
849
980
|
init_bech32();
|
|
850
981
|
import CryptoJS5 from "crypto-js";
|
|
851
982
|
import elliptic2 from "elliptic";
|
|
852
983
|
|
|
984
|
+
// l1/vestingState.ts
|
|
985
|
+
init_logger();
|
|
986
|
+
init_errors();
|
|
987
|
+
|
|
853
988
|
// l1/vesting.ts
|
|
989
|
+
init_logger();
|
|
854
990
|
init_network();
|
|
855
991
|
var VESTING_THRESHOLD = 28e4;
|
|
856
992
|
var currentBlockHeight = null;
|
|
@@ -1093,7 +1229,7 @@ var VestingClassifier = class {
|
|
|
1093
1229
|
await new Promise((resolve) => {
|
|
1094
1230
|
const req = indexedDB.deleteDatabase(this.dbName);
|
|
1095
1231
|
const timer = setTimeout(() => {
|
|
1096
|
-
|
|
1232
|
+
logger.warn("L1", ` destroy: deleteDatabase timed out for ${this.dbName}`);
|
|
1097
1233
|
resolve();
|
|
1098
1234
|
}, 3e3);
|
|
1099
1235
|
req.onsuccess = () => {
|
|
@@ -1105,7 +1241,7 @@ var VestingClassifier = class {
|
|
|
1105
1241
|
resolve();
|
|
1106
1242
|
};
|
|
1107
1243
|
req.onblocked = () => {
|
|
1108
|
-
|
|
1244
|
+
logger.warn("L1", ` destroy: deleteDatabase blocked for ${this.dbName}, waiting...`);
|
|
1109
1245
|
};
|
|
1110
1246
|
});
|
|
1111
1247
|
}
|
|
@@ -1123,7 +1259,7 @@ var VestingStateManager = class {
|
|
|
1123
1259
|
*/
|
|
1124
1260
|
setMode(mode) {
|
|
1125
1261
|
if (!["all", "vested", "unvested"].includes(mode)) {
|
|
1126
|
-
throw new
|
|
1262
|
+
throw new SphereError(`Invalid vesting mode: ${mode}`, "VALIDATION_ERROR");
|
|
1127
1263
|
}
|
|
1128
1264
|
this.currentMode = mode;
|
|
1129
1265
|
}
|
|
@@ -1160,10 +1296,10 @@ var VestingStateManager = class {
|
|
|
1160
1296
|
}
|
|
1161
1297
|
});
|
|
1162
1298
|
if (result.errors.length > 0) {
|
|
1163
|
-
|
|
1299
|
+
logger.warn("L1", `Vesting classification errors: ${result.errors.length}`);
|
|
1164
1300
|
result.errors.slice(0, 5).forEach((err) => {
|
|
1165
1301
|
const txHash = err.utxo.tx_hash || err.utxo.txid;
|
|
1166
|
-
|
|
1302
|
+
logger.warn("L1", ` ${txHash}: ${err.error}`);
|
|
1167
1303
|
});
|
|
1168
1304
|
}
|
|
1169
1305
|
} finally {
|
|
@@ -1240,6 +1376,7 @@ var VestingStateManager = class {
|
|
|
1240
1376
|
var vestingState = new VestingStateManager();
|
|
1241
1377
|
|
|
1242
1378
|
// l1/addressHelpers.ts
|
|
1379
|
+
init_errors();
|
|
1243
1380
|
var WalletAddressHelper = class {
|
|
1244
1381
|
/**
|
|
1245
1382
|
* Find address by BIP32 derivation path
|
|
@@ -1285,16 +1422,17 @@ var WalletAddressHelper = class {
|
|
|
1285
1422
|
*/
|
|
1286
1423
|
static add(wallet, newAddress) {
|
|
1287
1424
|
if (!newAddress.path) {
|
|
1288
|
-
throw new
|
|
1425
|
+
throw new SphereError("Cannot add address without a path", "INVALID_CONFIG");
|
|
1289
1426
|
}
|
|
1290
1427
|
const existing = this.findByPath(wallet, newAddress.path);
|
|
1291
1428
|
if (existing) {
|
|
1292
1429
|
if (existing.address !== newAddress.address) {
|
|
1293
|
-
throw new
|
|
1430
|
+
throw new SphereError(
|
|
1294
1431
|
`CRITICAL: Attempted to overwrite address for path ${newAddress.path}
|
|
1295
1432
|
Existing: ${existing.address}
|
|
1296
1433
|
New: ${newAddress.address}
|
|
1297
|
-
This indicates master key corruption or derivation logic error
|
|
1434
|
+
This indicates master key corruption or derivation logic error.`,
|
|
1435
|
+
"INVALID_CONFIG"
|
|
1298
1436
|
);
|
|
1299
1437
|
}
|
|
1300
1438
|
return wallet;
|
|
@@ -1353,9 +1491,10 @@ This indicates master key corruption or derivation logic error.`
|
|
|
1353
1491
|
const uniquePaths = new Set(paths);
|
|
1354
1492
|
if (paths.length !== uniquePaths.size) {
|
|
1355
1493
|
const duplicates = paths.filter((p, i) => paths.indexOf(p) !== i);
|
|
1356
|
-
throw new
|
|
1494
|
+
throw new SphereError(
|
|
1357
1495
|
`CRITICAL: Wallet has duplicate paths: ${duplicates.join(", ")}
|
|
1358
|
-
This indicates data corruption. Please restore from backup
|
|
1496
|
+
This indicates data corruption. Please restore from backup.`,
|
|
1497
|
+
"INVALID_CONFIG"
|
|
1359
1498
|
);
|
|
1360
1499
|
}
|
|
1361
1500
|
}
|
|
@@ -1387,11 +1526,11 @@ var DUST = 546;
|
|
|
1387
1526
|
var SAT = 1e8;
|
|
1388
1527
|
function createScriptPubKey(address) {
|
|
1389
1528
|
if (!address || typeof address !== "string") {
|
|
1390
|
-
throw new
|
|
1529
|
+
throw new SphereError("Invalid address: must be a string", "VALIDATION_ERROR");
|
|
1391
1530
|
}
|
|
1392
1531
|
const decoded = decodeBech32(address);
|
|
1393
1532
|
if (!decoded) {
|
|
1394
|
-
throw new
|
|
1533
|
+
throw new SphereError("Invalid bech32 address: " + address, "VALIDATION_ERROR");
|
|
1395
1534
|
}
|
|
1396
1535
|
const dataHex = Array.from(decoded.data).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1397
1536
|
return "0014" + dataHex;
|
|
@@ -1515,7 +1654,7 @@ function createAndSignTransaction(wallet, txPlan) {
|
|
|
1515
1654
|
privateKeyHex = wallet.masterPrivateKey;
|
|
1516
1655
|
}
|
|
1517
1656
|
if (!privateKeyHex) {
|
|
1518
|
-
throw new
|
|
1657
|
+
throw new SphereError("No private key available for address: " + fromAddress, "INVALID_CONFIG");
|
|
1519
1658
|
}
|
|
1520
1659
|
const keyPair = ec2.keyFromPrivate(privateKeyHex, "hex");
|
|
1521
1660
|
const publicKey = keyPair.getPublic(true, "hex");
|
|
@@ -1614,7 +1753,7 @@ function collectUtxosForAmount(utxoList, amountSats, recipientAddress, senderAdd
|
|
|
1614
1753
|
}
|
|
1615
1754
|
async function createTransactionPlan(wallet, toAddress, amountAlpha, fromAddress) {
|
|
1616
1755
|
if (!decodeBech32(toAddress)) {
|
|
1617
|
-
throw new
|
|
1756
|
+
throw new SphereError("Invalid recipient address", "INVALID_RECIPIENT");
|
|
1618
1757
|
}
|
|
1619
1758
|
const defaultAddr = WalletAddressHelper.getDefault(wallet);
|
|
1620
1759
|
const senderAddress = fromAddress || defaultAddr.address;
|
|
@@ -1623,21 +1762,21 @@ async function createTransactionPlan(wallet, toAddress, amountAlpha, fromAddress
|
|
|
1623
1762
|
const currentMode = vestingState.getMode();
|
|
1624
1763
|
if (vestingState.hasClassifiedData(senderAddress)) {
|
|
1625
1764
|
utxos = vestingState.getFilteredUtxos(senderAddress);
|
|
1626
|
-
|
|
1765
|
+
logger.debug("L1", `Using ${utxos.length} ${currentMode} UTXOs`);
|
|
1627
1766
|
} else {
|
|
1628
1767
|
utxos = await getUtxo(senderAddress);
|
|
1629
|
-
|
|
1768
|
+
logger.debug("L1", `Using ${utxos.length} UTXOs (vesting not classified yet)`);
|
|
1630
1769
|
}
|
|
1631
1770
|
if (!Array.isArray(utxos) || utxos.length === 0) {
|
|
1632
1771
|
const modeText = currentMode !== "all" ? ` (${currentMode} coins)` : "";
|
|
1633
|
-
throw new
|
|
1772
|
+
throw new SphereError(`No UTXOs available${modeText} for address: ` + senderAddress, "INSUFFICIENT_BALANCE");
|
|
1634
1773
|
}
|
|
1635
1774
|
return collectUtxosForAmount(utxos, amountSats, toAddress, senderAddress);
|
|
1636
1775
|
}
|
|
1637
1776
|
async function sendAlpha(wallet, toAddress, amountAlpha, fromAddress) {
|
|
1638
1777
|
const plan = await createTransactionPlan(wallet, toAddress, amountAlpha, fromAddress);
|
|
1639
1778
|
if (!plan.success) {
|
|
1640
|
-
throw new
|
|
1779
|
+
throw new SphereError(plan.error || "Transaction planning failed", "TRANSFER_FAILED");
|
|
1641
1780
|
}
|
|
1642
1781
|
const results = [];
|
|
1643
1782
|
for (const tx of plan.transactions) {
|
|
@@ -1704,7 +1843,7 @@ var L1PaymentsModule = class {
|
|
|
1704
1843
|
*/
|
|
1705
1844
|
async ensureConnected() {
|
|
1706
1845
|
if (this._disabled) {
|
|
1707
|
-
throw new
|
|
1846
|
+
throw new SphereError("L1 provider is disabled", "NOT_INITIALIZED");
|
|
1708
1847
|
}
|
|
1709
1848
|
if (!isWebSocketConnected() && this._config.electrumUrl) {
|
|
1710
1849
|
await connect(this._config.electrumUrl);
|
|
@@ -1759,8 +1898,9 @@ var L1PaymentsModule = class {
|
|
|
1759
1898
|
const l1Address = await this.resolveNametagToL1Address(recipient);
|
|
1760
1899
|
return l1Address;
|
|
1761
1900
|
} catch {
|
|
1762
|
-
throw new
|
|
1763
|
-
`Recipient "${recipient}" is not a valid nametag or L1 address. Use @nametag for explicit nametag or a valid alpha1... address
|
|
1901
|
+
throw new SphereError(
|
|
1902
|
+
`Recipient "${recipient}" is not a valid nametag or L1 address. Use @nametag for explicit nametag or a valid alpha1... address.`,
|
|
1903
|
+
"INVALID_RECIPIENT"
|
|
1764
1904
|
);
|
|
1765
1905
|
}
|
|
1766
1906
|
}
|
|
@@ -1769,15 +1909,16 @@ var L1PaymentsModule = class {
|
|
|
1769
1909
|
*/
|
|
1770
1910
|
async resolveNametagToL1Address(nametag) {
|
|
1771
1911
|
if (!this._transport?.resolve) {
|
|
1772
|
-
throw new
|
|
1912
|
+
throw new SphereError("Transport provider does not support resolution", "TRANSPORT_ERROR");
|
|
1773
1913
|
}
|
|
1774
1914
|
const info = await this._transport.resolve(nametag);
|
|
1775
1915
|
if (!info) {
|
|
1776
|
-
throw new
|
|
1916
|
+
throw new SphereError(`Nametag not found: ${nametag}`, "INVALID_RECIPIENT");
|
|
1777
1917
|
}
|
|
1778
1918
|
if (!info.l1Address) {
|
|
1779
|
-
throw new
|
|
1780
|
-
`Nametag @${nametag} does not have L1 address information. The owner needs to update their nametag registration
|
|
1919
|
+
throw new SphereError(
|
|
1920
|
+
`Nametag @${nametag} does not have L1 address information. The owner needs to update their nametag registration.`,
|
|
1921
|
+
"INVALID_RECIPIENT"
|
|
1781
1922
|
);
|
|
1782
1923
|
}
|
|
1783
1924
|
return info.l1Address;
|
|
@@ -2047,7 +2188,7 @@ var L1PaymentsModule = class {
|
|
|
2047
2188
|
}
|
|
2048
2189
|
ensureInitialized() {
|
|
2049
2190
|
if (!this._initialized) {
|
|
2050
|
-
throw new
|
|
2191
|
+
throw new SphereError("L1PaymentsModule not initialized", "NOT_INITIALIZED");
|
|
2051
2192
|
}
|
|
2052
2193
|
}
|
|
2053
2194
|
_getWatchedAddresses() {
|
|
@@ -2069,6 +2210,7 @@ var L1PaymentsModule = class {
|
|
|
2069
2210
|
};
|
|
2070
2211
|
|
|
2071
2212
|
// modules/payments/TokenSplitCalculator.ts
|
|
2213
|
+
init_logger();
|
|
2072
2214
|
import { Token as SdkToken } from "@unicitylabs/state-transition-sdk/lib/token/Token";
|
|
2073
2215
|
import { CoinId } from "@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId";
|
|
2074
2216
|
var TokenSplitCalculator = class {
|
|
@@ -2091,7 +2233,7 @@ var TokenSplitCalculator = class {
|
|
|
2091
2233
|
const sdkToken = await SdkToken.fromJSON(parsed);
|
|
2092
2234
|
const realAmount = this.getTokenBalance(sdkToken, targetCoinIdHex);
|
|
2093
2235
|
if (realAmount <= 0n) {
|
|
2094
|
-
|
|
2236
|
+
logger.warn("TokenSplit", `Token ${t.id} has 0 balance for coinId ${targetCoinIdHex}`);
|
|
2095
2237
|
continue;
|
|
2096
2238
|
}
|
|
2097
2239
|
candidates.push({
|
|
@@ -2100,14 +2242,15 @@ var TokenSplitCalculator = class {
|
|
|
2100
2242
|
uiToken: t
|
|
2101
2243
|
});
|
|
2102
2244
|
} catch (e) {
|
|
2103
|
-
|
|
2245
|
+
logger.warn("TokenSplit", "Failed to parse token", t.id, e);
|
|
2104
2246
|
}
|
|
2105
2247
|
}
|
|
2106
2248
|
candidates.sort((a, b) => a.amount < b.amount ? -1 : 1);
|
|
2107
2249
|
const totalAvailable = candidates.reduce((sum, t) => sum + t.amount, 0n);
|
|
2108
2250
|
if (totalAvailable < targetAmount) {
|
|
2109
|
-
|
|
2110
|
-
|
|
2251
|
+
logger.error(
|
|
2252
|
+
"TokenSplit",
|
|
2253
|
+
`Insufficient funds. Available: ${totalAvailable}, Required: ${targetAmount}`
|
|
2111
2254
|
);
|
|
2112
2255
|
return null;
|
|
2113
2256
|
}
|
|
@@ -2205,6 +2348,8 @@ var TokenSplitCalculator = class {
|
|
|
2205
2348
|
};
|
|
2206
2349
|
|
|
2207
2350
|
// modules/payments/TokenSplitExecutor.ts
|
|
2351
|
+
init_logger();
|
|
2352
|
+
init_errors();
|
|
2208
2353
|
import { Token } from "@unicitylabs/state-transition-sdk/lib/token/Token";
|
|
2209
2354
|
import { TokenId } from "@unicitylabs/state-transition-sdk/lib/token/TokenId";
|
|
2210
2355
|
import { TokenState } from "@unicitylabs/state-transition-sdk/lib/token/TokenState";
|
|
@@ -2244,7 +2389,7 @@ var TokenSplitExecutor = class {
|
|
|
2244
2389
|
}
|
|
2245
2390
|
async executeSplit(tokenToSplit, splitAmount, remainderAmount, coinIdHex, recipientAddress) {
|
|
2246
2391
|
const tokenIdHex = toHex(tokenToSplit.id.bytes);
|
|
2247
|
-
|
|
2392
|
+
logger.debug("TokenSplit", `Splitting token ${tokenIdHex.slice(0, 8)}...`);
|
|
2248
2393
|
const coinId = new CoinId2(fromHex(coinIdHex));
|
|
2249
2394
|
const seedString = `${tokenIdHex}_${splitAmount.toString()}_${remainderAmount.toString()}`;
|
|
2250
2395
|
const recipientTokenId = new TokenId(await sha2562(seedString));
|
|
@@ -2264,23 +2409,23 @@ var TokenSplitExecutor = class {
|
|
|
2264
2409
|
const coinDataB = TokenCoinData.create([[coinId, remainderAmount]]);
|
|
2265
2410
|
builder.createToken(senderTokenId, tokenToSplit.type, new Uint8Array(0), coinDataB, senderAddress, senderSalt, null);
|
|
2266
2411
|
const split = await builder.build(tokenToSplit);
|
|
2267
|
-
|
|
2412
|
+
logger.debug("TokenSplit", "Step 1: Burning original token...");
|
|
2268
2413
|
const burnSalt = await sha2562(seedString + "_burn_salt");
|
|
2269
2414
|
const burnCommitment = await split.createBurnCommitment(burnSalt, this.signingService);
|
|
2270
2415
|
const burnResponse = await this.client.submitTransferCommitment(burnCommitment);
|
|
2271
2416
|
if (burnResponse.status !== "SUCCESS" && burnResponse.status !== "REQUEST_ID_EXISTS") {
|
|
2272
|
-
throw new
|
|
2417
|
+
throw new SphereError(`Burn failed: ${burnResponse.status}`, "TRANSFER_FAILED");
|
|
2273
2418
|
}
|
|
2274
2419
|
const burnInclusionProof = await waitInclusionProof(this.trustBase, this.client, burnCommitment);
|
|
2275
2420
|
const burnTransaction = burnCommitment.toTransaction(burnInclusionProof);
|
|
2276
|
-
|
|
2277
|
-
|
|
2421
|
+
logger.debug("TokenSplit", "Original token burned.");
|
|
2422
|
+
logger.debug("TokenSplit", "Step 2: Minting split tokens...");
|
|
2278
2423
|
const mintCommitments = await split.createSplitMintCommitments(this.trustBase, burnTransaction);
|
|
2279
2424
|
const mintedTokensInfo = [];
|
|
2280
2425
|
for (const commitment of mintCommitments) {
|
|
2281
2426
|
const res = await this.client.submitMintCommitment(commitment);
|
|
2282
2427
|
if (res.status !== "SUCCESS" && res.status !== "REQUEST_ID_EXISTS") {
|
|
2283
|
-
throw new
|
|
2428
|
+
throw new SphereError(`Mint split token failed: ${res.status}`, "TRANSFER_FAILED");
|
|
2284
2429
|
}
|
|
2285
2430
|
const proof = await waitInclusionProof(this.trustBase, this.client, commitment);
|
|
2286
2431
|
const commTokenIdHex = toHex(commitment.transactionData.tokenId.bytes);
|
|
@@ -2293,7 +2438,7 @@ var TokenSplitExecutor = class {
|
|
|
2293
2438
|
salt: commitment.transactionData.salt
|
|
2294
2439
|
});
|
|
2295
2440
|
}
|
|
2296
|
-
|
|
2441
|
+
logger.debug("TokenSplit", "Split tokens minted.");
|
|
2297
2442
|
const recipientInfo = mintedTokensInfo.find((t) => t.isForRecipient);
|
|
2298
2443
|
const senderInfo = mintedTokensInfo.find((t) => !t.isForRecipient);
|
|
2299
2444
|
const createToken = async (info, label) => {
|
|
@@ -2301,12 +2446,12 @@ var TokenSplitExecutor = class {
|
|
|
2301
2446
|
const state = new TokenState(predicate, null);
|
|
2302
2447
|
const token = await Token.mint(this.trustBase, state, info.commitment.toTransaction(info.inclusionProof));
|
|
2303
2448
|
const verification = await token.verify(this.trustBase);
|
|
2304
|
-
if (!verification.isSuccessful) throw new
|
|
2449
|
+
if (!verification.isSuccessful) throw new SphereError(`Token verification failed: ${label}`, "TRANSFER_FAILED");
|
|
2305
2450
|
return token;
|
|
2306
2451
|
};
|
|
2307
2452
|
const recipientTokenBeforeTransfer = await createToken(recipientInfo, "Recipient");
|
|
2308
2453
|
const senderToken = await createToken(senderInfo, "Sender");
|
|
2309
|
-
|
|
2454
|
+
logger.debug("TokenSplit", "Step 3: Transferring to recipient...");
|
|
2310
2455
|
const transferSalt = await sha2562(seedString + "_transfer_salt");
|
|
2311
2456
|
const transferCommitment = await TransferCommitment.create(
|
|
2312
2457
|
recipientTokenBeforeTransfer,
|
|
@@ -2318,11 +2463,11 @@ var TokenSplitExecutor = class {
|
|
|
2318
2463
|
);
|
|
2319
2464
|
const transferRes = await this.client.submitTransferCommitment(transferCommitment);
|
|
2320
2465
|
if (transferRes.status !== "SUCCESS" && transferRes.status !== "REQUEST_ID_EXISTS") {
|
|
2321
|
-
throw new
|
|
2466
|
+
throw new SphereError(`Transfer failed: ${transferRes.status}`, "TRANSFER_FAILED");
|
|
2322
2467
|
}
|
|
2323
2468
|
const transferProof = await waitInclusionProof(this.trustBase, this.client, transferCommitment);
|
|
2324
2469
|
const transferTx = transferCommitment.toTransaction(transferProof);
|
|
2325
|
-
|
|
2470
|
+
logger.debug("TokenSplit", "Split transfer complete!");
|
|
2326
2471
|
return {
|
|
2327
2472
|
tokenForRecipient: recipientTokenBeforeTransfer,
|
|
2328
2473
|
tokenForSender: senderToken,
|
|
@@ -2332,6 +2477,7 @@ var TokenSplitExecutor = class {
|
|
|
2332
2477
|
};
|
|
2333
2478
|
|
|
2334
2479
|
// modules/payments/NametagMinter.ts
|
|
2480
|
+
init_logger();
|
|
2335
2481
|
import { Token as Token2 } from "@unicitylabs/state-transition-sdk/lib/token/Token";
|
|
2336
2482
|
import { TokenId as TokenId2 } from "@unicitylabs/state-transition-sdk/lib/token/TokenId";
|
|
2337
2483
|
import { TokenType } from "@unicitylabs/state-transition-sdk/lib/token/TokenType";
|
|
@@ -2356,10 +2502,8 @@ var NametagMinter = class {
|
|
|
2356
2502
|
this.skipVerification = config.skipVerification ?? false;
|
|
2357
2503
|
this.debug = config.debug ?? false;
|
|
2358
2504
|
}
|
|
2359
|
-
log(...args) {
|
|
2360
|
-
|
|
2361
|
-
console.log("[NametagMinter]", ...args);
|
|
2362
|
-
}
|
|
2505
|
+
log(message, ...args) {
|
|
2506
|
+
logger.debug("NametagMinter", message, ...args);
|
|
2363
2507
|
}
|
|
2364
2508
|
/**
|
|
2365
2509
|
* Check if a nametag is available (not already minted)
|
|
@@ -2543,6 +2687,7 @@ function parseForkedKey(key) {
|
|
|
2543
2687
|
}
|
|
2544
2688
|
|
|
2545
2689
|
// registry/TokenRegistry.ts
|
|
2690
|
+
init_logger();
|
|
2546
2691
|
init_constants();
|
|
2547
2692
|
var FETCH_TIMEOUT_MS = 1e4;
|
|
2548
2693
|
var TokenRegistry = class _TokenRegistry {
|
|
@@ -2764,14 +2909,12 @@ var TokenRegistry = class _TokenRegistry {
|
|
|
2764
2909
|
clearTimeout(timer);
|
|
2765
2910
|
}
|
|
2766
2911
|
if (!response.ok) {
|
|
2767
|
-
|
|
2768
|
-
`[TokenRegistry] Remote fetch failed: HTTP ${response.status} ${response.statusText}`
|
|
2769
|
-
);
|
|
2912
|
+
logger.warn("TokenRegistry", `Remote fetch failed: HTTP ${response.status} ${response.statusText}`);
|
|
2770
2913
|
return false;
|
|
2771
2914
|
}
|
|
2772
2915
|
const data = await response.json();
|
|
2773
2916
|
if (!this.isValidDefinitionsArray(data)) {
|
|
2774
|
-
|
|
2917
|
+
logger.warn("TokenRegistry", "Remote data is not a valid token definitions array");
|
|
2775
2918
|
return false;
|
|
2776
2919
|
}
|
|
2777
2920
|
const definitions = data;
|
|
@@ -2781,7 +2924,7 @@ var TokenRegistry = class _TokenRegistry {
|
|
|
2781
2924
|
return true;
|
|
2782
2925
|
} catch (error) {
|
|
2783
2926
|
const message = error instanceof Error ? error.message : String(error);
|
|
2784
|
-
|
|
2927
|
+
logger.warn("TokenRegistry", `Remote refresh failed: ${message}`);
|
|
2785
2928
|
return false;
|
|
2786
2929
|
}
|
|
2787
2930
|
}
|
|
@@ -3258,7 +3401,13 @@ function getCurrentStateHash(txf) {
|
|
|
3258
3401
|
return void 0;
|
|
3259
3402
|
}
|
|
3260
3403
|
|
|
3404
|
+
// modules/payments/PaymentsModule.ts
|
|
3405
|
+
init_logger();
|
|
3406
|
+
init_errors();
|
|
3407
|
+
|
|
3261
3408
|
// modules/payments/InstantSplitExecutor.ts
|
|
3409
|
+
init_logger();
|
|
3410
|
+
init_errors();
|
|
3262
3411
|
import { Token as Token3 } from "@unicitylabs/state-transition-sdk/lib/token/Token";
|
|
3263
3412
|
import { TokenId as TokenId3 } from "@unicitylabs/state-transition-sdk/lib/token/TokenId";
|
|
3264
3413
|
import { TokenState as TokenState3 } from "@unicitylabs/state-transition-sdk/lib/token/TokenState";
|
|
@@ -3314,7 +3463,7 @@ var InstantSplitExecutor = class {
|
|
|
3314
3463
|
async buildSplitBundle(tokenToSplit, splitAmount, remainderAmount, coinIdHex, recipientAddress, options) {
|
|
3315
3464
|
const splitGroupId = crypto.randomUUID();
|
|
3316
3465
|
const tokenIdHex = toHex2(tokenToSplit.id.bytes);
|
|
3317
|
-
|
|
3466
|
+
logger.debug("InstantSplit", `Building V5 bundle for token ${tokenIdHex.slice(0, 8)}...`);
|
|
3318
3467
|
const coinId = new CoinId3(fromHex2(coinIdHex));
|
|
3319
3468
|
const seedString = `${tokenIdHex}_${splitAmount.toString()}_${remainderAmount.toString()}_${Date.now()}`;
|
|
3320
3469
|
const recipientTokenId = new TokenId3(await sha2563(seedString));
|
|
@@ -3351,19 +3500,19 @@ var InstantSplitExecutor = class {
|
|
|
3351
3500
|
null
|
|
3352
3501
|
);
|
|
3353
3502
|
const split = await builder.build(tokenToSplit);
|
|
3354
|
-
|
|
3503
|
+
logger.debug("InstantSplit", "Step 1: Creating and submitting burn...");
|
|
3355
3504
|
const burnSalt = await sha2563(seedString + "_burn_salt");
|
|
3356
3505
|
const burnCommitment = await split.createBurnCommitment(burnSalt, this.signingService);
|
|
3357
3506
|
const burnResponse = await this.client.submitTransferCommitment(burnCommitment);
|
|
3358
3507
|
if (burnResponse.status !== "SUCCESS" && burnResponse.status !== "REQUEST_ID_EXISTS") {
|
|
3359
|
-
throw new
|
|
3508
|
+
throw new SphereError(`Burn submission failed: ${burnResponse.status}`, "TRANSFER_FAILED");
|
|
3360
3509
|
}
|
|
3361
|
-
|
|
3510
|
+
logger.debug("InstantSplit", "Step 2: Waiting for burn proof...");
|
|
3362
3511
|
const burnProof = this.devMode ? await this.waitInclusionProofWithDevBypass(burnCommitment, options?.burnProofTimeoutMs) : await waitInclusionProof3(this.trustBase, this.client, burnCommitment);
|
|
3363
3512
|
const burnTransaction = burnCommitment.toTransaction(burnProof);
|
|
3364
|
-
|
|
3513
|
+
logger.debug("InstantSplit", "Burn proof received");
|
|
3365
3514
|
options?.onBurnCompleted?.(JSON.stringify(burnTransaction.toJSON()));
|
|
3366
|
-
|
|
3515
|
+
logger.debug("InstantSplit", "Step 3: Creating mint commitments...");
|
|
3367
3516
|
const mintCommitments = await split.createSplitMintCommitments(this.trustBase, burnTransaction);
|
|
3368
3517
|
const recipientIdHex = toHex2(recipientTokenId.bytes);
|
|
3369
3518
|
const senderIdHex = toHex2(senderTokenId.bytes);
|
|
@@ -3374,9 +3523,9 @@ var InstantSplitExecutor = class {
|
|
|
3374
3523
|
(c) => toHex2(c.transactionData.tokenId.bytes) === senderIdHex
|
|
3375
3524
|
);
|
|
3376
3525
|
if (!recipientMintCommitment || !senderMintCommitment) {
|
|
3377
|
-
throw new
|
|
3526
|
+
throw new SphereError("Failed to find expected mint commitments", "TRANSFER_FAILED");
|
|
3378
3527
|
}
|
|
3379
|
-
|
|
3528
|
+
logger.debug("InstantSplit", "Step 4: Creating transfer commitment...");
|
|
3380
3529
|
const transferSalt = await sha2563(seedString + "_transfer_salt");
|
|
3381
3530
|
const transferCommitment = await this.createTransferCommitmentFromMintData(
|
|
3382
3531
|
recipientMintCommitment.transactionData,
|
|
@@ -3392,7 +3541,7 @@ var InstantSplitExecutor = class {
|
|
|
3392
3541
|
recipientSalt
|
|
3393
3542
|
);
|
|
3394
3543
|
const mintedState = new TokenState3(mintedPredicate, null);
|
|
3395
|
-
|
|
3544
|
+
logger.debug("InstantSplit", "Step 5: Packaging V5 bundle...");
|
|
3396
3545
|
const senderPubkey = toHex2(this.signingService.publicKey);
|
|
3397
3546
|
let nametagTokenJson;
|
|
3398
3547
|
const recipientAddressStr = recipientAddress.toString();
|
|
@@ -3464,7 +3613,7 @@ var InstantSplitExecutor = class {
|
|
|
3464
3613
|
recipientAddress,
|
|
3465
3614
|
options
|
|
3466
3615
|
);
|
|
3467
|
-
|
|
3616
|
+
logger.debug("InstantSplit", "Sending via transport...");
|
|
3468
3617
|
const senderPubkey = toHex2(this.signingService.publicKey);
|
|
3469
3618
|
const nostrEventId = await transport.sendTokenTransfer(recipientPubkey, {
|
|
3470
3619
|
token: JSON.stringify(buildResult.bundle),
|
|
@@ -3476,7 +3625,7 @@ var InstantSplitExecutor = class {
|
|
|
3476
3625
|
}
|
|
3477
3626
|
});
|
|
3478
3627
|
const criticalPathDuration = performance.now() - startTime;
|
|
3479
|
-
|
|
3628
|
+
logger.debug("InstantSplit", `V5 complete in ${criticalPathDuration.toFixed(0)}ms`);
|
|
3480
3629
|
options?.onNostrDelivered?.(nostrEventId);
|
|
3481
3630
|
const backgroundPromise = buildResult.startBackground();
|
|
3482
3631
|
return {
|
|
@@ -3490,7 +3639,7 @@ var InstantSplitExecutor = class {
|
|
|
3490
3639
|
} catch (error) {
|
|
3491
3640
|
const duration = performance.now() - startTime;
|
|
3492
3641
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3493
|
-
|
|
3642
|
+
logger.error("InstantSplit", `Failed after ${duration.toFixed(0)}ms:`, error);
|
|
3494
3643
|
return {
|
|
3495
3644
|
success: false,
|
|
3496
3645
|
criticalPathDurationMs: duration,
|
|
@@ -3539,7 +3688,7 @@ var InstantSplitExecutor = class {
|
|
|
3539
3688
|
* Then waits for sender's mint proof, reconstructs change token, and saves it.
|
|
3540
3689
|
*/
|
|
3541
3690
|
submitBackgroundV5(senderMintCommitment, recipientMintCommitment, transferCommitment, context) {
|
|
3542
|
-
|
|
3691
|
+
logger.debug("InstantSplit", "Background: Starting parallel mint submission...");
|
|
3543
3692
|
const startTime = performance.now();
|
|
3544
3693
|
const submissions = Promise.all([
|
|
3545
3694
|
this.client.submitMintCommitment(senderMintCommitment).then((res) => ({ type: "senderMint", status: res.status })).catch((err) => ({ type: "senderMint", status: "ERROR", error: err })),
|
|
@@ -3548,14 +3697,14 @@ var InstantSplitExecutor = class {
|
|
|
3548
3697
|
]);
|
|
3549
3698
|
return submissions.then(async (results) => {
|
|
3550
3699
|
const submitDuration = performance.now() - startTime;
|
|
3551
|
-
|
|
3700
|
+
logger.debug("InstantSplit", `Background: Submissions complete in ${submitDuration.toFixed(0)}ms`);
|
|
3552
3701
|
context.onProgress?.({
|
|
3553
3702
|
stage: "MINTS_SUBMITTED",
|
|
3554
3703
|
message: `All commitments submitted in ${submitDuration.toFixed(0)}ms`
|
|
3555
3704
|
});
|
|
3556
3705
|
const senderMintResult = results.find((r) => r.type === "senderMint");
|
|
3557
3706
|
if (senderMintResult?.status !== "SUCCESS" && senderMintResult?.status !== "REQUEST_ID_EXISTS") {
|
|
3558
|
-
|
|
3707
|
+
logger.error("InstantSplit", "Background: Sender mint failed - cannot save change token");
|
|
3559
3708
|
context.onProgress?.({
|
|
3560
3709
|
stage: "FAILED",
|
|
3561
3710
|
message: "Sender mint submission failed",
|
|
@@ -3563,12 +3712,12 @@ var InstantSplitExecutor = class {
|
|
|
3563
3712
|
});
|
|
3564
3713
|
return;
|
|
3565
3714
|
}
|
|
3566
|
-
|
|
3715
|
+
logger.debug("InstantSplit", "Background: Waiting for sender mint proof...");
|
|
3567
3716
|
const proofStartTime = performance.now();
|
|
3568
3717
|
try {
|
|
3569
3718
|
const senderMintProof = this.devMode ? await this.waitInclusionProofWithDevBypass(senderMintCommitment) : await waitInclusionProof3(this.trustBase, this.client, senderMintCommitment);
|
|
3570
3719
|
const proofDuration = performance.now() - proofStartTime;
|
|
3571
|
-
|
|
3720
|
+
logger.debug("InstantSplit", `Background: Sender mint proof received in ${proofDuration.toFixed(0)}ms`);
|
|
3572
3721
|
context.onProgress?.({
|
|
3573
3722
|
stage: "MINTS_PROVEN",
|
|
3574
3723
|
message: `Mint proof received in ${proofDuration.toFixed(0)}ms`
|
|
@@ -3586,38 +3735,38 @@ var InstantSplitExecutor = class {
|
|
|
3586
3735
|
if (!this.devMode) {
|
|
3587
3736
|
const verification = await changeToken.verify(this.trustBase);
|
|
3588
3737
|
if (!verification.isSuccessful) {
|
|
3589
|
-
throw new
|
|
3738
|
+
throw new SphereError("Change token verification failed", "TRANSFER_FAILED");
|
|
3590
3739
|
}
|
|
3591
3740
|
}
|
|
3592
|
-
|
|
3741
|
+
logger.debug("InstantSplit", "Background: Change token created");
|
|
3593
3742
|
context.onProgress?.({
|
|
3594
3743
|
stage: "CHANGE_TOKEN_SAVED",
|
|
3595
3744
|
message: "Change token created and verified"
|
|
3596
3745
|
});
|
|
3597
3746
|
if (context.onChangeTokenCreated) {
|
|
3598
3747
|
await context.onChangeTokenCreated(changeToken);
|
|
3599
|
-
|
|
3748
|
+
logger.debug("InstantSplit", "Background: Change token saved");
|
|
3600
3749
|
}
|
|
3601
3750
|
if (context.onStorageSync) {
|
|
3602
3751
|
try {
|
|
3603
3752
|
const syncSuccess = await context.onStorageSync();
|
|
3604
|
-
|
|
3753
|
+
logger.debug("InstantSplit", `Background: Storage sync ${syncSuccess ? "completed" : "deferred"}`);
|
|
3605
3754
|
context.onProgress?.({
|
|
3606
3755
|
stage: "STORAGE_SYNCED",
|
|
3607
3756
|
message: syncSuccess ? "Storage synchronized" : "Sync deferred"
|
|
3608
3757
|
});
|
|
3609
3758
|
} catch (syncError) {
|
|
3610
|
-
|
|
3759
|
+
logger.warn("InstantSplit", "Background: Storage sync error:", syncError);
|
|
3611
3760
|
}
|
|
3612
3761
|
}
|
|
3613
3762
|
const totalDuration = performance.now() - startTime;
|
|
3614
|
-
|
|
3763
|
+
logger.debug("InstantSplit", `Background: Complete in ${totalDuration.toFixed(0)}ms`);
|
|
3615
3764
|
context.onProgress?.({
|
|
3616
3765
|
stage: "COMPLETED",
|
|
3617
3766
|
message: `Background processing complete in ${totalDuration.toFixed(0)}ms`
|
|
3618
3767
|
});
|
|
3619
3768
|
} catch (proofError) {
|
|
3620
|
-
|
|
3769
|
+
logger.error("InstantSplit", "Background: Failed to get sender mint proof:", proofError);
|
|
3621
3770
|
context.onProgress?.({
|
|
3622
3771
|
stage: "FAILED",
|
|
3623
3772
|
message: "Failed to get mint proof",
|
|
@@ -3625,7 +3774,7 @@ var InstantSplitExecutor = class {
|
|
|
3625
3774
|
});
|
|
3626
3775
|
}
|
|
3627
3776
|
}).catch((err) => {
|
|
3628
|
-
|
|
3777
|
+
logger.error("InstantSplit", "Background: Submission batch failed:", err);
|
|
3629
3778
|
context.onProgress?.({
|
|
3630
3779
|
stage: "FAILED",
|
|
3631
3780
|
message: "Background submission failed",
|
|
@@ -3647,7 +3796,7 @@ var InstantSplitExecutor = class {
|
|
|
3647
3796
|
)
|
|
3648
3797
|
]);
|
|
3649
3798
|
} catch {
|
|
3650
|
-
|
|
3799
|
+
logger.debug("InstantSplit", "Dev mode: Using mock proof");
|
|
3651
3800
|
return {
|
|
3652
3801
|
toJSON: () => ({ mock: true })
|
|
3653
3802
|
};
|
|
@@ -3658,6 +3807,8 @@ var InstantSplitExecutor = class {
|
|
|
3658
3807
|
};
|
|
3659
3808
|
|
|
3660
3809
|
// modules/payments/InstantSplitProcessor.ts
|
|
3810
|
+
init_logger();
|
|
3811
|
+
init_errors();
|
|
3661
3812
|
import { Token as Token4 } from "@unicitylabs/state-transition-sdk/lib/token/Token";
|
|
3662
3813
|
import { TokenState as TokenState4 } from "@unicitylabs/state-transition-sdk/lib/token/TokenState";
|
|
3663
3814
|
import { TokenType as TokenType2 } from "@unicitylabs/state-transition-sdk/lib/token/TokenType";
|
|
@@ -3752,27 +3903,27 @@ var InstantSplitProcessor = class {
|
|
|
3752
3903
|
* 5. Create recipient's final state and finalize token
|
|
3753
3904
|
*/
|
|
3754
3905
|
async processV5Bundle(bundle, signingService, senderPubkey, options) {
|
|
3755
|
-
|
|
3906
|
+
logger.debug("InstantSplit", "Processing V5 bundle...");
|
|
3756
3907
|
const startTime = performance.now();
|
|
3757
3908
|
try {
|
|
3758
3909
|
if (bundle.senderPubkey !== senderPubkey) {
|
|
3759
|
-
|
|
3910
|
+
logger.warn("InstantSplit", "Sender pubkey mismatch (non-fatal)");
|
|
3760
3911
|
}
|
|
3761
3912
|
const burnTxJson = JSON.parse(bundle.burnTransaction);
|
|
3762
3913
|
const _burnTransaction = await TransferTransaction.fromJSON(burnTxJson);
|
|
3763
|
-
|
|
3914
|
+
logger.debug("InstantSplit", "Burn transaction validated");
|
|
3764
3915
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
3765
3916
|
const mintData = await MintTransactionData2.fromJSON(mintDataJson);
|
|
3766
3917
|
const mintCommitment = await MintCommitment2.create(mintData);
|
|
3767
|
-
|
|
3918
|
+
logger.debug("InstantSplit", "Mint commitment recreated");
|
|
3768
3919
|
const mintResponse = await this.client.submitMintCommitment(mintCommitment);
|
|
3769
3920
|
if (mintResponse.status !== "SUCCESS" && mintResponse.status !== "REQUEST_ID_EXISTS") {
|
|
3770
|
-
throw new
|
|
3921
|
+
throw new SphereError(`Mint submission failed: ${mintResponse.status}`, "TRANSFER_FAILED");
|
|
3771
3922
|
}
|
|
3772
|
-
|
|
3923
|
+
logger.debug("InstantSplit", `Mint submitted: ${mintResponse.status}`);
|
|
3773
3924
|
const mintProof = this.devMode ? await this.waitInclusionProofWithDevBypass(mintCommitment, options?.proofTimeoutMs) : await waitInclusionProof4(this.trustBase, this.client, mintCommitment);
|
|
3774
3925
|
const mintTransaction = mintCommitment.toTransaction(mintProof);
|
|
3775
|
-
|
|
3926
|
+
logger.debug("InstantSplit", "Mint proof received");
|
|
3776
3927
|
const tokenType = new TokenType2(fromHex3(bundle.tokenTypeHex));
|
|
3777
3928
|
const senderMintedStateJson = JSON.parse(bundle.mintedTokenStateJson);
|
|
3778
3929
|
const tokenJson = {
|
|
@@ -3783,17 +3934,17 @@ var InstantSplitProcessor = class {
|
|
|
3783
3934
|
nametags: []
|
|
3784
3935
|
};
|
|
3785
3936
|
const mintedToken = await Token4.fromJSON(tokenJson);
|
|
3786
|
-
|
|
3937
|
+
logger.debug("InstantSplit", "Minted token reconstructed from sender state");
|
|
3787
3938
|
const transferCommitmentJson = JSON.parse(bundle.transferCommitment);
|
|
3788
3939
|
const transferCommitment = await TransferCommitment3.fromJSON(transferCommitmentJson);
|
|
3789
3940
|
const transferResponse = await this.client.submitTransferCommitment(transferCommitment);
|
|
3790
3941
|
if (transferResponse.status !== "SUCCESS" && transferResponse.status !== "REQUEST_ID_EXISTS") {
|
|
3791
|
-
throw new
|
|
3942
|
+
throw new SphereError(`Transfer submission failed: ${transferResponse.status}`, "TRANSFER_FAILED");
|
|
3792
3943
|
}
|
|
3793
|
-
|
|
3944
|
+
logger.debug("InstantSplit", `Transfer submitted: ${transferResponse.status}`);
|
|
3794
3945
|
const transferProof = this.devMode ? await this.waitInclusionProofWithDevBypass(transferCommitment, options?.proofTimeoutMs) : await waitInclusionProof4(this.trustBase, this.client, transferCommitment);
|
|
3795
3946
|
const transferTransaction = transferCommitment.toTransaction(transferProof);
|
|
3796
|
-
|
|
3947
|
+
logger.debug("InstantSplit", "Transfer proof received");
|
|
3797
3948
|
const transferSalt = fromHex3(bundle.transferSaltHex);
|
|
3798
3949
|
const finalRecipientPredicate = await UnmaskedPredicate4.create(
|
|
3799
3950
|
mintData.tokenId,
|
|
@@ -3803,42 +3954,43 @@ var InstantSplitProcessor = class {
|
|
|
3803
3954
|
transferSalt
|
|
3804
3955
|
);
|
|
3805
3956
|
const finalRecipientState = new TokenState4(finalRecipientPredicate, null);
|
|
3806
|
-
|
|
3957
|
+
logger.debug("InstantSplit", "Final recipient state created");
|
|
3807
3958
|
let nametagTokens = [];
|
|
3808
3959
|
const recipientAddressStr = bundle.recipientAddressJson;
|
|
3809
3960
|
if (recipientAddressStr.startsWith("PROXY://")) {
|
|
3810
|
-
|
|
3961
|
+
logger.debug("InstantSplit", "PROXY address detected, finding nametag token...");
|
|
3811
3962
|
if (bundle.nametagTokenJson) {
|
|
3812
3963
|
try {
|
|
3813
3964
|
const nametagToken = await Token4.fromJSON(JSON.parse(bundle.nametagTokenJson));
|
|
3814
3965
|
const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
|
|
3815
3966
|
const proxy = await ProxyAddress.fromTokenId(nametagToken.id);
|
|
3816
3967
|
if (proxy.address !== recipientAddressStr) {
|
|
3817
|
-
|
|
3968
|
+
logger.warn("InstantSplit", "Nametag PROXY address mismatch, ignoring bundle token");
|
|
3818
3969
|
} else {
|
|
3819
3970
|
nametagTokens = [nametagToken];
|
|
3820
|
-
|
|
3971
|
+
logger.debug("InstantSplit", "Using nametag token from bundle (address validated)");
|
|
3821
3972
|
}
|
|
3822
3973
|
} catch (err) {
|
|
3823
|
-
|
|
3974
|
+
logger.warn("InstantSplit", "Failed to parse nametag token from bundle:", err);
|
|
3824
3975
|
}
|
|
3825
3976
|
}
|
|
3826
3977
|
if (nametagTokens.length === 0 && options?.findNametagToken) {
|
|
3827
3978
|
const token = await options.findNametagToken(recipientAddressStr);
|
|
3828
3979
|
if (token) {
|
|
3829
3980
|
nametagTokens = [token];
|
|
3830
|
-
|
|
3981
|
+
logger.debug("InstantSplit", "Found nametag token via callback");
|
|
3831
3982
|
}
|
|
3832
3983
|
}
|
|
3833
3984
|
if (nametagTokens.length === 0 && !this.devMode) {
|
|
3834
|
-
throw new
|
|
3835
|
-
`PROXY address transfer requires nametag token for verification. Address: ${recipientAddressStr}
|
|
3985
|
+
throw new SphereError(
|
|
3986
|
+
`PROXY address transfer requires nametag token for verification. Address: ${recipientAddressStr}`,
|
|
3987
|
+
"TRANSFER_FAILED"
|
|
3836
3988
|
);
|
|
3837
3989
|
}
|
|
3838
3990
|
}
|
|
3839
3991
|
let finalToken;
|
|
3840
3992
|
if (this.devMode) {
|
|
3841
|
-
|
|
3993
|
+
logger.debug("InstantSplit", "Dev mode: finalizing without verification");
|
|
3842
3994
|
const tokenJson2 = mintedToken.toJSON();
|
|
3843
3995
|
tokenJson2.state = finalRecipientState.toJSON();
|
|
3844
3996
|
tokenJson2.transactions = [transferTransaction.toJSON()];
|
|
@@ -3852,16 +4004,16 @@ var InstantSplitProcessor = class {
|
|
|
3852
4004
|
nametagTokens
|
|
3853
4005
|
);
|
|
3854
4006
|
}
|
|
3855
|
-
|
|
4007
|
+
logger.debug("InstantSplit", "Token finalized");
|
|
3856
4008
|
if (!this.devMode) {
|
|
3857
4009
|
const verification = await finalToken.verify(this.trustBase);
|
|
3858
4010
|
if (!verification.isSuccessful) {
|
|
3859
|
-
throw new
|
|
4011
|
+
throw new SphereError(`Token verification failed`, "TRANSFER_FAILED");
|
|
3860
4012
|
}
|
|
3861
|
-
|
|
4013
|
+
logger.debug("InstantSplit", "Token verified");
|
|
3862
4014
|
}
|
|
3863
4015
|
const duration = performance.now() - startTime;
|
|
3864
|
-
|
|
4016
|
+
logger.debug("InstantSplit", `V5 bundle processed in ${duration.toFixed(0)}ms`);
|
|
3865
4017
|
return {
|
|
3866
4018
|
success: true,
|
|
3867
4019
|
token: finalToken,
|
|
@@ -3870,7 +4022,7 @@ var InstantSplitProcessor = class {
|
|
|
3870
4022
|
} catch (error) {
|
|
3871
4023
|
const duration = performance.now() - startTime;
|
|
3872
4024
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3873
|
-
|
|
4025
|
+
logger.error("InstantSplit", "V5 processing failed:", error);
|
|
3874
4026
|
return {
|
|
3875
4027
|
success: false,
|
|
3876
4028
|
error: errorMessage,
|
|
@@ -3896,30 +4048,30 @@ var InstantSplitProcessor = class {
|
|
|
3896
4048
|
durationMs: 0
|
|
3897
4049
|
};
|
|
3898
4050
|
}
|
|
3899
|
-
|
|
4051
|
+
logger.debug("InstantSplit", "Processing V4 bundle (dev mode)...");
|
|
3900
4052
|
const startTime = performance.now();
|
|
3901
4053
|
try {
|
|
3902
4054
|
const burnCommitmentJson = JSON.parse(bundle.burnCommitment);
|
|
3903
4055
|
const burnCommitment = await TransferCommitment3.fromJSON(burnCommitmentJson);
|
|
3904
4056
|
const burnResponse = await this.client.submitTransferCommitment(burnCommitment);
|
|
3905
4057
|
if (burnResponse.status !== "SUCCESS" && burnResponse.status !== "REQUEST_ID_EXISTS") {
|
|
3906
|
-
throw new
|
|
4058
|
+
throw new SphereError(`Burn submission failed: ${burnResponse.status}`, "TRANSFER_FAILED");
|
|
3907
4059
|
}
|
|
3908
4060
|
await this.waitInclusionProofWithDevBypass(burnCommitment, options?.proofTimeoutMs);
|
|
3909
|
-
|
|
4061
|
+
logger.debug("InstantSplit", "V4: Burn proof received");
|
|
3910
4062
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
3911
4063
|
const mintData = await MintTransactionData2.fromJSON(mintDataJson);
|
|
3912
4064
|
const mintCommitment = await MintCommitment2.create(mintData);
|
|
3913
4065
|
const mintResponse = await this.client.submitMintCommitment(mintCommitment);
|
|
3914
4066
|
if (mintResponse.status !== "SUCCESS" && mintResponse.status !== "REQUEST_ID_EXISTS") {
|
|
3915
|
-
throw new
|
|
4067
|
+
throw new SphereError(`Mint submission failed: ${mintResponse.status}`, "TRANSFER_FAILED");
|
|
3916
4068
|
}
|
|
3917
4069
|
const mintProof = await this.waitInclusionProofWithDevBypass(
|
|
3918
4070
|
mintCommitment,
|
|
3919
4071
|
options?.proofTimeoutMs
|
|
3920
4072
|
);
|
|
3921
4073
|
const mintTransaction = mintCommitment.toTransaction(mintProof);
|
|
3922
|
-
|
|
4074
|
+
logger.debug("InstantSplit", "V4: Mint proof received");
|
|
3923
4075
|
const tokenType = new TokenType2(fromHex3(bundle.tokenTypeHex));
|
|
3924
4076
|
const recipientSalt = fromHex3(bundle.recipientSaltHex);
|
|
3925
4077
|
const recipientPredicate = await UnmaskedPredicate4.create(
|
|
@@ -3938,19 +4090,19 @@ var InstantSplitProcessor = class {
|
|
|
3938
4090
|
nametags: []
|
|
3939
4091
|
};
|
|
3940
4092
|
const mintedToken = await Token4.fromJSON(tokenJson);
|
|
3941
|
-
|
|
4093
|
+
logger.debug("InstantSplit", "V4: Minted token reconstructed");
|
|
3942
4094
|
const transferCommitmentJson = JSON.parse(bundle.transferCommitment);
|
|
3943
4095
|
const transferCommitment = await TransferCommitment3.fromJSON(transferCommitmentJson);
|
|
3944
4096
|
const transferResponse = await this.client.submitTransferCommitment(transferCommitment);
|
|
3945
4097
|
if (transferResponse.status !== "SUCCESS" && transferResponse.status !== "REQUEST_ID_EXISTS") {
|
|
3946
|
-
throw new
|
|
4098
|
+
throw new SphereError(`Transfer submission failed: ${transferResponse.status}`, "TRANSFER_FAILED");
|
|
3947
4099
|
}
|
|
3948
4100
|
const transferProof = await this.waitInclusionProofWithDevBypass(
|
|
3949
4101
|
transferCommitment,
|
|
3950
4102
|
options?.proofTimeoutMs
|
|
3951
4103
|
);
|
|
3952
4104
|
const transferTransaction = transferCommitment.toTransaction(transferProof);
|
|
3953
|
-
|
|
4105
|
+
logger.debug("InstantSplit", "V4: Transfer proof received");
|
|
3954
4106
|
const transferSalt = fromHex3(bundle.transferSaltHex);
|
|
3955
4107
|
const finalPredicate = await UnmaskedPredicate4.create(
|
|
3956
4108
|
mintData.tokenId,
|
|
@@ -3964,9 +4116,9 @@ var InstantSplitProcessor = class {
|
|
|
3964
4116
|
finalTokenJson.state = finalState.toJSON();
|
|
3965
4117
|
finalTokenJson.transactions = [transferTransaction.toJSON()];
|
|
3966
4118
|
const finalToken = await Token4.fromJSON(finalTokenJson);
|
|
3967
|
-
|
|
4119
|
+
logger.debug("InstantSplit", "V4: Token finalized");
|
|
3968
4120
|
const duration = performance.now() - startTime;
|
|
3969
|
-
|
|
4121
|
+
logger.debug("InstantSplit", `V4 bundle processed in ${duration.toFixed(0)}ms`);
|
|
3970
4122
|
return {
|
|
3971
4123
|
success: true,
|
|
3972
4124
|
token: finalToken,
|
|
@@ -3975,7 +4127,7 @@ var InstantSplitProcessor = class {
|
|
|
3975
4127
|
} catch (error) {
|
|
3976
4128
|
const duration = performance.now() - startTime;
|
|
3977
4129
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3978
|
-
|
|
4130
|
+
logger.error("InstantSplit", "V4 processing failed:", error);
|
|
3979
4131
|
return {
|
|
3980
4132
|
success: false,
|
|
3981
4133
|
error: errorMessage,
|
|
@@ -3996,7 +4148,7 @@ var InstantSplitProcessor = class {
|
|
|
3996
4148
|
)
|
|
3997
4149
|
]);
|
|
3998
4150
|
} catch {
|
|
3999
|
-
|
|
4151
|
+
logger.debug("InstantSplit", "Dev mode: Using mock proof");
|
|
4000
4152
|
return {
|
|
4001
4153
|
toJSON: () => ({ mock: true })
|
|
4002
4154
|
};
|
|
@@ -4181,7 +4333,7 @@ async function parseTokenInfo(tokenData) {
|
|
|
4181
4333
|
}
|
|
4182
4334
|
}
|
|
4183
4335
|
} catch (error) {
|
|
4184
|
-
|
|
4336
|
+
logger.warn("Payments", "Failed to parse token info:", error);
|
|
4185
4337
|
}
|
|
4186
4338
|
return defaultInfo;
|
|
4187
4339
|
}
|
|
@@ -4384,11 +4536,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4384
4536
|
}
|
|
4385
4537
|
/** Price provider (optional) */
|
|
4386
4538
|
priceProvider = null;
|
|
4387
|
-
log(...args) {
|
|
4388
|
-
if (this.moduleConfig.debug) {
|
|
4389
|
-
console.log("[PaymentsModule]", ...args);
|
|
4390
|
-
}
|
|
4391
|
-
}
|
|
4392
4539
|
// ===========================================================================
|
|
4393
4540
|
// Lifecycle
|
|
4394
4541
|
// ===========================================================================
|
|
@@ -4455,11 +4602,11 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4455
4602
|
if (txfData._history && txfData._history.length > 0) {
|
|
4456
4603
|
await this.importRemoteHistoryEntries(txfData._history);
|
|
4457
4604
|
}
|
|
4458
|
-
|
|
4605
|
+
logger.debug("Payments", `Loaded metadata from provider ${id}`);
|
|
4459
4606
|
break;
|
|
4460
4607
|
}
|
|
4461
4608
|
} catch (err) {
|
|
4462
|
-
|
|
4609
|
+
logger.error("Payments", `Failed to load from provider ${id}:`, err);
|
|
4463
4610
|
}
|
|
4464
4611
|
}
|
|
4465
4612
|
for (const [id, token] of this.tokens) {
|
|
@@ -4468,14 +4615,14 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4468
4615
|
const data = JSON.parse(token.sdkData);
|
|
4469
4616
|
if (data?._placeholder) {
|
|
4470
4617
|
this.tokens.delete(id);
|
|
4471
|
-
|
|
4618
|
+
logger.debug("Payments", `Removed stale placeholder token: ${id}`);
|
|
4472
4619
|
}
|
|
4473
4620
|
}
|
|
4474
4621
|
} catch {
|
|
4475
4622
|
}
|
|
4476
4623
|
}
|
|
4477
4624
|
const loadedTokens = Array.from(this.tokens.values()).map((t) => `${t.id.slice(0, 12)}(${t.status})`);
|
|
4478
|
-
|
|
4625
|
+
logger.debug("Payments", `load(): from TXF providers: ${this.tokens.size} tokens [${loadedTokens.join(", ")}]`);
|
|
4479
4626
|
await this.loadPendingV5Tokens();
|
|
4480
4627
|
await this.loadProcessedSplitGroupIds();
|
|
4481
4628
|
await this.loadProcessedCombinedTransferIds();
|
|
@@ -4491,8 +4638,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4491
4638
|
};
|
|
4492
4639
|
this.loadedPromise = doLoad();
|
|
4493
4640
|
await this.loadedPromise;
|
|
4494
|
-
this.resolveUnconfirmed().catch(() =>
|
|
4495
|
-
});
|
|
4641
|
+
this.resolveUnconfirmed().catch((err) => logger.debug("Payments", "resolveUnconfirmed failed", err));
|
|
4496
4642
|
this.scheduleResolveUnconfirmed();
|
|
4497
4643
|
}
|
|
4498
4644
|
/**
|
|
@@ -4545,11 +4691,11 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4545
4691
|
const signingService = await this.createSigningService();
|
|
4546
4692
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
4547
4693
|
if (!stClient) {
|
|
4548
|
-
throw new
|
|
4694
|
+
throw new SphereError("State transition client not available. Oracle provider must implement getStateTransitionClient()", "AGGREGATOR_ERROR");
|
|
4549
4695
|
}
|
|
4550
4696
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
4551
4697
|
if (!trustBase) {
|
|
4552
|
-
throw new
|
|
4698
|
+
throw new SphereError("Trust base not available. Oracle provider must implement getTrustBase()", "AGGREGATOR_ERROR");
|
|
4553
4699
|
}
|
|
4554
4700
|
const calculator = new TokenSplitCalculator();
|
|
4555
4701
|
const availableTokens = Array.from(this.tokens.values());
|
|
@@ -4559,7 +4705,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4559
4705
|
request.coinId
|
|
4560
4706
|
);
|
|
4561
4707
|
if (!splitPlan) {
|
|
4562
|
-
throw new
|
|
4708
|
+
throw new SphereError("Insufficient balance", "INSUFFICIENT_BALANCE");
|
|
4563
4709
|
}
|
|
4564
4710
|
const tokensToSend = splitPlan.tokensToTransferDirectly.map((t) => t.uiToken);
|
|
4565
4711
|
if (splitPlan.tokenToSplit) {
|
|
@@ -4577,7 +4723,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4577
4723
|
const transferMode = request.transferMode ?? "instant";
|
|
4578
4724
|
if (transferMode === "conservative") {
|
|
4579
4725
|
if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
|
|
4580
|
-
|
|
4726
|
+
logger.debug("Payments", "Executing conservative split...");
|
|
4581
4727
|
const splitExecutor = new TokenSplitExecutor({
|
|
4582
4728
|
stateTransitionClient: stClient,
|
|
4583
4729
|
trustBase,
|
|
@@ -4605,7 +4751,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4605
4751
|
sdkData: JSON.stringify(changeTokenData)
|
|
4606
4752
|
};
|
|
4607
4753
|
await this.addToken(changeUiToken);
|
|
4608
|
-
|
|
4754
|
+
logger.debug("Payments", `Conservative split: change token saved: ${changeUiToken.id}`);
|
|
4609
4755
|
await this.deps.transport.sendTokenTransfer(recipientPubkey, {
|
|
4610
4756
|
sourceToken: JSON.stringify(splitResult.tokenForRecipient.toJSON()),
|
|
4611
4757
|
transferTx: JSON.stringify(splitResult.recipientTransferTx.toJSON()),
|
|
@@ -4619,15 +4765,15 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4619
4765
|
method: "split",
|
|
4620
4766
|
requestIdHex: splitRequestIdHex
|
|
4621
4767
|
});
|
|
4622
|
-
|
|
4768
|
+
logger.debug("Payments", "Conservative split transfer completed");
|
|
4623
4769
|
}
|
|
4624
4770
|
for (const tokenWithAmount of splitPlan.tokensToTransferDirectly) {
|
|
4625
4771
|
const token = tokenWithAmount.uiToken;
|
|
4626
4772
|
const commitment = await this.createSdkCommitment(token, recipientAddress, signingService);
|
|
4627
|
-
|
|
4773
|
+
logger.debug("Payments", `CONSERVATIVE: Sending direct token ${token.id.slice(0, 8)}... to ${recipientPubkey.slice(0, 8)}...`);
|
|
4628
4774
|
const submitResponse = await stClient.submitTransferCommitment(commitment);
|
|
4629
4775
|
if (submitResponse.status !== "SUCCESS" && submitResponse.status !== "REQUEST_ID_EXISTS") {
|
|
4630
|
-
throw new
|
|
4776
|
+
throw new SphereError(`Transfer commitment failed: ${submitResponse.status}`, "TRANSFER_FAILED");
|
|
4631
4777
|
}
|
|
4632
4778
|
const inclusionProof = await waitInclusionProof5(trustBase, stClient, commitment);
|
|
4633
4779
|
const transferTx = commitment.toTransaction(inclusionProof);
|
|
@@ -4636,7 +4782,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4636
4782
|
transferTx: JSON.stringify(transferTx.toJSON()),
|
|
4637
4783
|
memo: request.memo
|
|
4638
4784
|
});
|
|
4639
|
-
|
|
4785
|
+
logger.debug("Payments", "CONSERVATIVE: Direct token sent successfully");
|
|
4640
4786
|
const requestIdBytes = commitment.requestId;
|
|
4641
4787
|
const requestIdHex = requestIdBytes instanceof Uint8Array ? Array.from(requestIdBytes).map((b) => b.toString(16).padStart(2, "0")).join("") : String(requestIdBytes);
|
|
4642
4788
|
result.tokenTransfers.push({
|
|
@@ -4644,7 +4790,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4644
4790
|
method: "direct",
|
|
4645
4791
|
requestIdHex
|
|
4646
4792
|
});
|
|
4647
|
-
|
|
4793
|
+
logger.debug("Payments", `Token ${token.id} sent via CONSERVATIVE, requestId: ${requestIdHex}`);
|
|
4648
4794
|
await this.removeToken(token.id);
|
|
4649
4795
|
}
|
|
4650
4796
|
} else {
|
|
@@ -4653,7 +4799,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4653
4799
|
let changeTokenPlaceholderId = null;
|
|
4654
4800
|
let builtSplit = null;
|
|
4655
4801
|
if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
|
|
4656
|
-
|
|
4802
|
+
logger.debug("Payments", "Building instant split bundle...");
|
|
4657
4803
|
const executor = new InstantSplitExecutor({
|
|
4658
4804
|
stateTransitionClient: stClient,
|
|
4659
4805
|
trustBase,
|
|
@@ -4687,7 +4833,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4687
4833
|
sdkData: JSON.stringify(changeTokenData)
|
|
4688
4834
|
};
|
|
4689
4835
|
await this.addToken(uiToken);
|
|
4690
|
-
|
|
4836
|
+
logger.debug("Payments", `Change token saved via background: ${uiToken.id}`);
|
|
4691
4837
|
},
|
|
4692
4838
|
onStorageSync: async () => {
|
|
4693
4839
|
await this.save();
|
|
@@ -4695,7 +4841,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4695
4841
|
}
|
|
4696
4842
|
}
|
|
4697
4843
|
);
|
|
4698
|
-
|
|
4844
|
+
logger.debug("Payments", `Split bundle built: splitGroupId=${builtSplit.splitGroupId}`);
|
|
4699
4845
|
}
|
|
4700
4846
|
const directCommitments = await Promise.all(
|
|
4701
4847
|
splitPlan.tokensToTransferDirectly.map(
|
|
@@ -4722,8 +4868,9 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4722
4868
|
senderPubkey,
|
|
4723
4869
|
memo: request.memo
|
|
4724
4870
|
};
|
|
4725
|
-
|
|
4726
|
-
|
|
4871
|
+
logger.debug(
|
|
4872
|
+
"Payments",
|
|
4873
|
+
`Sending V6 combined bundle: transfer=${result.id.slice(0, 8)}... split=${!!builtSplit} direct=${directTokenEntries.length}`
|
|
4727
4874
|
);
|
|
4728
4875
|
await this.deps.transport.sendTokenTransfer(recipientPubkey, {
|
|
4729
4876
|
token: JSON.stringify(combinedBundle),
|
|
@@ -4731,7 +4878,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4731
4878
|
memo: request.memo,
|
|
4732
4879
|
sender: { transportPubkey: senderPubkey }
|
|
4733
4880
|
});
|
|
4734
|
-
|
|
4881
|
+
logger.debug("Payments", "V6 combined bundle sent successfully");
|
|
4735
4882
|
if (builtSplit) {
|
|
4736
4883
|
const bgPromise = builtSplit.startBackground();
|
|
4737
4884
|
this.pendingBackgroundTasks.push(bgPromise);
|
|
@@ -4752,11 +4899,11 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4752
4899
|
sdkData: JSON.stringify({ _placeholder: true })
|
|
4753
4900
|
};
|
|
4754
4901
|
this.tokens.set(placeholder.id, placeholder);
|
|
4755
|
-
|
|
4902
|
+
logger.debug("Payments", `Placeholder change token created: ${placeholder.id} (${placeholder.amount})`);
|
|
4756
4903
|
}
|
|
4757
4904
|
for (const commitment of directCommitments) {
|
|
4758
4905
|
stClient.submitTransferCommitment(commitment).catch(
|
|
4759
|
-
(err) =>
|
|
4906
|
+
(err) => logger.error("Payments", "Background commitment submit failed:", err)
|
|
4760
4907
|
);
|
|
4761
4908
|
}
|
|
4762
4909
|
if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
|
|
@@ -4779,7 +4926,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4779
4926
|
});
|
|
4780
4927
|
await this.removeToken(token.id);
|
|
4781
4928
|
}
|
|
4782
|
-
|
|
4929
|
+
logger.debug("Payments", "V6 combined transfer completed");
|
|
4783
4930
|
}
|
|
4784
4931
|
result.status = "delivered";
|
|
4785
4932
|
await this.save();
|
|
@@ -4870,11 +5017,11 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4870
5017
|
const signingService = await this.createSigningService();
|
|
4871
5018
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
4872
5019
|
if (!stClient) {
|
|
4873
|
-
throw new
|
|
5020
|
+
throw new SphereError("State transition client not available", "AGGREGATOR_ERROR");
|
|
4874
5021
|
}
|
|
4875
5022
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
4876
5023
|
if (!trustBase) {
|
|
4877
|
-
throw new
|
|
5024
|
+
throw new SphereError("Trust base not available", "AGGREGATOR_ERROR");
|
|
4878
5025
|
}
|
|
4879
5026
|
const calculator = new TokenSplitCalculator();
|
|
4880
5027
|
const availableTokens = Array.from(this.tokens.values());
|
|
@@ -4884,10 +5031,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4884
5031
|
request.coinId
|
|
4885
5032
|
);
|
|
4886
5033
|
if (!splitPlan) {
|
|
4887
|
-
throw new
|
|
5034
|
+
throw new SphereError("Insufficient balance", "INSUFFICIENT_BALANCE");
|
|
4888
5035
|
}
|
|
4889
5036
|
if (!splitPlan.requiresSplit || !splitPlan.tokenToSplit) {
|
|
4890
|
-
|
|
5037
|
+
logger.debug("Payments", "No split required, falling back to standard send()");
|
|
4891
5038
|
const result2 = await this.send(request);
|
|
4892
5039
|
return {
|
|
4893
5040
|
success: result2.status === "completed",
|
|
@@ -4895,7 +5042,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4895
5042
|
error: result2.error
|
|
4896
5043
|
};
|
|
4897
5044
|
}
|
|
4898
|
-
|
|
5045
|
+
logger.debug("Payments", `InstantSplit: amount=${splitPlan.splitAmount}, remainder=${splitPlan.remainderAmount}`);
|
|
4899
5046
|
const tokenToSplit = splitPlan.tokenToSplit.uiToken;
|
|
4900
5047
|
tokenToSplit.status = "transferring";
|
|
4901
5048
|
this.tokens.set(tokenToSplit.id, tokenToSplit);
|
|
@@ -4933,7 +5080,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4933
5080
|
sdkData: JSON.stringify(changeTokenData)
|
|
4934
5081
|
};
|
|
4935
5082
|
await this.addToken(uiToken);
|
|
4936
|
-
|
|
5083
|
+
logger.debug("Payments", `Change token saved via background: ${uiToken.id}`);
|
|
4937
5084
|
},
|
|
4938
5085
|
onStorageSync: async () => {
|
|
4939
5086
|
await this.save();
|
|
@@ -4988,7 +5135,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4988
5135
|
async saveUnconfirmedV5Token(bundle, senderPubkey, deferPersistence = false) {
|
|
4989
5136
|
const deterministicId = `v5split_${bundle.splitGroupId}`;
|
|
4990
5137
|
if (this.tokens.has(deterministicId) || this.processedSplitGroupIds.has(bundle.splitGroupId)) {
|
|
4991
|
-
|
|
5138
|
+
logger.debug("Payments", `V5 bundle ${bundle.splitGroupId.slice(0, 12)}... already processed, skipping`);
|
|
4992
5139
|
return null;
|
|
4993
5140
|
}
|
|
4994
5141
|
const registry = TokenRegistry.getInstance();
|
|
@@ -5038,7 +5185,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5038
5185
|
const nostrTokenId = extractTokenIdFromSdkData(sdkData);
|
|
5039
5186
|
const nostrStateHash = extractStateHashFromSdkData(sdkData);
|
|
5040
5187
|
if (nostrTokenId && nostrStateHash && this.isStateTombstoned(nostrTokenId, nostrStateHash)) {
|
|
5041
|
-
|
|
5188
|
+
logger.debug("Payments", `NOSTR-FIRST: Rejecting tombstoned token ${nostrTokenId.slice(0, 8)}..._${nostrStateHash.slice(0, 8)}...`);
|
|
5042
5189
|
return null;
|
|
5043
5190
|
}
|
|
5044
5191
|
if (nostrTokenId) {
|
|
@@ -5047,14 +5194,16 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5047
5194
|
if (existingTokenId !== nostrTokenId) continue;
|
|
5048
5195
|
const existingStateHash = extractStateHashFromSdkData(existing.sdkData);
|
|
5049
5196
|
if (nostrStateHash && existingStateHash === nostrStateHash) {
|
|
5050
|
-
|
|
5051
|
-
|
|
5197
|
+
logger.debug(
|
|
5198
|
+
"Payments",
|
|
5199
|
+
`NOSTR-FIRST: Skipping duplicate token state ${nostrTokenId.slice(0, 8)}..._${nostrStateHash.slice(0, 8)}...`
|
|
5052
5200
|
);
|
|
5053
5201
|
return null;
|
|
5054
5202
|
}
|
|
5055
5203
|
if (!skipGenesisDedup) {
|
|
5056
|
-
|
|
5057
|
-
|
|
5204
|
+
logger.debug(
|
|
5205
|
+
"Payments",
|
|
5206
|
+
`NOSTR-FIRST: Skipping replay of finalized token ${nostrTokenId.slice(0, 8)}...`
|
|
5058
5207
|
);
|
|
5059
5208
|
return null;
|
|
5060
5209
|
}
|
|
@@ -5086,7 +5235,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5086
5235
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
5087
5236
|
if (stClient) {
|
|
5088
5237
|
const response = await stClient.submitTransferCommitment(commitment);
|
|
5089
|
-
|
|
5238
|
+
logger.debug("Payments", `NOSTR-FIRST recipient commitment submit: ${response.status}`);
|
|
5090
5239
|
}
|
|
5091
5240
|
}
|
|
5092
5241
|
this.addProofPollingJob({
|
|
@@ -5101,7 +5250,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5101
5250
|
}
|
|
5102
5251
|
});
|
|
5103
5252
|
} catch (err) {
|
|
5104
|
-
|
|
5253
|
+
logger.error("Payments", "Failed to parse commitment for proof polling:", err);
|
|
5105
5254
|
}
|
|
5106
5255
|
return token;
|
|
5107
5256
|
}
|
|
@@ -5123,11 +5272,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5123
5272
|
await this.loadedPromise;
|
|
5124
5273
|
}
|
|
5125
5274
|
if (this.processedCombinedTransferIds.has(bundle.transferId)) {
|
|
5126
|
-
|
|
5275
|
+
logger.debug("Payments", `V6 combined transfer ${bundle.transferId.slice(0, 12)}... already processed, skipping`);
|
|
5127
5276
|
return;
|
|
5128
5277
|
}
|
|
5129
|
-
|
|
5130
|
-
|
|
5278
|
+
logger.debug(
|
|
5279
|
+
"Payments",
|
|
5280
|
+
`Processing V6 combined transfer ${bundle.transferId.slice(0, 12)}... (split=${!!bundle.splitBundle}, direct=${bundle.directTokens.length})`
|
|
5131
5281
|
);
|
|
5132
5282
|
const allTokens = [];
|
|
5133
5283
|
const tokenBreakdown = [];
|
|
@@ -5141,7 +5291,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5141
5291
|
allTokens.push(splitToken);
|
|
5142
5292
|
tokenBreakdown.push({ id: splitToken.id, amount: splitToken.amount, source: "split" });
|
|
5143
5293
|
} else {
|
|
5144
|
-
|
|
5294
|
+
logger.warn("Payments", `V6: split token was deduped/failed \u2014 amount=${bundle.splitBundle.amount}`);
|
|
5145
5295
|
}
|
|
5146
5296
|
}
|
|
5147
5297
|
const directResults = await Promise.all(
|
|
@@ -5156,13 +5306,14 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5156
5306
|
tokenBreakdown.push({ id: token.id, amount: token.amount, source: "direct" });
|
|
5157
5307
|
} else {
|
|
5158
5308
|
const entry = bundle.directTokens[i];
|
|
5159
|
-
|
|
5160
|
-
|
|
5309
|
+
logger.warn(
|
|
5310
|
+
"Payments",
|
|
5311
|
+
`V6: direct token #${i} dropped (amount=${entry.amount}, tokenId=${entry.tokenId?.slice(0, 12) ?? "N/A"})`
|
|
5161
5312
|
);
|
|
5162
5313
|
}
|
|
5163
5314
|
}
|
|
5164
5315
|
if (allTokens.length === 0) {
|
|
5165
|
-
|
|
5316
|
+
logger.debug("Payments", "V6 combined transfer: all tokens deduped, nothing to save");
|
|
5166
5317
|
return;
|
|
5167
5318
|
}
|
|
5168
5319
|
this.processedCombinedTransferIds.add(bundle.transferId);
|
|
@@ -5178,7 +5329,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5178
5329
|
TransferCommitment4.fromJSON(commitment).then(
|
|
5179
5330
|
(c) => stClient.submitTransferCommitment(c)
|
|
5180
5331
|
).catch(
|
|
5181
|
-
(err) =>
|
|
5332
|
+
(err) => logger.error("Payments", "V6 background commitment submit failed:", err)
|
|
5182
5333
|
);
|
|
5183
5334
|
}
|
|
5184
5335
|
}
|
|
@@ -5205,8 +5356,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5205
5356
|
tokenIds: tokenBreakdown
|
|
5206
5357
|
});
|
|
5207
5358
|
if (bundle.splitBundle) {
|
|
5208
|
-
this.resolveUnconfirmed().catch(() =>
|
|
5209
|
-
});
|
|
5359
|
+
this.resolveUnconfirmed().catch((err) => logger.debug("Payments", "resolveUnconfirmed failed", err));
|
|
5210
5360
|
this.scheduleResolveUnconfirmed();
|
|
5211
5361
|
}
|
|
5212
5362
|
}
|
|
@@ -5284,8 +5434,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5284
5434
|
receivedAt: Date.now()
|
|
5285
5435
|
});
|
|
5286
5436
|
await this.save();
|
|
5287
|
-
this.resolveUnconfirmed().catch(() =>
|
|
5288
|
-
});
|
|
5437
|
+
this.resolveUnconfirmed().catch((err) => logger.debug("Payments", "resolveUnconfirmed failed", err));
|
|
5289
5438
|
this.scheduleResolveUnconfirmed();
|
|
5290
5439
|
return { success: true, durationMs: 0 };
|
|
5291
5440
|
} catch (error) {
|
|
@@ -5306,11 +5455,11 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5306
5455
|
const signingService = await this.createSigningService();
|
|
5307
5456
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
5308
5457
|
if (!stClient) {
|
|
5309
|
-
throw new
|
|
5458
|
+
throw new SphereError("State transition client not available", "AGGREGATOR_ERROR");
|
|
5310
5459
|
}
|
|
5311
5460
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
5312
5461
|
if (!trustBase) {
|
|
5313
|
-
throw new
|
|
5462
|
+
throw new SphereError("Trust base not available", "AGGREGATOR_ERROR");
|
|
5314
5463
|
}
|
|
5315
5464
|
const devMode = this.deps.oracle.isDevMode?.() ?? false;
|
|
5316
5465
|
const processor = new InstantSplitProcessor({
|
|
@@ -5333,10 +5482,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5333
5482
|
if (proxy.address === proxyAddress) {
|
|
5334
5483
|
return nametagToken;
|
|
5335
5484
|
}
|
|
5336
|
-
|
|
5485
|
+
logger.debug("Payments", `Nametag PROXY address mismatch: ${proxy.address} !== ${proxyAddress}`);
|
|
5337
5486
|
return null;
|
|
5338
5487
|
} catch (err) {
|
|
5339
|
-
|
|
5488
|
+
logger.debug("Payments", "Failed to parse nametag token:", err);
|
|
5340
5489
|
return null;
|
|
5341
5490
|
}
|
|
5342
5491
|
}
|
|
@@ -5444,7 +5593,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5444
5593
|
status: "pending"
|
|
5445
5594
|
};
|
|
5446
5595
|
this.outgoingPaymentRequests.set(requestId2, outgoingRequest);
|
|
5447
|
-
|
|
5596
|
+
logger.debug("Payments", `Payment request sent: ${eventId}`);
|
|
5448
5597
|
return {
|
|
5449
5598
|
success: true,
|
|
5450
5599
|
requestId: requestId2,
|
|
@@ -5452,7 +5601,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5452
5601
|
};
|
|
5453
5602
|
} catch (error) {
|
|
5454
5603
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
5455
|
-
|
|
5604
|
+
logger.debug("Payments", `Failed to send payment request: ${errorMsg}`);
|
|
5456
5605
|
return {
|
|
5457
5606
|
success: false,
|
|
5458
5607
|
error: errorMsg
|
|
@@ -5541,10 +5690,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5541
5690
|
async payPaymentRequest(requestId2, memo) {
|
|
5542
5691
|
const request = this.paymentRequests.find((r) => r.id === requestId2);
|
|
5543
5692
|
if (!request) {
|
|
5544
|
-
throw new
|
|
5693
|
+
throw new SphereError(`Payment request not found: ${requestId2}`, "VALIDATION_ERROR");
|
|
5545
5694
|
}
|
|
5546
5695
|
if (request.status !== "pending" && request.status !== "accepted") {
|
|
5547
|
-
throw new
|
|
5696
|
+
throw new SphereError(`Payment request is not pending or accepted: ${request.status}`, "VALIDATION_ERROR");
|
|
5548
5697
|
}
|
|
5549
5698
|
this.updatePaymentRequestStatus(requestId2, "accepted");
|
|
5550
5699
|
try {
|
|
@@ -5599,10 +5748,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5599
5748
|
try {
|
|
5600
5749
|
handler(request);
|
|
5601
5750
|
} catch (error) {
|
|
5602
|
-
|
|
5751
|
+
logger.debug("Payments", "Payment request handler error:", error);
|
|
5603
5752
|
}
|
|
5604
5753
|
}
|
|
5605
|
-
|
|
5754
|
+
logger.debug("Payments", `Incoming payment request: ${request.id} for ${request.amount} ${request.symbol}`);
|
|
5606
5755
|
}
|
|
5607
5756
|
// ===========================================================================
|
|
5608
5757
|
// Public API - Outgoing Payment Requests
|
|
@@ -5721,10 +5870,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5721
5870
|
try {
|
|
5722
5871
|
handler(response);
|
|
5723
5872
|
} catch (error) {
|
|
5724
|
-
|
|
5873
|
+
logger.debug("Payments", "Payment request response handler error:", error);
|
|
5725
5874
|
}
|
|
5726
5875
|
}
|
|
5727
|
-
|
|
5876
|
+
logger.debug("Payments", `Received payment request response: ${response.id} type: ${response.responseType}`);
|
|
5728
5877
|
}
|
|
5729
5878
|
/**
|
|
5730
5879
|
* Send a response to a payment request (used internally by accept/reject/pay methods)
|
|
@@ -5733,7 +5882,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5733
5882
|
const request = this.paymentRequests.find((r) => r.id === requestId2);
|
|
5734
5883
|
if (!request) return;
|
|
5735
5884
|
if (!this.deps?.transport.sendPaymentRequestResponse) {
|
|
5736
|
-
|
|
5885
|
+
logger.debug("Payments", "Transport does not support sendPaymentRequestResponse");
|
|
5737
5886
|
return;
|
|
5738
5887
|
}
|
|
5739
5888
|
try {
|
|
@@ -5744,9 +5893,9 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5744
5893
|
transferId
|
|
5745
5894
|
};
|
|
5746
5895
|
await this.deps.transport.sendPaymentRequestResponse(request.senderPubkey, payload);
|
|
5747
|
-
|
|
5896
|
+
logger.debug("Payments", `Sent payment request response: ${responseType} for ${requestId2}`);
|
|
5748
5897
|
} catch (error) {
|
|
5749
|
-
|
|
5898
|
+
logger.debug("Payments", "Failed to send payment request response:", error);
|
|
5750
5899
|
}
|
|
5751
5900
|
}
|
|
5752
5901
|
// ===========================================================================
|
|
@@ -5770,7 +5919,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5770
5919
|
async receive(options, callback) {
|
|
5771
5920
|
this.ensureInitialized();
|
|
5772
5921
|
if (!this.deps.transport.fetchPendingEvents) {
|
|
5773
|
-
throw new
|
|
5922
|
+
throw new SphereError("Transport provider does not support fetchPendingEvents", "TRANSPORT_ERROR");
|
|
5774
5923
|
}
|
|
5775
5924
|
const opts = options ?? {};
|
|
5776
5925
|
const tokensBefore = new Set(this.tokens.keys());
|
|
@@ -5917,7 +6066,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5917
6066
|
});
|
|
5918
6067
|
}
|
|
5919
6068
|
} catch (error) {
|
|
5920
|
-
|
|
6069
|
+
logger.warn("Payments", "Failed to fetch prices, returning assets without price data:", error);
|
|
5921
6070
|
}
|
|
5922
6071
|
return rawAssets;
|
|
5923
6072
|
}
|
|
@@ -6039,24 +6188,24 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6039
6188
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
6040
6189
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
6041
6190
|
if (!stClient || !trustBase) {
|
|
6042
|
-
|
|
6191
|
+
logger.debug("Payments", `[V5-RESOLVE] resolveUnconfirmed: EARLY EXIT \u2014 stClient=${!!stClient} trustBase=${!!trustBase}`);
|
|
6043
6192
|
return result;
|
|
6044
6193
|
}
|
|
6045
6194
|
const signingService = await this.createSigningService();
|
|
6046
6195
|
const submittedCount = Array.from(this.tokens.values()).filter((t) => t.status === "submitted").length;
|
|
6047
|
-
|
|
6196
|
+
logger.debug("Payments", `[V5-RESOLVE] resolveUnconfirmed: ${submittedCount} submitted token(s) to process`);
|
|
6048
6197
|
for (const [tokenId, token] of this.tokens) {
|
|
6049
6198
|
if (token.status !== "submitted") continue;
|
|
6050
6199
|
const pending2 = this.parsePendingFinalization(token.sdkData);
|
|
6051
6200
|
if (!pending2) {
|
|
6052
|
-
|
|
6201
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 16)}: no pending finalization metadata, skipping`);
|
|
6053
6202
|
result.stillPending++;
|
|
6054
6203
|
continue;
|
|
6055
6204
|
}
|
|
6056
6205
|
if (pending2.type === "v5_bundle") {
|
|
6057
|
-
|
|
6206
|
+
logger.debug("Payments", `[V5-RESOLVE] Processing ${tokenId.slice(0, 16)}... stage=${pending2.stage} attempt=${pending2.attemptCount}`);
|
|
6058
6207
|
const progress = await this.resolveV5Token(tokenId, token, pending2, stClient, trustBase, signingService);
|
|
6059
|
-
|
|
6208
|
+
logger.debug("Payments", `[V5-RESOLVE] Result for ${tokenId.slice(0, 16)}...: ${progress} (stage now: ${pending2.stage})`);
|
|
6060
6209
|
result.details.push({ tokenId, stage: pending2.stage, status: progress });
|
|
6061
6210
|
if (progress === "resolved") result.resolved++;
|
|
6062
6211
|
else if (progress === "failed") result.failed++;
|
|
@@ -6064,7 +6213,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6064
6213
|
}
|
|
6065
6214
|
}
|
|
6066
6215
|
if (result.resolved > 0 || result.failed > 0 || result.stillPending > 0) {
|
|
6067
|
-
|
|
6216
|
+
logger.debug("Payments", `[V5-RESOLVE] Saving: resolved=${result.resolved} failed=${result.failed} stillPending=${result.stillPending}`);
|
|
6068
6217
|
await this.save();
|
|
6069
6218
|
}
|
|
6070
6219
|
return result;
|
|
@@ -6080,19 +6229,19 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6080
6229
|
(t) => t.status === "submitted"
|
|
6081
6230
|
);
|
|
6082
6231
|
if (!hasUnconfirmed) {
|
|
6083
|
-
|
|
6232
|
+
logger.debug("Payments", "[V5-RESOLVE] scheduleResolveUnconfirmed: no submitted tokens, not starting timer");
|
|
6084
6233
|
return;
|
|
6085
6234
|
}
|
|
6086
|
-
|
|
6235
|
+
logger.debug("Payments", `[V5-RESOLVE] scheduleResolveUnconfirmed: starting periodic retry (every ${_PaymentsModule.RESOLVE_UNCONFIRMED_INTERVAL_MS}ms)`);
|
|
6087
6236
|
this.resolveUnconfirmedTimer = setInterval(async () => {
|
|
6088
6237
|
try {
|
|
6089
6238
|
const result = await this.resolveUnconfirmed();
|
|
6090
6239
|
if (result.stillPending === 0) {
|
|
6091
|
-
|
|
6240
|
+
logger.debug("Payments", "[V5-RESOLVE] All tokens resolved, stopping periodic retry");
|
|
6092
6241
|
this.stopResolveUnconfirmedPolling();
|
|
6093
6242
|
}
|
|
6094
6243
|
} catch (err) {
|
|
6095
|
-
|
|
6244
|
+
logger.debug("Payments", "[V5-RESOLVE] Periodic retry error:", err);
|
|
6096
6245
|
}
|
|
6097
6246
|
}, _PaymentsModule.RESOLVE_UNCONFIRMED_INTERVAL_MS);
|
|
6098
6247
|
}
|
|
@@ -6114,57 +6263,57 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6114
6263
|
pending2.lastAttemptAt = Date.now();
|
|
6115
6264
|
try {
|
|
6116
6265
|
if (pending2.stage === "RECEIVED") {
|
|
6117
|
-
|
|
6266
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: RECEIVED \u2192 submitting mint commitment...`);
|
|
6118
6267
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
6119
6268
|
const mintData = await MintTransactionData3.fromJSON(mintDataJson);
|
|
6120
6269
|
const mintCommitment = await MintCommitment3.create(mintData);
|
|
6121
6270
|
const mintResponse = await stClient.submitMintCommitment(mintCommitment);
|
|
6122
|
-
|
|
6271
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: mint response status=${mintResponse.status}`);
|
|
6123
6272
|
if (mintResponse.status !== "SUCCESS" && mintResponse.status !== "REQUEST_ID_EXISTS") {
|
|
6124
|
-
throw new
|
|
6273
|
+
throw new SphereError(`Mint submission failed: ${mintResponse.status}`, "TRANSFER_FAILED");
|
|
6125
6274
|
}
|
|
6126
6275
|
pending2.stage = "MINT_SUBMITTED";
|
|
6127
6276
|
this.updatePendingFinalization(token, pending2);
|
|
6128
6277
|
}
|
|
6129
6278
|
if (pending2.stage === "MINT_SUBMITTED") {
|
|
6130
|
-
|
|
6279
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: MINT_SUBMITTED \u2192 checking mint proof...`);
|
|
6131
6280
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
6132
6281
|
const mintData = await MintTransactionData3.fromJSON(mintDataJson);
|
|
6133
6282
|
const mintCommitment = await MintCommitment3.create(mintData);
|
|
6134
6283
|
const proof = await this.quickProofCheck(stClient, trustBase, mintCommitment);
|
|
6135
6284
|
if (!proof) {
|
|
6136
|
-
|
|
6285
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: mint proof not yet available, staying MINT_SUBMITTED`);
|
|
6137
6286
|
this.updatePendingFinalization(token, pending2);
|
|
6138
6287
|
return "pending";
|
|
6139
6288
|
}
|
|
6140
|
-
|
|
6289
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: mint proof obtained!`);
|
|
6141
6290
|
pending2.mintProofJson = JSON.stringify(proof);
|
|
6142
6291
|
pending2.stage = "MINT_PROVEN";
|
|
6143
6292
|
this.updatePendingFinalization(token, pending2);
|
|
6144
6293
|
}
|
|
6145
6294
|
if (pending2.stage === "MINT_PROVEN") {
|
|
6146
|
-
|
|
6295
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: MINT_PROVEN \u2192 submitting transfer commitment...`);
|
|
6147
6296
|
const transferCommitmentJson = JSON.parse(bundle.transferCommitment);
|
|
6148
6297
|
const transferCommitment = await TransferCommitment4.fromJSON(transferCommitmentJson);
|
|
6149
6298
|
const transferResponse = await stClient.submitTransferCommitment(transferCommitment);
|
|
6150
|
-
|
|
6299
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: transfer response status=${transferResponse.status}`);
|
|
6151
6300
|
if (transferResponse.status !== "SUCCESS" && transferResponse.status !== "REQUEST_ID_EXISTS") {
|
|
6152
|
-
throw new
|
|
6301
|
+
throw new SphereError(`Transfer submission failed: ${transferResponse.status}`, "TRANSFER_FAILED");
|
|
6153
6302
|
}
|
|
6154
6303
|
pending2.stage = "TRANSFER_SUBMITTED";
|
|
6155
6304
|
this.updatePendingFinalization(token, pending2);
|
|
6156
6305
|
}
|
|
6157
6306
|
if (pending2.stage === "TRANSFER_SUBMITTED") {
|
|
6158
|
-
|
|
6307
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: TRANSFER_SUBMITTED \u2192 checking transfer proof...`);
|
|
6159
6308
|
const transferCommitmentJson = JSON.parse(bundle.transferCommitment);
|
|
6160
6309
|
const transferCommitment = await TransferCommitment4.fromJSON(transferCommitmentJson);
|
|
6161
6310
|
const proof = await this.quickProofCheck(stClient, trustBase, transferCommitment);
|
|
6162
6311
|
if (!proof) {
|
|
6163
|
-
|
|
6312
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: transfer proof not yet available, staying TRANSFER_SUBMITTED`);
|
|
6164
6313
|
this.updatePendingFinalization(token, pending2);
|
|
6165
6314
|
return "pending";
|
|
6166
6315
|
}
|
|
6167
|
-
|
|
6316
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: transfer proof obtained! Finalizing...`);
|
|
6168
6317
|
const finalizedToken = await this.finalizeFromV5Bundle(bundle, pending2, signingService, stClient, trustBase);
|
|
6169
6318
|
const confirmedToken = {
|
|
6170
6319
|
id: token.id,
|
|
@@ -6186,12 +6335,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6186
6335
|
tokens: [confirmedToken],
|
|
6187
6336
|
tokenTransfers: []
|
|
6188
6337
|
});
|
|
6189
|
-
|
|
6338
|
+
logger.debug("Payments", `V5 token resolved: ${tokenId.slice(0, 8)}...`);
|
|
6190
6339
|
return "resolved";
|
|
6191
6340
|
}
|
|
6192
6341
|
return "pending";
|
|
6193
6342
|
} catch (error) {
|
|
6194
|
-
|
|
6343
|
+
logger.error("Payments", `resolveV5Token failed for ${tokenId.slice(0, 8)}:`, error);
|
|
6195
6344
|
if (pending2.attemptCount > 50) {
|
|
6196
6345
|
token.status = "invalid";
|
|
6197
6346
|
token.updatedAt = Date.now();
|
|
@@ -6328,19 +6477,19 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6328
6477
|
}
|
|
6329
6478
|
if (pendingTokens.length > 0) {
|
|
6330
6479
|
const json = JSON.stringify(pendingTokens);
|
|
6331
|
-
|
|
6480
|
+
logger.debug("Payments", `[V5-PERSIST] Saving ${pendingTokens.length} pending V5 token(s): ${pendingTokens.map((t) => t.id.slice(0, 16)).join(", ")} (${json.length} bytes)`);
|
|
6332
6481
|
await this.deps.storage.set(
|
|
6333
6482
|
STORAGE_KEYS_ADDRESS.PENDING_V5_TOKENS,
|
|
6334
6483
|
json
|
|
6335
6484
|
);
|
|
6336
6485
|
const verify = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.PENDING_V5_TOKENS);
|
|
6337
6486
|
if (!verify) {
|
|
6338
|
-
|
|
6487
|
+
logger.error("Payments", "[V5-PERSIST] CRITICAL: KV write succeeded but read-back is empty!");
|
|
6339
6488
|
} else {
|
|
6340
|
-
|
|
6489
|
+
logger.debug("Payments", `[V5-PERSIST] Verified: read-back ${verify.length} bytes`);
|
|
6341
6490
|
}
|
|
6342
6491
|
} else {
|
|
6343
|
-
|
|
6492
|
+
logger.debug("Payments", `[V5-PERSIST] No pending V5 tokens to save (total tokens: ${this.tokens.size}), clearing KV`);
|
|
6344
6493
|
await this.deps.storage.set(STORAGE_KEYS_ADDRESS.PENDING_V5_TOKENS, "");
|
|
6345
6494
|
}
|
|
6346
6495
|
}
|
|
@@ -6350,21 +6499,21 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6350
6499
|
*/
|
|
6351
6500
|
async loadPendingV5Tokens() {
|
|
6352
6501
|
const data = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.PENDING_V5_TOKENS);
|
|
6353
|
-
|
|
6502
|
+
logger.debug("Payments", `[V5-PERSIST] loadPendingV5Tokens: KV data = ${data ? `${data.length} bytes` : "null/empty"}`);
|
|
6354
6503
|
if (!data) return;
|
|
6355
6504
|
try {
|
|
6356
6505
|
const pendingTokens = JSON.parse(data);
|
|
6357
|
-
|
|
6506
|
+
logger.debug("Payments", `[V5-PERSIST] Parsed ${pendingTokens.length} pending V5 token(s): ${pendingTokens.map((t) => t.id.slice(0, 16)).join(", ")}`);
|
|
6358
6507
|
for (const token of pendingTokens) {
|
|
6359
6508
|
if (!this.tokens.has(token.id)) {
|
|
6360
6509
|
this.tokens.set(token.id, token);
|
|
6361
|
-
|
|
6510
|
+
logger.debug("Payments", `[V5-PERSIST] Restored token ${token.id.slice(0, 16)} (status=${token.status})`);
|
|
6362
6511
|
} else {
|
|
6363
|
-
|
|
6512
|
+
logger.debug("Payments", `[V5-PERSIST] Token ${token.id.slice(0, 16)} already in map, skipping`);
|
|
6364
6513
|
}
|
|
6365
6514
|
}
|
|
6366
6515
|
} catch (err) {
|
|
6367
|
-
|
|
6516
|
+
logger.error("Payments", "[V5-PERSIST] Failed to parse pending V5 tokens:", err);
|
|
6368
6517
|
}
|
|
6369
6518
|
}
|
|
6370
6519
|
/**
|
|
@@ -6417,13 +6566,13 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6417
6566
|
const incomingStateHash = extractStateHashFromSdkData(token.sdkData);
|
|
6418
6567
|
const incomingStateKey = incomingTokenId && incomingStateHash ? createTokenStateKey(incomingTokenId, incomingStateHash) : null;
|
|
6419
6568
|
if (incomingTokenId && incomingStateHash && this.isStateTombstoned(incomingTokenId, incomingStateHash)) {
|
|
6420
|
-
|
|
6569
|
+
logger.debug("Payments", `Rejecting tombstoned token: ${incomingTokenId.slice(0, 8)}..._${incomingStateHash.slice(0, 8)}...`);
|
|
6421
6570
|
return false;
|
|
6422
6571
|
}
|
|
6423
6572
|
if (incomingStateKey) {
|
|
6424
6573
|
for (const [_existingId, existing] of this.tokens) {
|
|
6425
6574
|
if (isSameTokenState(existing, token)) {
|
|
6426
|
-
|
|
6575
|
+
logger.debug("Payments", `Duplicate token state ignored: ${incomingTokenId?.slice(0, 8)}..._${incomingStateHash?.slice(0, 8)}...`);
|
|
6427
6576
|
return false;
|
|
6428
6577
|
}
|
|
6429
6578
|
}
|
|
@@ -6435,19 +6584,19 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6435
6584
|
continue;
|
|
6436
6585
|
}
|
|
6437
6586
|
if (existing.status === "spent" || existing.status === "invalid") {
|
|
6438
|
-
|
|
6587
|
+
logger.debug("Payments", `Replacing spent/invalid token ${incomingTokenId?.slice(0, 8)}...`);
|
|
6439
6588
|
this.tokens.delete(existingId);
|
|
6440
6589
|
break;
|
|
6441
6590
|
}
|
|
6442
6591
|
if (incomingStateHash && existingStateHash && incomingStateHash !== existingStateHash) {
|
|
6443
|
-
|
|
6592
|
+
logger.debug("Payments", `Token ${incomingTokenId?.slice(0, 8)}... state updated: ${existingStateHash.slice(0, 8)}... -> ${incomingStateHash.slice(0, 8)}...`);
|
|
6444
6593
|
await this.archiveToken(existing);
|
|
6445
6594
|
this.tokens.delete(existingId);
|
|
6446
6595
|
break;
|
|
6447
6596
|
}
|
|
6448
6597
|
if (!incomingStateHash || !existingStateHash) {
|
|
6449
6598
|
if (existingId !== token.id) {
|
|
6450
|
-
|
|
6599
|
+
logger.debug("Payments", `Token ${incomingTokenId?.slice(0, 8)}... .id changed, replacing`);
|
|
6451
6600
|
await this.archiveToken(existing);
|
|
6452
6601
|
this.tokens.delete(existingId);
|
|
6453
6602
|
break;
|
|
@@ -6458,7 +6607,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6458
6607
|
this.tokens.set(token.id, token);
|
|
6459
6608
|
await this.archiveToken(token);
|
|
6460
6609
|
await this.save();
|
|
6461
|
-
|
|
6610
|
+
logger.debug("Payments", `Added token ${token.id}, total: ${this.tokens.size}`);
|
|
6462
6611
|
return true;
|
|
6463
6612
|
}
|
|
6464
6613
|
/**
|
|
@@ -6488,7 +6637,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6488
6637
|
}
|
|
6489
6638
|
await this.archiveToken(token);
|
|
6490
6639
|
await this.save();
|
|
6491
|
-
|
|
6640
|
+
logger.debug("Payments", `Updated token ${token.id}`);
|
|
6492
6641
|
}
|
|
6493
6642
|
/**
|
|
6494
6643
|
* Remove a token from the wallet.
|
|
@@ -6511,10 +6660,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6511
6660
|
);
|
|
6512
6661
|
if (!alreadyTombstoned) {
|
|
6513
6662
|
this.tombstones.push(tombstone);
|
|
6514
|
-
|
|
6663
|
+
logger.debug("Payments", `Created tombstone for ${tombstone.tokenId.slice(0, 8)}..._${tombstone.stateHash.slice(0, 8)}...`);
|
|
6515
6664
|
}
|
|
6516
6665
|
} else {
|
|
6517
|
-
|
|
6666
|
+
logger.debug("Payments", `Warning: Could not create tombstone for token ${tokenId.slice(0, 8)}... (missing tokenId or stateHash)`);
|
|
6518
6667
|
}
|
|
6519
6668
|
this.tokens.delete(tokenId);
|
|
6520
6669
|
await this.save();
|
|
@@ -6571,7 +6720,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6571
6720
|
}
|
|
6572
6721
|
for (const token of tokensToRemove) {
|
|
6573
6722
|
this.tokens.delete(token.id);
|
|
6574
|
-
|
|
6723
|
+
logger.debug("Payments", `Removed tombstoned token ${token.id.slice(0, 8)}...`);
|
|
6575
6724
|
removedCount++;
|
|
6576
6725
|
}
|
|
6577
6726
|
for (const remoteTombstone of remoteTombstones) {
|
|
@@ -6597,7 +6746,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6597
6746
|
this.tombstones = pruneTombstonesByAge(this.tombstones, maxAge);
|
|
6598
6747
|
if (this.tombstones.length < originalCount) {
|
|
6599
6748
|
await this.save();
|
|
6600
|
-
|
|
6749
|
+
logger.debug("Payments", `Pruned tombstones from ${originalCount} to ${this.tombstones.length}`);
|
|
6601
6750
|
}
|
|
6602
6751
|
}
|
|
6603
6752
|
// ===========================================================================
|
|
@@ -6669,7 +6818,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6669
6818
|
const originalCount = this.archivedTokens.size;
|
|
6670
6819
|
this.archivedTokens = pruneMapByCount(this.archivedTokens, maxCount);
|
|
6671
6820
|
await this.save();
|
|
6672
|
-
|
|
6821
|
+
logger.debug("Payments", `Pruned archived tokens from ${originalCount} to ${this.archivedTokens.size}`);
|
|
6673
6822
|
}
|
|
6674
6823
|
// ===========================================================================
|
|
6675
6824
|
// Public API - Forked Tokens
|
|
@@ -6698,7 +6847,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6698
6847
|
const key = `${tokenId}_${stateHash}`;
|
|
6699
6848
|
if (this.forkedTokens.has(key)) return;
|
|
6700
6849
|
this.forkedTokens.set(key, txfToken);
|
|
6701
|
-
|
|
6850
|
+
logger.debug("Payments", `Stored forked token ${tokenId.slice(0, 8)}... state ${stateHash.slice(0, 12)}...`);
|
|
6702
6851
|
await this.save();
|
|
6703
6852
|
}
|
|
6704
6853
|
/**
|
|
@@ -6730,7 +6879,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6730
6879
|
const originalCount = this.forkedTokens.size;
|
|
6731
6880
|
this.forkedTokens = pruneMapByCount(this.forkedTokens, maxCount);
|
|
6732
6881
|
await this.save();
|
|
6733
|
-
|
|
6882
|
+
logger.debug("Payments", `Pruned forked tokens from ${originalCount} to ${this.forkedTokens.size}`);
|
|
6734
6883
|
}
|
|
6735
6884
|
// ===========================================================================
|
|
6736
6885
|
// Public API - Transaction History
|
|
@@ -6810,7 +6959,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6810
6959
|
const imported = await provider.importHistoryEntries?.(records) ?? 0;
|
|
6811
6960
|
if (imported > 0) {
|
|
6812
6961
|
this._historyCache = await provider.getHistoryEntries();
|
|
6813
|
-
|
|
6962
|
+
logger.debug("Payments", `Migrated ${imported} history entries from KV to history store`);
|
|
6814
6963
|
}
|
|
6815
6964
|
await this.deps.storage.remove(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
|
|
6816
6965
|
} catch {
|
|
@@ -6886,7 +7035,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6886
7035
|
this.nametags.push(nametag);
|
|
6887
7036
|
}
|
|
6888
7037
|
await this.save();
|
|
6889
|
-
|
|
7038
|
+
logger.debug("Payments", `Nametag set: ${nametag.name}`);
|
|
6890
7039
|
}
|
|
6891
7040
|
/**
|
|
6892
7041
|
* Get the current (first) nametag data.
|
|
@@ -6935,7 +7084,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6935
7084
|
const parsed = parseTxfStorageData(result.data);
|
|
6936
7085
|
if (parsed.nametags.length > 0) {
|
|
6937
7086
|
this.nametags = parsed.nametags;
|
|
6938
|
-
|
|
7087
|
+
logger.debug("Payments", `Reloaded ${parsed.nametags.length} nametag(s) from storage`);
|
|
6939
7088
|
return;
|
|
6940
7089
|
}
|
|
6941
7090
|
}
|
|
@@ -6988,7 +7137,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6988
7137
|
const result = await minter.mintNametag(nametag, ownerAddress);
|
|
6989
7138
|
if (result.success && result.nametagData) {
|
|
6990
7139
|
await this.setNametag(result.nametagData);
|
|
6991
|
-
|
|
7140
|
+
logger.debug("Payments", `Nametag minted and saved: ${result.nametagData.name}`);
|
|
6992
7141
|
this.deps.emitEvent("nametag:registered", {
|
|
6993
7142
|
nametag: result.nametagData.name,
|
|
6994
7143
|
addressIndex: 0
|
|
@@ -6998,7 +7147,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6998
7147
|
return result;
|
|
6999
7148
|
} catch (error) {
|
|
7000
7149
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
7001
|
-
|
|
7150
|
+
logger.debug("Payments", "mintNametag failed:", errorMsg);
|
|
7002
7151
|
return {
|
|
7003
7152
|
success: false,
|
|
7004
7153
|
error: errorMsg
|
|
@@ -7096,7 +7245,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7096
7245
|
restoredCount++;
|
|
7097
7246
|
}
|
|
7098
7247
|
if (restoredCount > 0) {
|
|
7099
|
-
|
|
7248
|
+
logger.debug("Payments", `Sync: restored ${restoredCount} token(s) lost by loadFromStorageData`);
|
|
7100
7249
|
}
|
|
7101
7250
|
if (this.nametags.length === 0 && savedNametags.length > 0) {
|
|
7102
7251
|
this.nametags = savedNametags;
|
|
@@ -7105,7 +7254,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7105
7254
|
if (txfData._history && txfData._history.length > 0) {
|
|
7106
7255
|
const imported = await this.importRemoteHistoryEntries(txfData._history);
|
|
7107
7256
|
if (imported > 0) {
|
|
7108
|
-
|
|
7257
|
+
logger.debug("Payments", `Imported ${imported} history entries from IPFS sync`);
|
|
7109
7258
|
}
|
|
7110
7259
|
}
|
|
7111
7260
|
totalAdded += result.added;
|
|
@@ -7118,7 +7267,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7118
7267
|
removed: result.removed
|
|
7119
7268
|
});
|
|
7120
7269
|
} catch (providerError) {
|
|
7121
|
-
|
|
7270
|
+
logger.warn("Payments", `Sync failed for provider ${providerId}:`, providerError);
|
|
7122
7271
|
this.deps.emitEvent("sync:provider", {
|
|
7123
7272
|
providerId,
|
|
7124
7273
|
success: false,
|
|
@@ -7156,7 +7305,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7156
7305
|
if (provider.onEvent) {
|
|
7157
7306
|
const unsub = provider.onEvent((event) => {
|
|
7158
7307
|
if (event.type === "storage:remote-updated") {
|
|
7159
|
-
|
|
7308
|
+
logger.debug("Payments", "Remote update detected from provider", providerId, event.data);
|
|
7160
7309
|
this.debouncedSyncFromRemoteUpdate(providerId, event.data);
|
|
7161
7310
|
}
|
|
7162
7311
|
});
|
|
@@ -7198,7 +7347,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7198
7347
|
removed: result.removed
|
|
7199
7348
|
});
|
|
7200
7349
|
}).catch((err) => {
|
|
7201
|
-
|
|
7350
|
+
logger.debug("Payments", "Auto-sync from remote update failed:", err);
|
|
7202
7351
|
});
|
|
7203
7352
|
}, _PaymentsModule.SYNC_DEBOUNCE_MS);
|
|
7204
7353
|
}
|
|
@@ -7303,8 +7452,9 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7303
7452
|
}
|
|
7304
7453
|
return recipient;
|
|
7305
7454
|
}
|
|
7306
|
-
throw new
|
|
7307
|
-
`Cannot resolve transport pubkey for "${recipient}". No binding event found. The recipient must publish their identity first
|
|
7455
|
+
throw new SphereError(
|
|
7456
|
+
`Cannot resolve transport pubkey for "${recipient}". No binding event found. The recipient must publish their identity first.`,
|
|
7457
|
+
"INVALID_RECIPIENT"
|
|
7308
7458
|
);
|
|
7309
7459
|
}
|
|
7310
7460
|
/**
|
|
@@ -7375,32 +7525,33 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7375
7525
|
return AddressFactory.createAddress(recipient);
|
|
7376
7526
|
}
|
|
7377
7527
|
if (recipient.length === 66 && /^[0-9a-fA-F]+$/.test(recipient)) {
|
|
7378
|
-
|
|
7528
|
+
logger.debug("Payments", "Creating DirectAddress from 33-byte compressed pubkey");
|
|
7379
7529
|
return this.createDirectAddressFromPubkey(recipient);
|
|
7380
7530
|
}
|
|
7381
7531
|
const info = peerInfo ?? await this.deps?.transport.resolve?.(recipient) ?? null;
|
|
7382
7532
|
if (!info) {
|
|
7383
|
-
throw new
|
|
7384
|
-
`Recipient "${recipient}" not found. Use @nametag, a valid PROXY:/DIRECT: address, or a 33-byte hex pubkey
|
|
7533
|
+
throw new SphereError(
|
|
7534
|
+
`Recipient "${recipient}" not found. Use @nametag, a valid PROXY:/DIRECT: address, or a 33-byte hex pubkey.`,
|
|
7535
|
+
"INVALID_RECIPIENT"
|
|
7385
7536
|
);
|
|
7386
7537
|
}
|
|
7387
7538
|
const nametag = recipient.startsWith("@") ? recipient.slice(1) : info.nametag || recipient;
|
|
7388
7539
|
if (addressMode === "proxy") {
|
|
7389
|
-
|
|
7540
|
+
logger.debug("Payments", `Using PROXY address for "${nametag}" (forced)`);
|
|
7390
7541
|
return ProxyAddress.fromNameTag(nametag);
|
|
7391
7542
|
}
|
|
7392
7543
|
if (addressMode === "direct") {
|
|
7393
7544
|
if (!info.directAddress) {
|
|
7394
|
-
throw new
|
|
7545
|
+
throw new SphereError(`"${nametag}" has no DirectAddress stored. It may be a legacy registration.`, "INVALID_RECIPIENT");
|
|
7395
7546
|
}
|
|
7396
|
-
|
|
7547
|
+
logger.debug("Payments", `Using DirectAddress for "${nametag}" (forced): ${info.directAddress.slice(0, 30)}...`);
|
|
7397
7548
|
return AddressFactory.createAddress(info.directAddress);
|
|
7398
7549
|
}
|
|
7399
7550
|
if (info.directAddress) {
|
|
7400
|
-
|
|
7551
|
+
logger.debug("Payments", `Using DirectAddress for "${nametag}": ${info.directAddress.slice(0, 30)}...`);
|
|
7401
7552
|
return AddressFactory.createAddress(info.directAddress);
|
|
7402
7553
|
}
|
|
7403
|
-
|
|
7554
|
+
logger.debug("Payments", `Using PROXY address for legacy nametag "${nametag}"`);
|
|
7404
7555
|
return ProxyAddress.fromNameTag(nametag);
|
|
7405
7556
|
}
|
|
7406
7557
|
/**
|
|
@@ -7413,7 +7564,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7413
7564
|
const sourceTokenInput = typeof payload.sourceToken === "string" ? JSON.parse(payload.sourceToken) : payload.sourceToken;
|
|
7414
7565
|
const commitmentInput = typeof payload.commitmentData === "string" ? JSON.parse(payload.commitmentData) : payload.commitmentData;
|
|
7415
7566
|
if (!sourceTokenInput || !commitmentInput) {
|
|
7416
|
-
|
|
7567
|
+
logger.warn("Payments", "Invalid NOSTR-FIRST transfer format");
|
|
7417
7568
|
return;
|
|
7418
7569
|
}
|
|
7419
7570
|
const token = await this.saveCommitmentOnlyToken(
|
|
@@ -7444,7 +7595,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7444
7595
|
tokenId: nostrTokenId || token.id
|
|
7445
7596
|
});
|
|
7446
7597
|
} catch (error) {
|
|
7447
|
-
|
|
7598
|
+
logger.error("Payments", "Failed to process NOSTR-FIRST transfer:", error);
|
|
7448
7599
|
}
|
|
7449
7600
|
}
|
|
7450
7601
|
/**
|
|
@@ -7469,18 +7620,19 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7469
7620
|
const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
|
|
7470
7621
|
let proxyNametag = this.getNametag();
|
|
7471
7622
|
if (!proxyNametag?.token) {
|
|
7472
|
-
|
|
7623
|
+
logger.debug("Payments", "Nametag missing in memory, attempting reload from storage...");
|
|
7473
7624
|
await this.reloadNametagsFromStorage();
|
|
7474
7625
|
proxyNametag = this.getNametag();
|
|
7475
7626
|
}
|
|
7476
7627
|
if (!proxyNametag?.token) {
|
|
7477
|
-
throw new
|
|
7628
|
+
throw new SphereError("Cannot finalize PROXY transfer - no nametag token", "VALIDATION_ERROR");
|
|
7478
7629
|
}
|
|
7479
7630
|
const nametagToken = await SdkToken2.fromJSON(proxyNametag.token);
|
|
7480
7631
|
const proxy = await ProxyAddress.fromTokenId(nametagToken.id);
|
|
7481
7632
|
if (proxy.address !== recipientAddress.address) {
|
|
7482
|
-
throw new
|
|
7483
|
-
`PROXY address mismatch: nametag resolves to ${proxy.address} but transfer targets ${recipientAddress.address}
|
|
7633
|
+
throw new SphereError(
|
|
7634
|
+
`PROXY address mismatch: nametag resolves to ${proxy.address} but transfer targets ${recipientAddress.address}`,
|
|
7635
|
+
"VALIDATION_ERROR"
|
|
7484
7636
|
);
|
|
7485
7637
|
}
|
|
7486
7638
|
nametagTokens = [nametagToken];
|
|
@@ -7500,12 +7652,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7500
7652
|
try {
|
|
7501
7653
|
const token = this.tokens.get(tokenId);
|
|
7502
7654
|
if (!token) {
|
|
7503
|
-
|
|
7655
|
+
logger.debug("Payments", `Token ${tokenId} not found for finalization`);
|
|
7504
7656
|
return;
|
|
7505
7657
|
}
|
|
7506
7658
|
const commitment = await TransferCommitment4.fromJSON(commitmentInput);
|
|
7507
7659
|
if (!this.deps.oracle.waitForProofSdk) {
|
|
7508
|
-
|
|
7660
|
+
logger.debug("Payments", "Cannot finalize - no waitForProofSdk");
|
|
7509
7661
|
token.status = "confirmed";
|
|
7510
7662
|
token.updatedAt = Date.now();
|
|
7511
7663
|
await this.save();
|
|
@@ -7517,7 +7669,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7517
7669
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
7518
7670
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
7519
7671
|
if (!stClient || !trustBase) {
|
|
7520
|
-
|
|
7672
|
+
logger.debug("Payments", "Cannot finalize - missing state transition client or trust base");
|
|
7521
7673
|
token.status = "confirmed";
|
|
7522
7674
|
token.updatedAt = Date.now();
|
|
7523
7675
|
await this.save();
|
|
@@ -7537,7 +7689,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7537
7689
|
};
|
|
7538
7690
|
this.tokens.set(tokenId, finalizedToken);
|
|
7539
7691
|
await this.save();
|
|
7540
|
-
|
|
7692
|
+
logger.debug("Payments", `NOSTR-FIRST: Token ${tokenId.slice(0, 8)}... finalized and confirmed`);
|
|
7541
7693
|
this.deps.emitEvent("transfer:confirmed", {
|
|
7542
7694
|
id: crypto.randomUUID(),
|
|
7543
7695
|
status: "completed",
|
|
@@ -7545,7 +7697,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7545
7697
|
tokenTransfers: []
|
|
7546
7698
|
});
|
|
7547
7699
|
} catch (error) {
|
|
7548
|
-
|
|
7700
|
+
logger.error("Payments", "Failed to finalize received token:", error);
|
|
7549
7701
|
const token = this.tokens.get(tokenId);
|
|
7550
7702
|
if (token && token.status === "submitted") {
|
|
7551
7703
|
token.status = "confirmed";
|
|
@@ -7560,7 +7712,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7560
7712
|
}
|
|
7561
7713
|
try {
|
|
7562
7714
|
const payload = transfer.payload;
|
|
7563
|
-
|
|
7715
|
+
logger.debug("Payments", "handleIncomingTransfer: keys=", Object.keys(payload).join(","));
|
|
7564
7716
|
let combinedBundle = null;
|
|
7565
7717
|
if (isCombinedTransferBundleV6(payload)) {
|
|
7566
7718
|
combinedBundle = payload;
|
|
@@ -7574,12 +7726,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7574
7726
|
}
|
|
7575
7727
|
}
|
|
7576
7728
|
if (combinedBundle) {
|
|
7577
|
-
|
|
7729
|
+
logger.debug("Payments", "Processing COMBINED_TRANSFER V6 bundle...");
|
|
7578
7730
|
try {
|
|
7579
7731
|
await this.processCombinedTransferBundle(combinedBundle, transfer.senderTransportPubkey);
|
|
7580
|
-
|
|
7732
|
+
logger.debug("Payments", "COMBINED_TRANSFER V6 processed successfully");
|
|
7581
7733
|
} catch (err) {
|
|
7582
|
-
|
|
7734
|
+
logger.error("Payments", "COMBINED_TRANSFER V6 processing error:", err);
|
|
7583
7735
|
}
|
|
7584
7736
|
return;
|
|
7585
7737
|
}
|
|
@@ -7596,7 +7748,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7596
7748
|
}
|
|
7597
7749
|
}
|
|
7598
7750
|
if (instantBundle) {
|
|
7599
|
-
|
|
7751
|
+
logger.debug("Payments", "Processing INSTANT_SPLIT bundle...");
|
|
7600
7752
|
try {
|
|
7601
7753
|
const result = await this.processInstantSplitBundle(
|
|
7602
7754
|
instantBundle,
|
|
@@ -7604,28 +7756,28 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7604
7756
|
payload.memo
|
|
7605
7757
|
);
|
|
7606
7758
|
if (result.success) {
|
|
7607
|
-
|
|
7759
|
+
logger.debug("Payments", "INSTANT_SPLIT processed successfully");
|
|
7608
7760
|
} else {
|
|
7609
|
-
|
|
7761
|
+
logger.warn("Payments", "INSTANT_SPLIT processing failed:", result.error);
|
|
7610
7762
|
}
|
|
7611
7763
|
} catch (err) {
|
|
7612
|
-
|
|
7764
|
+
logger.error("Payments", "INSTANT_SPLIT processing error:", err);
|
|
7613
7765
|
}
|
|
7614
7766
|
return;
|
|
7615
7767
|
}
|
|
7616
7768
|
if (payload.sourceToken && payload.commitmentData && !payload.transferTx) {
|
|
7617
|
-
|
|
7769
|
+
logger.debug("Payments", "NOSTR-FIRST commitment-only transfer detected");
|
|
7618
7770
|
await this.handleCommitmentOnlyTransfer(transfer, payload);
|
|
7619
7771
|
return;
|
|
7620
7772
|
}
|
|
7621
7773
|
let tokenData;
|
|
7622
7774
|
let finalizedSdkToken = null;
|
|
7623
7775
|
if (payload.sourceToken && payload.transferTx) {
|
|
7624
|
-
|
|
7776
|
+
logger.debug("Payments", "Processing Sphere wallet format transfer...");
|
|
7625
7777
|
const sourceTokenInput = typeof payload.sourceToken === "string" ? JSON.parse(payload.sourceToken) : payload.sourceToken;
|
|
7626
7778
|
const transferTxInput = typeof payload.transferTx === "string" ? JSON.parse(payload.transferTx) : payload.transferTx;
|
|
7627
7779
|
if (!sourceTokenInput || !transferTxInput) {
|
|
7628
|
-
|
|
7780
|
+
logger.warn("Payments", "Invalid Sphere wallet transfer format");
|
|
7629
7781
|
return;
|
|
7630
7782
|
}
|
|
7631
7783
|
let sourceToken;
|
|
@@ -7633,7 +7785,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7633
7785
|
try {
|
|
7634
7786
|
sourceToken = await SdkToken2.fromJSON(sourceTokenInput);
|
|
7635
7787
|
} catch (err) {
|
|
7636
|
-
|
|
7788
|
+
logger.error("Payments", "Failed to parse sourceToken:", err);
|
|
7637
7789
|
return;
|
|
7638
7790
|
}
|
|
7639
7791
|
try {
|
|
@@ -7647,16 +7799,16 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7647
7799
|
const commitment = await TransferCommitment4.fromJSON(transferTxInput);
|
|
7648
7800
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
7649
7801
|
if (!stClient) {
|
|
7650
|
-
|
|
7802
|
+
logger.error("Payments", "Cannot process commitment - no state transition client");
|
|
7651
7803
|
return;
|
|
7652
7804
|
}
|
|
7653
7805
|
const response = await stClient.submitTransferCommitment(commitment);
|
|
7654
7806
|
if (response.status !== "SUCCESS" && response.status !== "REQUEST_ID_EXISTS") {
|
|
7655
|
-
|
|
7807
|
+
logger.error("Payments", "Transfer commitment submission failed:", response.status);
|
|
7656
7808
|
return;
|
|
7657
7809
|
}
|
|
7658
7810
|
if (!this.deps.oracle.waitForProofSdk) {
|
|
7659
|
-
|
|
7811
|
+
logger.error("Payments", "Cannot wait for proof - missing oracle method");
|
|
7660
7812
|
return;
|
|
7661
7813
|
}
|
|
7662
7814
|
const inclusionProof = await this.deps.oracle.waitForProofSdk(commitment);
|
|
@@ -7668,7 +7820,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7668
7820
|
const commitment = await TransferCommitment4.fromJSON(transferTxInput);
|
|
7669
7821
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
7670
7822
|
if (!stClient || !this.deps.oracle.waitForProofSdk) {
|
|
7671
|
-
throw new
|
|
7823
|
+
throw new SphereError("Cannot submit commitment - missing oracle methods", "AGGREGATOR_ERROR");
|
|
7672
7824
|
}
|
|
7673
7825
|
await stClient.submitTransferCommitment(commitment);
|
|
7674
7826
|
const inclusionProof = await this.deps.oracle.waitForProofSdk(commitment);
|
|
@@ -7676,33 +7828,33 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7676
7828
|
}
|
|
7677
7829
|
}
|
|
7678
7830
|
} catch (err) {
|
|
7679
|
-
|
|
7831
|
+
logger.error("Payments", "Failed to parse transferTx:", err);
|
|
7680
7832
|
return;
|
|
7681
7833
|
}
|
|
7682
7834
|
try {
|
|
7683
7835
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
7684
7836
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
7685
7837
|
if (!stClient || !trustBase) {
|
|
7686
|
-
|
|
7838
|
+
logger.error("Payments", "Cannot finalize - missing state transition client or trust base. Token rejected.");
|
|
7687
7839
|
return;
|
|
7688
7840
|
}
|
|
7689
7841
|
finalizedSdkToken = await this.finalizeTransferToken(sourceToken, transferTx, stClient, trustBase);
|
|
7690
7842
|
tokenData = finalizedSdkToken.toJSON();
|
|
7691
7843
|
const addressScheme = transferTx.data.recipient.scheme;
|
|
7692
|
-
|
|
7844
|
+
logger.debug("Payments", `${addressScheme === AddressScheme.PROXY ? "PROXY" : "DIRECT"} finalization successful`);
|
|
7693
7845
|
} catch (finalizeError) {
|
|
7694
|
-
|
|
7846
|
+
logger.error("Payments", "Finalization FAILED - token rejected:", finalizeError);
|
|
7695
7847
|
return;
|
|
7696
7848
|
}
|
|
7697
7849
|
} else if (payload.token) {
|
|
7698
7850
|
tokenData = payload.token;
|
|
7699
7851
|
} else {
|
|
7700
|
-
|
|
7852
|
+
logger.warn("Payments", "Unknown transfer payload format");
|
|
7701
7853
|
return;
|
|
7702
7854
|
}
|
|
7703
7855
|
const validation = await this.deps.oracle.validateToken(tokenData);
|
|
7704
7856
|
if (!validation.valid) {
|
|
7705
|
-
|
|
7857
|
+
logger.warn("Payments", "Received invalid token");
|
|
7706
7858
|
return;
|
|
7707
7859
|
}
|
|
7708
7860
|
const tokenInfo = await parseTokenInfo(tokenData);
|
|
@@ -7743,12 +7895,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7743
7895
|
receivedAt: transfer.timestamp
|
|
7744
7896
|
};
|
|
7745
7897
|
this.deps.emitEvent("transfer:incoming", incomingTransfer);
|
|
7746
|
-
|
|
7898
|
+
logger.debug("Payments", `Incoming transfer processed: ${token.id}, ${token.amount} ${token.symbol}`);
|
|
7747
7899
|
} else {
|
|
7748
|
-
|
|
7900
|
+
logger.debug("Payments", `Duplicate transfer ignored: ${token.id}, ${token.amount} ${token.symbol}`);
|
|
7749
7901
|
}
|
|
7750
7902
|
} catch (error) {
|
|
7751
|
-
|
|
7903
|
+
logger.error("Payments", "Failed to process incoming transfer:", error);
|
|
7752
7904
|
}
|
|
7753
7905
|
}
|
|
7754
7906
|
// ===========================================================================
|
|
@@ -7763,15 +7915,15 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7763
7915
|
if (existingArchive) {
|
|
7764
7916
|
if (isIncrementalUpdate(existingArchive, txf)) {
|
|
7765
7917
|
this.archivedTokens.set(tokenId, txf);
|
|
7766
|
-
|
|
7918
|
+
logger.debug("Payments", `Updated archived token ${tokenId.slice(0, 8)}...`);
|
|
7767
7919
|
} else {
|
|
7768
7920
|
const stateHash = getCurrentStateHash(txf) || "";
|
|
7769
7921
|
await this.storeForkedToken(tokenId, stateHash, txf);
|
|
7770
|
-
|
|
7922
|
+
logger.debug("Payments", `Archived token ${tokenId.slice(0, 8)}... is a fork`);
|
|
7771
7923
|
}
|
|
7772
7924
|
} else {
|
|
7773
7925
|
this.archivedTokens.set(tokenId, txf);
|
|
7774
|
-
|
|
7926
|
+
logger.debug("Payments", `Archived token ${tokenId.slice(0, 8)}...`);
|
|
7775
7927
|
}
|
|
7776
7928
|
}
|
|
7777
7929
|
// ===========================================================================
|
|
@@ -7783,20 +7935,20 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7783
7935
|
const txf = tokenToTxf(t);
|
|
7784
7936
|
return `${t.id.slice(0, 12)}(${t.status},txf=${!!txf})`;
|
|
7785
7937
|
});
|
|
7786
|
-
|
|
7938
|
+
logger.debug("Payments", `save(): providers=${providers.size}, tokens=[${tokenStats.join(", ")}]`);
|
|
7787
7939
|
if (providers.size > 0) {
|
|
7788
7940
|
const data = await this.createStorageData();
|
|
7789
7941
|
const dataKeys = Object.keys(data).filter((k) => k.startsWith("token-"));
|
|
7790
|
-
|
|
7942
|
+
logger.debug("Payments", `save(): TXF keys=${dataKeys.length} (${dataKeys.join(", ")})`);
|
|
7791
7943
|
for (const [id, provider] of providers) {
|
|
7792
7944
|
try {
|
|
7793
7945
|
await provider.save(data);
|
|
7794
7946
|
} catch (err) {
|
|
7795
|
-
|
|
7947
|
+
logger.error("Payments", `Failed to save to provider ${id}:`, err);
|
|
7796
7948
|
}
|
|
7797
7949
|
}
|
|
7798
7950
|
} else {
|
|
7799
|
-
|
|
7951
|
+
logger.debug("Payments", "save(): No token storage providers - TXF not persisted");
|
|
7800
7952
|
}
|
|
7801
7953
|
await this.savePendingV5Tokens();
|
|
7802
7954
|
}
|
|
@@ -7834,14 +7986,14 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7834
7986
|
}
|
|
7835
7987
|
loadFromStorageData(data) {
|
|
7836
7988
|
const parsed = parseTxfStorageData(data);
|
|
7837
|
-
|
|
7989
|
+
logger.debug("Payments", `loadFromStorageData: parsed ${parsed.tokens.length} tokens, ${parsed.tombstones.length} tombstones, errors=[${parsed.validationErrors.join("; ")}]`);
|
|
7838
7990
|
this.tombstones = parsed.tombstones;
|
|
7839
7991
|
this.tokens.clear();
|
|
7840
7992
|
for (const token of parsed.tokens) {
|
|
7841
7993
|
const sdkTokenId = extractTokenIdFromSdkData(token.sdkData);
|
|
7842
7994
|
const stateHash = extractStateHashFromSdkData(token.sdkData);
|
|
7843
7995
|
if (sdkTokenId && stateHash && this.isStateTombstoned(sdkTokenId, stateHash)) {
|
|
7844
|
-
|
|
7996
|
+
logger.debug("Payments", `Skipping tombstoned token ${sdkTokenId.slice(0, 8)}... during load (exact state match)`);
|
|
7845
7997
|
continue;
|
|
7846
7998
|
}
|
|
7847
7999
|
this.tokens.set(token.id, token);
|
|
@@ -7861,12 +8013,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7861
8013
|
try {
|
|
7862
8014
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
7863
8015
|
if (!stClient) {
|
|
7864
|
-
|
|
8016
|
+
logger.debug("Payments", "Cannot submit commitment - no state transition client");
|
|
7865
8017
|
return;
|
|
7866
8018
|
}
|
|
7867
8019
|
const response = await stClient.submitTransferCommitment(commitment);
|
|
7868
8020
|
if (response.status !== "SUCCESS" && response.status !== "REQUEST_ID_EXISTS") {
|
|
7869
|
-
|
|
8021
|
+
logger.debug("Payments", `Transfer commitment submission failed: ${response.status}`);
|
|
7870
8022
|
const token = this.tokens.get(tokenId);
|
|
7871
8023
|
if (token) {
|
|
7872
8024
|
token.status = "invalid";
|
|
@@ -7886,7 +8038,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7886
8038
|
onProofReceived
|
|
7887
8039
|
});
|
|
7888
8040
|
} catch (error) {
|
|
7889
|
-
|
|
8041
|
+
logger.debug("Payments", "submitAndPollForProof error:", error);
|
|
7890
8042
|
}
|
|
7891
8043
|
}
|
|
7892
8044
|
/**
|
|
@@ -7894,7 +8046,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7894
8046
|
*/
|
|
7895
8047
|
addProofPollingJob(job) {
|
|
7896
8048
|
this.proofPollingJobs.set(job.tokenId, job);
|
|
7897
|
-
|
|
8049
|
+
logger.debug("Payments", `Added proof polling job for token ${job.tokenId.slice(0, 8)}...`);
|
|
7898
8050
|
this.startProofPolling();
|
|
7899
8051
|
}
|
|
7900
8052
|
/**
|
|
@@ -7903,7 +8055,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7903
8055
|
startProofPolling() {
|
|
7904
8056
|
if (this.proofPollingInterval) return;
|
|
7905
8057
|
if (this.proofPollingJobs.size === 0) return;
|
|
7906
|
-
|
|
8058
|
+
logger.debug("Payments", "Starting proof polling...");
|
|
7907
8059
|
this.proofPollingInterval = setInterval(
|
|
7908
8060
|
() => this.processProofPollingQueue(),
|
|
7909
8061
|
_PaymentsModule.PROOF_POLLING_INTERVAL_MS
|
|
@@ -7916,7 +8068,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7916
8068
|
if (this.proofPollingInterval) {
|
|
7917
8069
|
clearInterval(this.proofPollingInterval);
|
|
7918
8070
|
this.proofPollingInterval = null;
|
|
7919
|
-
|
|
8071
|
+
logger.debug("Payments", "Stopped proof polling");
|
|
7920
8072
|
}
|
|
7921
8073
|
}
|
|
7922
8074
|
/**
|
|
@@ -7933,7 +8085,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7933
8085
|
job.attemptCount++;
|
|
7934
8086
|
job.lastAttemptAt = Date.now();
|
|
7935
8087
|
if (job.attemptCount >= _PaymentsModule.PROOF_POLLING_MAX_ATTEMPTS) {
|
|
7936
|
-
|
|
8088
|
+
logger.debug("Payments", `Proof polling timeout for token ${tokenId.slice(0, 8)}...`);
|
|
7937
8089
|
const token2 = this.tokens.get(tokenId);
|
|
7938
8090
|
if (token2 && token2.status === "submitted") {
|
|
7939
8091
|
token2.status = "invalid";
|
|
@@ -7972,12 +8124,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7972
8124
|
token.updatedAt = Date.now();
|
|
7973
8125
|
this.tokens.set(tokenId, token);
|
|
7974
8126
|
await this.save();
|
|
7975
|
-
|
|
8127
|
+
logger.debug("Payments", `Proof received for token ${tokenId.slice(0, 8)}..., status: spent`);
|
|
7976
8128
|
}
|
|
7977
8129
|
job.onProofReceived?.(tokenId);
|
|
7978
8130
|
completedJobs.push(tokenId);
|
|
7979
8131
|
} catch (error) {
|
|
7980
|
-
|
|
8132
|
+
logger.debug("Payments", `Proof polling attempt ${job.attemptCount} for ${tokenId.slice(0, 8)}...: ${error}`);
|
|
7981
8133
|
}
|
|
7982
8134
|
}
|
|
7983
8135
|
for (const tokenId of completedJobs) {
|
|
@@ -7992,7 +8144,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7992
8144
|
// ===========================================================================
|
|
7993
8145
|
ensureInitialized() {
|
|
7994
8146
|
if (!this.deps) {
|
|
7995
|
-
throw new
|
|
8147
|
+
throw new SphereError("PaymentsModule not initialized", "NOT_INITIALIZED");
|
|
7996
8148
|
}
|
|
7997
8149
|
}
|
|
7998
8150
|
};
|
|
@@ -8000,7 +8152,12 @@ function createPaymentsModule(config) {
|
|
|
8000
8152
|
return new PaymentsModule(config);
|
|
8001
8153
|
}
|
|
8002
8154
|
|
|
8155
|
+
// modules/payments/BackgroundCommitmentService.ts
|
|
8156
|
+
init_logger();
|
|
8157
|
+
init_errors();
|
|
8158
|
+
|
|
8003
8159
|
// modules/payments/TokenRecoveryService.ts
|
|
8160
|
+
init_logger();
|
|
8004
8161
|
import { TokenId as TokenId4 } from "@unicitylabs/state-transition-sdk/lib/token/TokenId";
|
|
8005
8162
|
import { TokenState as TokenState6 } from "@unicitylabs/state-transition-sdk/lib/token/TokenState";
|
|
8006
8163
|
import { TokenType as TokenType4 } from "@unicitylabs/state-transition-sdk/lib/token/TokenType";
|
|
@@ -8009,6 +8166,8 @@ import { HashAlgorithm as HashAlgorithm6 } from "@unicitylabs/state-transition-s
|
|
|
8009
8166
|
import { UnmaskedPredicate as UnmaskedPredicate6 } from "@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate";
|
|
8010
8167
|
|
|
8011
8168
|
// modules/communications/CommunicationsModule.ts
|
|
8169
|
+
init_logger();
|
|
8170
|
+
init_errors();
|
|
8012
8171
|
init_constants();
|
|
8013
8172
|
var CommunicationsModule = class {
|
|
8014
8173
|
config;
|
|
@@ -8103,7 +8262,7 @@ var CommunicationsModule = class {
|
|
|
8103
8262
|
}
|
|
8104
8263
|
if (myMessages.length > 0) {
|
|
8105
8264
|
await this.save();
|
|
8106
|
-
|
|
8265
|
+
logger.debug("Communications", `Migrated ${myMessages.length} messages to per-address storage`);
|
|
8107
8266
|
}
|
|
8108
8267
|
}
|
|
8109
8268
|
}
|
|
@@ -8189,7 +8348,7 @@ var CommunicationsModule = class {
|
|
|
8189
8348
|
const msg = this.messages.get(id);
|
|
8190
8349
|
if (msg && msg.senderPubkey !== this.deps.identity.chainPubkey) {
|
|
8191
8350
|
this.deps.transport.sendReadReceipt(msg.senderPubkey, id).catch((err) => {
|
|
8192
|
-
|
|
8351
|
+
logger.warn("Communications", "Failed to send read receipt:", err);
|
|
8193
8352
|
});
|
|
8194
8353
|
}
|
|
8195
8354
|
}
|
|
@@ -8389,7 +8548,7 @@ var CommunicationsModule = class {
|
|
|
8389
8548
|
try {
|
|
8390
8549
|
handler(message);
|
|
8391
8550
|
} catch (error) {
|
|
8392
|
-
|
|
8551
|
+
logger.error("Communications", "Handler error:", error);
|
|
8393
8552
|
}
|
|
8394
8553
|
}
|
|
8395
8554
|
if (this.config.autoSave) {
|
|
@@ -8408,7 +8567,7 @@ var CommunicationsModule = class {
|
|
|
8408
8567
|
try {
|
|
8409
8568
|
handler(composing);
|
|
8410
8569
|
} catch (error) {
|
|
8411
|
-
|
|
8570
|
+
logger.error("Communications", "Composing handler error:", error);
|
|
8412
8571
|
}
|
|
8413
8572
|
}
|
|
8414
8573
|
}
|
|
@@ -8426,7 +8585,7 @@ var CommunicationsModule = class {
|
|
|
8426
8585
|
try {
|
|
8427
8586
|
handler(message);
|
|
8428
8587
|
} catch (error) {
|
|
8429
|
-
|
|
8588
|
+
logger.error("Communications", "Handler error:", error);
|
|
8430
8589
|
}
|
|
8431
8590
|
}
|
|
8432
8591
|
}
|
|
@@ -8467,7 +8626,7 @@ var CommunicationsModule = class {
|
|
|
8467
8626
|
const nametag = recipient.slice(1);
|
|
8468
8627
|
const pubkey = await this.deps.transport.resolveNametag?.(nametag);
|
|
8469
8628
|
if (!pubkey) {
|
|
8470
|
-
throw new
|
|
8629
|
+
throw new SphereError(`Nametag not found: ${recipient}`, "INVALID_RECIPIENT");
|
|
8471
8630
|
}
|
|
8472
8631
|
return { pubkey, nametag };
|
|
8473
8632
|
}
|
|
@@ -8475,7 +8634,7 @@ var CommunicationsModule = class {
|
|
|
8475
8634
|
}
|
|
8476
8635
|
ensureInitialized() {
|
|
8477
8636
|
if (!this.deps) {
|
|
8478
|
-
throw new
|
|
8637
|
+
throw new SphereError("CommunicationsModule not initialized", "NOT_INITIALIZED");
|
|
8479
8638
|
}
|
|
8480
8639
|
}
|
|
8481
8640
|
};
|
|
@@ -8484,6 +8643,8 @@ function createCommunicationsModule(config) {
|
|
|
8484
8643
|
}
|
|
8485
8644
|
|
|
8486
8645
|
// modules/groupchat/GroupChatModule.ts
|
|
8646
|
+
init_logger();
|
|
8647
|
+
init_errors();
|
|
8487
8648
|
init_constants();
|
|
8488
8649
|
import {
|
|
8489
8650
|
NostrClient,
|
|
@@ -8634,13 +8795,15 @@ var GroupChatModule = class {
|
|
|
8634
8795
|
for (const subId of this.subscriptionIds) {
|
|
8635
8796
|
try {
|
|
8636
8797
|
this.client.unsubscribe(subId);
|
|
8637
|
-
} catch {
|
|
8798
|
+
} catch (err) {
|
|
8799
|
+
logger.debug("GroupChat", "Failed to unsubscribe", err);
|
|
8638
8800
|
}
|
|
8639
8801
|
}
|
|
8640
8802
|
this.subscriptionIds = [];
|
|
8641
8803
|
try {
|
|
8642
8804
|
this.client.disconnect();
|
|
8643
|
-
} catch {
|
|
8805
|
+
} catch (err) {
|
|
8806
|
+
logger.debug("GroupChat", "Failed to disconnect", err);
|
|
8644
8807
|
}
|
|
8645
8808
|
this.client = null;
|
|
8646
8809
|
}
|
|
@@ -8680,7 +8843,8 @@ var GroupChatModule = class {
|
|
|
8680
8843
|
for (const subId of this.subscriptionIds) {
|
|
8681
8844
|
try {
|
|
8682
8845
|
this.client.unsubscribe(subId);
|
|
8683
|
-
} catch {
|
|
8846
|
+
} catch (err) {
|
|
8847
|
+
logger.debug("GroupChat", "Failed to unsubscribe", err);
|
|
8684
8848
|
}
|
|
8685
8849
|
}
|
|
8686
8850
|
this.subscriptionIds = [];
|
|
@@ -8715,21 +8879,21 @@ var GroupChatModule = class {
|
|
|
8715
8879
|
}
|
|
8716
8880
|
this.deps.emitEvent("groupchat:connection", { connected: true });
|
|
8717
8881
|
} catch (error) {
|
|
8718
|
-
|
|
8882
|
+
logger.error("GroupChat", "Failed to connect to relays", error);
|
|
8719
8883
|
this.deps.emitEvent("groupchat:connection", { connected: false });
|
|
8720
8884
|
this.scheduleReconnect();
|
|
8721
8885
|
}
|
|
8722
8886
|
}
|
|
8723
8887
|
scheduleReconnect() {
|
|
8724
8888
|
if (this.reconnectAttempts >= this.config.maxReconnectAttempts) {
|
|
8725
|
-
|
|
8889
|
+
logger.error("GroupChat", "Max reconnection attempts reached");
|
|
8726
8890
|
return;
|
|
8727
8891
|
}
|
|
8728
8892
|
this.reconnectAttempts++;
|
|
8729
8893
|
this.reconnectTimer = setTimeout(() => {
|
|
8730
8894
|
this.reconnectTimer = null;
|
|
8731
8895
|
if (this.deps) {
|
|
8732
|
-
this.connect().catch(
|
|
8896
|
+
this.connect().catch((err) => logger.error("GroupChat", "Reconnect failed:", err));
|
|
8733
8897
|
}
|
|
8734
8898
|
}, this.config.reconnectDelayMs);
|
|
8735
8899
|
}
|
|
@@ -8964,7 +9128,8 @@ var GroupChatModule = class {
|
|
|
8964
9128
|
},
|
|
8965
9129
|
onComplete: () => {
|
|
8966
9130
|
},
|
|
8967
|
-
timeoutMs: 15e3
|
|
9131
|
+
timeoutMs: 15e3,
|
|
9132
|
+
timeoutLabel: "restoreJoinedGroups"
|
|
8968
9133
|
}
|
|
8969
9134
|
);
|
|
8970
9135
|
if (groupIdsWithMembership.size === 0) return [];
|
|
@@ -8981,7 +9146,8 @@ var GroupChatModule = class {
|
|
|
8981
9146
|
this.fetchMessages(groupId)
|
|
8982
9147
|
]);
|
|
8983
9148
|
}
|
|
8984
|
-
} catch {
|
|
9149
|
+
} catch (error) {
|
|
9150
|
+
logger.warn("GroupChat", "Failed to restore group", groupId, error);
|
|
8985
9151
|
}
|
|
8986
9152
|
}
|
|
8987
9153
|
if (restoredGroups.length > 0) {
|
|
@@ -9014,7 +9180,8 @@ var GroupChatModule = class {
|
|
|
9014
9180
|
},
|
|
9015
9181
|
onComplete: () => {
|
|
9016
9182
|
},
|
|
9017
|
-
timeoutMs: 1e4
|
|
9183
|
+
timeoutMs: 1e4,
|
|
9184
|
+
timeoutLabel: "fetchAvailableGroups(metadata)"
|
|
9018
9185
|
}
|
|
9019
9186
|
),
|
|
9020
9187
|
this.oneshotSubscription(
|
|
@@ -9029,7 +9196,8 @@ var GroupChatModule = class {
|
|
|
9029
9196
|
},
|
|
9030
9197
|
onComplete: () => {
|
|
9031
9198
|
},
|
|
9032
|
-
timeoutMs: 1e4
|
|
9199
|
+
timeoutMs: 1e4,
|
|
9200
|
+
timeoutLabel: "fetchAvailableGroups(members)"
|
|
9033
9201
|
}
|
|
9034
9202
|
)
|
|
9035
9203
|
]);
|
|
@@ -9088,7 +9256,7 @@ var GroupChatModule = class {
|
|
|
9088
9256
|
return true;
|
|
9089
9257
|
}
|
|
9090
9258
|
}
|
|
9091
|
-
|
|
9259
|
+
logger.error("GroupChat", "Failed to join group", error);
|
|
9092
9260
|
return false;
|
|
9093
9261
|
}
|
|
9094
9262
|
}
|
|
@@ -9118,7 +9286,7 @@ var GroupChatModule = class {
|
|
|
9118
9286
|
this.persistAll();
|
|
9119
9287
|
return true;
|
|
9120
9288
|
}
|
|
9121
|
-
|
|
9289
|
+
logger.error("GroupChat", "Failed to leave group", error);
|
|
9122
9290
|
return false;
|
|
9123
9291
|
}
|
|
9124
9292
|
}
|
|
@@ -9169,10 +9337,8 @@ var GroupChatModule = class {
|
|
|
9169
9337
|
kind: NIP29_KINDS.JOIN_REQUEST,
|
|
9170
9338
|
tags: [["h", group.id]],
|
|
9171
9339
|
content: ""
|
|
9172
|
-
}).catch(() =>
|
|
9173
|
-
|
|
9174
|
-
await this.fetchAndSaveMembers(group.id).catch(() => {
|
|
9175
|
-
});
|
|
9340
|
+
}).catch((err) => logger.debug("GroupChat", "Background operation failed", err));
|
|
9341
|
+
await this.fetchAndSaveMembers(group.id).catch((err) => logger.debug("GroupChat", "Failed to fetch members", group.id, err));
|
|
9176
9342
|
this.saveMemberToMemory({
|
|
9177
9343
|
pubkey: creatorPubkey,
|
|
9178
9344
|
groupId: group.id,
|
|
@@ -9184,7 +9350,7 @@ var GroupChatModule = class {
|
|
|
9184
9350
|
this.schedulePersist();
|
|
9185
9351
|
return group;
|
|
9186
9352
|
} catch (error) {
|
|
9187
|
-
|
|
9353
|
+
logger.error("GroupChat", "Failed to create group", error);
|
|
9188
9354
|
return null;
|
|
9189
9355
|
}
|
|
9190
9356
|
}
|
|
@@ -9211,7 +9377,7 @@ var GroupChatModule = class {
|
|
|
9211
9377
|
}
|
|
9212
9378
|
return false;
|
|
9213
9379
|
} catch (error) {
|
|
9214
|
-
|
|
9380
|
+
logger.error("GroupChat", "Failed to delete group", error);
|
|
9215
9381
|
return false;
|
|
9216
9382
|
}
|
|
9217
9383
|
}
|
|
@@ -9231,7 +9397,7 @@ var GroupChatModule = class {
|
|
|
9231
9397
|
});
|
|
9232
9398
|
return eventId ? inviteCode : null;
|
|
9233
9399
|
} catch (error) {
|
|
9234
|
-
|
|
9400
|
+
logger.error("GroupChat", "Failed to create invite", error);
|
|
9235
9401
|
return null;
|
|
9236
9402
|
}
|
|
9237
9403
|
}
|
|
@@ -9281,7 +9447,7 @@ var GroupChatModule = class {
|
|
|
9281
9447
|
}
|
|
9282
9448
|
return null;
|
|
9283
9449
|
} catch (error) {
|
|
9284
|
-
|
|
9450
|
+
logger.error("GroupChat", "Failed to send message", error);
|
|
9285
9451
|
return null;
|
|
9286
9452
|
}
|
|
9287
9453
|
}
|
|
@@ -9320,7 +9486,8 @@ var GroupChatModule = class {
|
|
|
9320
9486
|
this.schedulePersist();
|
|
9321
9487
|
return fetchedMessages;
|
|
9322
9488
|
},
|
|
9323
|
-
timeoutMs: 1e4
|
|
9489
|
+
timeoutMs: 1e4,
|
|
9490
|
+
timeoutLabel: `fetchMessages(${groupId})`
|
|
9324
9491
|
});
|
|
9325
9492
|
}
|
|
9326
9493
|
// ===========================================================================
|
|
@@ -9381,7 +9548,7 @@ var GroupChatModule = class {
|
|
|
9381
9548
|
}
|
|
9382
9549
|
return false;
|
|
9383
9550
|
} catch (error) {
|
|
9384
|
-
|
|
9551
|
+
logger.error("GroupChat", "Failed to kick user", error);
|
|
9385
9552
|
return false;
|
|
9386
9553
|
}
|
|
9387
9554
|
}
|
|
@@ -9404,7 +9571,7 @@ var GroupChatModule = class {
|
|
|
9404
9571
|
}
|
|
9405
9572
|
return false;
|
|
9406
9573
|
} catch (error) {
|
|
9407
|
-
|
|
9574
|
+
logger.error("GroupChat", "Failed to delete message", error);
|
|
9408
9575
|
return false;
|
|
9409
9576
|
}
|
|
9410
9577
|
}
|
|
@@ -9689,7 +9856,7 @@ var GroupChatModule = class {
|
|
|
9689
9856
|
this.persistTimer = setTimeout(() => {
|
|
9690
9857
|
this.persistTimer = null;
|
|
9691
9858
|
this.persistPromise = this.doPersistAll().catch((err) => {
|
|
9692
|
-
|
|
9859
|
+
logger.error("GroupChat", "Persistence error:", err);
|
|
9693
9860
|
}).finally(() => {
|
|
9694
9861
|
this.persistPromise = null;
|
|
9695
9862
|
});
|
|
@@ -9869,7 +10036,8 @@ var GroupChatModule = class {
|
|
|
9869
10036
|
if (state.subId) {
|
|
9870
10037
|
try {
|
|
9871
10038
|
this.client.unsubscribe(state.subId);
|
|
9872
|
-
} catch {
|
|
10039
|
+
} catch (err) {
|
|
10040
|
+
logger.debug("GroupChat", "Failed to unsubscribe", err);
|
|
9873
10041
|
}
|
|
9874
10042
|
const idx = this.subscriptionIds.indexOf(state.subId);
|
|
9875
10043
|
if (idx >= 0) this.subscriptionIds.splice(idx, 1);
|
|
@@ -9884,12 +10052,17 @@ var GroupChatModule = class {
|
|
|
9884
10052
|
});
|
|
9885
10053
|
state.subId = subId;
|
|
9886
10054
|
this.subscriptionIds.push(subId);
|
|
9887
|
-
setTimeout(
|
|
10055
|
+
setTimeout(() => {
|
|
10056
|
+
if (!done && opts.timeoutLabel) {
|
|
10057
|
+
logger.warn("GroupChat", `${opts.timeoutLabel} timed out`);
|
|
10058
|
+
}
|
|
10059
|
+
finish();
|
|
10060
|
+
}, opts.timeoutMs ?? 5e3);
|
|
9888
10061
|
});
|
|
9889
10062
|
}
|
|
9890
10063
|
ensureInitialized() {
|
|
9891
10064
|
if (!this.deps) {
|
|
9892
|
-
throw new
|
|
10065
|
+
throw new SphereError("GroupChatModule not initialized", "NOT_INITIALIZED");
|
|
9893
10066
|
}
|
|
9894
10067
|
}
|
|
9895
10068
|
async ensureConnected() {
|
|
@@ -12058,6 +12231,7 @@ var Pointk1 = /* @__PURE__ */ weierstrass(secp256k1_CURVE, {
|
|
|
12058
12231
|
var secp256k1 = /* @__PURE__ */ ecdsa(Pointk1, sha2564);
|
|
12059
12232
|
|
|
12060
12233
|
// modules/market/MarketModule.ts
|
|
12234
|
+
init_errors();
|
|
12061
12235
|
var DEFAULT_MARKET_API_URL = "https://market-api.unicity.network";
|
|
12062
12236
|
function hexToBytes3(hex) {
|
|
12063
12237
|
const len = hex.length >> 1;
|
|
@@ -12247,7 +12421,7 @@ var MarketModule = class {
|
|
|
12247
12421
|
// ---------------------------------------------------------------------------
|
|
12248
12422
|
ensureIdentity() {
|
|
12249
12423
|
if (!this.identity) {
|
|
12250
|
-
throw new
|
|
12424
|
+
throw new SphereError("MarketModule not initialized \u2014 call initialize() first", "NOT_INITIALIZED");
|
|
12251
12425
|
}
|
|
12252
12426
|
}
|
|
12253
12427
|
/** Register the agent's public key with the server (idempotent) */
|
|
@@ -12273,7 +12447,7 @@ var MarketModule = class {
|
|
|
12273
12447
|
data = JSON.parse(text);
|
|
12274
12448
|
} catch {
|
|
12275
12449
|
}
|
|
12276
|
-
throw new
|
|
12450
|
+
throw new SphereError(data?.error ?? `Agent registration failed: HTTP ${res.status}`, "NETWORK_ERROR");
|
|
12277
12451
|
}
|
|
12278
12452
|
async parseResponse(res) {
|
|
12279
12453
|
const text = await res.text();
|
|
@@ -12281,9 +12455,9 @@ var MarketModule = class {
|
|
|
12281
12455
|
try {
|
|
12282
12456
|
data = JSON.parse(text);
|
|
12283
12457
|
} catch {
|
|
12284
|
-
throw new
|
|
12458
|
+
throw new SphereError(`Market API error: HTTP ${res.status} \u2014 unexpected response (not JSON)`, "NETWORK_ERROR");
|
|
12285
12459
|
}
|
|
12286
|
-
if (!res.ok) throw new
|
|
12460
|
+
if (!res.ok) throw new SphereError(data.error ?? `HTTP ${res.status}`, "NETWORK_ERROR");
|
|
12287
12461
|
return data;
|
|
12288
12462
|
}
|
|
12289
12463
|
async apiPost(path, body) {
|
|
@@ -12338,6 +12512,8 @@ function createMarketModule(config) {
|
|
|
12338
12512
|
init_constants();
|
|
12339
12513
|
|
|
12340
12514
|
// core/encryption.ts
|
|
12515
|
+
init_errors();
|
|
12516
|
+
init_logger();
|
|
12341
12517
|
import CryptoJS6 from "crypto-js";
|
|
12342
12518
|
var DEFAULT_ITERATIONS = 1e5;
|
|
12343
12519
|
var KEY_SIZE = 256;
|
|
@@ -12386,7 +12562,7 @@ function decrypt2(encryptedData, password) {
|
|
|
12386
12562
|
});
|
|
12387
12563
|
const result = decrypted.toString(CryptoJS6.enc.Utf8);
|
|
12388
12564
|
if (!result) {
|
|
12389
|
-
throw new
|
|
12565
|
+
throw new SphereError("Decryption failed: invalid password or corrupted data", "DECRYPTION_ERROR");
|
|
12390
12566
|
}
|
|
12391
12567
|
return result;
|
|
12392
12568
|
}
|
|
@@ -12395,7 +12571,7 @@ function decryptJson(encryptedData, password) {
|
|
|
12395
12571
|
try {
|
|
12396
12572
|
return JSON.parse(decrypted);
|
|
12397
12573
|
} catch {
|
|
12398
|
-
throw new
|
|
12574
|
+
throw new SphereError("Decryption failed: invalid JSON data", "DECRYPTION_ERROR");
|
|
12399
12575
|
}
|
|
12400
12576
|
}
|
|
12401
12577
|
function encryptSimple(plaintext, password) {
|
|
@@ -12405,7 +12581,7 @@ function decryptSimple(ciphertext, password) {
|
|
|
12405
12581
|
const decrypted = CryptoJS6.AES.decrypt(ciphertext, password);
|
|
12406
12582
|
const result = decrypted.toString(CryptoJS6.enc.Utf8);
|
|
12407
12583
|
if (!result) {
|
|
12408
|
-
throw new
|
|
12584
|
+
throw new SphereError("Decryption failed: invalid password or corrupted data", "DECRYPTION_ERROR");
|
|
12409
12585
|
}
|
|
12410
12586
|
return result;
|
|
12411
12587
|
}
|
|
@@ -12419,7 +12595,8 @@ function decryptWithSalt(ciphertext, password, salt) {
|
|
|
12419
12595
|
const decrypted = CryptoJS6.AES.decrypt(ciphertext, key);
|
|
12420
12596
|
const result = decrypted.toString(CryptoJS6.enc.Utf8);
|
|
12421
12597
|
return result || null;
|
|
12422
|
-
} catch {
|
|
12598
|
+
} catch (err) {
|
|
12599
|
+
logger.debug("Encryption", "decryptWithSalt failed", err);
|
|
12423
12600
|
return null;
|
|
12424
12601
|
}
|
|
12425
12602
|
}
|
|
@@ -12442,7 +12619,7 @@ function serializeEncrypted(data) {
|
|
|
12442
12619
|
function deserializeEncrypted(serialized) {
|
|
12443
12620
|
const parsed = JSON.parse(serialized);
|
|
12444
12621
|
if (!isEncryptedData(parsed)) {
|
|
12445
|
-
throw new
|
|
12622
|
+
throw new SphereError("Invalid encrypted data format", "VALIDATION_ERROR");
|
|
12446
12623
|
}
|
|
12447
12624
|
return parsed;
|
|
12448
12625
|
}
|
|
@@ -12451,6 +12628,7 @@ function generateRandomKey(bytes = 32) {
|
|
|
12451
12628
|
}
|
|
12452
12629
|
|
|
12453
12630
|
// core/scan.ts
|
|
12631
|
+
init_logger();
|
|
12454
12632
|
async function scanAddressesImpl(deriveAddress, options = {}) {
|
|
12455
12633
|
const maxAddresses = options.maxAddresses ?? 50;
|
|
12456
12634
|
const gapLimit = options.gapLimit ?? 20;
|
|
@@ -12489,7 +12667,8 @@ async function scanAddressesImpl(deriveAddress, options = {}) {
|
|
|
12489
12667
|
nametag = tag;
|
|
12490
12668
|
nametagsFoundCount++;
|
|
12491
12669
|
}
|
|
12492
|
-
} catch {
|
|
12670
|
+
} catch (err) {
|
|
12671
|
+
logger.debug("Sphere", "Nametag resolution failed during scan", err);
|
|
12493
12672
|
}
|
|
12494
12673
|
}
|
|
12495
12674
|
foundAddresses.push({
|
|
@@ -12506,7 +12685,7 @@ async function scanAddressesImpl(deriveAddress, options = {}) {
|
|
|
12506
12685
|
consecutiveEmpty++;
|
|
12507
12686
|
}
|
|
12508
12687
|
} catch (err) {
|
|
12509
|
-
|
|
12688
|
+
logger.warn("Sphere", `scanAddresses: Error checking ${addrInfo.address}:`, err);
|
|
12510
12689
|
consecutiveEmpty++;
|
|
12511
12690
|
}
|
|
12512
12691
|
if (consecutiveEmpty >= gapLimit) {
|
|
@@ -12598,6 +12777,7 @@ init_network();
|
|
|
12598
12777
|
import CryptoJS7 from "crypto-js";
|
|
12599
12778
|
|
|
12600
12779
|
// core/utils.ts
|
|
12780
|
+
init_errors();
|
|
12601
12781
|
var SECP256K1_ORDER = BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
|
|
12602
12782
|
var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
12603
12783
|
function isValidPrivateKey(hex) {
|
|
@@ -12637,7 +12817,7 @@ function base58Decode(str) {
|
|
|
12637
12817
|
for (let i = 0; i < str.length; i++) {
|
|
12638
12818
|
const char = str[i];
|
|
12639
12819
|
if (!(char in ALPHABET_MAP)) {
|
|
12640
|
-
throw new
|
|
12820
|
+
throw new SphereError("Invalid base58 character: " + char, "VALIDATION_ERROR");
|
|
12641
12821
|
}
|
|
12642
12822
|
num = num * BigInt(58) + BigInt(ALPHABET_MAP[char]);
|
|
12643
12823
|
}
|
|
@@ -12919,6 +13099,7 @@ function parseAndDecryptWalletText(content, password) {
|
|
|
12919
13099
|
}
|
|
12920
13100
|
|
|
12921
13101
|
// serialization/wallet-dat.ts
|
|
13102
|
+
init_errors();
|
|
12922
13103
|
import CryptoJS8 from "crypto-js";
|
|
12923
13104
|
function uint8ArrayToWordArray(u8arr) {
|
|
12924
13105
|
const hex = bytesToHex2(u8arr);
|
|
@@ -13104,7 +13285,7 @@ async function decryptCMasterKey(cmk, password, onProgress) {
|
|
|
13104
13285
|
);
|
|
13105
13286
|
const result = CryptoJS8.enc.Hex.stringify(decrypted);
|
|
13106
13287
|
if (!result || result.length !== 64) {
|
|
13107
|
-
throw new
|
|
13288
|
+
throw new SphereError("Master key decryption failed - incorrect password", "DECRYPTION_ERROR");
|
|
13108
13289
|
}
|
|
13109
13290
|
return result;
|
|
13110
13291
|
}
|
|
@@ -13399,6 +13580,7 @@ var Sphere = class _Sphere {
|
|
|
13399
13580
|
* ```
|
|
13400
13581
|
*/
|
|
13401
13582
|
static async init(options) {
|
|
13583
|
+
if (options.debug) logger.configure({ debug: true });
|
|
13402
13584
|
_Sphere.configureTokenRegistry(options.storage, options.network);
|
|
13403
13585
|
const groupChat = _Sphere.resolveGroupChatConfig(options.groupChat, options.network);
|
|
13404
13586
|
const market = _Sphere.resolveMarketConfig(options.market);
|
|
@@ -13426,8 +13608,9 @@ var Sphere = class _Sphere {
|
|
|
13426
13608
|
mnemonic = _Sphere.generateMnemonic();
|
|
13427
13609
|
generatedMnemonic = mnemonic;
|
|
13428
13610
|
} else {
|
|
13429
|
-
throw new
|
|
13430
|
-
"No wallet exists and no mnemonic provided. Provide a mnemonic or set autoGenerate: true."
|
|
13611
|
+
throw new SphereError(
|
|
13612
|
+
"No wallet exists and no mnemonic provided. Provide a mnemonic or set autoGenerate: true.",
|
|
13613
|
+
"INVALID_CONFIG"
|
|
13431
13614
|
);
|
|
13432
13615
|
}
|
|
13433
13616
|
}
|
|
@@ -13500,11 +13683,12 @@ var Sphere = class _Sphere {
|
|
|
13500
13683
|
* Create new wallet with mnemonic
|
|
13501
13684
|
*/
|
|
13502
13685
|
static async create(options) {
|
|
13686
|
+
if (options.debug) logger.configure({ debug: true });
|
|
13503
13687
|
if (!options.mnemonic || !_Sphere.validateMnemonic(options.mnemonic)) {
|
|
13504
|
-
throw new
|
|
13688
|
+
throw new SphereError("Invalid mnemonic", "INVALID_IDENTITY");
|
|
13505
13689
|
}
|
|
13506
13690
|
if (await _Sphere.exists(options.storage)) {
|
|
13507
|
-
throw new
|
|
13691
|
+
throw new SphereError("Wallet already exists. Use Sphere.load() or Sphere.clear() first.", "ALREADY_INITIALIZED");
|
|
13508
13692
|
}
|
|
13509
13693
|
const progress = options.onProgress;
|
|
13510
13694
|
if (!options.storage.isConnected()) {
|
|
@@ -13550,10 +13734,10 @@ var Sphere = class _Sphere {
|
|
|
13550
13734
|
const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
|
|
13551
13735
|
const result = await sphere.discoverAddresses(discoverOpts);
|
|
13552
13736
|
if (result.addresses.length > 0) {
|
|
13553
|
-
|
|
13737
|
+
logger.debug("Sphere", `Address discovery: found ${result.addresses.length} address(es)`);
|
|
13554
13738
|
}
|
|
13555
13739
|
} catch (err) {
|
|
13556
|
-
|
|
13740
|
+
logger.warn("Sphere", "Address discovery failed (non-fatal):", err);
|
|
13557
13741
|
}
|
|
13558
13742
|
}
|
|
13559
13743
|
progress?.({ step: "complete", message: "Wallet created" });
|
|
@@ -13563,8 +13747,9 @@ var Sphere = class _Sphere {
|
|
|
13563
13747
|
* Load existing wallet from storage
|
|
13564
13748
|
*/
|
|
13565
13749
|
static async load(options) {
|
|
13750
|
+
if (options.debug) logger.configure({ debug: true });
|
|
13566
13751
|
if (!await _Sphere.exists(options.storage)) {
|
|
13567
|
-
throw new
|
|
13752
|
+
throw new SphereError("No wallet found. Use Sphere.create() to create a new wallet.", "NOT_INITIALIZED");
|
|
13568
13753
|
}
|
|
13569
13754
|
const progress = options.onProgress;
|
|
13570
13755
|
_Sphere.configureTokenRegistry(options.storage, options.network);
|
|
@@ -13595,16 +13780,16 @@ var Sphere = class _Sphere {
|
|
|
13595
13780
|
_Sphere.instance = sphere;
|
|
13596
13781
|
if (sphere._identity?.nametag && !sphere._payments.hasNametag()) {
|
|
13597
13782
|
progress?.({ step: "registering_nametag", message: "Restoring nametag token..." });
|
|
13598
|
-
|
|
13783
|
+
logger.debug("Sphere", `Nametag @${sphere._identity.nametag} has no token, attempting to mint...`);
|
|
13599
13784
|
try {
|
|
13600
13785
|
const result = await sphere.mintNametag(sphere._identity.nametag);
|
|
13601
13786
|
if (result.success) {
|
|
13602
|
-
|
|
13787
|
+
logger.debug("Sphere", `Nametag token minted successfully on load`);
|
|
13603
13788
|
} else {
|
|
13604
|
-
|
|
13789
|
+
logger.warn("Sphere", `Could not mint nametag token: ${result.error}`);
|
|
13605
13790
|
}
|
|
13606
13791
|
} catch (err) {
|
|
13607
|
-
|
|
13792
|
+
logger.warn("Sphere", `Nametag token mint failed:`, err);
|
|
13608
13793
|
}
|
|
13609
13794
|
}
|
|
13610
13795
|
if (options.discoverAddresses !== false && sphere._transport.discoverAddresses && sphere._masterKey) {
|
|
@@ -13613,10 +13798,10 @@ var Sphere = class _Sphere {
|
|
|
13613
13798
|
const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
|
|
13614
13799
|
const result = await sphere.discoverAddresses(discoverOpts);
|
|
13615
13800
|
if (result.addresses.length > 0) {
|
|
13616
|
-
|
|
13801
|
+
logger.debug("Sphere", `Address discovery: found ${result.addresses.length} address(es)`);
|
|
13617
13802
|
}
|
|
13618
13803
|
} catch (err) {
|
|
13619
|
-
|
|
13804
|
+
logger.warn("Sphere", "Address discovery failed (non-fatal):", err);
|
|
13620
13805
|
}
|
|
13621
13806
|
}
|
|
13622
13807
|
progress?.({ step: "complete", message: "Wallet loaded" });
|
|
@@ -13626,24 +13811,25 @@ var Sphere = class _Sphere {
|
|
|
13626
13811
|
* Import wallet from mnemonic or master key
|
|
13627
13812
|
*/
|
|
13628
13813
|
static async import(options) {
|
|
13814
|
+
if (options.debug) logger.configure({ debug: true });
|
|
13629
13815
|
if (!options.mnemonic && !options.masterKey) {
|
|
13630
|
-
throw new
|
|
13816
|
+
throw new SphereError("Either mnemonic or masterKey is required", "INVALID_CONFIG");
|
|
13631
13817
|
}
|
|
13632
13818
|
const progress = options.onProgress;
|
|
13633
|
-
|
|
13819
|
+
logger.debug("Sphere", "Starting import...");
|
|
13634
13820
|
const needsClear = _Sphere.instance !== null || await _Sphere.exists(options.storage);
|
|
13635
13821
|
if (needsClear) {
|
|
13636
13822
|
progress?.({ step: "clearing", message: "Clearing previous wallet data..." });
|
|
13637
|
-
|
|
13823
|
+
logger.debug("Sphere", "Clearing existing wallet data...");
|
|
13638
13824
|
await _Sphere.clear({ storage: options.storage, tokenStorage: options.tokenStorage });
|
|
13639
|
-
|
|
13825
|
+
logger.debug("Sphere", "Clear done");
|
|
13640
13826
|
} else {
|
|
13641
|
-
|
|
13827
|
+
logger.debug("Sphere", "No existing wallet \u2014 skipping clear");
|
|
13642
13828
|
}
|
|
13643
13829
|
if (!options.storage.isConnected()) {
|
|
13644
|
-
|
|
13830
|
+
logger.debug("Sphere", "Reconnecting storage...");
|
|
13645
13831
|
await options.storage.connect();
|
|
13646
|
-
|
|
13832
|
+
logger.debug("Sphere", "Storage reconnected");
|
|
13647
13833
|
}
|
|
13648
13834
|
const groupChatConfig = _Sphere.resolveGroupChatConfig(options.groupChat);
|
|
13649
13835
|
const marketConfig = _Sphere.resolveMarketConfig(options.market);
|
|
@@ -13661,14 +13847,14 @@ var Sphere = class _Sphere {
|
|
|
13661
13847
|
progress?.({ step: "storing_keys", message: "Storing wallet keys..." });
|
|
13662
13848
|
if (options.mnemonic) {
|
|
13663
13849
|
if (!_Sphere.validateMnemonic(options.mnemonic)) {
|
|
13664
|
-
throw new
|
|
13850
|
+
throw new SphereError("Invalid mnemonic", "INVALID_IDENTITY");
|
|
13665
13851
|
}
|
|
13666
|
-
|
|
13852
|
+
logger.debug("Sphere", "Storing mnemonic...");
|
|
13667
13853
|
await sphere.storeMnemonic(options.mnemonic, options.derivationPath, options.basePath);
|
|
13668
|
-
|
|
13854
|
+
logger.debug("Sphere", "Initializing identity from mnemonic...");
|
|
13669
13855
|
await sphere.initializeIdentityFromMnemonic(options.mnemonic, options.derivationPath);
|
|
13670
13856
|
} else if (options.masterKey) {
|
|
13671
|
-
|
|
13857
|
+
logger.debug("Sphere", "Storing master key...");
|
|
13672
13858
|
await sphere.storeMasterKey(
|
|
13673
13859
|
options.masterKey,
|
|
13674
13860
|
options.chainCode,
|
|
@@ -13676,7 +13862,7 @@ var Sphere = class _Sphere {
|
|
|
13676
13862
|
options.basePath,
|
|
13677
13863
|
options.derivationMode
|
|
13678
13864
|
);
|
|
13679
|
-
|
|
13865
|
+
logger.debug("Sphere", "Initializing identity from master key...");
|
|
13680
13866
|
await sphere.initializeIdentityFromMasterKey(
|
|
13681
13867
|
options.masterKey,
|
|
13682
13868
|
options.chainCode,
|
|
@@ -13684,38 +13870,38 @@ var Sphere = class _Sphere {
|
|
|
13684
13870
|
);
|
|
13685
13871
|
}
|
|
13686
13872
|
progress?.({ step: "initializing", message: "Initializing wallet..." });
|
|
13687
|
-
|
|
13873
|
+
logger.debug("Sphere", "Initializing providers...");
|
|
13688
13874
|
await sphere.initializeProviders();
|
|
13689
|
-
|
|
13875
|
+
logger.debug("Sphere", "Providers initialized. Initializing modules...");
|
|
13690
13876
|
await sphere.initializeModules();
|
|
13691
|
-
|
|
13877
|
+
logger.debug("Sphere", "Modules initialized");
|
|
13692
13878
|
if (!options.nametag) {
|
|
13693
13879
|
progress?.({ step: "recovering_nametag", message: "Recovering nametag..." });
|
|
13694
|
-
|
|
13880
|
+
logger.debug("Sphere", "Recovering nametag from transport...");
|
|
13695
13881
|
await sphere.recoverNametagFromTransport();
|
|
13696
|
-
|
|
13882
|
+
logger.debug("Sphere", "Nametag recovery done");
|
|
13697
13883
|
progress?.({ step: "syncing_identity", message: "Publishing identity..." });
|
|
13698
13884
|
await sphere.syncIdentityWithTransport();
|
|
13699
13885
|
}
|
|
13700
13886
|
progress?.({ step: "finalizing", message: "Finalizing wallet..." });
|
|
13701
|
-
|
|
13887
|
+
logger.debug("Sphere", "Finalizing wallet creation...");
|
|
13702
13888
|
await sphere.finalizeWalletCreation();
|
|
13703
13889
|
sphere._initialized = true;
|
|
13704
13890
|
_Sphere.instance = sphere;
|
|
13705
|
-
|
|
13891
|
+
logger.debug("Sphere", "Tracking address 0...");
|
|
13706
13892
|
await sphere.ensureAddressTracked(0);
|
|
13707
13893
|
if (options.nametag) {
|
|
13708
13894
|
progress?.({ step: "registering_nametag", message: "Registering nametag..." });
|
|
13709
|
-
|
|
13895
|
+
logger.debug("Sphere", "Registering nametag...");
|
|
13710
13896
|
await sphere.registerNametag(options.nametag);
|
|
13711
13897
|
}
|
|
13712
13898
|
if (sphere._tokenStorageProviders.size > 0) {
|
|
13713
13899
|
progress?.({ step: "syncing_tokens", message: "Syncing tokens..." });
|
|
13714
13900
|
try {
|
|
13715
13901
|
const syncResult = await sphere._payments.sync();
|
|
13716
|
-
|
|
13902
|
+
logger.debug("Sphere", `Auto-sync: +${syncResult.added} -${syncResult.removed}`);
|
|
13717
13903
|
} catch (err) {
|
|
13718
|
-
|
|
13904
|
+
logger.warn("Sphere", "Auto-sync failed (non-fatal):", err);
|
|
13719
13905
|
}
|
|
13720
13906
|
}
|
|
13721
13907
|
if (options.discoverAddresses !== false && sphere._transport.discoverAddresses) {
|
|
@@ -13724,14 +13910,14 @@ var Sphere = class _Sphere {
|
|
|
13724
13910
|
const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
|
|
13725
13911
|
const result = await sphere.discoverAddresses(discoverOpts);
|
|
13726
13912
|
if (result.addresses.length > 0) {
|
|
13727
|
-
|
|
13913
|
+
logger.debug("Sphere", `Address discovery: found ${result.addresses.length} address(es)`);
|
|
13728
13914
|
}
|
|
13729
13915
|
} catch (err) {
|
|
13730
|
-
|
|
13916
|
+
logger.warn("Sphere", "Address discovery failed (non-fatal):", err);
|
|
13731
13917
|
}
|
|
13732
13918
|
}
|
|
13733
13919
|
progress?.({ step: "complete", message: "Import complete" });
|
|
13734
|
-
|
|
13920
|
+
logger.debug("Sphere", "Import complete");
|
|
13735
13921
|
return sphere;
|
|
13736
13922
|
}
|
|
13737
13923
|
/**
|
|
@@ -13757,26 +13943,26 @@ var Sphere = class _Sphere {
|
|
|
13757
13943
|
const storage = "get" in storageOrOptions ? storageOrOptions : storageOrOptions.storage;
|
|
13758
13944
|
const tokenStorage = "get" in storageOrOptions ? void 0 : storageOrOptions.tokenStorage;
|
|
13759
13945
|
if (_Sphere.instance) {
|
|
13760
|
-
|
|
13946
|
+
logger.debug("Sphere", "Destroying Sphere instance...");
|
|
13761
13947
|
await _Sphere.instance.destroy();
|
|
13762
|
-
|
|
13948
|
+
logger.debug("Sphere", "Sphere instance destroyed");
|
|
13763
13949
|
}
|
|
13764
|
-
|
|
13950
|
+
logger.debug("Sphere", "Clearing L1 vesting cache...");
|
|
13765
13951
|
await vestingClassifier.destroy();
|
|
13766
|
-
|
|
13952
|
+
logger.debug("Sphere", "Yielding 50ms for IDB transaction settlement...");
|
|
13767
13953
|
await new Promise((r) => setTimeout(r, 50));
|
|
13768
13954
|
if (tokenStorage?.clear) {
|
|
13769
|
-
|
|
13955
|
+
logger.debug("Sphere", "Clearing token storage...");
|
|
13770
13956
|
try {
|
|
13771
13957
|
await tokenStorage.clear();
|
|
13772
|
-
|
|
13958
|
+
logger.debug("Sphere", "Token storage cleared");
|
|
13773
13959
|
} catch (err) {
|
|
13774
|
-
|
|
13960
|
+
logger.warn("Sphere", "Token storage clear failed:", err);
|
|
13775
13961
|
}
|
|
13776
13962
|
} else {
|
|
13777
|
-
|
|
13963
|
+
logger.debug("Sphere", "No token storage provider to clear");
|
|
13778
13964
|
}
|
|
13779
|
-
|
|
13965
|
+
logger.debug("Sphere", "Clearing KV storage...");
|
|
13780
13966
|
if (!storage.isConnected()) {
|
|
13781
13967
|
try {
|
|
13782
13968
|
await storage.connect();
|
|
@@ -13785,11 +13971,11 @@ var Sphere = class _Sphere {
|
|
|
13785
13971
|
}
|
|
13786
13972
|
if (storage.isConnected()) {
|
|
13787
13973
|
await storage.clear();
|
|
13788
|
-
|
|
13974
|
+
logger.debug("Sphere", "KV storage cleared");
|
|
13789
13975
|
} else {
|
|
13790
|
-
|
|
13976
|
+
logger.debug("Sphere", "KV storage not connected, skipping");
|
|
13791
13977
|
}
|
|
13792
|
-
|
|
13978
|
+
logger.debug("Sphere", "Done");
|
|
13793
13979
|
}
|
|
13794
13980
|
/**
|
|
13795
13981
|
* Get current instance
|
|
@@ -13881,7 +14067,7 @@ var Sphere = class _Sphere {
|
|
|
13881
14067
|
*/
|
|
13882
14068
|
async addTokenStorageProvider(provider) {
|
|
13883
14069
|
if (this._tokenStorageProviders.has(provider.id)) {
|
|
13884
|
-
throw new
|
|
14070
|
+
throw new SphereError(`Token storage provider '${provider.id}' already exists`, "INVALID_CONFIG");
|
|
13885
14071
|
}
|
|
13886
14072
|
if (this._identity) {
|
|
13887
14073
|
provider.setIdentity(this._identity);
|
|
@@ -14001,7 +14187,7 @@ var Sphere = class _Sphere {
|
|
|
14001
14187
|
exportToJSON(options = {}) {
|
|
14002
14188
|
this.ensureReady();
|
|
14003
14189
|
if (!this._masterKey && !this._identity) {
|
|
14004
|
-
throw new
|
|
14190
|
+
throw new SphereError("Wallet not initialized", "NOT_INITIALIZED");
|
|
14005
14191
|
}
|
|
14006
14192
|
const addressCount = options.addressCount || 1;
|
|
14007
14193
|
const addresses = [];
|
|
@@ -14081,7 +14267,7 @@ var Sphere = class _Sphere {
|
|
|
14081
14267
|
exportToTxt(options = {}) {
|
|
14082
14268
|
this.ensureReady();
|
|
14083
14269
|
if (!this._masterKey && !this._identity) {
|
|
14084
|
-
throw new
|
|
14270
|
+
throw new SphereError("Wallet not initialized", "NOT_INITIALIZED");
|
|
14085
14271
|
}
|
|
14086
14272
|
const addressCount = options.addressCount || 1;
|
|
14087
14273
|
const addresses = [];
|
|
@@ -14520,7 +14706,7 @@ var Sphere = class _Sphere {
|
|
|
14520
14706
|
this.ensureReady();
|
|
14521
14707
|
const entry = this._trackedAddresses.get(index);
|
|
14522
14708
|
if (!entry) {
|
|
14523
|
-
throw new
|
|
14709
|
+
throw new SphereError(`Address at index ${index} is not tracked. Switch to it first.`, "INVALID_CONFIG");
|
|
14524
14710
|
}
|
|
14525
14711
|
if (entry.hidden === hidden) return;
|
|
14526
14712
|
entry.hidden = hidden;
|
|
@@ -14550,14 +14736,14 @@ var Sphere = class _Sphere {
|
|
|
14550
14736
|
async switchToAddress(index, options) {
|
|
14551
14737
|
this.ensureReady();
|
|
14552
14738
|
if (!this._masterKey) {
|
|
14553
|
-
throw new
|
|
14739
|
+
throw new SphereError("HD derivation requires master key with chain code. Cannot switch addresses.", "INVALID_CONFIG");
|
|
14554
14740
|
}
|
|
14555
14741
|
if (index < 0) {
|
|
14556
|
-
throw new
|
|
14742
|
+
throw new SphereError("Address index must be non-negative", "INVALID_CONFIG");
|
|
14557
14743
|
}
|
|
14558
14744
|
const newNametag = options?.nametag ? this.cleanNametag(options.nametag) : void 0;
|
|
14559
14745
|
if (newNametag && !isValidNametag(newNametag)) {
|
|
14560
|
-
throw new
|
|
14746
|
+
throw new SphereError("Invalid nametag format. Use lowercase alphanumeric, underscore, or hyphen (3-20 chars), or a valid phone number.", "VALIDATION_ERROR");
|
|
14561
14747
|
}
|
|
14562
14748
|
const addressInfo = this.deriveAddress(index, false);
|
|
14563
14749
|
const ipnsHash = sha256(addressInfo.publicKey, "hex").slice(0, 40);
|
|
@@ -14567,7 +14753,7 @@ var Sphere = class _Sphere {
|
|
|
14567
14753
|
if (newNametag) {
|
|
14568
14754
|
const existing = await this._transport.resolveNametag?.(newNametag);
|
|
14569
14755
|
if (existing) {
|
|
14570
|
-
throw new
|
|
14756
|
+
throw new SphereError(`Nametag @${newNametag} is already taken`, "VALIDATION_ERROR");
|
|
14571
14757
|
}
|
|
14572
14758
|
let nametags = this._addressNametags.get(addressId);
|
|
14573
14759
|
if (!nametags) {
|
|
@@ -14590,12 +14776,12 @@ var Sphere = class _Sphere {
|
|
|
14590
14776
|
await this._storage.set(STORAGE_KEYS_GLOBAL.CURRENT_ADDRESS_INDEX, index.toString());
|
|
14591
14777
|
this._storage.setIdentity(this._identity);
|
|
14592
14778
|
await this._transport.setIdentity(this._identity);
|
|
14593
|
-
|
|
14779
|
+
logger.debug("Sphere", `switchToAddress(${index}): re-initializing ${this._tokenStorageProviders.size} token storage provider(s)`);
|
|
14594
14780
|
for (const [providerId, provider] of this._tokenStorageProviders.entries()) {
|
|
14595
|
-
|
|
14781
|
+
logger.debug("Sphere", `switchToAddress(${index}): shutdown provider=${providerId}`);
|
|
14596
14782
|
await provider.shutdown();
|
|
14597
14783
|
provider.setIdentity(this._identity);
|
|
14598
|
-
|
|
14784
|
+
logger.debug("Sphere", `switchToAddress(${index}): initialize provider=${providerId}`);
|
|
14599
14785
|
await provider.initialize();
|
|
14600
14786
|
}
|
|
14601
14787
|
await this.reinitializeModulesForNewAddress();
|
|
@@ -14606,9 +14792,9 @@ var Sphere = class _Sphere {
|
|
|
14606
14792
|
nametag: this._identity.nametag,
|
|
14607
14793
|
addressIndex: index
|
|
14608
14794
|
});
|
|
14609
|
-
|
|
14795
|
+
logger.debug("Sphere", `Switched to address ${index}:`, this._identity.l1Address);
|
|
14610
14796
|
this.postSwitchSync(index, newNametag).catch((err) => {
|
|
14611
|
-
|
|
14797
|
+
logger.warn("Sphere", `Post-switch sync failed for address ${index}:`, err);
|
|
14612
14798
|
});
|
|
14613
14799
|
}
|
|
14614
14800
|
/**
|
|
@@ -14622,16 +14808,16 @@ var Sphere = class _Sphere {
|
|
|
14622
14808
|
if (newNametag) {
|
|
14623
14809
|
await this.persistAddressNametags();
|
|
14624
14810
|
if (!this._payments.hasNametag()) {
|
|
14625
|
-
|
|
14811
|
+
logger.debug("Sphere", `Minting nametag token for @${newNametag}...`);
|
|
14626
14812
|
try {
|
|
14627
14813
|
const result = await this.mintNametag(newNametag);
|
|
14628
14814
|
if (result.success) {
|
|
14629
|
-
|
|
14815
|
+
logger.debug("Sphere", `Nametag token minted successfully`);
|
|
14630
14816
|
} else {
|
|
14631
|
-
|
|
14817
|
+
logger.warn("Sphere", `Could not mint nametag token: ${result.error}`);
|
|
14632
14818
|
}
|
|
14633
14819
|
} catch (err) {
|
|
14634
|
-
|
|
14820
|
+
logger.warn("Sphere", `Nametag token mint failed:`, err);
|
|
14635
14821
|
}
|
|
14636
14822
|
}
|
|
14637
14823
|
this.emitEvent("nametag:registered", {
|
|
@@ -14639,16 +14825,16 @@ var Sphere = class _Sphere {
|
|
|
14639
14825
|
addressIndex: index
|
|
14640
14826
|
});
|
|
14641
14827
|
} else if (this._identity?.nametag && !this._payments.hasNametag()) {
|
|
14642
|
-
|
|
14828
|
+
logger.debug("Sphere", `Nametag @${this._identity.nametag} has no token after switch, minting...`);
|
|
14643
14829
|
try {
|
|
14644
14830
|
const result = await this.mintNametag(this._identity.nametag);
|
|
14645
14831
|
if (result.success) {
|
|
14646
|
-
|
|
14832
|
+
logger.debug("Sphere", `Nametag token minted successfully after switch`);
|
|
14647
14833
|
} else {
|
|
14648
|
-
|
|
14834
|
+
logger.warn("Sphere", `Could not mint nametag token after switch: ${result.error}`);
|
|
14649
14835
|
}
|
|
14650
14836
|
} catch (err) {
|
|
14651
|
-
|
|
14837
|
+
logger.warn("Sphere", `Nametag token mint failed after switch:`, err);
|
|
14652
14838
|
}
|
|
14653
14839
|
}
|
|
14654
14840
|
}
|
|
@@ -14687,7 +14873,7 @@ var Sphere = class _Sphere {
|
|
|
14687
14873
|
await this._groupChat?.load();
|
|
14688
14874
|
await this._market?.load();
|
|
14689
14875
|
this._payments.sync().catch((err) => {
|
|
14690
|
-
|
|
14876
|
+
logger.warn("Sphere", "Post-switch sync failed:", err);
|
|
14691
14877
|
});
|
|
14692
14878
|
}
|
|
14693
14879
|
/**
|
|
@@ -14721,7 +14907,7 @@ var Sphere = class _Sphere {
|
|
|
14721
14907
|
*/
|
|
14722
14908
|
_deriveAddressInternal(index, isChange = false) {
|
|
14723
14909
|
if (!this._masterKey) {
|
|
14724
|
-
throw new
|
|
14910
|
+
throw new SphereError("HD derivation requires master key with chain code", "INVALID_CONFIG");
|
|
14725
14911
|
}
|
|
14726
14912
|
if (this._derivationMode === "wif_hmac") {
|
|
14727
14913
|
return generateAddressFromMasterKey(this._masterKey.privateKey, index);
|
|
@@ -14751,7 +14937,7 @@ var Sphere = class _Sphere {
|
|
|
14751
14937
|
deriveAddressAtPath(path) {
|
|
14752
14938
|
this.ensureReady();
|
|
14753
14939
|
if (!this._masterKey) {
|
|
14754
|
-
throw new
|
|
14940
|
+
throw new SphereError("HD derivation requires master key with chain code", "INVALID_CONFIG");
|
|
14755
14941
|
}
|
|
14756
14942
|
const match = path.match(/\/(\d+)$/);
|
|
14757
14943
|
const index = match ? parseInt(match[1], 10) : 0;
|
|
@@ -14818,13 +15004,14 @@ var Sphere = class _Sphere {
|
|
|
14818
15004
|
async scanAddresses(options = {}) {
|
|
14819
15005
|
this.ensureReady();
|
|
14820
15006
|
if (!this._masterKey) {
|
|
14821
|
-
throw new
|
|
15007
|
+
throw new SphereError("Address scanning requires HD master key", "INVALID_CONFIG");
|
|
14822
15008
|
}
|
|
14823
15009
|
const resolveNametag = options.resolveNametag ?? (this._transport.resolveAddressInfo ? async (l1Address) => {
|
|
14824
15010
|
try {
|
|
14825
15011
|
const info = await this._transport.resolveAddressInfo(l1Address);
|
|
14826
15012
|
return info?.nametag ?? null;
|
|
14827
|
-
} catch {
|
|
15013
|
+
} catch (err) {
|
|
15014
|
+
logger.debug("Sphere", "Nametag resolution failed during scan", err);
|
|
14828
15015
|
return null;
|
|
14829
15016
|
}
|
|
14830
15017
|
} : void 0);
|
|
@@ -14875,10 +15062,10 @@ var Sphere = class _Sphere {
|
|
|
14875
15062
|
async discoverAddresses(options = {}) {
|
|
14876
15063
|
this.ensureReady();
|
|
14877
15064
|
if (!this._masterKey) {
|
|
14878
|
-
throw new
|
|
15065
|
+
throw new SphereError("Address discovery requires HD master key", "INVALID_CONFIG");
|
|
14879
15066
|
}
|
|
14880
15067
|
if (!this._transport.discoverAddresses) {
|
|
14881
|
-
throw new
|
|
15068
|
+
throw new SphereError("Transport provider does not support address discovery", "INVALID_CONFIG");
|
|
14882
15069
|
}
|
|
14883
15070
|
const includeL1Scan = options.includeL1Scan ?? true;
|
|
14884
15071
|
const transportResult = await discoverAddressesImpl(
|
|
@@ -14934,7 +15121,7 @@ var Sphere = class _Sphere {
|
|
|
14934
15121
|
}
|
|
14935
15122
|
transportResult.addresses.sort((a, b) => a.index - b.index);
|
|
14936
15123
|
} catch (err) {
|
|
14937
|
-
|
|
15124
|
+
logger.warn("Sphere", "L1 scan failed during discovery (non-fatal):", err);
|
|
14938
15125
|
}
|
|
14939
15126
|
}
|
|
14940
15127
|
if (options.autoTrack && transportResult.addresses.length > 0) {
|
|
@@ -15032,7 +15219,7 @@ var Sphere = class _Sphere {
|
|
|
15032
15219
|
*/
|
|
15033
15220
|
async disableProvider(providerId) {
|
|
15034
15221
|
if (providerId === this._storage.id) {
|
|
15035
|
-
throw new
|
|
15222
|
+
throw new SphereError("Cannot disable the main storage provider", "INVALID_CONFIG");
|
|
15036
15223
|
}
|
|
15037
15224
|
const provider = this.findProviderById(providerId);
|
|
15038
15225
|
if (!provider) return false;
|
|
@@ -15235,10 +15422,10 @@ var Sphere = class _Sphere {
|
|
|
15235
15422
|
this.ensureReady();
|
|
15236
15423
|
const cleanNametag = this.cleanNametag(nametag);
|
|
15237
15424
|
if (!isValidNametag(cleanNametag)) {
|
|
15238
|
-
throw new
|
|
15425
|
+
throw new SphereError("Invalid nametag format. Use lowercase alphanumeric, underscore, or hyphen (3-20 chars), or a valid phone number.", "VALIDATION_ERROR");
|
|
15239
15426
|
}
|
|
15240
15427
|
if (this._identity?.nametag) {
|
|
15241
|
-
throw new
|
|
15428
|
+
throw new SphereError(`Nametag already registered for address ${this._currentAddressIndex}: @${this._identity.nametag}`, "ALREADY_INITIALIZED");
|
|
15242
15429
|
}
|
|
15243
15430
|
if (this._transport.publishIdentityBinding) {
|
|
15244
15431
|
const success = await this._transport.publishIdentityBinding(
|
|
@@ -15248,7 +15435,7 @@ var Sphere = class _Sphere {
|
|
|
15248
15435
|
cleanNametag
|
|
15249
15436
|
);
|
|
15250
15437
|
if (!success) {
|
|
15251
|
-
throw new
|
|
15438
|
+
throw new SphereError("Failed to register nametag. It may already be taken.", "VALIDATION_ERROR");
|
|
15252
15439
|
}
|
|
15253
15440
|
}
|
|
15254
15441
|
this._identity.nametag = cleanNametag;
|
|
@@ -15264,19 +15451,19 @@ var Sphere = class _Sphere {
|
|
|
15264
15451
|
}
|
|
15265
15452
|
await this.persistAddressNametags();
|
|
15266
15453
|
if (!this._payments.hasNametag()) {
|
|
15267
|
-
|
|
15454
|
+
logger.debug("Sphere", `Minting nametag token for @${cleanNametag}...`);
|
|
15268
15455
|
const result = await this.mintNametag(cleanNametag);
|
|
15269
15456
|
if (!result.success) {
|
|
15270
|
-
|
|
15457
|
+
logger.warn("Sphere", `Failed to mint nametag token: ${result.error}`);
|
|
15271
15458
|
} else {
|
|
15272
|
-
|
|
15459
|
+
logger.debug("Sphere", `Nametag token minted successfully`);
|
|
15273
15460
|
}
|
|
15274
15461
|
}
|
|
15275
15462
|
this.emitEvent("nametag:registered", {
|
|
15276
15463
|
nametag: cleanNametag,
|
|
15277
15464
|
addressIndex: this._currentAddressIndex
|
|
15278
15465
|
});
|
|
15279
|
-
|
|
15466
|
+
logger.debug("Sphere", `Nametag registered for address ${this._currentAddressIndex}:`, cleanNametag);
|
|
15280
15467
|
}
|
|
15281
15468
|
/**
|
|
15282
15469
|
* Persist tracked addresses to storage (only minimal fields via StorageProvider)
|
|
@@ -15516,13 +15703,13 @@ var Sphere = class _Sphere {
|
|
|
15516
15703
|
this._identity.directAddress || "",
|
|
15517
15704
|
recoveredNametag
|
|
15518
15705
|
);
|
|
15519
|
-
|
|
15706
|
+
logger.debug("Sphere", `Migrated legacy binding with nametag @${recoveredNametag}`);
|
|
15520
15707
|
return;
|
|
15521
15708
|
}
|
|
15522
15709
|
}
|
|
15523
15710
|
const needsUpdate = !existing.directAddress || !existing.l1Address || !existing.chainPubkey || this._identity?.nametag && !existing.nametag;
|
|
15524
15711
|
if (needsUpdate) {
|
|
15525
|
-
|
|
15712
|
+
logger.debug("Sphere", "Existing binding incomplete, re-publishing with full data");
|
|
15526
15713
|
await this._transport.publishIdentityBinding(
|
|
15527
15714
|
this._identity.chainPubkey,
|
|
15528
15715
|
this._identity.l1Address,
|
|
@@ -15531,11 +15718,11 @@ var Sphere = class _Sphere {
|
|
|
15531
15718
|
);
|
|
15532
15719
|
return;
|
|
15533
15720
|
}
|
|
15534
|
-
|
|
15721
|
+
logger.debug("Sphere", "Existing binding found, skipping re-publish");
|
|
15535
15722
|
return;
|
|
15536
15723
|
}
|
|
15537
15724
|
} catch (e) {
|
|
15538
|
-
|
|
15725
|
+
logger.warn("Sphere", "resolve() failed, skipping publish to avoid overwrite", e);
|
|
15539
15726
|
return;
|
|
15540
15727
|
}
|
|
15541
15728
|
}
|
|
@@ -15547,12 +15734,12 @@ var Sphere = class _Sphere {
|
|
|
15547
15734
|
nametag || void 0
|
|
15548
15735
|
);
|
|
15549
15736
|
if (success) {
|
|
15550
|
-
|
|
15737
|
+
logger.debug("Sphere", `Identity binding published${nametag ? ` with nametag @${nametag}` : ""}`);
|
|
15551
15738
|
} else if (nametag) {
|
|
15552
|
-
|
|
15739
|
+
logger.warn("Sphere", `Nametag @${nametag} is taken by another pubkey`);
|
|
15553
15740
|
}
|
|
15554
15741
|
} catch (error) {
|
|
15555
|
-
|
|
15742
|
+
logger.warn("Sphere", `Identity binding sync failed:`, error);
|
|
15556
15743
|
}
|
|
15557
15744
|
}
|
|
15558
15745
|
/**
|
|
@@ -15705,7 +15892,7 @@ var Sphere = class _Sphere {
|
|
|
15705
15892
|
if (encryptedMnemonic) {
|
|
15706
15893
|
const mnemonic = this.decrypt(encryptedMnemonic);
|
|
15707
15894
|
if (!mnemonic) {
|
|
15708
|
-
throw new
|
|
15895
|
+
throw new SphereError("Failed to decrypt mnemonic", "STORAGE_ERROR");
|
|
15709
15896
|
}
|
|
15710
15897
|
this._mnemonic = mnemonic;
|
|
15711
15898
|
this._source = "mnemonic";
|
|
@@ -15713,7 +15900,7 @@ var Sphere = class _Sphere {
|
|
|
15713
15900
|
} else if (encryptedMasterKey) {
|
|
15714
15901
|
const masterKey = this.decrypt(encryptedMasterKey);
|
|
15715
15902
|
if (!masterKey) {
|
|
15716
|
-
throw new
|
|
15903
|
+
throw new SphereError("Failed to decrypt master key", "STORAGE_ERROR");
|
|
15717
15904
|
}
|
|
15718
15905
|
this._mnemonic = null;
|
|
15719
15906
|
if (this._source === "unknown") {
|
|
@@ -15725,7 +15912,7 @@ var Sphere = class _Sphere {
|
|
|
15725
15912
|
derivationPath ?? void 0
|
|
15726
15913
|
);
|
|
15727
15914
|
} else {
|
|
15728
|
-
throw new
|
|
15915
|
+
throw new SphereError("No wallet data found in storage", "NOT_INITIALIZED");
|
|
15729
15916
|
}
|
|
15730
15917
|
if (this._identity) {
|
|
15731
15918
|
this._storage.setIdentity(this._identity);
|
|
@@ -15747,7 +15934,7 @@ var Sphere = class _Sphere {
|
|
|
15747
15934
|
nametag
|
|
15748
15935
|
};
|
|
15749
15936
|
this._storage.setIdentity(this._identity);
|
|
15750
|
-
|
|
15937
|
+
logger.debug("Sphere", `Restored to address ${this._currentAddressIndex}:`, this._identity.l1Address);
|
|
15751
15938
|
} else if (this._identity && nametag) {
|
|
15752
15939
|
this._identity.nametag = nametag;
|
|
15753
15940
|
}
|
|
@@ -15938,7 +16125,7 @@ var Sphere = class _Sphere {
|
|
|
15938
16125
|
// ===========================================================================
|
|
15939
16126
|
ensureReady() {
|
|
15940
16127
|
if (!this._initialized) {
|
|
15941
|
-
throw new
|
|
16128
|
+
throw new SphereError("Sphere not initialized", "NOT_INITIALIZED");
|
|
15942
16129
|
}
|
|
15943
16130
|
}
|
|
15944
16131
|
emitEvent(type, data) {
|
|
@@ -15948,7 +16135,7 @@ var Sphere = class _Sphere {
|
|
|
15948
16135
|
try {
|
|
15949
16136
|
handler(data);
|
|
15950
16137
|
} catch (error) {
|
|
15951
|
-
|
|
16138
|
+
logger.error("Sphere", "Event handler error:", error);
|
|
15952
16139
|
}
|
|
15953
16140
|
}
|
|
15954
16141
|
}
|
|
@@ -15985,6 +16172,7 @@ var getSphere = Sphere.getInstance.bind(Sphere);
|
|
|
15985
16172
|
var sphereExists = Sphere.exists.bind(Sphere);
|
|
15986
16173
|
|
|
15987
16174
|
// core/currency.ts
|
|
16175
|
+
init_logger();
|
|
15988
16176
|
var DEFAULT_TOKEN_DECIMALS = 18;
|
|
15989
16177
|
function toSmallestUnit(amount, decimals = DEFAULT_TOKEN_DECIMALS) {
|
|
15990
16178
|
if (!amount) return 0n;
|
|
@@ -15993,7 +16181,8 @@ function toSmallestUnit(amount, decimals = DEFAULT_TOKEN_DECIMALS) {
|
|
|
15993
16181
|
const [integer, fraction = ""] = str.split(".");
|
|
15994
16182
|
const paddedFraction = fraction.padEnd(decimals, "0").slice(0, decimals);
|
|
15995
16183
|
return BigInt(integer + paddedFraction);
|
|
15996
|
-
} catch {
|
|
16184
|
+
} catch (err) {
|
|
16185
|
+
logger.debug("Currency", "toSmallestUnit conversion failed", err);
|
|
15997
16186
|
return 0n;
|
|
15998
16187
|
}
|
|
15999
16188
|
}
|
|
@@ -16022,6 +16211,8 @@ var CurrencyUtils = {
|
|
|
16022
16211
|
|
|
16023
16212
|
// core/index.ts
|
|
16024
16213
|
init_bech32();
|
|
16214
|
+
init_logger();
|
|
16215
|
+
init_errors();
|
|
16025
16216
|
|
|
16026
16217
|
// core/network-health.ts
|
|
16027
16218
|
init_constants();
|
|
@@ -16215,6 +16406,7 @@ export {
|
|
|
16215
16406
|
DEFAULT_DERIVATION_PATH2 as DEFAULT_DERIVATION_PATH,
|
|
16216
16407
|
DEFAULT_TOKEN_DECIMALS,
|
|
16217
16408
|
Sphere,
|
|
16409
|
+
SphereError,
|
|
16218
16410
|
base58Decode,
|
|
16219
16411
|
base58Encode,
|
|
16220
16412
|
bytesToHex2 as bytesToHex,
|
|
@@ -16261,10 +16453,12 @@ export {
|
|
|
16261
16453
|
importSphere,
|
|
16262
16454
|
initSphere,
|
|
16263
16455
|
isEncryptedData,
|
|
16456
|
+
isSphereError,
|
|
16264
16457
|
isValidBech32,
|
|
16265
16458
|
isValidNametag,
|
|
16266
16459
|
isValidPrivateKey,
|
|
16267
16460
|
loadSphere,
|
|
16461
|
+
logger,
|
|
16268
16462
|
mnemonicToEntropy2 as mnemonicToEntropy,
|
|
16269
16463
|
mnemonicToSeed2 as mnemonicToSeed,
|
|
16270
16464
|
mnemonicToSeedSync2 as mnemonicToSeedSync,
|