@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.cjs
CHANGED
|
@@ -30,6 +30,125 @@ var __toESM = (mod2, isNodeMode, target) => (target = mod2 != null ? __create(__
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
|
|
32
32
|
|
|
33
|
+
// core/logger.ts
|
|
34
|
+
function getState() {
|
|
35
|
+
const g = globalThis;
|
|
36
|
+
if (!g[LOGGER_KEY]) {
|
|
37
|
+
g[LOGGER_KEY] = { debug: false, tags: {}, handler: null };
|
|
38
|
+
}
|
|
39
|
+
return g[LOGGER_KEY];
|
|
40
|
+
}
|
|
41
|
+
function isEnabled(tag) {
|
|
42
|
+
const state = getState();
|
|
43
|
+
if (tag in state.tags) return state.tags[tag];
|
|
44
|
+
return state.debug;
|
|
45
|
+
}
|
|
46
|
+
var LOGGER_KEY, logger;
|
|
47
|
+
var init_logger = __esm({
|
|
48
|
+
"core/logger.ts"() {
|
|
49
|
+
"use strict";
|
|
50
|
+
LOGGER_KEY = "__sphere_sdk_logger__";
|
|
51
|
+
logger = {
|
|
52
|
+
/**
|
|
53
|
+
* Configure the logger. Can be called multiple times (last write wins).
|
|
54
|
+
* Typically called by createBrowserProviders(), createNodeProviders(), or Sphere.init().
|
|
55
|
+
*/
|
|
56
|
+
configure(config) {
|
|
57
|
+
const state = getState();
|
|
58
|
+
if (config.debug !== void 0) state.debug = config.debug;
|
|
59
|
+
if (config.handler !== void 0) state.handler = config.handler;
|
|
60
|
+
},
|
|
61
|
+
/**
|
|
62
|
+
* Enable/disable debug logging for a specific tag.
|
|
63
|
+
* Per-tag setting overrides the global debug flag.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* logger.setTagDebug('Nostr', true); // enable only Nostr logs
|
|
68
|
+
* logger.setTagDebug('Nostr', false); // disable Nostr logs even if global debug=true
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
setTagDebug(tag, enabled) {
|
|
72
|
+
getState().tags[tag] = enabled;
|
|
73
|
+
},
|
|
74
|
+
/**
|
|
75
|
+
* Clear per-tag override, falling back to global debug flag.
|
|
76
|
+
*/
|
|
77
|
+
clearTagDebug(tag) {
|
|
78
|
+
delete getState().tags[tag];
|
|
79
|
+
},
|
|
80
|
+
/** Returns true if debug mode is enabled for the given tag (or globally). */
|
|
81
|
+
isDebugEnabled(tag) {
|
|
82
|
+
if (tag) return isEnabled(tag);
|
|
83
|
+
return getState().debug;
|
|
84
|
+
},
|
|
85
|
+
/**
|
|
86
|
+
* Debug-level log. Only shown when debug is enabled (globally or for this tag).
|
|
87
|
+
* Use for detailed operational information.
|
|
88
|
+
*/
|
|
89
|
+
debug(tag, message, ...args) {
|
|
90
|
+
if (!isEnabled(tag)) return;
|
|
91
|
+
const state = getState();
|
|
92
|
+
if (state.handler) {
|
|
93
|
+
state.handler("debug", tag, message, ...args);
|
|
94
|
+
} else {
|
|
95
|
+
console.log(`[${tag}]`, message, ...args);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
/**
|
|
99
|
+
* Warning-level log. ALWAYS shown regardless of debug flag.
|
|
100
|
+
* Use for important but non-critical issues (timeouts, retries, degraded state).
|
|
101
|
+
*/
|
|
102
|
+
warn(tag, message, ...args) {
|
|
103
|
+
const state = getState();
|
|
104
|
+
if (state.handler) {
|
|
105
|
+
state.handler("warn", tag, message, ...args);
|
|
106
|
+
} else {
|
|
107
|
+
console.warn(`[${tag}]`, message, ...args);
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
/**
|
|
111
|
+
* Error-level log. ALWAYS shown regardless of debug flag.
|
|
112
|
+
* Use for critical failures that should never be silenced.
|
|
113
|
+
*/
|
|
114
|
+
error(tag, message, ...args) {
|
|
115
|
+
const state = getState();
|
|
116
|
+
if (state.handler) {
|
|
117
|
+
state.handler("error", tag, message, ...args);
|
|
118
|
+
} else {
|
|
119
|
+
console.error(`[${tag}]`, message, ...args);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
/** Reset all logger state (debug flag, tags, handler). Primarily for tests. */
|
|
123
|
+
reset() {
|
|
124
|
+
const g = globalThis;
|
|
125
|
+
delete g[LOGGER_KEY];
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// core/errors.ts
|
|
132
|
+
function isSphereError(err) {
|
|
133
|
+
return err instanceof SphereError;
|
|
134
|
+
}
|
|
135
|
+
var SphereError;
|
|
136
|
+
var init_errors = __esm({
|
|
137
|
+
"core/errors.ts"() {
|
|
138
|
+
"use strict";
|
|
139
|
+
SphereError = class extends Error {
|
|
140
|
+
code;
|
|
141
|
+
cause;
|
|
142
|
+
constructor(message, code, cause) {
|
|
143
|
+
super(message);
|
|
144
|
+
this.name = "SphereError";
|
|
145
|
+
this.code = code;
|
|
146
|
+
this.cause = cause;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
33
152
|
// constants.ts
|
|
34
153
|
function getAddressId(directAddress) {
|
|
35
154
|
let hash = directAddress;
|
|
@@ -257,11 +376,11 @@ function bech32Checksum(hrp, data) {
|
|
|
257
376
|
}
|
|
258
377
|
function encodeBech32(hrp, version, program) {
|
|
259
378
|
if (version < 0 || version > 16) {
|
|
260
|
-
throw new
|
|
379
|
+
throw new SphereError("Invalid witness version", "VALIDATION_ERROR");
|
|
261
380
|
}
|
|
262
381
|
const converted = convertBits(Array.from(program), 8, 5, true);
|
|
263
382
|
if (!converted) {
|
|
264
|
-
throw new
|
|
383
|
+
throw new SphereError("Failed to convert bits", "VALIDATION_ERROR");
|
|
265
384
|
}
|
|
266
385
|
const data = [version].concat(converted);
|
|
267
386
|
const checksum = bech32Checksum(hrp, data);
|
|
@@ -314,6 +433,7 @@ var CHARSET, GENERATOR, createBech32;
|
|
|
314
433
|
var init_bech32 = __esm({
|
|
315
434
|
"core/bech32.ts"() {
|
|
316
435
|
"use strict";
|
|
436
|
+
init_errors();
|
|
317
437
|
CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
318
438
|
GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
319
439
|
createBech32 = encodeBech32;
|
|
@@ -326,7 +446,7 @@ function bytesToHex(buf) {
|
|
|
326
446
|
}
|
|
327
447
|
function addressToScriptHash(address) {
|
|
328
448
|
const decoded = decodeBech32(address);
|
|
329
|
-
if (!decoded) throw new
|
|
449
|
+
if (!decoded) throw new SphereError("Invalid bech32 address: " + address, "VALIDATION_ERROR");
|
|
330
450
|
const scriptHex = "0014" + bytesToHex(decoded.data);
|
|
331
451
|
const sha = import_crypto_js.default.SHA256(import_crypto_js.default.enc.Hex.parse(scriptHex)).toString();
|
|
332
452
|
return sha.match(/../g).reverse().join("");
|
|
@@ -336,6 +456,7 @@ var init_addressToScriptHash = __esm({
|
|
|
336
456
|
"l1/addressToScriptHash.ts"() {
|
|
337
457
|
"use strict";
|
|
338
458
|
init_bech32();
|
|
459
|
+
init_errors();
|
|
339
460
|
import_crypto_js = __toESM(require("crypto-js"), 1);
|
|
340
461
|
}
|
|
341
462
|
});
|
|
@@ -396,7 +517,7 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
|
|
|
396
517
|
try {
|
|
397
518
|
ws = new WebSocket(endpoint);
|
|
398
519
|
} catch (err) {
|
|
399
|
-
|
|
520
|
+
logger.error("L1", "WebSocket constructor threw exception:", err);
|
|
400
521
|
isConnecting = false;
|
|
401
522
|
reject(err);
|
|
402
523
|
return;
|
|
@@ -432,7 +553,7 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
|
|
|
432
553
|
return;
|
|
433
554
|
}
|
|
434
555
|
if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
|
435
|
-
|
|
556
|
+
logger.error("L1", "Max reconnect attempts reached. Giving up.");
|
|
436
557
|
isConnecting = false;
|
|
437
558
|
const error = new Error("Max reconnect attempts reached");
|
|
438
559
|
connectionCallbacks.forEach((cb) => {
|
|
@@ -448,8 +569,9 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
|
|
|
448
569
|
}
|
|
449
570
|
const delay = Math.min(BASE_DELAY * Math.pow(2, reconnectAttempts), MAX_DELAY);
|
|
450
571
|
reconnectAttempts++;
|
|
451
|
-
|
|
452
|
-
|
|
572
|
+
logger.warn(
|
|
573
|
+
"L1",
|
|
574
|
+
`WebSocket closed unexpectedly. Reconnecting in ${delay}ms (attempt ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`
|
|
453
575
|
);
|
|
454
576
|
setTimeout(() => {
|
|
455
577
|
connect(endpoint).then(() => {
|
|
@@ -466,7 +588,7 @@ function connect(endpoint = DEFAULT_ENDPOINT) {
|
|
|
466
588
|
}, delay);
|
|
467
589
|
};
|
|
468
590
|
ws.onerror = (err) => {
|
|
469
|
-
|
|
591
|
+
logger.error("L1", "WebSocket error:", err);
|
|
470
592
|
};
|
|
471
593
|
ws.onmessage = (msg) => handleMessage(msg);
|
|
472
594
|
});
|
|
@@ -524,7 +646,7 @@ async function getUtxo(address) {
|
|
|
524
646
|
const scripthash = addressToScriptHash(address);
|
|
525
647
|
const result = await rpc("blockchain.scripthash.listunspent", [scripthash]);
|
|
526
648
|
if (!Array.isArray(result)) {
|
|
527
|
-
|
|
649
|
+
logger.warn("L1", "listunspent returned non-array:", result);
|
|
528
650
|
return [];
|
|
529
651
|
}
|
|
530
652
|
return result.map((u) => ({
|
|
@@ -576,7 +698,7 @@ async function getTransactionHistory(address) {
|
|
|
576
698
|
const scriptHash = addressToScriptHash(address);
|
|
577
699
|
const result = await rpc("blockchain.scripthash.get_history", [scriptHash]);
|
|
578
700
|
if (!Array.isArray(result)) {
|
|
579
|
-
|
|
701
|
+
logger.warn("L1", "get_history returned non-array:", result);
|
|
580
702
|
return [];
|
|
581
703
|
}
|
|
582
704
|
return result;
|
|
@@ -592,7 +714,7 @@ async function getCurrentBlockHeight() {
|
|
|
592
714
|
const header = await rpc("blockchain.headers.subscribe", []);
|
|
593
715
|
return header?.height || 0;
|
|
594
716
|
} catch (err) {
|
|
595
|
-
|
|
717
|
+
logger.error("L1", "Error getting current block height:", err);
|
|
596
718
|
return 0;
|
|
597
719
|
}
|
|
598
720
|
}
|
|
@@ -621,6 +743,7 @@ var DEFAULT_ENDPOINT, ws, isConnected, isConnecting, requestId, intentionalClose
|
|
|
621
743
|
var init_network = __esm({
|
|
622
744
|
"l1/network.ts"() {
|
|
623
745
|
"use strict";
|
|
746
|
+
init_logger();
|
|
624
747
|
init_addressToScriptHash();
|
|
625
748
|
init_constants();
|
|
626
749
|
DEFAULT_ENDPOINT = DEFAULT_ELECTRUM_URL;
|
|
@@ -651,6 +774,7 @@ __export(core_exports, {
|
|
|
651
774
|
DEFAULT_DERIVATION_PATH: () => DEFAULT_DERIVATION_PATH2,
|
|
652
775
|
DEFAULT_TOKEN_DECIMALS: () => DEFAULT_TOKEN_DECIMALS,
|
|
653
776
|
Sphere: () => Sphere,
|
|
777
|
+
SphereError: () => SphereError,
|
|
654
778
|
base58Decode: () => base58Decode,
|
|
655
779
|
base58Encode: () => base58Encode,
|
|
656
780
|
bytesToHex: () => bytesToHex2,
|
|
@@ -697,10 +821,12 @@ __export(core_exports, {
|
|
|
697
821
|
importSphere: () => importSphere,
|
|
698
822
|
initSphere: () => initSphere,
|
|
699
823
|
isEncryptedData: () => isEncryptedData,
|
|
824
|
+
isSphereError: () => isSphereError,
|
|
700
825
|
isValidBech32: () => isValidBech32,
|
|
701
826
|
isValidNametag: () => isValidNametag,
|
|
702
827
|
isValidPrivateKey: () => isValidPrivateKey,
|
|
703
828
|
loadSphere: () => loadSphere,
|
|
829
|
+
logger: () => logger,
|
|
704
830
|
mnemonicToEntropy: () => mnemonicToEntropy2,
|
|
705
831
|
mnemonicToSeed: () => mnemonicToSeed2,
|
|
706
832
|
mnemonicToSeedSync: () => mnemonicToSeedSync2,
|
|
@@ -721,7 +847,12 @@ __export(core_exports, {
|
|
|
721
847
|
});
|
|
722
848
|
module.exports = __toCommonJS(core_exports);
|
|
723
849
|
|
|
850
|
+
// core/Sphere.ts
|
|
851
|
+
init_logger();
|
|
852
|
+
init_errors();
|
|
853
|
+
|
|
724
854
|
// modules/payments/L1PaymentsModule.ts
|
|
855
|
+
init_errors();
|
|
725
856
|
init_constants();
|
|
726
857
|
|
|
727
858
|
// l1/index.ts
|
|
@@ -733,6 +864,7 @@ var bip39 = __toESM(require("bip39"), 1);
|
|
|
733
864
|
var import_crypto_js2 = __toESM(require("crypto-js"), 1);
|
|
734
865
|
var import_elliptic = __toESM(require("elliptic"), 1);
|
|
735
866
|
init_bech32();
|
|
867
|
+
init_errors();
|
|
736
868
|
var ec = new import_elliptic.default.ec("secp256k1");
|
|
737
869
|
var CURVE_ORDER = BigInt(
|
|
738
870
|
"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
|
|
@@ -767,7 +899,7 @@ function generateMasterKey(seedHex) {
|
|
|
767
899
|
const IR = I.substring(64);
|
|
768
900
|
const masterKeyBigInt = BigInt("0x" + IL);
|
|
769
901
|
if (masterKeyBigInt === 0n || masterKeyBigInt >= CURVE_ORDER) {
|
|
770
|
-
throw new
|
|
902
|
+
throw new SphereError("Invalid master key generated", "VALIDATION_ERROR");
|
|
771
903
|
}
|
|
772
904
|
return {
|
|
773
905
|
privateKey: IL,
|
|
@@ -795,11 +927,11 @@ function deriveChildKey(parentPrivKey, parentChainCode, index) {
|
|
|
795
927
|
const ilBigInt = BigInt("0x" + IL);
|
|
796
928
|
const parentKeyBigInt = BigInt("0x" + parentPrivKey);
|
|
797
929
|
if (ilBigInt >= CURVE_ORDER) {
|
|
798
|
-
throw new
|
|
930
|
+
throw new SphereError("Invalid key: IL >= curve order", "VALIDATION_ERROR");
|
|
799
931
|
}
|
|
800
932
|
const childKeyBigInt = (ilBigInt + parentKeyBigInt) % CURVE_ORDER;
|
|
801
933
|
if (childKeyBigInt === 0n) {
|
|
802
|
-
throw new
|
|
934
|
+
throw new SphereError("Invalid key: child key is zero", "VALIDATION_ERROR");
|
|
803
935
|
}
|
|
804
936
|
const childPrivKey = childKeyBigInt.toString(16).padStart(64, "0");
|
|
805
937
|
return {
|
|
@@ -885,14 +1017,14 @@ function randomBytes(length) {
|
|
|
885
1017
|
}
|
|
886
1018
|
async function identityFromMnemonic(mnemonic, passphrase = "") {
|
|
887
1019
|
if (!validateMnemonic2(mnemonic)) {
|
|
888
|
-
throw new
|
|
1020
|
+
throw new SphereError("Invalid mnemonic phrase", "INVALID_IDENTITY");
|
|
889
1021
|
}
|
|
890
1022
|
const seedHex = await mnemonicToSeed2(mnemonic, passphrase);
|
|
891
1023
|
return generateMasterKey(seedHex);
|
|
892
1024
|
}
|
|
893
1025
|
function identityFromMnemonicSync(mnemonic, passphrase = "") {
|
|
894
1026
|
if (!validateMnemonic2(mnemonic)) {
|
|
895
|
-
throw new
|
|
1027
|
+
throw new SphereError("Invalid mnemonic phrase", "INVALID_IDENTITY");
|
|
896
1028
|
}
|
|
897
1029
|
const seedHex = mnemonicToSeedSync2(mnemonic, passphrase);
|
|
898
1030
|
return generateMasterKey(seedHex);
|
|
@@ -940,12 +1072,19 @@ function generateAddressFromMasterKey(masterPrivateKey, index) {
|
|
|
940
1072
|
init_network();
|
|
941
1073
|
|
|
942
1074
|
// l1/tx.ts
|
|
1075
|
+
init_logger();
|
|
1076
|
+
init_errors();
|
|
943
1077
|
init_network();
|
|
944
1078
|
init_bech32();
|
|
945
1079
|
var import_crypto_js5 = __toESM(require("crypto-js"), 1);
|
|
946
1080
|
var import_elliptic2 = __toESM(require("elliptic"), 1);
|
|
947
1081
|
|
|
1082
|
+
// l1/vestingState.ts
|
|
1083
|
+
init_logger();
|
|
1084
|
+
init_errors();
|
|
1085
|
+
|
|
948
1086
|
// l1/vesting.ts
|
|
1087
|
+
init_logger();
|
|
949
1088
|
init_network();
|
|
950
1089
|
var VESTING_THRESHOLD = 28e4;
|
|
951
1090
|
var currentBlockHeight = null;
|
|
@@ -1188,7 +1327,7 @@ var VestingClassifier = class {
|
|
|
1188
1327
|
await new Promise((resolve) => {
|
|
1189
1328
|
const req = indexedDB.deleteDatabase(this.dbName);
|
|
1190
1329
|
const timer = setTimeout(() => {
|
|
1191
|
-
|
|
1330
|
+
logger.warn("L1", ` destroy: deleteDatabase timed out for ${this.dbName}`);
|
|
1192
1331
|
resolve();
|
|
1193
1332
|
}, 3e3);
|
|
1194
1333
|
req.onsuccess = () => {
|
|
@@ -1200,7 +1339,7 @@ var VestingClassifier = class {
|
|
|
1200
1339
|
resolve();
|
|
1201
1340
|
};
|
|
1202
1341
|
req.onblocked = () => {
|
|
1203
|
-
|
|
1342
|
+
logger.warn("L1", ` destroy: deleteDatabase blocked for ${this.dbName}, waiting...`);
|
|
1204
1343
|
};
|
|
1205
1344
|
});
|
|
1206
1345
|
}
|
|
@@ -1218,7 +1357,7 @@ var VestingStateManager = class {
|
|
|
1218
1357
|
*/
|
|
1219
1358
|
setMode(mode) {
|
|
1220
1359
|
if (!["all", "vested", "unvested"].includes(mode)) {
|
|
1221
|
-
throw new
|
|
1360
|
+
throw new SphereError(`Invalid vesting mode: ${mode}`, "VALIDATION_ERROR");
|
|
1222
1361
|
}
|
|
1223
1362
|
this.currentMode = mode;
|
|
1224
1363
|
}
|
|
@@ -1255,10 +1394,10 @@ var VestingStateManager = class {
|
|
|
1255
1394
|
}
|
|
1256
1395
|
});
|
|
1257
1396
|
if (result.errors.length > 0) {
|
|
1258
|
-
|
|
1397
|
+
logger.warn("L1", `Vesting classification errors: ${result.errors.length}`);
|
|
1259
1398
|
result.errors.slice(0, 5).forEach((err) => {
|
|
1260
1399
|
const txHash = err.utxo.tx_hash || err.utxo.txid;
|
|
1261
|
-
|
|
1400
|
+
logger.warn("L1", ` ${txHash}: ${err.error}`);
|
|
1262
1401
|
});
|
|
1263
1402
|
}
|
|
1264
1403
|
} finally {
|
|
@@ -1335,6 +1474,7 @@ var VestingStateManager = class {
|
|
|
1335
1474
|
var vestingState = new VestingStateManager();
|
|
1336
1475
|
|
|
1337
1476
|
// l1/addressHelpers.ts
|
|
1477
|
+
init_errors();
|
|
1338
1478
|
var WalletAddressHelper = class {
|
|
1339
1479
|
/**
|
|
1340
1480
|
* Find address by BIP32 derivation path
|
|
@@ -1380,16 +1520,17 @@ var WalletAddressHelper = class {
|
|
|
1380
1520
|
*/
|
|
1381
1521
|
static add(wallet, newAddress) {
|
|
1382
1522
|
if (!newAddress.path) {
|
|
1383
|
-
throw new
|
|
1523
|
+
throw new SphereError("Cannot add address without a path", "INVALID_CONFIG");
|
|
1384
1524
|
}
|
|
1385
1525
|
const existing = this.findByPath(wallet, newAddress.path);
|
|
1386
1526
|
if (existing) {
|
|
1387
1527
|
if (existing.address !== newAddress.address) {
|
|
1388
|
-
throw new
|
|
1528
|
+
throw new SphereError(
|
|
1389
1529
|
`CRITICAL: Attempted to overwrite address for path ${newAddress.path}
|
|
1390
1530
|
Existing: ${existing.address}
|
|
1391
1531
|
New: ${newAddress.address}
|
|
1392
|
-
This indicates master key corruption or derivation logic error
|
|
1532
|
+
This indicates master key corruption or derivation logic error.`,
|
|
1533
|
+
"INVALID_CONFIG"
|
|
1393
1534
|
);
|
|
1394
1535
|
}
|
|
1395
1536
|
return wallet;
|
|
@@ -1448,9 +1589,10 @@ This indicates master key corruption or derivation logic error.`
|
|
|
1448
1589
|
const uniquePaths = new Set(paths);
|
|
1449
1590
|
if (paths.length !== uniquePaths.size) {
|
|
1450
1591
|
const duplicates = paths.filter((p, i) => paths.indexOf(p) !== i);
|
|
1451
|
-
throw new
|
|
1592
|
+
throw new SphereError(
|
|
1452
1593
|
`CRITICAL: Wallet has duplicate paths: ${duplicates.join(", ")}
|
|
1453
|
-
This indicates data corruption. Please restore from backup
|
|
1594
|
+
This indicates data corruption. Please restore from backup.`,
|
|
1595
|
+
"INVALID_CONFIG"
|
|
1454
1596
|
);
|
|
1455
1597
|
}
|
|
1456
1598
|
}
|
|
@@ -1482,11 +1624,11 @@ var DUST = 546;
|
|
|
1482
1624
|
var SAT = 1e8;
|
|
1483
1625
|
function createScriptPubKey(address) {
|
|
1484
1626
|
if (!address || typeof address !== "string") {
|
|
1485
|
-
throw new
|
|
1627
|
+
throw new SphereError("Invalid address: must be a string", "VALIDATION_ERROR");
|
|
1486
1628
|
}
|
|
1487
1629
|
const decoded = decodeBech32(address);
|
|
1488
1630
|
if (!decoded) {
|
|
1489
|
-
throw new
|
|
1631
|
+
throw new SphereError("Invalid bech32 address: " + address, "VALIDATION_ERROR");
|
|
1490
1632
|
}
|
|
1491
1633
|
const dataHex = Array.from(decoded.data).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1492
1634
|
return "0014" + dataHex;
|
|
@@ -1610,7 +1752,7 @@ function createAndSignTransaction(wallet, txPlan) {
|
|
|
1610
1752
|
privateKeyHex = wallet.masterPrivateKey;
|
|
1611
1753
|
}
|
|
1612
1754
|
if (!privateKeyHex) {
|
|
1613
|
-
throw new
|
|
1755
|
+
throw new SphereError("No private key available for address: " + fromAddress, "INVALID_CONFIG");
|
|
1614
1756
|
}
|
|
1615
1757
|
const keyPair = ec2.keyFromPrivate(privateKeyHex, "hex");
|
|
1616
1758
|
const publicKey = keyPair.getPublic(true, "hex");
|
|
@@ -1709,7 +1851,7 @@ function collectUtxosForAmount(utxoList, amountSats, recipientAddress, senderAdd
|
|
|
1709
1851
|
}
|
|
1710
1852
|
async function createTransactionPlan(wallet, toAddress, amountAlpha, fromAddress) {
|
|
1711
1853
|
if (!decodeBech32(toAddress)) {
|
|
1712
|
-
throw new
|
|
1854
|
+
throw new SphereError("Invalid recipient address", "INVALID_RECIPIENT");
|
|
1713
1855
|
}
|
|
1714
1856
|
const defaultAddr = WalletAddressHelper.getDefault(wallet);
|
|
1715
1857
|
const senderAddress = fromAddress || defaultAddr.address;
|
|
@@ -1718,21 +1860,21 @@ async function createTransactionPlan(wallet, toAddress, amountAlpha, fromAddress
|
|
|
1718
1860
|
const currentMode = vestingState.getMode();
|
|
1719
1861
|
if (vestingState.hasClassifiedData(senderAddress)) {
|
|
1720
1862
|
utxos = vestingState.getFilteredUtxos(senderAddress);
|
|
1721
|
-
|
|
1863
|
+
logger.debug("L1", `Using ${utxos.length} ${currentMode} UTXOs`);
|
|
1722
1864
|
} else {
|
|
1723
1865
|
utxos = await getUtxo(senderAddress);
|
|
1724
|
-
|
|
1866
|
+
logger.debug("L1", `Using ${utxos.length} UTXOs (vesting not classified yet)`);
|
|
1725
1867
|
}
|
|
1726
1868
|
if (!Array.isArray(utxos) || utxos.length === 0) {
|
|
1727
1869
|
const modeText = currentMode !== "all" ? ` (${currentMode} coins)` : "";
|
|
1728
|
-
throw new
|
|
1870
|
+
throw new SphereError(`No UTXOs available${modeText} for address: ` + senderAddress, "INSUFFICIENT_BALANCE");
|
|
1729
1871
|
}
|
|
1730
1872
|
return collectUtxosForAmount(utxos, amountSats, toAddress, senderAddress);
|
|
1731
1873
|
}
|
|
1732
1874
|
async function sendAlpha(wallet, toAddress, amountAlpha, fromAddress) {
|
|
1733
1875
|
const plan = await createTransactionPlan(wallet, toAddress, amountAlpha, fromAddress);
|
|
1734
1876
|
if (!plan.success) {
|
|
1735
|
-
throw new
|
|
1877
|
+
throw new SphereError(plan.error || "Transaction planning failed", "TRANSFER_FAILED");
|
|
1736
1878
|
}
|
|
1737
1879
|
const results = [];
|
|
1738
1880
|
for (const tx of plan.transactions) {
|
|
@@ -1799,7 +1941,7 @@ var L1PaymentsModule = class {
|
|
|
1799
1941
|
*/
|
|
1800
1942
|
async ensureConnected() {
|
|
1801
1943
|
if (this._disabled) {
|
|
1802
|
-
throw new
|
|
1944
|
+
throw new SphereError("L1 provider is disabled", "NOT_INITIALIZED");
|
|
1803
1945
|
}
|
|
1804
1946
|
if (!isWebSocketConnected() && this._config.electrumUrl) {
|
|
1805
1947
|
await connect(this._config.electrumUrl);
|
|
@@ -1854,8 +1996,9 @@ var L1PaymentsModule = class {
|
|
|
1854
1996
|
const l1Address = await this.resolveNametagToL1Address(recipient);
|
|
1855
1997
|
return l1Address;
|
|
1856
1998
|
} catch {
|
|
1857
|
-
throw new
|
|
1858
|
-
`Recipient "${recipient}" is not a valid nametag or L1 address. Use @nametag for explicit nametag or a valid alpha1... address
|
|
1999
|
+
throw new SphereError(
|
|
2000
|
+
`Recipient "${recipient}" is not a valid nametag or L1 address. Use @nametag for explicit nametag or a valid alpha1... address.`,
|
|
2001
|
+
"INVALID_RECIPIENT"
|
|
1859
2002
|
);
|
|
1860
2003
|
}
|
|
1861
2004
|
}
|
|
@@ -1864,15 +2007,16 @@ var L1PaymentsModule = class {
|
|
|
1864
2007
|
*/
|
|
1865
2008
|
async resolveNametagToL1Address(nametag) {
|
|
1866
2009
|
if (!this._transport?.resolve) {
|
|
1867
|
-
throw new
|
|
2010
|
+
throw new SphereError("Transport provider does not support resolution", "TRANSPORT_ERROR");
|
|
1868
2011
|
}
|
|
1869
2012
|
const info = await this._transport.resolve(nametag);
|
|
1870
2013
|
if (!info) {
|
|
1871
|
-
throw new
|
|
2014
|
+
throw new SphereError(`Nametag not found: ${nametag}`, "INVALID_RECIPIENT");
|
|
1872
2015
|
}
|
|
1873
2016
|
if (!info.l1Address) {
|
|
1874
|
-
throw new
|
|
1875
|
-
`Nametag @${nametag} does not have L1 address information. The owner needs to update their nametag registration
|
|
2017
|
+
throw new SphereError(
|
|
2018
|
+
`Nametag @${nametag} does not have L1 address information. The owner needs to update their nametag registration.`,
|
|
2019
|
+
"INVALID_RECIPIENT"
|
|
1876
2020
|
);
|
|
1877
2021
|
}
|
|
1878
2022
|
return info.l1Address;
|
|
@@ -2142,7 +2286,7 @@ var L1PaymentsModule = class {
|
|
|
2142
2286
|
}
|
|
2143
2287
|
ensureInitialized() {
|
|
2144
2288
|
if (!this._initialized) {
|
|
2145
|
-
throw new
|
|
2289
|
+
throw new SphereError("L1PaymentsModule not initialized", "NOT_INITIALIZED");
|
|
2146
2290
|
}
|
|
2147
2291
|
}
|
|
2148
2292
|
_getWatchedAddresses() {
|
|
@@ -2164,6 +2308,7 @@ var L1PaymentsModule = class {
|
|
|
2164
2308
|
};
|
|
2165
2309
|
|
|
2166
2310
|
// modules/payments/TokenSplitCalculator.ts
|
|
2311
|
+
init_logger();
|
|
2167
2312
|
var import_Token = require("@unicitylabs/state-transition-sdk/lib/token/Token");
|
|
2168
2313
|
var import_CoinId = require("@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId");
|
|
2169
2314
|
var TokenSplitCalculator = class {
|
|
@@ -2186,7 +2331,7 @@ var TokenSplitCalculator = class {
|
|
|
2186
2331
|
const sdkToken = await import_Token.Token.fromJSON(parsed);
|
|
2187
2332
|
const realAmount = this.getTokenBalance(sdkToken, targetCoinIdHex);
|
|
2188
2333
|
if (realAmount <= 0n) {
|
|
2189
|
-
|
|
2334
|
+
logger.warn("TokenSplit", `Token ${t.id} has 0 balance for coinId ${targetCoinIdHex}`);
|
|
2190
2335
|
continue;
|
|
2191
2336
|
}
|
|
2192
2337
|
candidates.push({
|
|
@@ -2195,14 +2340,15 @@ var TokenSplitCalculator = class {
|
|
|
2195
2340
|
uiToken: t
|
|
2196
2341
|
});
|
|
2197
2342
|
} catch (e) {
|
|
2198
|
-
|
|
2343
|
+
logger.warn("TokenSplit", "Failed to parse token", t.id, e);
|
|
2199
2344
|
}
|
|
2200
2345
|
}
|
|
2201
2346
|
candidates.sort((a, b) => a.amount < b.amount ? -1 : 1);
|
|
2202
2347
|
const totalAvailable = candidates.reduce((sum, t) => sum + t.amount, 0n);
|
|
2203
2348
|
if (totalAvailable < targetAmount) {
|
|
2204
|
-
|
|
2205
|
-
|
|
2349
|
+
logger.error(
|
|
2350
|
+
"TokenSplit",
|
|
2351
|
+
`Insufficient funds. Available: ${totalAvailable}, Required: ${targetAmount}`
|
|
2206
2352
|
);
|
|
2207
2353
|
return null;
|
|
2208
2354
|
}
|
|
@@ -2300,6 +2446,8 @@ var TokenSplitCalculator = class {
|
|
|
2300
2446
|
};
|
|
2301
2447
|
|
|
2302
2448
|
// modules/payments/TokenSplitExecutor.ts
|
|
2449
|
+
init_logger();
|
|
2450
|
+
init_errors();
|
|
2303
2451
|
var import_Token2 = require("@unicitylabs/state-transition-sdk/lib/token/Token");
|
|
2304
2452
|
var import_TokenId = require("@unicitylabs/state-transition-sdk/lib/token/TokenId");
|
|
2305
2453
|
var import_TokenState = require("@unicitylabs/state-transition-sdk/lib/token/TokenState");
|
|
@@ -2339,7 +2487,7 @@ var TokenSplitExecutor = class {
|
|
|
2339
2487
|
}
|
|
2340
2488
|
async executeSplit(tokenToSplit, splitAmount, remainderAmount, coinIdHex, recipientAddress) {
|
|
2341
2489
|
const tokenIdHex = toHex(tokenToSplit.id.bytes);
|
|
2342
|
-
|
|
2490
|
+
logger.debug("TokenSplit", `Splitting token ${tokenIdHex.slice(0, 8)}...`);
|
|
2343
2491
|
const coinId = new import_CoinId2.CoinId(fromHex(coinIdHex));
|
|
2344
2492
|
const seedString = `${tokenIdHex}_${splitAmount.toString()}_${remainderAmount.toString()}`;
|
|
2345
2493
|
const recipientTokenId = new import_TokenId.TokenId(await sha2562(seedString));
|
|
@@ -2359,23 +2507,23 @@ var TokenSplitExecutor = class {
|
|
|
2359
2507
|
const coinDataB = import_TokenCoinData.TokenCoinData.create([[coinId, remainderAmount]]);
|
|
2360
2508
|
builder.createToken(senderTokenId, tokenToSplit.type, new Uint8Array(0), coinDataB, senderAddress, senderSalt, null);
|
|
2361
2509
|
const split = await builder.build(tokenToSplit);
|
|
2362
|
-
|
|
2510
|
+
logger.debug("TokenSplit", "Step 1: Burning original token...");
|
|
2363
2511
|
const burnSalt = await sha2562(seedString + "_burn_salt");
|
|
2364
2512
|
const burnCommitment = await split.createBurnCommitment(burnSalt, this.signingService);
|
|
2365
2513
|
const burnResponse = await this.client.submitTransferCommitment(burnCommitment);
|
|
2366
2514
|
if (burnResponse.status !== "SUCCESS" && burnResponse.status !== "REQUEST_ID_EXISTS") {
|
|
2367
|
-
throw new
|
|
2515
|
+
throw new SphereError(`Burn failed: ${burnResponse.status}`, "TRANSFER_FAILED");
|
|
2368
2516
|
}
|
|
2369
2517
|
const burnInclusionProof = await (0, import_InclusionProofUtils.waitInclusionProof)(this.trustBase, this.client, burnCommitment);
|
|
2370
2518
|
const burnTransaction = burnCommitment.toTransaction(burnInclusionProof);
|
|
2371
|
-
|
|
2372
|
-
|
|
2519
|
+
logger.debug("TokenSplit", "Original token burned.");
|
|
2520
|
+
logger.debug("TokenSplit", "Step 2: Minting split tokens...");
|
|
2373
2521
|
const mintCommitments = await split.createSplitMintCommitments(this.trustBase, burnTransaction);
|
|
2374
2522
|
const mintedTokensInfo = [];
|
|
2375
2523
|
for (const commitment of mintCommitments) {
|
|
2376
2524
|
const res = await this.client.submitMintCommitment(commitment);
|
|
2377
2525
|
if (res.status !== "SUCCESS" && res.status !== "REQUEST_ID_EXISTS") {
|
|
2378
|
-
throw new
|
|
2526
|
+
throw new SphereError(`Mint split token failed: ${res.status}`, "TRANSFER_FAILED");
|
|
2379
2527
|
}
|
|
2380
2528
|
const proof = await (0, import_InclusionProofUtils.waitInclusionProof)(this.trustBase, this.client, commitment);
|
|
2381
2529
|
const commTokenIdHex = toHex(commitment.transactionData.tokenId.bytes);
|
|
@@ -2388,7 +2536,7 @@ var TokenSplitExecutor = class {
|
|
|
2388
2536
|
salt: commitment.transactionData.salt
|
|
2389
2537
|
});
|
|
2390
2538
|
}
|
|
2391
|
-
|
|
2539
|
+
logger.debug("TokenSplit", "Split tokens minted.");
|
|
2392
2540
|
const recipientInfo = mintedTokensInfo.find((t) => t.isForRecipient);
|
|
2393
2541
|
const senderInfo = mintedTokensInfo.find((t) => !t.isForRecipient);
|
|
2394
2542
|
const createToken = async (info, label) => {
|
|
@@ -2396,12 +2544,12 @@ var TokenSplitExecutor = class {
|
|
|
2396
2544
|
const state = new import_TokenState.TokenState(predicate, null);
|
|
2397
2545
|
const token = await import_Token2.Token.mint(this.trustBase, state, info.commitment.toTransaction(info.inclusionProof));
|
|
2398
2546
|
const verification = await token.verify(this.trustBase);
|
|
2399
|
-
if (!verification.isSuccessful) throw new
|
|
2547
|
+
if (!verification.isSuccessful) throw new SphereError(`Token verification failed: ${label}`, "TRANSFER_FAILED");
|
|
2400
2548
|
return token;
|
|
2401
2549
|
};
|
|
2402
2550
|
const recipientTokenBeforeTransfer = await createToken(recipientInfo, "Recipient");
|
|
2403
2551
|
const senderToken = await createToken(senderInfo, "Sender");
|
|
2404
|
-
|
|
2552
|
+
logger.debug("TokenSplit", "Step 3: Transferring to recipient...");
|
|
2405
2553
|
const transferSalt = await sha2562(seedString + "_transfer_salt");
|
|
2406
2554
|
const transferCommitment = await import_TransferCommitment.TransferCommitment.create(
|
|
2407
2555
|
recipientTokenBeforeTransfer,
|
|
@@ -2413,11 +2561,11 @@ var TokenSplitExecutor = class {
|
|
|
2413
2561
|
);
|
|
2414
2562
|
const transferRes = await this.client.submitTransferCommitment(transferCommitment);
|
|
2415
2563
|
if (transferRes.status !== "SUCCESS" && transferRes.status !== "REQUEST_ID_EXISTS") {
|
|
2416
|
-
throw new
|
|
2564
|
+
throw new SphereError(`Transfer failed: ${transferRes.status}`, "TRANSFER_FAILED");
|
|
2417
2565
|
}
|
|
2418
2566
|
const transferProof = await (0, import_InclusionProofUtils.waitInclusionProof)(this.trustBase, this.client, transferCommitment);
|
|
2419
2567
|
const transferTx = transferCommitment.toTransaction(transferProof);
|
|
2420
|
-
|
|
2568
|
+
logger.debug("TokenSplit", "Split transfer complete!");
|
|
2421
2569
|
return {
|
|
2422
2570
|
tokenForRecipient: recipientTokenBeforeTransfer,
|
|
2423
2571
|
tokenForSender: senderToken,
|
|
@@ -2427,6 +2575,7 @@ var TokenSplitExecutor = class {
|
|
|
2427
2575
|
};
|
|
2428
2576
|
|
|
2429
2577
|
// modules/payments/NametagMinter.ts
|
|
2578
|
+
init_logger();
|
|
2430
2579
|
var import_Token3 = require("@unicitylabs/state-transition-sdk/lib/token/Token");
|
|
2431
2580
|
var import_TokenId2 = require("@unicitylabs/state-transition-sdk/lib/token/TokenId");
|
|
2432
2581
|
var import_TokenType = require("@unicitylabs/state-transition-sdk/lib/token/TokenType");
|
|
@@ -2451,10 +2600,8 @@ var NametagMinter = class {
|
|
|
2451
2600
|
this.skipVerification = config.skipVerification ?? false;
|
|
2452
2601
|
this.debug = config.debug ?? false;
|
|
2453
2602
|
}
|
|
2454
|
-
log(...args) {
|
|
2455
|
-
|
|
2456
|
-
console.log("[NametagMinter]", ...args);
|
|
2457
|
-
}
|
|
2603
|
+
log(message, ...args) {
|
|
2604
|
+
logger.debug("NametagMinter", message, ...args);
|
|
2458
2605
|
}
|
|
2459
2606
|
/**
|
|
2460
2607
|
* Check if a nametag is available (not already minted)
|
|
@@ -2638,6 +2785,7 @@ function parseForkedKey(key) {
|
|
|
2638
2785
|
}
|
|
2639
2786
|
|
|
2640
2787
|
// registry/TokenRegistry.ts
|
|
2788
|
+
init_logger();
|
|
2641
2789
|
init_constants();
|
|
2642
2790
|
var FETCH_TIMEOUT_MS = 1e4;
|
|
2643
2791
|
var TokenRegistry = class _TokenRegistry {
|
|
@@ -2859,14 +3007,12 @@ var TokenRegistry = class _TokenRegistry {
|
|
|
2859
3007
|
clearTimeout(timer);
|
|
2860
3008
|
}
|
|
2861
3009
|
if (!response.ok) {
|
|
2862
|
-
|
|
2863
|
-
`[TokenRegistry] Remote fetch failed: HTTP ${response.status} ${response.statusText}`
|
|
2864
|
-
);
|
|
3010
|
+
logger.warn("TokenRegistry", `Remote fetch failed: HTTP ${response.status} ${response.statusText}`);
|
|
2865
3011
|
return false;
|
|
2866
3012
|
}
|
|
2867
3013
|
const data = await response.json();
|
|
2868
3014
|
if (!this.isValidDefinitionsArray(data)) {
|
|
2869
|
-
|
|
3015
|
+
logger.warn("TokenRegistry", "Remote data is not a valid token definitions array");
|
|
2870
3016
|
return false;
|
|
2871
3017
|
}
|
|
2872
3018
|
const definitions = data;
|
|
@@ -2876,7 +3022,7 @@ var TokenRegistry = class _TokenRegistry {
|
|
|
2876
3022
|
return true;
|
|
2877
3023
|
} catch (error) {
|
|
2878
3024
|
const message = error instanceof Error ? error.message : String(error);
|
|
2879
|
-
|
|
3025
|
+
logger.warn("TokenRegistry", `Remote refresh failed: ${message}`);
|
|
2880
3026
|
return false;
|
|
2881
3027
|
}
|
|
2882
3028
|
}
|
|
@@ -3353,7 +3499,13 @@ function getCurrentStateHash(txf) {
|
|
|
3353
3499
|
return void 0;
|
|
3354
3500
|
}
|
|
3355
3501
|
|
|
3502
|
+
// modules/payments/PaymentsModule.ts
|
|
3503
|
+
init_logger();
|
|
3504
|
+
init_errors();
|
|
3505
|
+
|
|
3356
3506
|
// modules/payments/InstantSplitExecutor.ts
|
|
3507
|
+
init_logger();
|
|
3508
|
+
init_errors();
|
|
3357
3509
|
var import_Token4 = require("@unicitylabs/state-transition-sdk/lib/token/Token");
|
|
3358
3510
|
var import_TokenId3 = require("@unicitylabs/state-transition-sdk/lib/token/TokenId");
|
|
3359
3511
|
var import_TokenState3 = require("@unicitylabs/state-transition-sdk/lib/token/TokenState");
|
|
@@ -3409,7 +3561,7 @@ var InstantSplitExecutor = class {
|
|
|
3409
3561
|
async buildSplitBundle(tokenToSplit, splitAmount, remainderAmount, coinIdHex, recipientAddress, options) {
|
|
3410
3562
|
const splitGroupId = crypto.randomUUID();
|
|
3411
3563
|
const tokenIdHex = toHex2(tokenToSplit.id.bytes);
|
|
3412
|
-
|
|
3564
|
+
logger.debug("InstantSplit", `Building V5 bundle for token ${tokenIdHex.slice(0, 8)}...`);
|
|
3413
3565
|
const coinId = new import_CoinId3.CoinId(fromHex2(coinIdHex));
|
|
3414
3566
|
const seedString = `${tokenIdHex}_${splitAmount.toString()}_${remainderAmount.toString()}_${Date.now()}`;
|
|
3415
3567
|
const recipientTokenId = new import_TokenId3.TokenId(await sha2563(seedString));
|
|
@@ -3446,19 +3598,19 @@ var InstantSplitExecutor = class {
|
|
|
3446
3598
|
null
|
|
3447
3599
|
);
|
|
3448
3600
|
const split = await builder.build(tokenToSplit);
|
|
3449
|
-
|
|
3601
|
+
logger.debug("InstantSplit", "Step 1: Creating and submitting burn...");
|
|
3450
3602
|
const burnSalt = await sha2563(seedString + "_burn_salt");
|
|
3451
3603
|
const burnCommitment = await split.createBurnCommitment(burnSalt, this.signingService);
|
|
3452
3604
|
const burnResponse = await this.client.submitTransferCommitment(burnCommitment);
|
|
3453
3605
|
if (burnResponse.status !== "SUCCESS" && burnResponse.status !== "REQUEST_ID_EXISTS") {
|
|
3454
|
-
throw new
|
|
3606
|
+
throw new SphereError(`Burn submission failed: ${burnResponse.status}`, "TRANSFER_FAILED");
|
|
3455
3607
|
}
|
|
3456
|
-
|
|
3608
|
+
logger.debug("InstantSplit", "Step 2: Waiting for burn proof...");
|
|
3457
3609
|
const burnProof = this.devMode ? await this.waitInclusionProofWithDevBypass(burnCommitment, options?.burnProofTimeoutMs) : await (0, import_InclusionProofUtils3.waitInclusionProof)(this.trustBase, this.client, burnCommitment);
|
|
3458
3610
|
const burnTransaction = burnCommitment.toTransaction(burnProof);
|
|
3459
|
-
|
|
3611
|
+
logger.debug("InstantSplit", "Burn proof received");
|
|
3460
3612
|
options?.onBurnCompleted?.(JSON.stringify(burnTransaction.toJSON()));
|
|
3461
|
-
|
|
3613
|
+
logger.debug("InstantSplit", "Step 3: Creating mint commitments...");
|
|
3462
3614
|
const mintCommitments = await split.createSplitMintCommitments(this.trustBase, burnTransaction);
|
|
3463
3615
|
const recipientIdHex = toHex2(recipientTokenId.bytes);
|
|
3464
3616
|
const senderIdHex = toHex2(senderTokenId.bytes);
|
|
@@ -3469,9 +3621,9 @@ var InstantSplitExecutor = class {
|
|
|
3469
3621
|
(c) => toHex2(c.transactionData.tokenId.bytes) === senderIdHex
|
|
3470
3622
|
);
|
|
3471
3623
|
if (!recipientMintCommitment || !senderMintCommitment) {
|
|
3472
|
-
throw new
|
|
3624
|
+
throw new SphereError("Failed to find expected mint commitments", "TRANSFER_FAILED");
|
|
3473
3625
|
}
|
|
3474
|
-
|
|
3626
|
+
logger.debug("InstantSplit", "Step 4: Creating transfer commitment...");
|
|
3475
3627
|
const transferSalt = await sha2563(seedString + "_transfer_salt");
|
|
3476
3628
|
const transferCommitment = await this.createTransferCommitmentFromMintData(
|
|
3477
3629
|
recipientMintCommitment.transactionData,
|
|
@@ -3487,7 +3639,7 @@ var InstantSplitExecutor = class {
|
|
|
3487
3639
|
recipientSalt
|
|
3488
3640
|
);
|
|
3489
3641
|
const mintedState = new import_TokenState3.TokenState(mintedPredicate, null);
|
|
3490
|
-
|
|
3642
|
+
logger.debug("InstantSplit", "Step 5: Packaging V5 bundle...");
|
|
3491
3643
|
const senderPubkey = toHex2(this.signingService.publicKey);
|
|
3492
3644
|
let nametagTokenJson;
|
|
3493
3645
|
const recipientAddressStr = recipientAddress.toString();
|
|
@@ -3559,7 +3711,7 @@ var InstantSplitExecutor = class {
|
|
|
3559
3711
|
recipientAddress,
|
|
3560
3712
|
options
|
|
3561
3713
|
);
|
|
3562
|
-
|
|
3714
|
+
logger.debug("InstantSplit", "Sending via transport...");
|
|
3563
3715
|
const senderPubkey = toHex2(this.signingService.publicKey);
|
|
3564
3716
|
const nostrEventId = await transport.sendTokenTransfer(recipientPubkey, {
|
|
3565
3717
|
token: JSON.stringify(buildResult.bundle),
|
|
@@ -3571,7 +3723,7 @@ var InstantSplitExecutor = class {
|
|
|
3571
3723
|
}
|
|
3572
3724
|
});
|
|
3573
3725
|
const criticalPathDuration = performance.now() - startTime;
|
|
3574
|
-
|
|
3726
|
+
logger.debug("InstantSplit", `V5 complete in ${criticalPathDuration.toFixed(0)}ms`);
|
|
3575
3727
|
options?.onNostrDelivered?.(nostrEventId);
|
|
3576
3728
|
const backgroundPromise = buildResult.startBackground();
|
|
3577
3729
|
return {
|
|
@@ -3585,7 +3737,7 @@ var InstantSplitExecutor = class {
|
|
|
3585
3737
|
} catch (error) {
|
|
3586
3738
|
const duration = performance.now() - startTime;
|
|
3587
3739
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3588
|
-
|
|
3740
|
+
logger.error("InstantSplit", `Failed after ${duration.toFixed(0)}ms:`, error);
|
|
3589
3741
|
return {
|
|
3590
3742
|
success: false,
|
|
3591
3743
|
criticalPathDurationMs: duration,
|
|
@@ -3634,7 +3786,7 @@ var InstantSplitExecutor = class {
|
|
|
3634
3786
|
* Then waits for sender's mint proof, reconstructs change token, and saves it.
|
|
3635
3787
|
*/
|
|
3636
3788
|
submitBackgroundV5(senderMintCommitment, recipientMintCommitment, transferCommitment, context) {
|
|
3637
|
-
|
|
3789
|
+
logger.debug("InstantSplit", "Background: Starting parallel mint submission...");
|
|
3638
3790
|
const startTime = performance.now();
|
|
3639
3791
|
const submissions = Promise.all([
|
|
3640
3792
|
this.client.submitMintCommitment(senderMintCommitment).then((res) => ({ type: "senderMint", status: res.status })).catch((err) => ({ type: "senderMint", status: "ERROR", error: err })),
|
|
@@ -3643,14 +3795,14 @@ var InstantSplitExecutor = class {
|
|
|
3643
3795
|
]);
|
|
3644
3796
|
return submissions.then(async (results) => {
|
|
3645
3797
|
const submitDuration = performance.now() - startTime;
|
|
3646
|
-
|
|
3798
|
+
logger.debug("InstantSplit", `Background: Submissions complete in ${submitDuration.toFixed(0)}ms`);
|
|
3647
3799
|
context.onProgress?.({
|
|
3648
3800
|
stage: "MINTS_SUBMITTED",
|
|
3649
3801
|
message: `All commitments submitted in ${submitDuration.toFixed(0)}ms`
|
|
3650
3802
|
});
|
|
3651
3803
|
const senderMintResult = results.find((r) => r.type === "senderMint");
|
|
3652
3804
|
if (senderMintResult?.status !== "SUCCESS" && senderMintResult?.status !== "REQUEST_ID_EXISTS") {
|
|
3653
|
-
|
|
3805
|
+
logger.error("InstantSplit", "Background: Sender mint failed - cannot save change token");
|
|
3654
3806
|
context.onProgress?.({
|
|
3655
3807
|
stage: "FAILED",
|
|
3656
3808
|
message: "Sender mint submission failed",
|
|
@@ -3658,12 +3810,12 @@ var InstantSplitExecutor = class {
|
|
|
3658
3810
|
});
|
|
3659
3811
|
return;
|
|
3660
3812
|
}
|
|
3661
|
-
|
|
3813
|
+
logger.debug("InstantSplit", "Background: Waiting for sender mint proof...");
|
|
3662
3814
|
const proofStartTime = performance.now();
|
|
3663
3815
|
try {
|
|
3664
3816
|
const senderMintProof = this.devMode ? await this.waitInclusionProofWithDevBypass(senderMintCommitment) : await (0, import_InclusionProofUtils3.waitInclusionProof)(this.trustBase, this.client, senderMintCommitment);
|
|
3665
3817
|
const proofDuration = performance.now() - proofStartTime;
|
|
3666
|
-
|
|
3818
|
+
logger.debug("InstantSplit", `Background: Sender mint proof received in ${proofDuration.toFixed(0)}ms`);
|
|
3667
3819
|
context.onProgress?.({
|
|
3668
3820
|
stage: "MINTS_PROVEN",
|
|
3669
3821
|
message: `Mint proof received in ${proofDuration.toFixed(0)}ms`
|
|
@@ -3681,38 +3833,38 @@ var InstantSplitExecutor = class {
|
|
|
3681
3833
|
if (!this.devMode) {
|
|
3682
3834
|
const verification = await changeToken.verify(this.trustBase);
|
|
3683
3835
|
if (!verification.isSuccessful) {
|
|
3684
|
-
throw new
|
|
3836
|
+
throw new SphereError("Change token verification failed", "TRANSFER_FAILED");
|
|
3685
3837
|
}
|
|
3686
3838
|
}
|
|
3687
|
-
|
|
3839
|
+
logger.debug("InstantSplit", "Background: Change token created");
|
|
3688
3840
|
context.onProgress?.({
|
|
3689
3841
|
stage: "CHANGE_TOKEN_SAVED",
|
|
3690
3842
|
message: "Change token created and verified"
|
|
3691
3843
|
});
|
|
3692
3844
|
if (context.onChangeTokenCreated) {
|
|
3693
3845
|
await context.onChangeTokenCreated(changeToken);
|
|
3694
|
-
|
|
3846
|
+
logger.debug("InstantSplit", "Background: Change token saved");
|
|
3695
3847
|
}
|
|
3696
3848
|
if (context.onStorageSync) {
|
|
3697
3849
|
try {
|
|
3698
3850
|
const syncSuccess = await context.onStorageSync();
|
|
3699
|
-
|
|
3851
|
+
logger.debug("InstantSplit", `Background: Storage sync ${syncSuccess ? "completed" : "deferred"}`);
|
|
3700
3852
|
context.onProgress?.({
|
|
3701
3853
|
stage: "STORAGE_SYNCED",
|
|
3702
3854
|
message: syncSuccess ? "Storage synchronized" : "Sync deferred"
|
|
3703
3855
|
});
|
|
3704
3856
|
} catch (syncError) {
|
|
3705
|
-
|
|
3857
|
+
logger.warn("InstantSplit", "Background: Storage sync error:", syncError);
|
|
3706
3858
|
}
|
|
3707
3859
|
}
|
|
3708
3860
|
const totalDuration = performance.now() - startTime;
|
|
3709
|
-
|
|
3861
|
+
logger.debug("InstantSplit", `Background: Complete in ${totalDuration.toFixed(0)}ms`);
|
|
3710
3862
|
context.onProgress?.({
|
|
3711
3863
|
stage: "COMPLETED",
|
|
3712
3864
|
message: `Background processing complete in ${totalDuration.toFixed(0)}ms`
|
|
3713
3865
|
});
|
|
3714
3866
|
} catch (proofError) {
|
|
3715
|
-
|
|
3867
|
+
logger.error("InstantSplit", "Background: Failed to get sender mint proof:", proofError);
|
|
3716
3868
|
context.onProgress?.({
|
|
3717
3869
|
stage: "FAILED",
|
|
3718
3870
|
message: "Failed to get mint proof",
|
|
@@ -3720,7 +3872,7 @@ var InstantSplitExecutor = class {
|
|
|
3720
3872
|
});
|
|
3721
3873
|
}
|
|
3722
3874
|
}).catch((err) => {
|
|
3723
|
-
|
|
3875
|
+
logger.error("InstantSplit", "Background: Submission batch failed:", err);
|
|
3724
3876
|
context.onProgress?.({
|
|
3725
3877
|
stage: "FAILED",
|
|
3726
3878
|
message: "Background submission failed",
|
|
@@ -3742,7 +3894,7 @@ var InstantSplitExecutor = class {
|
|
|
3742
3894
|
)
|
|
3743
3895
|
]);
|
|
3744
3896
|
} catch {
|
|
3745
|
-
|
|
3897
|
+
logger.debug("InstantSplit", "Dev mode: Using mock proof");
|
|
3746
3898
|
return {
|
|
3747
3899
|
toJSON: () => ({ mock: true })
|
|
3748
3900
|
};
|
|
@@ -3753,6 +3905,8 @@ var InstantSplitExecutor = class {
|
|
|
3753
3905
|
};
|
|
3754
3906
|
|
|
3755
3907
|
// modules/payments/InstantSplitProcessor.ts
|
|
3908
|
+
init_logger();
|
|
3909
|
+
init_errors();
|
|
3756
3910
|
var import_Token5 = require("@unicitylabs/state-transition-sdk/lib/token/Token");
|
|
3757
3911
|
var import_TokenState4 = require("@unicitylabs/state-transition-sdk/lib/token/TokenState");
|
|
3758
3912
|
var import_TokenType2 = require("@unicitylabs/state-transition-sdk/lib/token/TokenType");
|
|
@@ -3847,27 +4001,27 @@ var InstantSplitProcessor = class {
|
|
|
3847
4001
|
* 5. Create recipient's final state and finalize token
|
|
3848
4002
|
*/
|
|
3849
4003
|
async processV5Bundle(bundle, signingService, senderPubkey, options) {
|
|
3850
|
-
|
|
4004
|
+
logger.debug("InstantSplit", "Processing V5 bundle...");
|
|
3851
4005
|
const startTime = performance.now();
|
|
3852
4006
|
try {
|
|
3853
4007
|
if (bundle.senderPubkey !== senderPubkey) {
|
|
3854
|
-
|
|
4008
|
+
logger.warn("InstantSplit", "Sender pubkey mismatch (non-fatal)");
|
|
3855
4009
|
}
|
|
3856
4010
|
const burnTxJson = JSON.parse(bundle.burnTransaction);
|
|
3857
4011
|
const _burnTransaction = await import_TransferTransaction.TransferTransaction.fromJSON(burnTxJson);
|
|
3858
|
-
|
|
4012
|
+
logger.debug("InstantSplit", "Burn transaction validated");
|
|
3859
4013
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
3860
4014
|
const mintData = await import_MintTransactionData2.MintTransactionData.fromJSON(mintDataJson);
|
|
3861
4015
|
const mintCommitment = await import_MintCommitment2.MintCommitment.create(mintData);
|
|
3862
|
-
|
|
4016
|
+
logger.debug("InstantSplit", "Mint commitment recreated");
|
|
3863
4017
|
const mintResponse = await this.client.submitMintCommitment(mintCommitment);
|
|
3864
4018
|
if (mintResponse.status !== "SUCCESS" && mintResponse.status !== "REQUEST_ID_EXISTS") {
|
|
3865
|
-
throw new
|
|
4019
|
+
throw new SphereError(`Mint submission failed: ${mintResponse.status}`, "TRANSFER_FAILED");
|
|
3866
4020
|
}
|
|
3867
|
-
|
|
4021
|
+
logger.debug("InstantSplit", `Mint submitted: ${mintResponse.status}`);
|
|
3868
4022
|
const mintProof = this.devMode ? await this.waitInclusionProofWithDevBypass(mintCommitment, options?.proofTimeoutMs) : await (0, import_InclusionProofUtils4.waitInclusionProof)(this.trustBase, this.client, mintCommitment);
|
|
3869
4023
|
const mintTransaction = mintCommitment.toTransaction(mintProof);
|
|
3870
|
-
|
|
4024
|
+
logger.debug("InstantSplit", "Mint proof received");
|
|
3871
4025
|
const tokenType = new import_TokenType2.TokenType(fromHex3(bundle.tokenTypeHex));
|
|
3872
4026
|
const senderMintedStateJson = JSON.parse(bundle.mintedTokenStateJson);
|
|
3873
4027
|
const tokenJson = {
|
|
@@ -3878,17 +4032,17 @@ var InstantSplitProcessor = class {
|
|
|
3878
4032
|
nametags: []
|
|
3879
4033
|
};
|
|
3880
4034
|
const mintedToken = await import_Token5.Token.fromJSON(tokenJson);
|
|
3881
|
-
|
|
4035
|
+
logger.debug("InstantSplit", "Minted token reconstructed from sender state");
|
|
3882
4036
|
const transferCommitmentJson = JSON.parse(bundle.transferCommitment);
|
|
3883
4037
|
const transferCommitment = await import_TransferCommitment3.TransferCommitment.fromJSON(transferCommitmentJson);
|
|
3884
4038
|
const transferResponse = await this.client.submitTransferCommitment(transferCommitment);
|
|
3885
4039
|
if (transferResponse.status !== "SUCCESS" && transferResponse.status !== "REQUEST_ID_EXISTS") {
|
|
3886
|
-
throw new
|
|
4040
|
+
throw new SphereError(`Transfer submission failed: ${transferResponse.status}`, "TRANSFER_FAILED");
|
|
3887
4041
|
}
|
|
3888
|
-
|
|
4042
|
+
logger.debug("InstantSplit", `Transfer submitted: ${transferResponse.status}`);
|
|
3889
4043
|
const transferProof = this.devMode ? await this.waitInclusionProofWithDevBypass(transferCommitment, options?.proofTimeoutMs) : await (0, import_InclusionProofUtils4.waitInclusionProof)(this.trustBase, this.client, transferCommitment);
|
|
3890
4044
|
const transferTransaction = transferCommitment.toTransaction(transferProof);
|
|
3891
|
-
|
|
4045
|
+
logger.debug("InstantSplit", "Transfer proof received");
|
|
3892
4046
|
const transferSalt = fromHex3(bundle.transferSaltHex);
|
|
3893
4047
|
const finalRecipientPredicate = await import_UnmaskedPredicate4.UnmaskedPredicate.create(
|
|
3894
4048
|
mintData.tokenId,
|
|
@@ -3898,42 +4052,43 @@ var InstantSplitProcessor = class {
|
|
|
3898
4052
|
transferSalt
|
|
3899
4053
|
);
|
|
3900
4054
|
const finalRecipientState = new import_TokenState4.TokenState(finalRecipientPredicate, null);
|
|
3901
|
-
|
|
4055
|
+
logger.debug("InstantSplit", "Final recipient state created");
|
|
3902
4056
|
let nametagTokens = [];
|
|
3903
4057
|
const recipientAddressStr = bundle.recipientAddressJson;
|
|
3904
4058
|
if (recipientAddressStr.startsWith("PROXY://")) {
|
|
3905
|
-
|
|
4059
|
+
logger.debug("InstantSplit", "PROXY address detected, finding nametag token...");
|
|
3906
4060
|
if (bundle.nametagTokenJson) {
|
|
3907
4061
|
try {
|
|
3908
4062
|
const nametagToken = await import_Token5.Token.fromJSON(JSON.parse(bundle.nametagTokenJson));
|
|
3909
4063
|
const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
|
|
3910
4064
|
const proxy = await ProxyAddress.fromTokenId(nametagToken.id);
|
|
3911
4065
|
if (proxy.address !== recipientAddressStr) {
|
|
3912
|
-
|
|
4066
|
+
logger.warn("InstantSplit", "Nametag PROXY address mismatch, ignoring bundle token");
|
|
3913
4067
|
} else {
|
|
3914
4068
|
nametagTokens = [nametagToken];
|
|
3915
|
-
|
|
4069
|
+
logger.debug("InstantSplit", "Using nametag token from bundle (address validated)");
|
|
3916
4070
|
}
|
|
3917
4071
|
} catch (err) {
|
|
3918
|
-
|
|
4072
|
+
logger.warn("InstantSplit", "Failed to parse nametag token from bundle:", err);
|
|
3919
4073
|
}
|
|
3920
4074
|
}
|
|
3921
4075
|
if (nametagTokens.length === 0 && options?.findNametagToken) {
|
|
3922
4076
|
const token = await options.findNametagToken(recipientAddressStr);
|
|
3923
4077
|
if (token) {
|
|
3924
4078
|
nametagTokens = [token];
|
|
3925
|
-
|
|
4079
|
+
logger.debug("InstantSplit", "Found nametag token via callback");
|
|
3926
4080
|
}
|
|
3927
4081
|
}
|
|
3928
4082
|
if (nametagTokens.length === 0 && !this.devMode) {
|
|
3929
|
-
throw new
|
|
3930
|
-
`PROXY address transfer requires nametag token for verification. Address: ${recipientAddressStr}
|
|
4083
|
+
throw new SphereError(
|
|
4084
|
+
`PROXY address transfer requires nametag token for verification. Address: ${recipientAddressStr}`,
|
|
4085
|
+
"TRANSFER_FAILED"
|
|
3931
4086
|
);
|
|
3932
4087
|
}
|
|
3933
4088
|
}
|
|
3934
4089
|
let finalToken;
|
|
3935
4090
|
if (this.devMode) {
|
|
3936
|
-
|
|
4091
|
+
logger.debug("InstantSplit", "Dev mode: finalizing without verification");
|
|
3937
4092
|
const tokenJson2 = mintedToken.toJSON();
|
|
3938
4093
|
tokenJson2.state = finalRecipientState.toJSON();
|
|
3939
4094
|
tokenJson2.transactions = [transferTransaction.toJSON()];
|
|
@@ -3947,16 +4102,16 @@ var InstantSplitProcessor = class {
|
|
|
3947
4102
|
nametagTokens
|
|
3948
4103
|
);
|
|
3949
4104
|
}
|
|
3950
|
-
|
|
4105
|
+
logger.debug("InstantSplit", "Token finalized");
|
|
3951
4106
|
if (!this.devMode) {
|
|
3952
4107
|
const verification = await finalToken.verify(this.trustBase);
|
|
3953
4108
|
if (!verification.isSuccessful) {
|
|
3954
|
-
throw new
|
|
4109
|
+
throw new SphereError(`Token verification failed`, "TRANSFER_FAILED");
|
|
3955
4110
|
}
|
|
3956
|
-
|
|
4111
|
+
logger.debug("InstantSplit", "Token verified");
|
|
3957
4112
|
}
|
|
3958
4113
|
const duration = performance.now() - startTime;
|
|
3959
|
-
|
|
4114
|
+
logger.debug("InstantSplit", `V5 bundle processed in ${duration.toFixed(0)}ms`);
|
|
3960
4115
|
return {
|
|
3961
4116
|
success: true,
|
|
3962
4117
|
token: finalToken,
|
|
@@ -3965,7 +4120,7 @@ var InstantSplitProcessor = class {
|
|
|
3965
4120
|
} catch (error) {
|
|
3966
4121
|
const duration = performance.now() - startTime;
|
|
3967
4122
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3968
|
-
|
|
4123
|
+
logger.error("InstantSplit", "V5 processing failed:", error);
|
|
3969
4124
|
return {
|
|
3970
4125
|
success: false,
|
|
3971
4126
|
error: errorMessage,
|
|
@@ -3991,30 +4146,30 @@ var InstantSplitProcessor = class {
|
|
|
3991
4146
|
durationMs: 0
|
|
3992
4147
|
};
|
|
3993
4148
|
}
|
|
3994
|
-
|
|
4149
|
+
logger.debug("InstantSplit", "Processing V4 bundle (dev mode)...");
|
|
3995
4150
|
const startTime = performance.now();
|
|
3996
4151
|
try {
|
|
3997
4152
|
const burnCommitmentJson = JSON.parse(bundle.burnCommitment);
|
|
3998
4153
|
const burnCommitment = await import_TransferCommitment3.TransferCommitment.fromJSON(burnCommitmentJson);
|
|
3999
4154
|
const burnResponse = await this.client.submitTransferCommitment(burnCommitment);
|
|
4000
4155
|
if (burnResponse.status !== "SUCCESS" && burnResponse.status !== "REQUEST_ID_EXISTS") {
|
|
4001
|
-
throw new
|
|
4156
|
+
throw new SphereError(`Burn submission failed: ${burnResponse.status}`, "TRANSFER_FAILED");
|
|
4002
4157
|
}
|
|
4003
4158
|
await this.waitInclusionProofWithDevBypass(burnCommitment, options?.proofTimeoutMs);
|
|
4004
|
-
|
|
4159
|
+
logger.debug("InstantSplit", "V4: Burn proof received");
|
|
4005
4160
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
4006
4161
|
const mintData = await import_MintTransactionData2.MintTransactionData.fromJSON(mintDataJson);
|
|
4007
4162
|
const mintCommitment = await import_MintCommitment2.MintCommitment.create(mintData);
|
|
4008
4163
|
const mintResponse = await this.client.submitMintCommitment(mintCommitment);
|
|
4009
4164
|
if (mintResponse.status !== "SUCCESS" && mintResponse.status !== "REQUEST_ID_EXISTS") {
|
|
4010
|
-
throw new
|
|
4165
|
+
throw new SphereError(`Mint submission failed: ${mintResponse.status}`, "TRANSFER_FAILED");
|
|
4011
4166
|
}
|
|
4012
4167
|
const mintProof = await this.waitInclusionProofWithDevBypass(
|
|
4013
4168
|
mintCommitment,
|
|
4014
4169
|
options?.proofTimeoutMs
|
|
4015
4170
|
);
|
|
4016
4171
|
const mintTransaction = mintCommitment.toTransaction(mintProof);
|
|
4017
|
-
|
|
4172
|
+
logger.debug("InstantSplit", "V4: Mint proof received");
|
|
4018
4173
|
const tokenType = new import_TokenType2.TokenType(fromHex3(bundle.tokenTypeHex));
|
|
4019
4174
|
const recipientSalt = fromHex3(bundle.recipientSaltHex);
|
|
4020
4175
|
const recipientPredicate = await import_UnmaskedPredicate4.UnmaskedPredicate.create(
|
|
@@ -4033,19 +4188,19 @@ var InstantSplitProcessor = class {
|
|
|
4033
4188
|
nametags: []
|
|
4034
4189
|
};
|
|
4035
4190
|
const mintedToken = await import_Token5.Token.fromJSON(tokenJson);
|
|
4036
|
-
|
|
4191
|
+
logger.debug("InstantSplit", "V4: Minted token reconstructed");
|
|
4037
4192
|
const transferCommitmentJson = JSON.parse(bundle.transferCommitment);
|
|
4038
4193
|
const transferCommitment = await import_TransferCommitment3.TransferCommitment.fromJSON(transferCommitmentJson);
|
|
4039
4194
|
const transferResponse = await this.client.submitTransferCommitment(transferCommitment);
|
|
4040
4195
|
if (transferResponse.status !== "SUCCESS" && transferResponse.status !== "REQUEST_ID_EXISTS") {
|
|
4041
|
-
throw new
|
|
4196
|
+
throw new SphereError(`Transfer submission failed: ${transferResponse.status}`, "TRANSFER_FAILED");
|
|
4042
4197
|
}
|
|
4043
4198
|
const transferProof = await this.waitInclusionProofWithDevBypass(
|
|
4044
4199
|
transferCommitment,
|
|
4045
4200
|
options?.proofTimeoutMs
|
|
4046
4201
|
);
|
|
4047
4202
|
const transferTransaction = transferCommitment.toTransaction(transferProof);
|
|
4048
|
-
|
|
4203
|
+
logger.debug("InstantSplit", "V4: Transfer proof received");
|
|
4049
4204
|
const transferSalt = fromHex3(bundle.transferSaltHex);
|
|
4050
4205
|
const finalPredicate = await import_UnmaskedPredicate4.UnmaskedPredicate.create(
|
|
4051
4206
|
mintData.tokenId,
|
|
@@ -4059,9 +4214,9 @@ var InstantSplitProcessor = class {
|
|
|
4059
4214
|
finalTokenJson.state = finalState.toJSON();
|
|
4060
4215
|
finalTokenJson.transactions = [transferTransaction.toJSON()];
|
|
4061
4216
|
const finalToken = await import_Token5.Token.fromJSON(finalTokenJson);
|
|
4062
|
-
|
|
4217
|
+
logger.debug("InstantSplit", "V4: Token finalized");
|
|
4063
4218
|
const duration = performance.now() - startTime;
|
|
4064
|
-
|
|
4219
|
+
logger.debug("InstantSplit", `V4 bundle processed in ${duration.toFixed(0)}ms`);
|
|
4065
4220
|
return {
|
|
4066
4221
|
success: true,
|
|
4067
4222
|
token: finalToken,
|
|
@@ -4070,7 +4225,7 @@ var InstantSplitProcessor = class {
|
|
|
4070
4225
|
} catch (error) {
|
|
4071
4226
|
const duration = performance.now() - startTime;
|
|
4072
4227
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4073
|
-
|
|
4228
|
+
logger.error("InstantSplit", "V4 processing failed:", error);
|
|
4074
4229
|
return {
|
|
4075
4230
|
success: false,
|
|
4076
4231
|
error: errorMessage,
|
|
@@ -4091,7 +4246,7 @@ var InstantSplitProcessor = class {
|
|
|
4091
4246
|
)
|
|
4092
4247
|
]);
|
|
4093
4248
|
} catch {
|
|
4094
|
-
|
|
4249
|
+
logger.debug("InstantSplit", "Dev mode: Using mock proof");
|
|
4095
4250
|
return {
|
|
4096
4251
|
toJSON: () => ({ mock: true })
|
|
4097
4252
|
};
|
|
@@ -4276,7 +4431,7 @@ async function parseTokenInfo(tokenData) {
|
|
|
4276
4431
|
}
|
|
4277
4432
|
}
|
|
4278
4433
|
} catch (error) {
|
|
4279
|
-
|
|
4434
|
+
logger.warn("Payments", "Failed to parse token info:", error);
|
|
4280
4435
|
}
|
|
4281
4436
|
return defaultInfo;
|
|
4282
4437
|
}
|
|
@@ -4479,11 +4634,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4479
4634
|
}
|
|
4480
4635
|
/** Price provider (optional) */
|
|
4481
4636
|
priceProvider = null;
|
|
4482
|
-
log(...args) {
|
|
4483
|
-
if (this.moduleConfig.debug) {
|
|
4484
|
-
console.log("[PaymentsModule]", ...args);
|
|
4485
|
-
}
|
|
4486
|
-
}
|
|
4487
4637
|
// ===========================================================================
|
|
4488
4638
|
// Lifecycle
|
|
4489
4639
|
// ===========================================================================
|
|
@@ -4550,11 +4700,11 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4550
4700
|
if (txfData._history && txfData._history.length > 0) {
|
|
4551
4701
|
await this.importRemoteHistoryEntries(txfData._history);
|
|
4552
4702
|
}
|
|
4553
|
-
|
|
4703
|
+
logger.debug("Payments", `Loaded metadata from provider ${id}`);
|
|
4554
4704
|
break;
|
|
4555
4705
|
}
|
|
4556
4706
|
} catch (err) {
|
|
4557
|
-
|
|
4707
|
+
logger.error("Payments", `Failed to load from provider ${id}:`, err);
|
|
4558
4708
|
}
|
|
4559
4709
|
}
|
|
4560
4710
|
for (const [id, token] of this.tokens) {
|
|
@@ -4563,14 +4713,14 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4563
4713
|
const data = JSON.parse(token.sdkData);
|
|
4564
4714
|
if (data?._placeholder) {
|
|
4565
4715
|
this.tokens.delete(id);
|
|
4566
|
-
|
|
4716
|
+
logger.debug("Payments", `Removed stale placeholder token: ${id}`);
|
|
4567
4717
|
}
|
|
4568
4718
|
}
|
|
4569
4719
|
} catch {
|
|
4570
4720
|
}
|
|
4571
4721
|
}
|
|
4572
4722
|
const loadedTokens = Array.from(this.tokens.values()).map((t) => `${t.id.slice(0, 12)}(${t.status})`);
|
|
4573
|
-
|
|
4723
|
+
logger.debug("Payments", `load(): from TXF providers: ${this.tokens.size} tokens [${loadedTokens.join(", ")}]`);
|
|
4574
4724
|
await this.loadPendingV5Tokens();
|
|
4575
4725
|
await this.loadProcessedSplitGroupIds();
|
|
4576
4726
|
await this.loadProcessedCombinedTransferIds();
|
|
@@ -4586,8 +4736,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4586
4736
|
};
|
|
4587
4737
|
this.loadedPromise = doLoad();
|
|
4588
4738
|
await this.loadedPromise;
|
|
4589
|
-
this.resolveUnconfirmed().catch(() =>
|
|
4590
|
-
});
|
|
4739
|
+
this.resolveUnconfirmed().catch((err) => logger.debug("Payments", "resolveUnconfirmed failed", err));
|
|
4591
4740
|
this.scheduleResolveUnconfirmed();
|
|
4592
4741
|
}
|
|
4593
4742
|
/**
|
|
@@ -4640,11 +4789,11 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4640
4789
|
const signingService = await this.createSigningService();
|
|
4641
4790
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
4642
4791
|
if (!stClient) {
|
|
4643
|
-
throw new
|
|
4792
|
+
throw new SphereError("State transition client not available. Oracle provider must implement getStateTransitionClient()", "AGGREGATOR_ERROR");
|
|
4644
4793
|
}
|
|
4645
4794
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
4646
4795
|
if (!trustBase) {
|
|
4647
|
-
throw new
|
|
4796
|
+
throw new SphereError("Trust base not available. Oracle provider must implement getTrustBase()", "AGGREGATOR_ERROR");
|
|
4648
4797
|
}
|
|
4649
4798
|
const calculator = new TokenSplitCalculator();
|
|
4650
4799
|
const availableTokens = Array.from(this.tokens.values());
|
|
@@ -4654,7 +4803,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4654
4803
|
request.coinId
|
|
4655
4804
|
);
|
|
4656
4805
|
if (!splitPlan) {
|
|
4657
|
-
throw new
|
|
4806
|
+
throw new SphereError("Insufficient balance", "INSUFFICIENT_BALANCE");
|
|
4658
4807
|
}
|
|
4659
4808
|
const tokensToSend = splitPlan.tokensToTransferDirectly.map((t) => t.uiToken);
|
|
4660
4809
|
if (splitPlan.tokenToSplit) {
|
|
@@ -4672,7 +4821,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4672
4821
|
const transferMode = request.transferMode ?? "instant";
|
|
4673
4822
|
if (transferMode === "conservative") {
|
|
4674
4823
|
if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
|
|
4675
|
-
|
|
4824
|
+
logger.debug("Payments", "Executing conservative split...");
|
|
4676
4825
|
const splitExecutor = new TokenSplitExecutor({
|
|
4677
4826
|
stateTransitionClient: stClient,
|
|
4678
4827
|
trustBase,
|
|
@@ -4700,7 +4849,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4700
4849
|
sdkData: JSON.stringify(changeTokenData)
|
|
4701
4850
|
};
|
|
4702
4851
|
await this.addToken(changeUiToken);
|
|
4703
|
-
|
|
4852
|
+
logger.debug("Payments", `Conservative split: change token saved: ${changeUiToken.id}`);
|
|
4704
4853
|
await this.deps.transport.sendTokenTransfer(recipientPubkey, {
|
|
4705
4854
|
sourceToken: JSON.stringify(splitResult.tokenForRecipient.toJSON()),
|
|
4706
4855
|
transferTx: JSON.stringify(splitResult.recipientTransferTx.toJSON()),
|
|
@@ -4714,15 +4863,15 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4714
4863
|
method: "split",
|
|
4715
4864
|
requestIdHex: splitRequestIdHex
|
|
4716
4865
|
});
|
|
4717
|
-
|
|
4866
|
+
logger.debug("Payments", "Conservative split transfer completed");
|
|
4718
4867
|
}
|
|
4719
4868
|
for (const tokenWithAmount of splitPlan.tokensToTransferDirectly) {
|
|
4720
4869
|
const token = tokenWithAmount.uiToken;
|
|
4721
4870
|
const commitment = await this.createSdkCommitment(token, recipientAddress, signingService);
|
|
4722
|
-
|
|
4871
|
+
logger.debug("Payments", `CONSERVATIVE: Sending direct token ${token.id.slice(0, 8)}... to ${recipientPubkey.slice(0, 8)}...`);
|
|
4723
4872
|
const submitResponse = await stClient.submitTransferCommitment(commitment);
|
|
4724
4873
|
if (submitResponse.status !== "SUCCESS" && submitResponse.status !== "REQUEST_ID_EXISTS") {
|
|
4725
|
-
throw new
|
|
4874
|
+
throw new SphereError(`Transfer commitment failed: ${submitResponse.status}`, "TRANSFER_FAILED");
|
|
4726
4875
|
}
|
|
4727
4876
|
const inclusionProof = await (0, import_InclusionProofUtils5.waitInclusionProof)(trustBase, stClient, commitment);
|
|
4728
4877
|
const transferTx = commitment.toTransaction(inclusionProof);
|
|
@@ -4731,7 +4880,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4731
4880
|
transferTx: JSON.stringify(transferTx.toJSON()),
|
|
4732
4881
|
memo: request.memo
|
|
4733
4882
|
});
|
|
4734
|
-
|
|
4883
|
+
logger.debug("Payments", "CONSERVATIVE: Direct token sent successfully");
|
|
4735
4884
|
const requestIdBytes = commitment.requestId;
|
|
4736
4885
|
const requestIdHex = requestIdBytes instanceof Uint8Array ? Array.from(requestIdBytes).map((b) => b.toString(16).padStart(2, "0")).join("") : String(requestIdBytes);
|
|
4737
4886
|
result.tokenTransfers.push({
|
|
@@ -4739,7 +4888,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4739
4888
|
method: "direct",
|
|
4740
4889
|
requestIdHex
|
|
4741
4890
|
});
|
|
4742
|
-
|
|
4891
|
+
logger.debug("Payments", `Token ${token.id} sent via CONSERVATIVE, requestId: ${requestIdHex}`);
|
|
4743
4892
|
await this.removeToken(token.id);
|
|
4744
4893
|
}
|
|
4745
4894
|
} else {
|
|
@@ -4748,7 +4897,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4748
4897
|
let changeTokenPlaceholderId = null;
|
|
4749
4898
|
let builtSplit = null;
|
|
4750
4899
|
if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
|
|
4751
|
-
|
|
4900
|
+
logger.debug("Payments", "Building instant split bundle...");
|
|
4752
4901
|
const executor = new InstantSplitExecutor({
|
|
4753
4902
|
stateTransitionClient: stClient,
|
|
4754
4903
|
trustBase,
|
|
@@ -4782,7 +4931,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4782
4931
|
sdkData: JSON.stringify(changeTokenData)
|
|
4783
4932
|
};
|
|
4784
4933
|
await this.addToken(uiToken);
|
|
4785
|
-
|
|
4934
|
+
logger.debug("Payments", `Change token saved via background: ${uiToken.id}`);
|
|
4786
4935
|
},
|
|
4787
4936
|
onStorageSync: async () => {
|
|
4788
4937
|
await this.save();
|
|
@@ -4790,7 +4939,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4790
4939
|
}
|
|
4791
4940
|
}
|
|
4792
4941
|
);
|
|
4793
|
-
|
|
4942
|
+
logger.debug("Payments", `Split bundle built: splitGroupId=${builtSplit.splitGroupId}`);
|
|
4794
4943
|
}
|
|
4795
4944
|
const directCommitments = await Promise.all(
|
|
4796
4945
|
splitPlan.tokensToTransferDirectly.map(
|
|
@@ -4817,8 +4966,9 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4817
4966
|
senderPubkey,
|
|
4818
4967
|
memo: request.memo
|
|
4819
4968
|
};
|
|
4820
|
-
|
|
4821
|
-
|
|
4969
|
+
logger.debug(
|
|
4970
|
+
"Payments",
|
|
4971
|
+
`Sending V6 combined bundle: transfer=${result.id.slice(0, 8)}... split=${!!builtSplit} direct=${directTokenEntries.length}`
|
|
4822
4972
|
);
|
|
4823
4973
|
await this.deps.transport.sendTokenTransfer(recipientPubkey, {
|
|
4824
4974
|
token: JSON.stringify(combinedBundle),
|
|
@@ -4826,7 +4976,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4826
4976
|
memo: request.memo,
|
|
4827
4977
|
sender: { transportPubkey: senderPubkey }
|
|
4828
4978
|
});
|
|
4829
|
-
|
|
4979
|
+
logger.debug("Payments", "V6 combined bundle sent successfully");
|
|
4830
4980
|
if (builtSplit) {
|
|
4831
4981
|
const bgPromise = builtSplit.startBackground();
|
|
4832
4982
|
this.pendingBackgroundTasks.push(bgPromise);
|
|
@@ -4847,11 +4997,11 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4847
4997
|
sdkData: JSON.stringify({ _placeholder: true })
|
|
4848
4998
|
};
|
|
4849
4999
|
this.tokens.set(placeholder.id, placeholder);
|
|
4850
|
-
|
|
5000
|
+
logger.debug("Payments", `Placeholder change token created: ${placeholder.id} (${placeholder.amount})`);
|
|
4851
5001
|
}
|
|
4852
5002
|
for (const commitment of directCommitments) {
|
|
4853
5003
|
stClient.submitTransferCommitment(commitment).catch(
|
|
4854
|
-
(err) =>
|
|
5004
|
+
(err) => logger.error("Payments", "Background commitment submit failed:", err)
|
|
4855
5005
|
);
|
|
4856
5006
|
}
|
|
4857
5007
|
if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
|
|
@@ -4874,7 +5024,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4874
5024
|
});
|
|
4875
5025
|
await this.removeToken(token.id);
|
|
4876
5026
|
}
|
|
4877
|
-
|
|
5027
|
+
logger.debug("Payments", "V6 combined transfer completed");
|
|
4878
5028
|
}
|
|
4879
5029
|
result.status = "delivered";
|
|
4880
5030
|
await this.save();
|
|
@@ -4965,11 +5115,11 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4965
5115
|
const signingService = await this.createSigningService();
|
|
4966
5116
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
4967
5117
|
if (!stClient) {
|
|
4968
|
-
throw new
|
|
5118
|
+
throw new SphereError("State transition client not available", "AGGREGATOR_ERROR");
|
|
4969
5119
|
}
|
|
4970
5120
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
4971
5121
|
if (!trustBase) {
|
|
4972
|
-
throw new
|
|
5122
|
+
throw new SphereError("Trust base not available", "AGGREGATOR_ERROR");
|
|
4973
5123
|
}
|
|
4974
5124
|
const calculator = new TokenSplitCalculator();
|
|
4975
5125
|
const availableTokens = Array.from(this.tokens.values());
|
|
@@ -4979,10 +5129,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4979
5129
|
request.coinId
|
|
4980
5130
|
);
|
|
4981
5131
|
if (!splitPlan) {
|
|
4982
|
-
throw new
|
|
5132
|
+
throw new SphereError("Insufficient balance", "INSUFFICIENT_BALANCE");
|
|
4983
5133
|
}
|
|
4984
5134
|
if (!splitPlan.requiresSplit || !splitPlan.tokenToSplit) {
|
|
4985
|
-
|
|
5135
|
+
logger.debug("Payments", "No split required, falling back to standard send()");
|
|
4986
5136
|
const result2 = await this.send(request);
|
|
4987
5137
|
return {
|
|
4988
5138
|
success: result2.status === "completed",
|
|
@@ -4990,7 +5140,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4990
5140
|
error: result2.error
|
|
4991
5141
|
};
|
|
4992
5142
|
}
|
|
4993
|
-
|
|
5143
|
+
logger.debug("Payments", `InstantSplit: amount=${splitPlan.splitAmount}, remainder=${splitPlan.remainderAmount}`);
|
|
4994
5144
|
const tokenToSplit = splitPlan.tokenToSplit.uiToken;
|
|
4995
5145
|
tokenToSplit.status = "transferring";
|
|
4996
5146
|
this.tokens.set(tokenToSplit.id, tokenToSplit);
|
|
@@ -5028,7 +5178,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5028
5178
|
sdkData: JSON.stringify(changeTokenData)
|
|
5029
5179
|
};
|
|
5030
5180
|
await this.addToken(uiToken);
|
|
5031
|
-
|
|
5181
|
+
logger.debug("Payments", `Change token saved via background: ${uiToken.id}`);
|
|
5032
5182
|
},
|
|
5033
5183
|
onStorageSync: async () => {
|
|
5034
5184
|
await this.save();
|
|
@@ -5083,7 +5233,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5083
5233
|
async saveUnconfirmedV5Token(bundle, senderPubkey, deferPersistence = false) {
|
|
5084
5234
|
const deterministicId = `v5split_${bundle.splitGroupId}`;
|
|
5085
5235
|
if (this.tokens.has(deterministicId) || this.processedSplitGroupIds.has(bundle.splitGroupId)) {
|
|
5086
|
-
|
|
5236
|
+
logger.debug("Payments", `V5 bundle ${bundle.splitGroupId.slice(0, 12)}... already processed, skipping`);
|
|
5087
5237
|
return null;
|
|
5088
5238
|
}
|
|
5089
5239
|
const registry = TokenRegistry.getInstance();
|
|
@@ -5133,7 +5283,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5133
5283
|
const nostrTokenId = extractTokenIdFromSdkData(sdkData);
|
|
5134
5284
|
const nostrStateHash = extractStateHashFromSdkData(sdkData);
|
|
5135
5285
|
if (nostrTokenId && nostrStateHash && this.isStateTombstoned(nostrTokenId, nostrStateHash)) {
|
|
5136
|
-
|
|
5286
|
+
logger.debug("Payments", `NOSTR-FIRST: Rejecting tombstoned token ${nostrTokenId.slice(0, 8)}..._${nostrStateHash.slice(0, 8)}...`);
|
|
5137
5287
|
return null;
|
|
5138
5288
|
}
|
|
5139
5289
|
if (nostrTokenId) {
|
|
@@ -5142,14 +5292,16 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5142
5292
|
if (existingTokenId !== nostrTokenId) continue;
|
|
5143
5293
|
const existingStateHash = extractStateHashFromSdkData(existing.sdkData);
|
|
5144
5294
|
if (nostrStateHash && existingStateHash === nostrStateHash) {
|
|
5145
|
-
|
|
5146
|
-
|
|
5295
|
+
logger.debug(
|
|
5296
|
+
"Payments",
|
|
5297
|
+
`NOSTR-FIRST: Skipping duplicate token state ${nostrTokenId.slice(0, 8)}..._${nostrStateHash.slice(0, 8)}...`
|
|
5147
5298
|
);
|
|
5148
5299
|
return null;
|
|
5149
5300
|
}
|
|
5150
5301
|
if (!skipGenesisDedup) {
|
|
5151
|
-
|
|
5152
|
-
|
|
5302
|
+
logger.debug(
|
|
5303
|
+
"Payments",
|
|
5304
|
+
`NOSTR-FIRST: Skipping replay of finalized token ${nostrTokenId.slice(0, 8)}...`
|
|
5153
5305
|
);
|
|
5154
5306
|
return null;
|
|
5155
5307
|
}
|
|
@@ -5181,7 +5333,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5181
5333
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
5182
5334
|
if (stClient) {
|
|
5183
5335
|
const response = await stClient.submitTransferCommitment(commitment);
|
|
5184
|
-
|
|
5336
|
+
logger.debug("Payments", `NOSTR-FIRST recipient commitment submit: ${response.status}`);
|
|
5185
5337
|
}
|
|
5186
5338
|
}
|
|
5187
5339
|
this.addProofPollingJob({
|
|
@@ -5196,7 +5348,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5196
5348
|
}
|
|
5197
5349
|
});
|
|
5198
5350
|
} catch (err) {
|
|
5199
|
-
|
|
5351
|
+
logger.error("Payments", "Failed to parse commitment for proof polling:", err);
|
|
5200
5352
|
}
|
|
5201
5353
|
return token;
|
|
5202
5354
|
}
|
|
@@ -5218,11 +5370,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5218
5370
|
await this.loadedPromise;
|
|
5219
5371
|
}
|
|
5220
5372
|
if (this.processedCombinedTransferIds.has(bundle.transferId)) {
|
|
5221
|
-
|
|
5373
|
+
logger.debug("Payments", `V6 combined transfer ${bundle.transferId.slice(0, 12)}... already processed, skipping`);
|
|
5222
5374
|
return;
|
|
5223
5375
|
}
|
|
5224
|
-
|
|
5225
|
-
|
|
5376
|
+
logger.debug(
|
|
5377
|
+
"Payments",
|
|
5378
|
+
`Processing V6 combined transfer ${bundle.transferId.slice(0, 12)}... (split=${!!bundle.splitBundle}, direct=${bundle.directTokens.length})`
|
|
5226
5379
|
);
|
|
5227
5380
|
const allTokens = [];
|
|
5228
5381
|
const tokenBreakdown = [];
|
|
@@ -5236,7 +5389,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5236
5389
|
allTokens.push(splitToken);
|
|
5237
5390
|
tokenBreakdown.push({ id: splitToken.id, amount: splitToken.amount, source: "split" });
|
|
5238
5391
|
} else {
|
|
5239
|
-
|
|
5392
|
+
logger.warn("Payments", `V6: split token was deduped/failed \u2014 amount=${bundle.splitBundle.amount}`);
|
|
5240
5393
|
}
|
|
5241
5394
|
}
|
|
5242
5395
|
const directResults = await Promise.all(
|
|
@@ -5251,13 +5404,14 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5251
5404
|
tokenBreakdown.push({ id: token.id, amount: token.amount, source: "direct" });
|
|
5252
5405
|
} else {
|
|
5253
5406
|
const entry = bundle.directTokens[i];
|
|
5254
|
-
|
|
5255
|
-
|
|
5407
|
+
logger.warn(
|
|
5408
|
+
"Payments",
|
|
5409
|
+
`V6: direct token #${i} dropped (amount=${entry.amount}, tokenId=${entry.tokenId?.slice(0, 12) ?? "N/A"})`
|
|
5256
5410
|
);
|
|
5257
5411
|
}
|
|
5258
5412
|
}
|
|
5259
5413
|
if (allTokens.length === 0) {
|
|
5260
|
-
|
|
5414
|
+
logger.debug("Payments", "V6 combined transfer: all tokens deduped, nothing to save");
|
|
5261
5415
|
return;
|
|
5262
5416
|
}
|
|
5263
5417
|
this.processedCombinedTransferIds.add(bundle.transferId);
|
|
@@ -5273,7 +5427,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5273
5427
|
import_TransferCommitment4.TransferCommitment.fromJSON(commitment).then(
|
|
5274
5428
|
(c) => stClient.submitTransferCommitment(c)
|
|
5275
5429
|
).catch(
|
|
5276
|
-
(err) =>
|
|
5430
|
+
(err) => logger.error("Payments", "V6 background commitment submit failed:", err)
|
|
5277
5431
|
);
|
|
5278
5432
|
}
|
|
5279
5433
|
}
|
|
@@ -5300,8 +5454,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5300
5454
|
tokenIds: tokenBreakdown
|
|
5301
5455
|
});
|
|
5302
5456
|
if (bundle.splitBundle) {
|
|
5303
|
-
this.resolveUnconfirmed().catch(() =>
|
|
5304
|
-
});
|
|
5457
|
+
this.resolveUnconfirmed().catch((err) => logger.debug("Payments", "resolveUnconfirmed failed", err));
|
|
5305
5458
|
this.scheduleResolveUnconfirmed();
|
|
5306
5459
|
}
|
|
5307
5460
|
}
|
|
@@ -5379,8 +5532,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5379
5532
|
receivedAt: Date.now()
|
|
5380
5533
|
});
|
|
5381
5534
|
await this.save();
|
|
5382
|
-
this.resolveUnconfirmed().catch(() =>
|
|
5383
|
-
});
|
|
5535
|
+
this.resolveUnconfirmed().catch((err) => logger.debug("Payments", "resolveUnconfirmed failed", err));
|
|
5384
5536
|
this.scheduleResolveUnconfirmed();
|
|
5385
5537
|
return { success: true, durationMs: 0 };
|
|
5386
5538
|
} catch (error) {
|
|
@@ -5401,11 +5553,11 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5401
5553
|
const signingService = await this.createSigningService();
|
|
5402
5554
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
5403
5555
|
if (!stClient) {
|
|
5404
|
-
throw new
|
|
5556
|
+
throw new SphereError("State transition client not available", "AGGREGATOR_ERROR");
|
|
5405
5557
|
}
|
|
5406
5558
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
5407
5559
|
if (!trustBase) {
|
|
5408
|
-
throw new
|
|
5560
|
+
throw new SphereError("Trust base not available", "AGGREGATOR_ERROR");
|
|
5409
5561
|
}
|
|
5410
5562
|
const devMode = this.deps.oracle.isDevMode?.() ?? false;
|
|
5411
5563
|
const processor = new InstantSplitProcessor({
|
|
@@ -5428,10 +5580,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5428
5580
|
if (proxy.address === proxyAddress) {
|
|
5429
5581
|
return nametagToken;
|
|
5430
5582
|
}
|
|
5431
|
-
|
|
5583
|
+
logger.debug("Payments", `Nametag PROXY address mismatch: ${proxy.address} !== ${proxyAddress}`);
|
|
5432
5584
|
return null;
|
|
5433
5585
|
} catch (err) {
|
|
5434
|
-
|
|
5586
|
+
logger.debug("Payments", "Failed to parse nametag token:", err);
|
|
5435
5587
|
return null;
|
|
5436
5588
|
}
|
|
5437
5589
|
}
|
|
@@ -5539,7 +5691,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5539
5691
|
status: "pending"
|
|
5540
5692
|
};
|
|
5541
5693
|
this.outgoingPaymentRequests.set(requestId2, outgoingRequest);
|
|
5542
|
-
|
|
5694
|
+
logger.debug("Payments", `Payment request sent: ${eventId}`);
|
|
5543
5695
|
return {
|
|
5544
5696
|
success: true,
|
|
5545
5697
|
requestId: requestId2,
|
|
@@ -5547,7 +5699,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5547
5699
|
};
|
|
5548
5700
|
} catch (error) {
|
|
5549
5701
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
5550
|
-
|
|
5702
|
+
logger.debug("Payments", `Failed to send payment request: ${errorMsg}`);
|
|
5551
5703
|
return {
|
|
5552
5704
|
success: false,
|
|
5553
5705
|
error: errorMsg
|
|
@@ -5636,10 +5788,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5636
5788
|
async payPaymentRequest(requestId2, memo) {
|
|
5637
5789
|
const request = this.paymentRequests.find((r) => r.id === requestId2);
|
|
5638
5790
|
if (!request) {
|
|
5639
|
-
throw new
|
|
5791
|
+
throw new SphereError(`Payment request not found: ${requestId2}`, "VALIDATION_ERROR");
|
|
5640
5792
|
}
|
|
5641
5793
|
if (request.status !== "pending" && request.status !== "accepted") {
|
|
5642
|
-
throw new
|
|
5794
|
+
throw new SphereError(`Payment request is not pending or accepted: ${request.status}`, "VALIDATION_ERROR");
|
|
5643
5795
|
}
|
|
5644
5796
|
this.updatePaymentRequestStatus(requestId2, "accepted");
|
|
5645
5797
|
try {
|
|
@@ -5694,10 +5846,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5694
5846
|
try {
|
|
5695
5847
|
handler(request);
|
|
5696
5848
|
} catch (error) {
|
|
5697
|
-
|
|
5849
|
+
logger.debug("Payments", "Payment request handler error:", error);
|
|
5698
5850
|
}
|
|
5699
5851
|
}
|
|
5700
|
-
|
|
5852
|
+
logger.debug("Payments", `Incoming payment request: ${request.id} for ${request.amount} ${request.symbol}`);
|
|
5701
5853
|
}
|
|
5702
5854
|
// ===========================================================================
|
|
5703
5855
|
// Public API - Outgoing Payment Requests
|
|
@@ -5816,10 +5968,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5816
5968
|
try {
|
|
5817
5969
|
handler(response);
|
|
5818
5970
|
} catch (error) {
|
|
5819
|
-
|
|
5971
|
+
logger.debug("Payments", "Payment request response handler error:", error);
|
|
5820
5972
|
}
|
|
5821
5973
|
}
|
|
5822
|
-
|
|
5974
|
+
logger.debug("Payments", `Received payment request response: ${response.id} type: ${response.responseType}`);
|
|
5823
5975
|
}
|
|
5824
5976
|
/**
|
|
5825
5977
|
* Send a response to a payment request (used internally by accept/reject/pay methods)
|
|
@@ -5828,7 +5980,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5828
5980
|
const request = this.paymentRequests.find((r) => r.id === requestId2);
|
|
5829
5981
|
if (!request) return;
|
|
5830
5982
|
if (!this.deps?.transport.sendPaymentRequestResponse) {
|
|
5831
|
-
|
|
5983
|
+
logger.debug("Payments", "Transport does not support sendPaymentRequestResponse");
|
|
5832
5984
|
return;
|
|
5833
5985
|
}
|
|
5834
5986
|
try {
|
|
@@ -5839,9 +5991,9 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5839
5991
|
transferId
|
|
5840
5992
|
};
|
|
5841
5993
|
await this.deps.transport.sendPaymentRequestResponse(request.senderPubkey, payload);
|
|
5842
|
-
|
|
5994
|
+
logger.debug("Payments", `Sent payment request response: ${responseType} for ${requestId2}`);
|
|
5843
5995
|
} catch (error) {
|
|
5844
|
-
|
|
5996
|
+
logger.debug("Payments", "Failed to send payment request response:", error);
|
|
5845
5997
|
}
|
|
5846
5998
|
}
|
|
5847
5999
|
// ===========================================================================
|
|
@@ -5865,7 +6017,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5865
6017
|
async receive(options, callback) {
|
|
5866
6018
|
this.ensureInitialized();
|
|
5867
6019
|
if (!this.deps.transport.fetchPendingEvents) {
|
|
5868
|
-
throw new
|
|
6020
|
+
throw new SphereError("Transport provider does not support fetchPendingEvents", "TRANSPORT_ERROR");
|
|
5869
6021
|
}
|
|
5870
6022
|
const opts = options ?? {};
|
|
5871
6023
|
const tokensBefore = new Set(this.tokens.keys());
|
|
@@ -6012,7 +6164,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6012
6164
|
});
|
|
6013
6165
|
}
|
|
6014
6166
|
} catch (error) {
|
|
6015
|
-
|
|
6167
|
+
logger.warn("Payments", "Failed to fetch prices, returning assets without price data:", error);
|
|
6016
6168
|
}
|
|
6017
6169
|
return rawAssets;
|
|
6018
6170
|
}
|
|
@@ -6134,24 +6286,24 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6134
6286
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
6135
6287
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
6136
6288
|
if (!stClient || !trustBase) {
|
|
6137
|
-
|
|
6289
|
+
logger.debug("Payments", `[V5-RESOLVE] resolveUnconfirmed: EARLY EXIT \u2014 stClient=${!!stClient} trustBase=${!!trustBase}`);
|
|
6138
6290
|
return result;
|
|
6139
6291
|
}
|
|
6140
6292
|
const signingService = await this.createSigningService();
|
|
6141
6293
|
const submittedCount = Array.from(this.tokens.values()).filter((t) => t.status === "submitted").length;
|
|
6142
|
-
|
|
6294
|
+
logger.debug("Payments", `[V5-RESOLVE] resolveUnconfirmed: ${submittedCount} submitted token(s) to process`);
|
|
6143
6295
|
for (const [tokenId, token] of this.tokens) {
|
|
6144
6296
|
if (token.status !== "submitted") continue;
|
|
6145
6297
|
const pending2 = this.parsePendingFinalization(token.sdkData);
|
|
6146
6298
|
if (!pending2) {
|
|
6147
|
-
|
|
6299
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 16)}: no pending finalization metadata, skipping`);
|
|
6148
6300
|
result.stillPending++;
|
|
6149
6301
|
continue;
|
|
6150
6302
|
}
|
|
6151
6303
|
if (pending2.type === "v5_bundle") {
|
|
6152
|
-
|
|
6304
|
+
logger.debug("Payments", `[V5-RESOLVE] Processing ${tokenId.slice(0, 16)}... stage=${pending2.stage} attempt=${pending2.attemptCount}`);
|
|
6153
6305
|
const progress = await this.resolveV5Token(tokenId, token, pending2, stClient, trustBase, signingService);
|
|
6154
|
-
|
|
6306
|
+
logger.debug("Payments", `[V5-RESOLVE] Result for ${tokenId.slice(0, 16)}...: ${progress} (stage now: ${pending2.stage})`);
|
|
6155
6307
|
result.details.push({ tokenId, stage: pending2.stage, status: progress });
|
|
6156
6308
|
if (progress === "resolved") result.resolved++;
|
|
6157
6309
|
else if (progress === "failed") result.failed++;
|
|
@@ -6159,7 +6311,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6159
6311
|
}
|
|
6160
6312
|
}
|
|
6161
6313
|
if (result.resolved > 0 || result.failed > 0 || result.stillPending > 0) {
|
|
6162
|
-
|
|
6314
|
+
logger.debug("Payments", `[V5-RESOLVE] Saving: resolved=${result.resolved} failed=${result.failed} stillPending=${result.stillPending}`);
|
|
6163
6315
|
await this.save();
|
|
6164
6316
|
}
|
|
6165
6317
|
return result;
|
|
@@ -6175,19 +6327,19 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6175
6327
|
(t) => t.status === "submitted"
|
|
6176
6328
|
);
|
|
6177
6329
|
if (!hasUnconfirmed) {
|
|
6178
|
-
|
|
6330
|
+
logger.debug("Payments", "[V5-RESOLVE] scheduleResolveUnconfirmed: no submitted tokens, not starting timer");
|
|
6179
6331
|
return;
|
|
6180
6332
|
}
|
|
6181
|
-
|
|
6333
|
+
logger.debug("Payments", `[V5-RESOLVE] scheduleResolveUnconfirmed: starting periodic retry (every ${_PaymentsModule.RESOLVE_UNCONFIRMED_INTERVAL_MS}ms)`);
|
|
6182
6334
|
this.resolveUnconfirmedTimer = setInterval(async () => {
|
|
6183
6335
|
try {
|
|
6184
6336
|
const result = await this.resolveUnconfirmed();
|
|
6185
6337
|
if (result.stillPending === 0) {
|
|
6186
|
-
|
|
6338
|
+
logger.debug("Payments", "[V5-RESOLVE] All tokens resolved, stopping periodic retry");
|
|
6187
6339
|
this.stopResolveUnconfirmedPolling();
|
|
6188
6340
|
}
|
|
6189
6341
|
} catch (err) {
|
|
6190
|
-
|
|
6342
|
+
logger.debug("Payments", "[V5-RESOLVE] Periodic retry error:", err);
|
|
6191
6343
|
}
|
|
6192
6344
|
}, _PaymentsModule.RESOLVE_UNCONFIRMED_INTERVAL_MS);
|
|
6193
6345
|
}
|
|
@@ -6209,57 +6361,57 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6209
6361
|
pending2.lastAttemptAt = Date.now();
|
|
6210
6362
|
try {
|
|
6211
6363
|
if (pending2.stage === "RECEIVED") {
|
|
6212
|
-
|
|
6364
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: RECEIVED \u2192 submitting mint commitment...`);
|
|
6213
6365
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
6214
6366
|
const mintData = await import_MintTransactionData3.MintTransactionData.fromJSON(mintDataJson);
|
|
6215
6367
|
const mintCommitment = await import_MintCommitment3.MintCommitment.create(mintData);
|
|
6216
6368
|
const mintResponse = await stClient.submitMintCommitment(mintCommitment);
|
|
6217
|
-
|
|
6369
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: mint response status=${mintResponse.status}`);
|
|
6218
6370
|
if (mintResponse.status !== "SUCCESS" && mintResponse.status !== "REQUEST_ID_EXISTS") {
|
|
6219
|
-
throw new
|
|
6371
|
+
throw new SphereError(`Mint submission failed: ${mintResponse.status}`, "TRANSFER_FAILED");
|
|
6220
6372
|
}
|
|
6221
6373
|
pending2.stage = "MINT_SUBMITTED";
|
|
6222
6374
|
this.updatePendingFinalization(token, pending2);
|
|
6223
6375
|
}
|
|
6224
6376
|
if (pending2.stage === "MINT_SUBMITTED") {
|
|
6225
|
-
|
|
6377
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: MINT_SUBMITTED \u2192 checking mint proof...`);
|
|
6226
6378
|
const mintDataJson = JSON.parse(bundle.recipientMintData);
|
|
6227
6379
|
const mintData = await import_MintTransactionData3.MintTransactionData.fromJSON(mintDataJson);
|
|
6228
6380
|
const mintCommitment = await import_MintCommitment3.MintCommitment.create(mintData);
|
|
6229
6381
|
const proof = await this.quickProofCheck(stClient, trustBase, mintCommitment);
|
|
6230
6382
|
if (!proof) {
|
|
6231
|
-
|
|
6383
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: mint proof not yet available, staying MINT_SUBMITTED`);
|
|
6232
6384
|
this.updatePendingFinalization(token, pending2);
|
|
6233
6385
|
return "pending";
|
|
6234
6386
|
}
|
|
6235
|
-
|
|
6387
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: mint proof obtained!`);
|
|
6236
6388
|
pending2.mintProofJson = JSON.stringify(proof);
|
|
6237
6389
|
pending2.stage = "MINT_PROVEN";
|
|
6238
6390
|
this.updatePendingFinalization(token, pending2);
|
|
6239
6391
|
}
|
|
6240
6392
|
if (pending2.stage === "MINT_PROVEN") {
|
|
6241
|
-
|
|
6393
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: MINT_PROVEN \u2192 submitting transfer commitment...`);
|
|
6242
6394
|
const transferCommitmentJson = JSON.parse(bundle.transferCommitment);
|
|
6243
6395
|
const transferCommitment = await import_TransferCommitment4.TransferCommitment.fromJSON(transferCommitmentJson);
|
|
6244
6396
|
const transferResponse = await stClient.submitTransferCommitment(transferCommitment);
|
|
6245
|
-
|
|
6397
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: transfer response status=${transferResponse.status}`);
|
|
6246
6398
|
if (transferResponse.status !== "SUCCESS" && transferResponse.status !== "REQUEST_ID_EXISTS") {
|
|
6247
|
-
throw new
|
|
6399
|
+
throw new SphereError(`Transfer submission failed: ${transferResponse.status}`, "TRANSFER_FAILED");
|
|
6248
6400
|
}
|
|
6249
6401
|
pending2.stage = "TRANSFER_SUBMITTED";
|
|
6250
6402
|
this.updatePendingFinalization(token, pending2);
|
|
6251
6403
|
}
|
|
6252
6404
|
if (pending2.stage === "TRANSFER_SUBMITTED") {
|
|
6253
|
-
|
|
6405
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: TRANSFER_SUBMITTED \u2192 checking transfer proof...`);
|
|
6254
6406
|
const transferCommitmentJson = JSON.parse(bundle.transferCommitment);
|
|
6255
6407
|
const transferCommitment = await import_TransferCommitment4.TransferCommitment.fromJSON(transferCommitmentJson);
|
|
6256
6408
|
const proof = await this.quickProofCheck(stClient, trustBase, transferCommitment);
|
|
6257
6409
|
if (!proof) {
|
|
6258
|
-
|
|
6410
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: transfer proof not yet available, staying TRANSFER_SUBMITTED`);
|
|
6259
6411
|
this.updatePendingFinalization(token, pending2);
|
|
6260
6412
|
return "pending";
|
|
6261
6413
|
}
|
|
6262
|
-
|
|
6414
|
+
logger.debug("Payments", `[V5-RESOLVE] ${tokenId.slice(0, 12)}: transfer proof obtained! Finalizing...`);
|
|
6263
6415
|
const finalizedToken = await this.finalizeFromV5Bundle(bundle, pending2, signingService, stClient, trustBase);
|
|
6264
6416
|
const confirmedToken = {
|
|
6265
6417
|
id: token.id,
|
|
@@ -6281,12 +6433,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6281
6433
|
tokens: [confirmedToken],
|
|
6282
6434
|
tokenTransfers: []
|
|
6283
6435
|
});
|
|
6284
|
-
|
|
6436
|
+
logger.debug("Payments", `V5 token resolved: ${tokenId.slice(0, 8)}...`);
|
|
6285
6437
|
return "resolved";
|
|
6286
6438
|
}
|
|
6287
6439
|
return "pending";
|
|
6288
6440
|
} catch (error) {
|
|
6289
|
-
|
|
6441
|
+
logger.error("Payments", `resolveV5Token failed for ${tokenId.slice(0, 8)}:`, error);
|
|
6290
6442
|
if (pending2.attemptCount > 50) {
|
|
6291
6443
|
token.status = "invalid";
|
|
6292
6444
|
token.updatedAt = Date.now();
|
|
@@ -6423,19 +6575,19 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6423
6575
|
}
|
|
6424
6576
|
if (pendingTokens.length > 0) {
|
|
6425
6577
|
const json = JSON.stringify(pendingTokens);
|
|
6426
|
-
|
|
6578
|
+
logger.debug("Payments", `[V5-PERSIST] Saving ${pendingTokens.length} pending V5 token(s): ${pendingTokens.map((t) => t.id.slice(0, 16)).join(", ")} (${json.length} bytes)`);
|
|
6427
6579
|
await this.deps.storage.set(
|
|
6428
6580
|
STORAGE_KEYS_ADDRESS.PENDING_V5_TOKENS,
|
|
6429
6581
|
json
|
|
6430
6582
|
);
|
|
6431
6583
|
const verify = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.PENDING_V5_TOKENS);
|
|
6432
6584
|
if (!verify) {
|
|
6433
|
-
|
|
6585
|
+
logger.error("Payments", "[V5-PERSIST] CRITICAL: KV write succeeded but read-back is empty!");
|
|
6434
6586
|
} else {
|
|
6435
|
-
|
|
6587
|
+
logger.debug("Payments", `[V5-PERSIST] Verified: read-back ${verify.length} bytes`);
|
|
6436
6588
|
}
|
|
6437
6589
|
} else {
|
|
6438
|
-
|
|
6590
|
+
logger.debug("Payments", `[V5-PERSIST] No pending V5 tokens to save (total tokens: ${this.tokens.size}), clearing KV`);
|
|
6439
6591
|
await this.deps.storage.set(STORAGE_KEYS_ADDRESS.PENDING_V5_TOKENS, "");
|
|
6440
6592
|
}
|
|
6441
6593
|
}
|
|
@@ -6445,21 +6597,21 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6445
6597
|
*/
|
|
6446
6598
|
async loadPendingV5Tokens() {
|
|
6447
6599
|
const data = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.PENDING_V5_TOKENS);
|
|
6448
|
-
|
|
6600
|
+
logger.debug("Payments", `[V5-PERSIST] loadPendingV5Tokens: KV data = ${data ? `${data.length} bytes` : "null/empty"}`);
|
|
6449
6601
|
if (!data) return;
|
|
6450
6602
|
try {
|
|
6451
6603
|
const pendingTokens = JSON.parse(data);
|
|
6452
|
-
|
|
6604
|
+
logger.debug("Payments", `[V5-PERSIST] Parsed ${pendingTokens.length} pending V5 token(s): ${pendingTokens.map((t) => t.id.slice(0, 16)).join(", ")}`);
|
|
6453
6605
|
for (const token of pendingTokens) {
|
|
6454
6606
|
if (!this.tokens.has(token.id)) {
|
|
6455
6607
|
this.tokens.set(token.id, token);
|
|
6456
|
-
|
|
6608
|
+
logger.debug("Payments", `[V5-PERSIST] Restored token ${token.id.slice(0, 16)} (status=${token.status})`);
|
|
6457
6609
|
} else {
|
|
6458
|
-
|
|
6610
|
+
logger.debug("Payments", `[V5-PERSIST] Token ${token.id.slice(0, 16)} already in map, skipping`);
|
|
6459
6611
|
}
|
|
6460
6612
|
}
|
|
6461
6613
|
} catch (err) {
|
|
6462
|
-
|
|
6614
|
+
logger.error("Payments", "[V5-PERSIST] Failed to parse pending V5 tokens:", err);
|
|
6463
6615
|
}
|
|
6464
6616
|
}
|
|
6465
6617
|
/**
|
|
@@ -6512,13 +6664,13 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6512
6664
|
const incomingStateHash = extractStateHashFromSdkData(token.sdkData);
|
|
6513
6665
|
const incomingStateKey = incomingTokenId && incomingStateHash ? createTokenStateKey(incomingTokenId, incomingStateHash) : null;
|
|
6514
6666
|
if (incomingTokenId && incomingStateHash && this.isStateTombstoned(incomingTokenId, incomingStateHash)) {
|
|
6515
|
-
|
|
6667
|
+
logger.debug("Payments", `Rejecting tombstoned token: ${incomingTokenId.slice(0, 8)}..._${incomingStateHash.slice(0, 8)}...`);
|
|
6516
6668
|
return false;
|
|
6517
6669
|
}
|
|
6518
6670
|
if (incomingStateKey) {
|
|
6519
6671
|
for (const [_existingId, existing] of this.tokens) {
|
|
6520
6672
|
if (isSameTokenState(existing, token)) {
|
|
6521
|
-
|
|
6673
|
+
logger.debug("Payments", `Duplicate token state ignored: ${incomingTokenId?.slice(0, 8)}..._${incomingStateHash?.slice(0, 8)}...`);
|
|
6522
6674
|
return false;
|
|
6523
6675
|
}
|
|
6524
6676
|
}
|
|
@@ -6530,19 +6682,19 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6530
6682
|
continue;
|
|
6531
6683
|
}
|
|
6532
6684
|
if (existing.status === "spent" || existing.status === "invalid") {
|
|
6533
|
-
|
|
6685
|
+
logger.debug("Payments", `Replacing spent/invalid token ${incomingTokenId?.slice(0, 8)}...`);
|
|
6534
6686
|
this.tokens.delete(existingId);
|
|
6535
6687
|
break;
|
|
6536
6688
|
}
|
|
6537
6689
|
if (incomingStateHash && existingStateHash && incomingStateHash !== existingStateHash) {
|
|
6538
|
-
|
|
6690
|
+
logger.debug("Payments", `Token ${incomingTokenId?.slice(0, 8)}... state updated: ${existingStateHash.slice(0, 8)}... -> ${incomingStateHash.slice(0, 8)}...`);
|
|
6539
6691
|
await this.archiveToken(existing);
|
|
6540
6692
|
this.tokens.delete(existingId);
|
|
6541
6693
|
break;
|
|
6542
6694
|
}
|
|
6543
6695
|
if (!incomingStateHash || !existingStateHash) {
|
|
6544
6696
|
if (existingId !== token.id) {
|
|
6545
|
-
|
|
6697
|
+
logger.debug("Payments", `Token ${incomingTokenId?.slice(0, 8)}... .id changed, replacing`);
|
|
6546
6698
|
await this.archiveToken(existing);
|
|
6547
6699
|
this.tokens.delete(existingId);
|
|
6548
6700
|
break;
|
|
@@ -6553,7 +6705,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6553
6705
|
this.tokens.set(token.id, token);
|
|
6554
6706
|
await this.archiveToken(token);
|
|
6555
6707
|
await this.save();
|
|
6556
|
-
|
|
6708
|
+
logger.debug("Payments", `Added token ${token.id}, total: ${this.tokens.size}`);
|
|
6557
6709
|
return true;
|
|
6558
6710
|
}
|
|
6559
6711
|
/**
|
|
@@ -6583,7 +6735,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6583
6735
|
}
|
|
6584
6736
|
await this.archiveToken(token);
|
|
6585
6737
|
await this.save();
|
|
6586
|
-
|
|
6738
|
+
logger.debug("Payments", `Updated token ${token.id}`);
|
|
6587
6739
|
}
|
|
6588
6740
|
/**
|
|
6589
6741
|
* Remove a token from the wallet.
|
|
@@ -6606,10 +6758,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6606
6758
|
);
|
|
6607
6759
|
if (!alreadyTombstoned) {
|
|
6608
6760
|
this.tombstones.push(tombstone);
|
|
6609
|
-
|
|
6761
|
+
logger.debug("Payments", `Created tombstone for ${tombstone.tokenId.slice(0, 8)}..._${tombstone.stateHash.slice(0, 8)}...`);
|
|
6610
6762
|
}
|
|
6611
6763
|
} else {
|
|
6612
|
-
|
|
6764
|
+
logger.debug("Payments", `Warning: Could not create tombstone for token ${tokenId.slice(0, 8)}... (missing tokenId or stateHash)`);
|
|
6613
6765
|
}
|
|
6614
6766
|
this.tokens.delete(tokenId);
|
|
6615
6767
|
await this.save();
|
|
@@ -6666,7 +6818,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6666
6818
|
}
|
|
6667
6819
|
for (const token of tokensToRemove) {
|
|
6668
6820
|
this.tokens.delete(token.id);
|
|
6669
|
-
|
|
6821
|
+
logger.debug("Payments", `Removed tombstoned token ${token.id.slice(0, 8)}...`);
|
|
6670
6822
|
removedCount++;
|
|
6671
6823
|
}
|
|
6672
6824
|
for (const remoteTombstone of remoteTombstones) {
|
|
@@ -6692,7 +6844,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6692
6844
|
this.tombstones = pruneTombstonesByAge(this.tombstones, maxAge);
|
|
6693
6845
|
if (this.tombstones.length < originalCount) {
|
|
6694
6846
|
await this.save();
|
|
6695
|
-
|
|
6847
|
+
logger.debug("Payments", `Pruned tombstones from ${originalCount} to ${this.tombstones.length}`);
|
|
6696
6848
|
}
|
|
6697
6849
|
}
|
|
6698
6850
|
// ===========================================================================
|
|
@@ -6764,7 +6916,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6764
6916
|
const originalCount = this.archivedTokens.size;
|
|
6765
6917
|
this.archivedTokens = pruneMapByCount(this.archivedTokens, maxCount);
|
|
6766
6918
|
await this.save();
|
|
6767
|
-
|
|
6919
|
+
logger.debug("Payments", `Pruned archived tokens from ${originalCount} to ${this.archivedTokens.size}`);
|
|
6768
6920
|
}
|
|
6769
6921
|
// ===========================================================================
|
|
6770
6922
|
// Public API - Forked Tokens
|
|
@@ -6793,7 +6945,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6793
6945
|
const key = `${tokenId}_${stateHash}`;
|
|
6794
6946
|
if (this.forkedTokens.has(key)) return;
|
|
6795
6947
|
this.forkedTokens.set(key, txfToken);
|
|
6796
|
-
|
|
6948
|
+
logger.debug("Payments", `Stored forked token ${tokenId.slice(0, 8)}... state ${stateHash.slice(0, 12)}...`);
|
|
6797
6949
|
await this.save();
|
|
6798
6950
|
}
|
|
6799
6951
|
/**
|
|
@@ -6825,7 +6977,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6825
6977
|
const originalCount = this.forkedTokens.size;
|
|
6826
6978
|
this.forkedTokens = pruneMapByCount(this.forkedTokens, maxCount);
|
|
6827
6979
|
await this.save();
|
|
6828
|
-
|
|
6980
|
+
logger.debug("Payments", `Pruned forked tokens from ${originalCount} to ${this.forkedTokens.size}`);
|
|
6829
6981
|
}
|
|
6830
6982
|
// ===========================================================================
|
|
6831
6983
|
// Public API - Transaction History
|
|
@@ -6905,7 +7057,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6905
7057
|
const imported = await provider.importHistoryEntries?.(records) ?? 0;
|
|
6906
7058
|
if (imported > 0) {
|
|
6907
7059
|
this._historyCache = await provider.getHistoryEntries();
|
|
6908
|
-
|
|
7060
|
+
logger.debug("Payments", `Migrated ${imported} history entries from KV to history store`);
|
|
6909
7061
|
}
|
|
6910
7062
|
await this.deps.storage.remove(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
|
|
6911
7063
|
} catch {
|
|
@@ -6981,7 +7133,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6981
7133
|
this.nametags.push(nametag);
|
|
6982
7134
|
}
|
|
6983
7135
|
await this.save();
|
|
6984
|
-
|
|
7136
|
+
logger.debug("Payments", `Nametag set: ${nametag.name}`);
|
|
6985
7137
|
}
|
|
6986
7138
|
/**
|
|
6987
7139
|
* Get the current (first) nametag data.
|
|
@@ -7030,7 +7182,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7030
7182
|
const parsed = parseTxfStorageData(result.data);
|
|
7031
7183
|
if (parsed.nametags.length > 0) {
|
|
7032
7184
|
this.nametags = parsed.nametags;
|
|
7033
|
-
|
|
7185
|
+
logger.debug("Payments", `Reloaded ${parsed.nametags.length} nametag(s) from storage`);
|
|
7034
7186
|
return;
|
|
7035
7187
|
}
|
|
7036
7188
|
}
|
|
@@ -7083,7 +7235,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7083
7235
|
const result = await minter.mintNametag(nametag, ownerAddress);
|
|
7084
7236
|
if (result.success && result.nametagData) {
|
|
7085
7237
|
await this.setNametag(result.nametagData);
|
|
7086
|
-
|
|
7238
|
+
logger.debug("Payments", `Nametag minted and saved: ${result.nametagData.name}`);
|
|
7087
7239
|
this.deps.emitEvent("nametag:registered", {
|
|
7088
7240
|
nametag: result.nametagData.name,
|
|
7089
7241
|
addressIndex: 0
|
|
@@ -7093,7 +7245,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7093
7245
|
return result;
|
|
7094
7246
|
} catch (error) {
|
|
7095
7247
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
7096
|
-
|
|
7248
|
+
logger.debug("Payments", "mintNametag failed:", errorMsg);
|
|
7097
7249
|
return {
|
|
7098
7250
|
success: false,
|
|
7099
7251
|
error: errorMsg
|
|
@@ -7191,7 +7343,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7191
7343
|
restoredCount++;
|
|
7192
7344
|
}
|
|
7193
7345
|
if (restoredCount > 0) {
|
|
7194
|
-
|
|
7346
|
+
logger.debug("Payments", `Sync: restored ${restoredCount} token(s) lost by loadFromStorageData`);
|
|
7195
7347
|
}
|
|
7196
7348
|
if (this.nametags.length === 0 && savedNametags.length > 0) {
|
|
7197
7349
|
this.nametags = savedNametags;
|
|
@@ -7200,7 +7352,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7200
7352
|
if (txfData._history && txfData._history.length > 0) {
|
|
7201
7353
|
const imported = await this.importRemoteHistoryEntries(txfData._history);
|
|
7202
7354
|
if (imported > 0) {
|
|
7203
|
-
|
|
7355
|
+
logger.debug("Payments", `Imported ${imported} history entries from IPFS sync`);
|
|
7204
7356
|
}
|
|
7205
7357
|
}
|
|
7206
7358
|
totalAdded += result.added;
|
|
@@ -7213,7 +7365,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7213
7365
|
removed: result.removed
|
|
7214
7366
|
});
|
|
7215
7367
|
} catch (providerError) {
|
|
7216
|
-
|
|
7368
|
+
logger.warn("Payments", `Sync failed for provider ${providerId}:`, providerError);
|
|
7217
7369
|
this.deps.emitEvent("sync:provider", {
|
|
7218
7370
|
providerId,
|
|
7219
7371
|
success: false,
|
|
@@ -7251,7 +7403,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7251
7403
|
if (provider.onEvent) {
|
|
7252
7404
|
const unsub = provider.onEvent((event) => {
|
|
7253
7405
|
if (event.type === "storage:remote-updated") {
|
|
7254
|
-
|
|
7406
|
+
logger.debug("Payments", "Remote update detected from provider", providerId, event.data);
|
|
7255
7407
|
this.debouncedSyncFromRemoteUpdate(providerId, event.data);
|
|
7256
7408
|
}
|
|
7257
7409
|
});
|
|
@@ -7293,7 +7445,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7293
7445
|
removed: result.removed
|
|
7294
7446
|
});
|
|
7295
7447
|
}).catch((err) => {
|
|
7296
|
-
|
|
7448
|
+
logger.debug("Payments", "Auto-sync from remote update failed:", err);
|
|
7297
7449
|
});
|
|
7298
7450
|
}, _PaymentsModule.SYNC_DEBOUNCE_MS);
|
|
7299
7451
|
}
|
|
@@ -7398,8 +7550,9 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7398
7550
|
}
|
|
7399
7551
|
return recipient;
|
|
7400
7552
|
}
|
|
7401
|
-
throw new
|
|
7402
|
-
`Cannot resolve transport pubkey for "${recipient}". No binding event found. The recipient must publish their identity first
|
|
7553
|
+
throw new SphereError(
|
|
7554
|
+
`Cannot resolve transport pubkey for "${recipient}". No binding event found. The recipient must publish their identity first.`,
|
|
7555
|
+
"INVALID_RECIPIENT"
|
|
7403
7556
|
);
|
|
7404
7557
|
}
|
|
7405
7558
|
/**
|
|
@@ -7470,32 +7623,33 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7470
7623
|
return AddressFactory.createAddress(recipient);
|
|
7471
7624
|
}
|
|
7472
7625
|
if (recipient.length === 66 && /^[0-9a-fA-F]+$/.test(recipient)) {
|
|
7473
|
-
|
|
7626
|
+
logger.debug("Payments", "Creating DirectAddress from 33-byte compressed pubkey");
|
|
7474
7627
|
return this.createDirectAddressFromPubkey(recipient);
|
|
7475
7628
|
}
|
|
7476
7629
|
const info = peerInfo ?? await this.deps?.transport.resolve?.(recipient) ?? null;
|
|
7477
7630
|
if (!info) {
|
|
7478
|
-
throw new
|
|
7479
|
-
`Recipient "${recipient}" not found. Use @nametag, a valid PROXY:/DIRECT: address, or a 33-byte hex pubkey
|
|
7631
|
+
throw new SphereError(
|
|
7632
|
+
`Recipient "${recipient}" not found. Use @nametag, a valid PROXY:/DIRECT: address, or a 33-byte hex pubkey.`,
|
|
7633
|
+
"INVALID_RECIPIENT"
|
|
7480
7634
|
);
|
|
7481
7635
|
}
|
|
7482
7636
|
const nametag = recipient.startsWith("@") ? recipient.slice(1) : info.nametag || recipient;
|
|
7483
7637
|
if (addressMode === "proxy") {
|
|
7484
|
-
|
|
7638
|
+
logger.debug("Payments", `Using PROXY address for "${nametag}" (forced)`);
|
|
7485
7639
|
return ProxyAddress.fromNameTag(nametag);
|
|
7486
7640
|
}
|
|
7487
7641
|
if (addressMode === "direct") {
|
|
7488
7642
|
if (!info.directAddress) {
|
|
7489
|
-
throw new
|
|
7643
|
+
throw new SphereError(`"${nametag}" has no DirectAddress stored. It may be a legacy registration.`, "INVALID_RECIPIENT");
|
|
7490
7644
|
}
|
|
7491
|
-
|
|
7645
|
+
logger.debug("Payments", `Using DirectAddress for "${nametag}" (forced): ${info.directAddress.slice(0, 30)}...`);
|
|
7492
7646
|
return AddressFactory.createAddress(info.directAddress);
|
|
7493
7647
|
}
|
|
7494
7648
|
if (info.directAddress) {
|
|
7495
|
-
|
|
7649
|
+
logger.debug("Payments", `Using DirectAddress for "${nametag}": ${info.directAddress.slice(0, 30)}...`);
|
|
7496
7650
|
return AddressFactory.createAddress(info.directAddress);
|
|
7497
7651
|
}
|
|
7498
|
-
|
|
7652
|
+
logger.debug("Payments", `Using PROXY address for legacy nametag "${nametag}"`);
|
|
7499
7653
|
return ProxyAddress.fromNameTag(nametag);
|
|
7500
7654
|
}
|
|
7501
7655
|
/**
|
|
@@ -7508,7 +7662,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7508
7662
|
const sourceTokenInput = typeof payload.sourceToken === "string" ? JSON.parse(payload.sourceToken) : payload.sourceToken;
|
|
7509
7663
|
const commitmentInput = typeof payload.commitmentData === "string" ? JSON.parse(payload.commitmentData) : payload.commitmentData;
|
|
7510
7664
|
if (!sourceTokenInput || !commitmentInput) {
|
|
7511
|
-
|
|
7665
|
+
logger.warn("Payments", "Invalid NOSTR-FIRST transfer format");
|
|
7512
7666
|
return;
|
|
7513
7667
|
}
|
|
7514
7668
|
const token = await this.saveCommitmentOnlyToken(
|
|
@@ -7539,7 +7693,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7539
7693
|
tokenId: nostrTokenId || token.id
|
|
7540
7694
|
});
|
|
7541
7695
|
} catch (error) {
|
|
7542
|
-
|
|
7696
|
+
logger.error("Payments", "Failed to process NOSTR-FIRST transfer:", error);
|
|
7543
7697
|
}
|
|
7544
7698
|
}
|
|
7545
7699
|
/**
|
|
@@ -7564,18 +7718,19 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7564
7718
|
const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
|
|
7565
7719
|
let proxyNametag = this.getNametag();
|
|
7566
7720
|
if (!proxyNametag?.token) {
|
|
7567
|
-
|
|
7721
|
+
logger.debug("Payments", "Nametag missing in memory, attempting reload from storage...");
|
|
7568
7722
|
await this.reloadNametagsFromStorage();
|
|
7569
7723
|
proxyNametag = this.getNametag();
|
|
7570
7724
|
}
|
|
7571
7725
|
if (!proxyNametag?.token) {
|
|
7572
|
-
throw new
|
|
7726
|
+
throw new SphereError("Cannot finalize PROXY transfer - no nametag token", "VALIDATION_ERROR");
|
|
7573
7727
|
}
|
|
7574
7728
|
const nametagToken = await import_Token6.Token.fromJSON(proxyNametag.token);
|
|
7575
7729
|
const proxy = await ProxyAddress.fromTokenId(nametagToken.id);
|
|
7576
7730
|
if (proxy.address !== recipientAddress.address) {
|
|
7577
|
-
throw new
|
|
7578
|
-
`PROXY address mismatch: nametag resolves to ${proxy.address} but transfer targets ${recipientAddress.address}
|
|
7731
|
+
throw new SphereError(
|
|
7732
|
+
`PROXY address mismatch: nametag resolves to ${proxy.address} but transfer targets ${recipientAddress.address}`,
|
|
7733
|
+
"VALIDATION_ERROR"
|
|
7579
7734
|
);
|
|
7580
7735
|
}
|
|
7581
7736
|
nametagTokens = [nametagToken];
|
|
@@ -7595,12 +7750,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7595
7750
|
try {
|
|
7596
7751
|
const token = this.tokens.get(tokenId);
|
|
7597
7752
|
if (!token) {
|
|
7598
|
-
|
|
7753
|
+
logger.debug("Payments", `Token ${tokenId} not found for finalization`);
|
|
7599
7754
|
return;
|
|
7600
7755
|
}
|
|
7601
7756
|
const commitment = await import_TransferCommitment4.TransferCommitment.fromJSON(commitmentInput);
|
|
7602
7757
|
if (!this.deps.oracle.waitForProofSdk) {
|
|
7603
|
-
|
|
7758
|
+
logger.debug("Payments", "Cannot finalize - no waitForProofSdk");
|
|
7604
7759
|
token.status = "confirmed";
|
|
7605
7760
|
token.updatedAt = Date.now();
|
|
7606
7761
|
await this.save();
|
|
@@ -7612,7 +7767,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7612
7767
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
7613
7768
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
7614
7769
|
if (!stClient || !trustBase) {
|
|
7615
|
-
|
|
7770
|
+
logger.debug("Payments", "Cannot finalize - missing state transition client or trust base");
|
|
7616
7771
|
token.status = "confirmed";
|
|
7617
7772
|
token.updatedAt = Date.now();
|
|
7618
7773
|
await this.save();
|
|
@@ -7632,7 +7787,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7632
7787
|
};
|
|
7633
7788
|
this.tokens.set(tokenId, finalizedToken);
|
|
7634
7789
|
await this.save();
|
|
7635
|
-
|
|
7790
|
+
logger.debug("Payments", `NOSTR-FIRST: Token ${tokenId.slice(0, 8)}... finalized and confirmed`);
|
|
7636
7791
|
this.deps.emitEvent("transfer:confirmed", {
|
|
7637
7792
|
id: crypto.randomUUID(),
|
|
7638
7793
|
status: "completed",
|
|
@@ -7640,7 +7795,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7640
7795
|
tokenTransfers: []
|
|
7641
7796
|
});
|
|
7642
7797
|
} catch (error) {
|
|
7643
|
-
|
|
7798
|
+
logger.error("Payments", "Failed to finalize received token:", error);
|
|
7644
7799
|
const token = this.tokens.get(tokenId);
|
|
7645
7800
|
if (token && token.status === "submitted") {
|
|
7646
7801
|
token.status = "confirmed";
|
|
@@ -7655,7 +7810,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7655
7810
|
}
|
|
7656
7811
|
try {
|
|
7657
7812
|
const payload = transfer.payload;
|
|
7658
|
-
|
|
7813
|
+
logger.debug("Payments", "handleIncomingTransfer: keys=", Object.keys(payload).join(","));
|
|
7659
7814
|
let combinedBundle = null;
|
|
7660
7815
|
if (isCombinedTransferBundleV6(payload)) {
|
|
7661
7816
|
combinedBundle = payload;
|
|
@@ -7669,12 +7824,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7669
7824
|
}
|
|
7670
7825
|
}
|
|
7671
7826
|
if (combinedBundle) {
|
|
7672
|
-
|
|
7827
|
+
logger.debug("Payments", "Processing COMBINED_TRANSFER V6 bundle...");
|
|
7673
7828
|
try {
|
|
7674
7829
|
await this.processCombinedTransferBundle(combinedBundle, transfer.senderTransportPubkey);
|
|
7675
|
-
|
|
7830
|
+
logger.debug("Payments", "COMBINED_TRANSFER V6 processed successfully");
|
|
7676
7831
|
} catch (err) {
|
|
7677
|
-
|
|
7832
|
+
logger.error("Payments", "COMBINED_TRANSFER V6 processing error:", err);
|
|
7678
7833
|
}
|
|
7679
7834
|
return;
|
|
7680
7835
|
}
|
|
@@ -7691,7 +7846,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7691
7846
|
}
|
|
7692
7847
|
}
|
|
7693
7848
|
if (instantBundle) {
|
|
7694
|
-
|
|
7849
|
+
logger.debug("Payments", "Processing INSTANT_SPLIT bundle...");
|
|
7695
7850
|
try {
|
|
7696
7851
|
const result = await this.processInstantSplitBundle(
|
|
7697
7852
|
instantBundle,
|
|
@@ -7699,28 +7854,28 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7699
7854
|
payload.memo
|
|
7700
7855
|
);
|
|
7701
7856
|
if (result.success) {
|
|
7702
|
-
|
|
7857
|
+
logger.debug("Payments", "INSTANT_SPLIT processed successfully");
|
|
7703
7858
|
} else {
|
|
7704
|
-
|
|
7859
|
+
logger.warn("Payments", "INSTANT_SPLIT processing failed:", result.error);
|
|
7705
7860
|
}
|
|
7706
7861
|
} catch (err) {
|
|
7707
|
-
|
|
7862
|
+
logger.error("Payments", "INSTANT_SPLIT processing error:", err);
|
|
7708
7863
|
}
|
|
7709
7864
|
return;
|
|
7710
7865
|
}
|
|
7711
7866
|
if (payload.sourceToken && payload.commitmentData && !payload.transferTx) {
|
|
7712
|
-
|
|
7867
|
+
logger.debug("Payments", "NOSTR-FIRST commitment-only transfer detected");
|
|
7713
7868
|
await this.handleCommitmentOnlyTransfer(transfer, payload);
|
|
7714
7869
|
return;
|
|
7715
7870
|
}
|
|
7716
7871
|
let tokenData;
|
|
7717
7872
|
let finalizedSdkToken = null;
|
|
7718
7873
|
if (payload.sourceToken && payload.transferTx) {
|
|
7719
|
-
|
|
7874
|
+
logger.debug("Payments", "Processing Sphere wallet format transfer...");
|
|
7720
7875
|
const sourceTokenInput = typeof payload.sourceToken === "string" ? JSON.parse(payload.sourceToken) : payload.sourceToken;
|
|
7721
7876
|
const transferTxInput = typeof payload.transferTx === "string" ? JSON.parse(payload.transferTx) : payload.transferTx;
|
|
7722
7877
|
if (!sourceTokenInput || !transferTxInput) {
|
|
7723
|
-
|
|
7878
|
+
logger.warn("Payments", "Invalid Sphere wallet transfer format");
|
|
7724
7879
|
return;
|
|
7725
7880
|
}
|
|
7726
7881
|
let sourceToken;
|
|
@@ -7728,7 +7883,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7728
7883
|
try {
|
|
7729
7884
|
sourceToken = await import_Token6.Token.fromJSON(sourceTokenInput);
|
|
7730
7885
|
} catch (err) {
|
|
7731
|
-
|
|
7886
|
+
logger.error("Payments", "Failed to parse sourceToken:", err);
|
|
7732
7887
|
return;
|
|
7733
7888
|
}
|
|
7734
7889
|
try {
|
|
@@ -7742,16 +7897,16 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7742
7897
|
const commitment = await import_TransferCommitment4.TransferCommitment.fromJSON(transferTxInput);
|
|
7743
7898
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
7744
7899
|
if (!stClient) {
|
|
7745
|
-
|
|
7900
|
+
logger.error("Payments", "Cannot process commitment - no state transition client");
|
|
7746
7901
|
return;
|
|
7747
7902
|
}
|
|
7748
7903
|
const response = await stClient.submitTransferCommitment(commitment);
|
|
7749
7904
|
if (response.status !== "SUCCESS" && response.status !== "REQUEST_ID_EXISTS") {
|
|
7750
|
-
|
|
7905
|
+
logger.error("Payments", "Transfer commitment submission failed:", response.status);
|
|
7751
7906
|
return;
|
|
7752
7907
|
}
|
|
7753
7908
|
if (!this.deps.oracle.waitForProofSdk) {
|
|
7754
|
-
|
|
7909
|
+
logger.error("Payments", "Cannot wait for proof - missing oracle method");
|
|
7755
7910
|
return;
|
|
7756
7911
|
}
|
|
7757
7912
|
const inclusionProof = await this.deps.oracle.waitForProofSdk(commitment);
|
|
@@ -7763,7 +7918,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7763
7918
|
const commitment = await import_TransferCommitment4.TransferCommitment.fromJSON(transferTxInput);
|
|
7764
7919
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
7765
7920
|
if (!stClient || !this.deps.oracle.waitForProofSdk) {
|
|
7766
|
-
throw new
|
|
7921
|
+
throw new SphereError("Cannot submit commitment - missing oracle methods", "AGGREGATOR_ERROR");
|
|
7767
7922
|
}
|
|
7768
7923
|
await stClient.submitTransferCommitment(commitment);
|
|
7769
7924
|
const inclusionProof = await this.deps.oracle.waitForProofSdk(commitment);
|
|
@@ -7771,33 +7926,33 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7771
7926
|
}
|
|
7772
7927
|
}
|
|
7773
7928
|
} catch (err) {
|
|
7774
|
-
|
|
7929
|
+
logger.error("Payments", "Failed to parse transferTx:", err);
|
|
7775
7930
|
return;
|
|
7776
7931
|
}
|
|
7777
7932
|
try {
|
|
7778
7933
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
7779
7934
|
const trustBase = this.deps.oracle.getTrustBase?.();
|
|
7780
7935
|
if (!stClient || !trustBase) {
|
|
7781
|
-
|
|
7936
|
+
logger.error("Payments", "Cannot finalize - missing state transition client or trust base. Token rejected.");
|
|
7782
7937
|
return;
|
|
7783
7938
|
}
|
|
7784
7939
|
finalizedSdkToken = await this.finalizeTransferToken(sourceToken, transferTx, stClient, trustBase);
|
|
7785
7940
|
tokenData = finalizedSdkToken.toJSON();
|
|
7786
7941
|
const addressScheme = transferTx.data.recipient.scheme;
|
|
7787
|
-
|
|
7942
|
+
logger.debug("Payments", `${addressScheme === import_AddressScheme.AddressScheme.PROXY ? "PROXY" : "DIRECT"} finalization successful`);
|
|
7788
7943
|
} catch (finalizeError) {
|
|
7789
|
-
|
|
7944
|
+
logger.error("Payments", "Finalization FAILED - token rejected:", finalizeError);
|
|
7790
7945
|
return;
|
|
7791
7946
|
}
|
|
7792
7947
|
} else if (payload.token) {
|
|
7793
7948
|
tokenData = payload.token;
|
|
7794
7949
|
} else {
|
|
7795
|
-
|
|
7950
|
+
logger.warn("Payments", "Unknown transfer payload format");
|
|
7796
7951
|
return;
|
|
7797
7952
|
}
|
|
7798
7953
|
const validation = await this.deps.oracle.validateToken(tokenData);
|
|
7799
7954
|
if (!validation.valid) {
|
|
7800
|
-
|
|
7955
|
+
logger.warn("Payments", "Received invalid token");
|
|
7801
7956
|
return;
|
|
7802
7957
|
}
|
|
7803
7958
|
const tokenInfo = await parseTokenInfo(tokenData);
|
|
@@ -7838,12 +7993,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7838
7993
|
receivedAt: transfer.timestamp
|
|
7839
7994
|
};
|
|
7840
7995
|
this.deps.emitEvent("transfer:incoming", incomingTransfer);
|
|
7841
|
-
|
|
7996
|
+
logger.debug("Payments", `Incoming transfer processed: ${token.id}, ${token.amount} ${token.symbol}`);
|
|
7842
7997
|
} else {
|
|
7843
|
-
|
|
7998
|
+
logger.debug("Payments", `Duplicate transfer ignored: ${token.id}, ${token.amount} ${token.symbol}`);
|
|
7844
7999
|
}
|
|
7845
8000
|
} catch (error) {
|
|
7846
|
-
|
|
8001
|
+
logger.error("Payments", "Failed to process incoming transfer:", error);
|
|
7847
8002
|
}
|
|
7848
8003
|
}
|
|
7849
8004
|
// ===========================================================================
|
|
@@ -7858,15 +8013,15 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7858
8013
|
if (existingArchive) {
|
|
7859
8014
|
if (isIncrementalUpdate(existingArchive, txf)) {
|
|
7860
8015
|
this.archivedTokens.set(tokenId, txf);
|
|
7861
|
-
|
|
8016
|
+
logger.debug("Payments", `Updated archived token ${tokenId.slice(0, 8)}...`);
|
|
7862
8017
|
} else {
|
|
7863
8018
|
const stateHash = getCurrentStateHash(txf) || "";
|
|
7864
8019
|
await this.storeForkedToken(tokenId, stateHash, txf);
|
|
7865
|
-
|
|
8020
|
+
logger.debug("Payments", `Archived token ${tokenId.slice(0, 8)}... is a fork`);
|
|
7866
8021
|
}
|
|
7867
8022
|
} else {
|
|
7868
8023
|
this.archivedTokens.set(tokenId, txf);
|
|
7869
|
-
|
|
8024
|
+
logger.debug("Payments", `Archived token ${tokenId.slice(0, 8)}...`);
|
|
7870
8025
|
}
|
|
7871
8026
|
}
|
|
7872
8027
|
// ===========================================================================
|
|
@@ -7878,20 +8033,20 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7878
8033
|
const txf = tokenToTxf(t);
|
|
7879
8034
|
return `${t.id.slice(0, 12)}(${t.status},txf=${!!txf})`;
|
|
7880
8035
|
});
|
|
7881
|
-
|
|
8036
|
+
logger.debug("Payments", `save(): providers=${providers.size}, tokens=[${tokenStats.join(", ")}]`);
|
|
7882
8037
|
if (providers.size > 0) {
|
|
7883
8038
|
const data = await this.createStorageData();
|
|
7884
8039
|
const dataKeys = Object.keys(data).filter((k) => k.startsWith("token-"));
|
|
7885
|
-
|
|
8040
|
+
logger.debug("Payments", `save(): TXF keys=${dataKeys.length} (${dataKeys.join(", ")})`);
|
|
7886
8041
|
for (const [id, provider] of providers) {
|
|
7887
8042
|
try {
|
|
7888
8043
|
await provider.save(data);
|
|
7889
8044
|
} catch (err) {
|
|
7890
|
-
|
|
8045
|
+
logger.error("Payments", `Failed to save to provider ${id}:`, err);
|
|
7891
8046
|
}
|
|
7892
8047
|
}
|
|
7893
8048
|
} else {
|
|
7894
|
-
|
|
8049
|
+
logger.debug("Payments", "save(): No token storage providers - TXF not persisted");
|
|
7895
8050
|
}
|
|
7896
8051
|
await this.savePendingV5Tokens();
|
|
7897
8052
|
}
|
|
@@ -7929,14 +8084,14 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7929
8084
|
}
|
|
7930
8085
|
loadFromStorageData(data) {
|
|
7931
8086
|
const parsed = parseTxfStorageData(data);
|
|
7932
|
-
|
|
8087
|
+
logger.debug("Payments", `loadFromStorageData: parsed ${parsed.tokens.length} tokens, ${parsed.tombstones.length} tombstones, errors=[${parsed.validationErrors.join("; ")}]`);
|
|
7933
8088
|
this.tombstones = parsed.tombstones;
|
|
7934
8089
|
this.tokens.clear();
|
|
7935
8090
|
for (const token of parsed.tokens) {
|
|
7936
8091
|
const sdkTokenId = extractTokenIdFromSdkData(token.sdkData);
|
|
7937
8092
|
const stateHash = extractStateHashFromSdkData(token.sdkData);
|
|
7938
8093
|
if (sdkTokenId && stateHash && this.isStateTombstoned(sdkTokenId, stateHash)) {
|
|
7939
|
-
|
|
8094
|
+
logger.debug("Payments", `Skipping tombstoned token ${sdkTokenId.slice(0, 8)}... during load (exact state match)`);
|
|
7940
8095
|
continue;
|
|
7941
8096
|
}
|
|
7942
8097
|
this.tokens.set(token.id, token);
|
|
@@ -7956,12 +8111,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7956
8111
|
try {
|
|
7957
8112
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
7958
8113
|
if (!stClient) {
|
|
7959
|
-
|
|
8114
|
+
logger.debug("Payments", "Cannot submit commitment - no state transition client");
|
|
7960
8115
|
return;
|
|
7961
8116
|
}
|
|
7962
8117
|
const response = await stClient.submitTransferCommitment(commitment);
|
|
7963
8118
|
if (response.status !== "SUCCESS" && response.status !== "REQUEST_ID_EXISTS") {
|
|
7964
|
-
|
|
8119
|
+
logger.debug("Payments", `Transfer commitment submission failed: ${response.status}`);
|
|
7965
8120
|
const token = this.tokens.get(tokenId);
|
|
7966
8121
|
if (token) {
|
|
7967
8122
|
token.status = "invalid";
|
|
@@ -7981,7 +8136,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7981
8136
|
onProofReceived
|
|
7982
8137
|
});
|
|
7983
8138
|
} catch (error) {
|
|
7984
|
-
|
|
8139
|
+
logger.debug("Payments", "submitAndPollForProof error:", error);
|
|
7985
8140
|
}
|
|
7986
8141
|
}
|
|
7987
8142
|
/**
|
|
@@ -7989,7 +8144,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7989
8144
|
*/
|
|
7990
8145
|
addProofPollingJob(job) {
|
|
7991
8146
|
this.proofPollingJobs.set(job.tokenId, job);
|
|
7992
|
-
|
|
8147
|
+
logger.debug("Payments", `Added proof polling job for token ${job.tokenId.slice(0, 8)}...`);
|
|
7993
8148
|
this.startProofPolling();
|
|
7994
8149
|
}
|
|
7995
8150
|
/**
|
|
@@ -7998,7 +8153,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7998
8153
|
startProofPolling() {
|
|
7999
8154
|
if (this.proofPollingInterval) return;
|
|
8000
8155
|
if (this.proofPollingJobs.size === 0) return;
|
|
8001
|
-
|
|
8156
|
+
logger.debug("Payments", "Starting proof polling...");
|
|
8002
8157
|
this.proofPollingInterval = setInterval(
|
|
8003
8158
|
() => this.processProofPollingQueue(),
|
|
8004
8159
|
_PaymentsModule.PROOF_POLLING_INTERVAL_MS
|
|
@@ -8011,7 +8166,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
8011
8166
|
if (this.proofPollingInterval) {
|
|
8012
8167
|
clearInterval(this.proofPollingInterval);
|
|
8013
8168
|
this.proofPollingInterval = null;
|
|
8014
|
-
|
|
8169
|
+
logger.debug("Payments", "Stopped proof polling");
|
|
8015
8170
|
}
|
|
8016
8171
|
}
|
|
8017
8172
|
/**
|
|
@@ -8028,7 +8183,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
8028
8183
|
job.attemptCount++;
|
|
8029
8184
|
job.lastAttemptAt = Date.now();
|
|
8030
8185
|
if (job.attemptCount >= _PaymentsModule.PROOF_POLLING_MAX_ATTEMPTS) {
|
|
8031
|
-
|
|
8186
|
+
logger.debug("Payments", `Proof polling timeout for token ${tokenId.slice(0, 8)}...`);
|
|
8032
8187
|
const token2 = this.tokens.get(tokenId);
|
|
8033
8188
|
if (token2 && token2.status === "submitted") {
|
|
8034
8189
|
token2.status = "invalid";
|
|
@@ -8067,12 +8222,12 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
8067
8222
|
token.updatedAt = Date.now();
|
|
8068
8223
|
this.tokens.set(tokenId, token);
|
|
8069
8224
|
await this.save();
|
|
8070
|
-
|
|
8225
|
+
logger.debug("Payments", `Proof received for token ${tokenId.slice(0, 8)}..., status: spent`);
|
|
8071
8226
|
}
|
|
8072
8227
|
job.onProofReceived?.(tokenId);
|
|
8073
8228
|
completedJobs.push(tokenId);
|
|
8074
8229
|
} catch (error) {
|
|
8075
|
-
|
|
8230
|
+
logger.debug("Payments", `Proof polling attempt ${job.attemptCount} for ${tokenId.slice(0, 8)}...: ${error}`);
|
|
8076
8231
|
}
|
|
8077
8232
|
}
|
|
8078
8233
|
for (const tokenId of completedJobs) {
|
|
@@ -8087,7 +8242,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
8087
8242
|
// ===========================================================================
|
|
8088
8243
|
ensureInitialized() {
|
|
8089
8244
|
if (!this.deps) {
|
|
8090
|
-
throw new
|
|
8245
|
+
throw new SphereError("PaymentsModule not initialized", "NOT_INITIALIZED");
|
|
8091
8246
|
}
|
|
8092
8247
|
}
|
|
8093
8248
|
};
|
|
@@ -8095,7 +8250,12 @@ function createPaymentsModule(config) {
|
|
|
8095
8250
|
return new PaymentsModule(config);
|
|
8096
8251
|
}
|
|
8097
8252
|
|
|
8253
|
+
// modules/payments/BackgroundCommitmentService.ts
|
|
8254
|
+
init_logger();
|
|
8255
|
+
init_errors();
|
|
8256
|
+
|
|
8098
8257
|
// modules/payments/TokenRecoveryService.ts
|
|
8258
|
+
init_logger();
|
|
8099
8259
|
var import_TokenId4 = require("@unicitylabs/state-transition-sdk/lib/token/TokenId");
|
|
8100
8260
|
var import_TokenState6 = require("@unicitylabs/state-transition-sdk/lib/token/TokenState");
|
|
8101
8261
|
var import_TokenType4 = require("@unicitylabs/state-transition-sdk/lib/token/TokenType");
|
|
@@ -8104,6 +8264,8 @@ var import_HashAlgorithm6 = require("@unicitylabs/state-transition-sdk/lib/hash/
|
|
|
8104
8264
|
var import_UnmaskedPredicate6 = require("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate");
|
|
8105
8265
|
|
|
8106
8266
|
// modules/communications/CommunicationsModule.ts
|
|
8267
|
+
init_logger();
|
|
8268
|
+
init_errors();
|
|
8107
8269
|
init_constants();
|
|
8108
8270
|
var CommunicationsModule = class {
|
|
8109
8271
|
config;
|
|
@@ -8198,7 +8360,7 @@ var CommunicationsModule = class {
|
|
|
8198
8360
|
}
|
|
8199
8361
|
if (myMessages.length > 0) {
|
|
8200
8362
|
await this.save();
|
|
8201
|
-
|
|
8363
|
+
logger.debug("Communications", `Migrated ${myMessages.length} messages to per-address storage`);
|
|
8202
8364
|
}
|
|
8203
8365
|
}
|
|
8204
8366
|
}
|
|
@@ -8284,7 +8446,7 @@ var CommunicationsModule = class {
|
|
|
8284
8446
|
const msg = this.messages.get(id);
|
|
8285
8447
|
if (msg && msg.senderPubkey !== this.deps.identity.chainPubkey) {
|
|
8286
8448
|
this.deps.transport.sendReadReceipt(msg.senderPubkey, id).catch((err) => {
|
|
8287
|
-
|
|
8449
|
+
logger.warn("Communications", "Failed to send read receipt:", err);
|
|
8288
8450
|
});
|
|
8289
8451
|
}
|
|
8290
8452
|
}
|
|
@@ -8484,7 +8646,7 @@ var CommunicationsModule = class {
|
|
|
8484
8646
|
try {
|
|
8485
8647
|
handler(message);
|
|
8486
8648
|
} catch (error) {
|
|
8487
|
-
|
|
8649
|
+
logger.error("Communications", "Handler error:", error);
|
|
8488
8650
|
}
|
|
8489
8651
|
}
|
|
8490
8652
|
if (this.config.autoSave) {
|
|
@@ -8503,7 +8665,7 @@ var CommunicationsModule = class {
|
|
|
8503
8665
|
try {
|
|
8504
8666
|
handler(composing);
|
|
8505
8667
|
} catch (error) {
|
|
8506
|
-
|
|
8668
|
+
logger.error("Communications", "Composing handler error:", error);
|
|
8507
8669
|
}
|
|
8508
8670
|
}
|
|
8509
8671
|
}
|
|
@@ -8521,7 +8683,7 @@ var CommunicationsModule = class {
|
|
|
8521
8683
|
try {
|
|
8522
8684
|
handler(message);
|
|
8523
8685
|
} catch (error) {
|
|
8524
|
-
|
|
8686
|
+
logger.error("Communications", "Handler error:", error);
|
|
8525
8687
|
}
|
|
8526
8688
|
}
|
|
8527
8689
|
}
|
|
@@ -8562,7 +8724,7 @@ var CommunicationsModule = class {
|
|
|
8562
8724
|
const nametag = recipient.slice(1);
|
|
8563
8725
|
const pubkey = await this.deps.transport.resolveNametag?.(nametag);
|
|
8564
8726
|
if (!pubkey) {
|
|
8565
|
-
throw new
|
|
8727
|
+
throw new SphereError(`Nametag not found: ${recipient}`, "INVALID_RECIPIENT");
|
|
8566
8728
|
}
|
|
8567
8729
|
return { pubkey, nametag };
|
|
8568
8730
|
}
|
|
@@ -8570,7 +8732,7 @@ var CommunicationsModule = class {
|
|
|
8570
8732
|
}
|
|
8571
8733
|
ensureInitialized() {
|
|
8572
8734
|
if (!this.deps) {
|
|
8573
|
-
throw new
|
|
8735
|
+
throw new SphereError("CommunicationsModule not initialized", "NOT_INITIALIZED");
|
|
8574
8736
|
}
|
|
8575
8737
|
}
|
|
8576
8738
|
};
|
|
@@ -8580,6 +8742,8 @@ function createCommunicationsModule(config) {
|
|
|
8580
8742
|
|
|
8581
8743
|
// modules/groupchat/GroupChatModule.ts
|
|
8582
8744
|
var import_nostr_js_sdk2 = require("@unicitylabs/nostr-js-sdk");
|
|
8745
|
+
init_logger();
|
|
8746
|
+
init_errors();
|
|
8583
8747
|
init_constants();
|
|
8584
8748
|
|
|
8585
8749
|
// modules/groupchat/types.ts
|
|
@@ -8725,13 +8889,15 @@ var GroupChatModule = class {
|
|
|
8725
8889
|
for (const subId of this.subscriptionIds) {
|
|
8726
8890
|
try {
|
|
8727
8891
|
this.client.unsubscribe(subId);
|
|
8728
|
-
} catch {
|
|
8892
|
+
} catch (err) {
|
|
8893
|
+
logger.debug("GroupChat", "Failed to unsubscribe", err);
|
|
8729
8894
|
}
|
|
8730
8895
|
}
|
|
8731
8896
|
this.subscriptionIds = [];
|
|
8732
8897
|
try {
|
|
8733
8898
|
this.client.disconnect();
|
|
8734
|
-
} catch {
|
|
8899
|
+
} catch (err) {
|
|
8900
|
+
logger.debug("GroupChat", "Failed to disconnect", err);
|
|
8735
8901
|
}
|
|
8736
8902
|
this.client = null;
|
|
8737
8903
|
}
|
|
@@ -8771,7 +8937,8 @@ var GroupChatModule = class {
|
|
|
8771
8937
|
for (const subId of this.subscriptionIds) {
|
|
8772
8938
|
try {
|
|
8773
8939
|
this.client.unsubscribe(subId);
|
|
8774
|
-
} catch {
|
|
8940
|
+
} catch (err) {
|
|
8941
|
+
logger.debug("GroupChat", "Failed to unsubscribe", err);
|
|
8775
8942
|
}
|
|
8776
8943
|
}
|
|
8777
8944
|
this.subscriptionIds = [];
|
|
@@ -8806,21 +8973,21 @@ var GroupChatModule = class {
|
|
|
8806
8973
|
}
|
|
8807
8974
|
this.deps.emitEvent("groupchat:connection", { connected: true });
|
|
8808
8975
|
} catch (error) {
|
|
8809
|
-
|
|
8976
|
+
logger.error("GroupChat", "Failed to connect to relays", error);
|
|
8810
8977
|
this.deps.emitEvent("groupchat:connection", { connected: false });
|
|
8811
8978
|
this.scheduleReconnect();
|
|
8812
8979
|
}
|
|
8813
8980
|
}
|
|
8814
8981
|
scheduleReconnect() {
|
|
8815
8982
|
if (this.reconnectAttempts >= this.config.maxReconnectAttempts) {
|
|
8816
|
-
|
|
8983
|
+
logger.error("GroupChat", "Max reconnection attempts reached");
|
|
8817
8984
|
return;
|
|
8818
8985
|
}
|
|
8819
8986
|
this.reconnectAttempts++;
|
|
8820
8987
|
this.reconnectTimer = setTimeout(() => {
|
|
8821
8988
|
this.reconnectTimer = null;
|
|
8822
8989
|
if (this.deps) {
|
|
8823
|
-
this.connect().catch(
|
|
8990
|
+
this.connect().catch((err) => logger.error("GroupChat", "Reconnect failed:", err));
|
|
8824
8991
|
}
|
|
8825
8992
|
}, this.config.reconnectDelayMs);
|
|
8826
8993
|
}
|
|
@@ -9055,7 +9222,8 @@ var GroupChatModule = class {
|
|
|
9055
9222
|
},
|
|
9056
9223
|
onComplete: () => {
|
|
9057
9224
|
},
|
|
9058
|
-
timeoutMs: 15e3
|
|
9225
|
+
timeoutMs: 15e3,
|
|
9226
|
+
timeoutLabel: "restoreJoinedGroups"
|
|
9059
9227
|
}
|
|
9060
9228
|
);
|
|
9061
9229
|
if (groupIdsWithMembership.size === 0) return [];
|
|
@@ -9072,7 +9240,8 @@ var GroupChatModule = class {
|
|
|
9072
9240
|
this.fetchMessages(groupId)
|
|
9073
9241
|
]);
|
|
9074
9242
|
}
|
|
9075
|
-
} catch {
|
|
9243
|
+
} catch (error) {
|
|
9244
|
+
logger.warn("GroupChat", "Failed to restore group", groupId, error);
|
|
9076
9245
|
}
|
|
9077
9246
|
}
|
|
9078
9247
|
if (restoredGroups.length > 0) {
|
|
@@ -9105,7 +9274,8 @@ var GroupChatModule = class {
|
|
|
9105
9274
|
},
|
|
9106
9275
|
onComplete: () => {
|
|
9107
9276
|
},
|
|
9108
|
-
timeoutMs: 1e4
|
|
9277
|
+
timeoutMs: 1e4,
|
|
9278
|
+
timeoutLabel: "fetchAvailableGroups(metadata)"
|
|
9109
9279
|
}
|
|
9110
9280
|
),
|
|
9111
9281
|
this.oneshotSubscription(
|
|
@@ -9120,7 +9290,8 @@ var GroupChatModule = class {
|
|
|
9120
9290
|
},
|
|
9121
9291
|
onComplete: () => {
|
|
9122
9292
|
},
|
|
9123
|
-
timeoutMs: 1e4
|
|
9293
|
+
timeoutMs: 1e4,
|
|
9294
|
+
timeoutLabel: "fetchAvailableGroups(members)"
|
|
9124
9295
|
}
|
|
9125
9296
|
)
|
|
9126
9297
|
]);
|
|
@@ -9179,7 +9350,7 @@ var GroupChatModule = class {
|
|
|
9179
9350
|
return true;
|
|
9180
9351
|
}
|
|
9181
9352
|
}
|
|
9182
|
-
|
|
9353
|
+
logger.error("GroupChat", "Failed to join group", error);
|
|
9183
9354
|
return false;
|
|
9184
9355
|
}
|
|
9185
9356
|
}
|
|
@@ -9209,7 +9380,7 @@ var GroupChatModule = class {
|
|
|
9209
9380
|
this.persistAll();
|
|
9210
9381
|
return true;
|
|
9211
9382
|
}
|
|
9212
|
-
|
|
9383
|
+
logger.error("GroupChat", "Failed to leave group", error);
|
|
9213
9384
|
return false;
|
|
9214
9385
|
}
|
|
9215
9386
|
}
|
|
@@ -9260,10 +9431,8 @@ var GroupChatModule = class {
|
|
|
9260
9431
|
kind: NIP29_KINDS.JOIN_REQUEST,
|
|
9261
9432
|
tags: [["h", group.id]],
|
|
9262
9433
|
content: ""
|
|
9263
|
-
}).catch(() =>
|
|
9264
|
-
|
|
9265
|
-
await this.fetchAndSaveMembers(group.id).catch(() => {
|
|
9266
|
-
});
|
|
9434
|
+
}).catch((err) => logger.debug("GroupChat", "Background operation failed", err));
|
|
9435
|
+
await this.fetchAndSaveMembers(group.id).catch((err) => logger.debug("GroupChat", "Failed to fetch members", group.id, err));
|
|
9267
9436
|
this.saveMemberToMemory({
|
|
9268
9437
|
pubkey: creatorPubkey,
|
|
9269
9438
|
groupId: group.id,
|
|
@@ -9275,7 +9444,7 @@ var GroupChatModule = class {
|
|
|
9275
9444
|
this.schedulePersist();
|
|
9276
9445
|
return group;
|
|
9277
9446
|
} catch (error) {
|
|
9278
|
-
|
|
9447
|
+
logger.error("GroupChat", "Failed to create group", error);
|
|
9279
9448
|
return null;
|
|
9280
9449
|
}
|
|
9281
9450
|
}
|
|
@@ -9302,7 +9471,7 @@ var GroupChatModule = class {
|
|
|
9302
9471
|
}
|
|
9303
9472
|
return false;
|
|
9304
9473
|
} catch (error) {
|
|
9305
|
-
|
|
9474
|
+
logger.error("GroupChat", "Failed to delete group", error);
|
|
9306
9475
|
return false;
|
|
9307
9476
|
}
|
|
9308
9477
|
}
|
|
@@ -9322,7 +9491,7 @@ var GroupChatModule = class {
|
|
|
9322
9491
|
});
|
|
9323
9492
|
return eventId ? inviteCode : null;
|
|
9324
9493
|
} catch (error) {
|
|
9325
|
-
|
|
9494
|
+
logger.error("GroupChat", "Failed to create invite", error);
|
|
9326
9495
|
return null;
|
|
9327
9496
|
}
|
|
9328
9497
|
}
|
|
@@ -9372,7 +9541,7 @@ var GroupChatModule = class {
|
|
|
9372
9541
|
}
|
|
9373
9542
|
return null;
|
|
9374
9543
|
} catch (error) {
|
|
9375
|
-
|
|
9544
|
+
logger.error("GroupChat", "Failed to send message", error);
|
|
9376
9545
|
return null;
|
|
9377
9546
|
}
|
|
9378
9547
|
}
|
|
@@ -9411,7 +9580,8 @@ var GroupChatModule = class {
|
|
|
9411
9580
|
this.schedulePersist();
|
|
9412
9581
|
return fetchedMessages;
|
|
9413
9582
|
},
|
|
9414
|
-
timeoutMs: 1e4
|
|
9583
|
+
timeoutMs: 1e4,
|
|
9584
|
+
timeoutLabel: `fetchMessages(${groupId})`
|
|
9415
9585
|
});
|
|
9416
9586
|
}
|
|
9417
9587
|
// ===========================================================================
|
|
@@ -9472,7 +9642,7 @@ var GroupChatModule = class {
|
|
|
9472
9642
|
}
|
|
9473
9643
|
return false;
|
|
9474
9644
|
} catch (error) {
|
|
9475
|
-
|
|
9645
|
+
logger.error("GroupChat", "Failed to kick user", error);
|
|
9476
9646
|
return false;
|
|
9477
9647
|
}
|
|
9478
9648
|
}
|
|
@@ -9495,7 +9665,7 @@ var GroupChatModule = class {
|
|
|
9495
9665
|
}
|
|
9496
9666
|
return false;
|
|
9497
9667
|
} catch (error) {
|
|
9498
|
-
|
|
9668
|
+
logger.error("GroupChat", "Failed to delete message", error);
|
|
9499
9669
|
return false;
|
|
9500
9670
|
}
|
|
9501
9671
|
}
|
|
@@ -9780,7 +9950,7 @@ var GroupChatModule = class {
|
|
|
9780
9950
|
this.persistTimer = setTimeout(() => {
|
|
9781
9951
|
this.persistTimer = null;
|
|
9782
9952
|
this.persistPromise = this.doPersistAll().catch((err) => {
|
|
9783
|
-
|
|
9953
|
+
logger.error("GroupChat", "Persistence error:", err);
|
|
9784
9954
|
}).finally(() => {
|
|
9785
9955
|
this.persistPromise = null;
|
|
9786
9956
|
});
|
|
@@ -9960,7 +10130,8 @@ var GroupChatModule = class {
|
|
|
9960
10130
|
if (state.subId) {
|
|
9961
10131
|
try {
|
|
9962
10132
|
this.client.unsubscribe(state.subId);
|
|
9963
|
-
} catch {
|
|
10133
|
+
} catch (err) {
|
|
10134
|
+
logger.debug("GroupChat", "Failed to unsubscribe", err);
|
|
9964
10135
|
}
|
|
9965
10136
|
const idx = this.subscriptionIds.indexOf(state.subId);
|
|
9966
10137
|
if (idx >= 0) this.subscriptionIds.splice(idx, 1);
|
|
@@ -9975,12 +10146,17 @@ var GroupChatModule = class {
|
|
|
9975
10146
|
});
|
|
9976
10147
|
state.subId = subId;
|
|
9977
10148
|
this.subscriptionIds.push(subId);
|
|
9978
|
-
setTimeout(
|
|
10149
|
+
setTimeout(() => {
|
|
10150
|
+
if (!done && opts.timeoutLabel) {
|
|
10151
|
+
logger.warn("GroupChat", `${opts.timeoutLabel} timed out`);
|
|
10152
|
+
}
|
|
10153
|
+
finish();
|
|
10154
|
+
}, opts.timeoutMs ?? 5e3);
|
|
9979
10155
|
});
|
|
9980
10156
|
}
|
|
9981
10157
|
ensureInitialized() {
|
|
9982
10158
|
if (!this.deps) {
|
|
9983
|
-
throw new
|
|
10159
|
+
throw new SphereError("GroupChatModule not initialized", "NOT_INITIALIZED");
|
|
9984
10160
|
}
|
|
9985
10161
|
}
|
|
9986
10162
|
async ensureConnected() {
|
|
@@ -12149,6 +12325,7 @@ var Pointk1 = /* @__PURE__ */ weierstrass(secp256k1_CURVE, {
|
|
|
12149
12325
|
var secp256k1 = /* @__PURE__ */ ecdsa(Pointk1, sha2564);
|
|
12150
12326
|
|
|
12151
12327
|
// modules/market/MarketModule.ts
|
|
12328
|
+
init_errors();
|
|
12152
12329
|
var DEFAULT_MARKET_API_URL = "https://market-api.unicity.network";
|
|
12153
12330
|
function hexToBytes3(hex) {
|
|
12154
12331
|
const len = hex.length >> 1;
|
|
@@ -12338,7 +12515,7 @@ var MarketModule = class {
|
|
|
12338
12515
|
// ---------------------------------------------------------------------------
|
|
12339
12516
|
ensureIdentity() {
|
|
12340
12517
|
if (!this.identity) {
|
|
12341
|
-
throw new
|
|
12518
|
+
throw new SphereError("MarketModule not initialized \u2014 call initialize() first", "NOT_INITIALIZED");
|
|
12342
12519
|
}
|
|
12343
12520
|
}
|
|
12344
12521
|
/** Register the agent's public key with the server (idempotent) */
|
|
@@ -12364,7 +12541,7 @@ var MarketModule = class {
|
|
|
12364
12541
|
data = JSON.parse(text);
|
|
12365
12542
|
} catch {
|
|
12366
12543
|
}
|
|
12367
|
-
throw new
|
|
12544
|
+
throw new SphereError(data?.error ?? `Agent registration failed: HTTP ${res.status}`, "NETWORK_ERROR");
|
|
12368
12545
|
}
|
|
12369
12546
|
async parseResponse(res) {
|
|
12370
12547
|
const text = await res.text();
|
|
@@ -12372,9 +12549,9 @@ var MarketModule = class {
|
|
|
12372
12549
|
try {
|
|
12373
12550
|
data = JSON.parse(text);
|
|
12374
12551
|
} catch {
|
|
12375
|
-
throw new
|
|
12552
|
+
throw new SphereError(`Market API error: HTTP ${res.status} \u2014 unexpected response (not JSON)`, "NETWORK_ERROR");
|
|
12376
12553
|
}
|
|
12377
|
-
if (!res.ok) throw new
|
|
12554
|
+
if (!res.ok) throw new SphereError(data.error ?? `HTTP ${res.status}`, "NETWORK_ERROR");
|
|
12378
12555
|
return data;
|
|
12379
12556
|
}
|
|
12380
12557
|
async apiPost(path, body) {
|
|
@@ -12430,6 +12607,8 @@ init_constants();
|
|
|
12430
12607
|
|
|
12431
12608
|
// core/encryption.ts
|
|
12432
12609
|
var import_crypto_js6 = __toESM(require("crypto-js"), 1);
|
|
12610
|
+
init_errors();
|
|
12611
|
+
init_logger();
|
|
12433
12612
|
var DEFAULT_ITERATIONS = 1e5;
|
|
12434
12613
|
var KEY_SIZE = 256;
|
|
12435
12614
|
var SALT_SIZE = 16;
|
|
@@ -12477,7 +12656,7 @@ function decrypt2(encryptedData, password) {
|
|
|
12477
12656
|
});
|
|
12478
12657
|
const result = decrypted.toString(import_crypto_js6.default.enc.Utf8);
|
|
12479
12658
|
if (!result) {
|
|
12480
|
-
throw new
|
|
12659
|
+
throw new SphereError("Decryption failed: invalid password or corrupted data", "DECRYPTION_ERROR");
|
|
12481
12660
|
}
|
|
12482
12661
|
return result;
|
|
12483
12662
|
}
|
|
@@ -12486,7 +12665,7 @@ function decryptJson(encryptedData, password) {
|
|
|
12486
12665
|
try {
|
|
12487
12666
|
return JSON.parse(decrypted);
|
|
12488
12667
|
} catch {
|
|
12489
|
-
throw new
|
|
12668
|
+
throw new SphereError("Decryption failed: invalid JSON data", "DECRYPTION_ERROR");
|
|
12490
12669
|
}
|
|
12491
12670
|
}
|
|
12492
12671
|
function encryptSimple(plaintext, password) {
|
|
@@ -12496,7 +12675,7 @@ function decryptSimple(ciphertext, password) {
|
|
|
12496
12675
|
const decrypted = import_crypto_js6.default.AES.decrypt(ciphertext, password);
|
|
12497
12676
|
const result = decrypted.toString(import_crypto_js6.default.enc.Utf8);
|
|
12498
12677
|
if (!result) {
|
|
12499
|
-
throw new
|
|
12678
|
+
throw new SphereError("Decryption failed: invalid password or corrupted data", "DECRYPTION_ERROR");
|
|
12500
12679
|
}
|
|
12501
12680
|
return result;
|
|
12502
12681
|
}
|
|
@@ -12510,7 +12689,8 @@ function decryptWithSalt(ciphertext, password, salt) {
|
|
|
12510
12689
|
const decrypted = import_crypto_js6.default.AES.decrypt(ciphertext, key);
|
|
12511
12690
|
const result = decrypted.toString(import_crypto_js6.default.enc.Utf8);
|
|
12512
12691
|
return result || null;
|
|
12513
|
-
} catch {
|
|
12692
|
+
} catch (err) {
|
|
12693
|
+
logger.debug("Encryption", "decryptWithSalt failed", err);
|
|
12514
12694
|
return null;
|
|
12515
12695
|
}
|
|
12516
12696
|
}
|
|
@@ -12533,7 +12713,7 @@ function serializeEncrypted(data) {
|
|
|
12533
12713
|
function deserializeEncrypted(serialized) {
|
|
12534
12714
|
const parsed = JSON.parse(serialized);
|
|
12535
12715
|
if (!isEncryptedData(parsed)) {
|
|
12536
|
-
throw new
|
|
12716
|
+
throw new SphereError("Invalid encrypted data format", "VALIDATION_ERROR");
|
|
12537
12717
|
}
|
|
12538
12718
|
return parsed;
|
|
12539
12719
|
}
|
|
@@ -12542,6 +12722,7 @@ function generateRandomKey(bytes = 32) {
|
|
|
12542
12722
|
}
|
|
12543
12723
|
|
|
12544
12724
|
// core/scan.ts
|
|
12725
|
+
init_logger();
|
|
12545
12726
|
async function scanAddressesImpl(deriveAddress, options = {}) {
|
|
12546
12727
|
const maxAddresses = options.maxAddresses ?? 50;
|
|
12547
12728
|
const gapLimit = options.gapLimit ?? 20;
|
|
@@ -12580,7 +12761,8 @@ async function scanAddressesImpl(deriveAddress, options = {}) {
|
|
|
12580
12761
|
nametag = tag;
|
|
12581
12762
|
nametagsFoundCount++;
|
|
12582
12763
|
}
|
|
12583
|
-
} catch {
|
|
12764
|
+
} catch (err) {
|
|
12765
|
+
logger.debug("Sphere", "Nametag resolution failed during scan", err);
|
|
12584
12766
|
}
|
|
12585
12767
|
}
|
|
12586
12768
|
foundAddresses.push({
|
|
@@ -12597,7 +12779,7 @@ async function scanAddressesImpl(deriveAddress, options = {}) {
|
|
|
12597
12779
|
consecutiveEmpty++;
|
|
12598
12780
|
}
|
|
12599
12781
|
} catch (err) {
|
|
12600
|
-
|
|
12782
|
+
logger.warn("Sphere", `scanAddresses: Error checking ${addrInfo.address}:`, err);
|
|
12601
12783
|
consecutiveEmpty++;
|
|
12602
12784
|
}
|
|
12603
12785
|
if (consecutiveEmpty >= gapLimit) {
|
|
@@ -12689,6 +12871,7 @@ init_network();
|
|
|
12689
12871
|
var import_crypto_js7 = __toESM(require("crypto-js"), 1);
|
|
12690
12872
|
|
|
12691
12873
|
// core/utils.ts
|
|
12874
|
+
init_errors();
|
|
12692
12875
|
var SECP256K1_ORDER = BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
|
|
12693
12876
|
var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
12694
12877
|
function isValidPrivateKey(hex) {
|
|
@@ -12728,7 +12911,7 @@ function base58Decode(str) {
|
|
|
12728
12911
|
for (let i = 0; i < str.length; i++) {
|
|
12729
12912
|
const char = str[i];
|
|
12730
12913
|
if (!(char in ALPHABET_MAP)) {
|
|
12731
|
-
throw new
|
|
12914
|
+
throw new SphereError("Invalid base58 character: " + char, "VALIDATION_ERROR");
|
|
12732
12915
|
}
|
|
12733
12916
|
num = num * BigInt(58) + BigInt(ALPHABET_MAP[char]);
|
|
12734
12917
|
}
|
|
@@ -13011,6 +13194,7 @@ function parseAndDecryptWalletText(content, password) {
|
|
|
13011
13194
|
|
|
13012
13195
|
// serialization/wallet-dat.ts
|
|
13013
13196
|
var import_crypto_js8 = __toESM(require("crypto-js"), 1);
|
|
13197
|
+
init_errors();
|
|
13014
13198
|
function uint8ArrayToWordArray(u8arr) {
|
|
13015
13199
|
const hex = bytesToHex2(u8arr);
|
|
13016
13200
|
return import_crypto_js8.default.enc.Hex.parse(hex);
|
|
@@ -13195,7 +13379,7 @@ async function decryptCMasterKey(cmk, password, onProgress) {
|
|
|
13195
13379
|
);
|
|
13196
13380
|
const result = import_crypto_js8.default.enc.Hex.stringify(decrypted);
|
|
13197
13381
|
if (!result || result.length !== 64) {
|
|
13198
|
-
throw new
|
|
13382
|
+
throw new SphereError("Master key decryption failed - incorrect password", "DECRYPTION_ERROR");
|
|
13199
13383
|
}
|
|
13200
13384
|
return result;
|
|
13201
13385
|
}
|
|
@@ -13490,6 +13674,7 @@ var Sphere = class _Sphere {
|
|
|
13490
13674
|
* ```
|
|
13491
13675
|
*/
|
|
13492
13676
|
static async init(options) {
|
|
13677
|
+
if (options.debug) logger.configure({ debug: true });
|
|
13493
13678
|
_Sphere.configureTokenRegistry(options.storage, options.network);
|
|
13494
13679
|
const groupChat = _Sphere.resolveGroupChatConfig(options.groupChat, options.network);
|
|
13495
13680
|
const market = _Sphere.resolveMarketConfig(options.market);
|
|
@@ -13517,8 +13702,9 @@ var Sphere = class _Sphere {
|
|
|
13517
13702
|
mnemonic = _Sphere.generateMnemonic();
|
|
13518
13703
|
generatedMnemonic = mnemonic;
|
|
13519
13704
|
} else {
|
|
13520
|
-
throw new
|
|
13521
|
-
"No wallet exists and no mnemonic provided. Provide a mnemonic or set autoGenerate: true."
|
|
13705
|
+
throw new SphereError(
|
|
13706
|
+
"No wallet exists and no mnemonic provided. Provide a mnemonic or set autoGenerate: true.",
|
|
13707
|
+
"INVALID_CONFIG"
|
|
13522
13708
|
);
|
|
13523
13709
|
}
|
|
13524
13710
|
}
|
|
@@ -13591,11 +13777,12 @@ var Sphere = class _Sphere {
|
|
|
13591
13777
|
* Create new wallet with mnemonic
|
|
13592
13778
|
*/
|
|
13593
13779
|
static async create(options) {
|
|
13780
|
+
if (options.debug) logger.configure({ debug: true });
|
|
13594
13781
|
if (!options.mnemonic || !_Sphere.validateMnemonic(options.mnemonic)) {
|
|
13595
|
-
throw new
|
|
13782
|
+
throw new SphereError("Invalid mnemonic", "INVALID_IDENTITY");
|
|
13596
13783
|
}
|
|
13597
13784
|
if (await _Sphere.exists(options.storage)) {
|
|
13598
|
-
throw new
|
|
13785
|
+
throw new SphereError("Wallet already exists. Use Sphere.load() or Sphere.clear() first.", "ALREADY_INITIALIZED");
|
|
13599
13786
|
}
|
|
13600
13787
|
const progress = options.onProgress;
|
|
13601
13788
|
if (!options.storage.isConnected()) {
|
|
@@ -13641,10 +13828,10 @@ var Sphere = class _Sphere {
|
|
|
13641
13828
|
const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
|
|
13642
13829
|
const result = await sphere.discoverAddresses(discoverOpts);
|
|
13643
13830
|
if (result.addresses.length > 0) {
|
|
13644
|
-
|
|
13831
|
+
logger.debug("Sphere", `Address discovery: found ${result.addresses.length} address(es)`);
|
|
13645
13832
|
}
|
|
13646
13833
|
} catch (err) {
|
|
13647
|
-
|
|
13834
|
+
logger.warn("Sphere", "Address discovery failed (non-fatal):", err);
|
|
13648
13835
|
}
|
|
13649
13836
|
}
|
|
13650
13837
|
progress?.({ step: "complete", message: "Wallet created" });
|
|
@@ -13654,8 +13841,9 @@ var Sphere = class _Sphere {
|
|
|
13654
13841
|
* Load existing wallet from storage
|
|
13655
13842
|
*/
|
|
13656
13843
|
static async load(options) {
|
|
13844
|
+
if (options.debug) logger.configure({ debug: true });
|
|
13657
13845
|
if (!await _Sphere.exists(options.storage)) {
|
|
13658
|
-
throw new
|
|
13846
|
+
throw new SphereError("No wallet found. Use Sphere.create() to create a new wallet.", "NOT_INITIALIZED");
|
|
13659
13847
|
}
|
|
13660
13848
|
const progress = options.onProgress;
|
|
13661
13849
|
_Sphere.configureTokenRegistry(options.storage, options.network);
|
|
@@ -13686,16 +13874,16 @@ var Sphere = class _Sphere {
|
|
|
13686
13874
|
_Sphere.instance = sphere;
|
|
13687
13875
|
if (sphere._identity?.nametag && !sphere._payments.hasNametag()) {
|
|
13688
13876
|
progress?.({ step: "registering_nametag", message: "Restoring nametag token..." });
|
|
13689
|
-
|
|
13877
|
+
logger.debug("Sphere", `Nametag @${sphere._identity.nametag} has no token, attempting to mint...`);
|
|
13690
13878
|
try {
|
|
13691
13879
|
const result = await sphere.mintNametag(sphere._identity.nametag);
|
|
13692
13880
|
if (result.success) {
|
|
13693
|
-
|
|
13881
|
+
logger.debug("Sphere", `Nametag token minted successfully on load`);
|
|
13694
13882
|
} else {
|
|
13695
|
-
|
|
13883
|
+
logger.warn("Sphere", `Could not mint nametag token: ${result.error}`);
|
|
13696
13884
|
}
|
|
13697
13885
|
} catch (err) {
|
|
13698
|
-
|
|
13886
|
+
logger.warn("Sphere", `Nametag token mint failed:`, err);
|
|
13699
13887
|
}
|
|
13700
13888
|
}
|
|
13701
13889
|
if (options.discoverAddresses !== false && sphere._transport.discoverAddresses && sphere._masterKey) {
|
|
@@ -13704,10 +13892,10 @@ var Sphere = class _Sphere {
|
|
|
13704
13892
|
const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
|
|
13705
13893
|
const result = await sphere.discoverAddresses(discoverOpts);
|
|
13706
13894
|
if (result.addresses.length > 0) {
|
|
13707
|
-
|
|
13895
|
+
logger.debug("Sphere", `Address discovery: found ${result.addresses.length} address(es)`);
|
|
13708
13896
|
}
|
|
13709
13897
|
} catch (err) {
|
|
13710
|
-
|
|
13898
|
+
logger.warn("Sphere", "Address discovery failed (non-fatal):", err);
|
|
13711
13899
|
}
|
|
13712
13900
|
}
|
|
13713
13901
|
progress?.({ step: "complete", message: "Wallet loaded" });
|
|
@@ -13717,24 +13905,25 @@ var Sphere = class _Sphere {
|
|
|
13717
13905
|
* Import wallet from mnemonic or master key
|
|
13718
13906
|
*/
|
|
13719
13907
|
static async import(options) {
|
|
13908
|
+
if (options.debug) logger.configure({ debug: true });
|
|
13720
13909
|
if (!options.mnemonic && !options.masterKey) {
|
|
13721
|
-
throw new
|
|
13910
|
+
throw new SphereError("Either mnemonic or masterKey is required", "INVALID_CONFIG");
|
|
13722
13911
|
}
|
|
13723
13912
|
const progress = options.onProgress;
|
|
13724
|
-
|
|
13913
|
+
logger.debug("Sphere", "Starting import...");
|
|
13725
13914
|
const needsClear = _Sphere.instance !== null || await _Sphere.exists(options.storage);
|
|
13726
13915
|
if (needsClear) {
|
|
13727
13916
|
progress?.({ step: "clearing", message: "Clearing previous wallet data..." });
|
|
13728
|
-
|
|
13917
|
+
logger.debug("Sphere", "Clearing existing wallet data...");
|
|
13729
13918
|
await _Sphere.clear({ storage: options.storage, tokenStorage: options.tokenStorage });
|
|
13730
|
-
|
|
13919
|
+
logger.debug("Sphere", "Clear done");
|
|
13731
13920
|
} else {
|
|
13732
|
-
|
|
13921
|
+
logger.debug("Sphere", "No existing wallet \u2014 skipping clear");
|
|
13733
13922
|
}
|
|
13734
13923
|
if (!options.storage.isConnected()) {
|
|
13735
|
-
|
|
13924
|
+
logger.debug("Sphere", "Reconnecting storage...");
|
|
13736
13925
|
await options.storage.connect();
|
|
13737
|
-
|
|
13926
|
+
logger.debug("Sphere", "Storage reconnected");
|
|
13738
13927
|
}
|
|
13739
13928
|
const groupChatConfig = _Sphere.resolveGroupChatConfig(options.groupChat);
|
|
13740
13929
|
const marketConfig = _Sphere.resolveMarketConfig(options.market);
|
|
@@ -13752,14 +13941,14 @@ var Sphere = class _Sphere {
|
|
|
13752
13941
|
progress?.({ step: "storing_keys", message: "Storing wallet keys..." });
|
|
13753
13942
|
if (options.mnemonic) {
|
|
13754
13943
|
if (!_Sphere.validateMnemonic(options.mnemonic)) {
|
|
13755
|
-
throw new
|
|
13944
|
+
throw new SphereError("Invalid mnemonic", "INVALID_IDENTITY");
|
|
13756
13945
|
}
|
|
13757
|
-
|
|
13946
|
+
logger.debug("Sphere", "Storing mnemonic...");
|
|
13758
13947
|
await sphere.storeMnemonic(options.mnemonic, options.derivationPath, options.basePath);
|
|
13759
|
-
|
|
13948
|
+
logger.debug("Sphere", "Initializing identity from mnemonic...");
|
|
13760
13949
|
await sphere.initializeIdentityFromMnemonic(options.mnemonic, options.derivationPath);
|
|
13761
13950
|
} else if (options.masterKey) {
|
|
13762
|
-
|
|
13951
|
+
logger.debug("Sphere", "Storing master key...");
|
|
13763
13952
|
await sphere.storeMasterKey(
|
|
13764
13953
|
options.masterKey,
|
|
13765
13954
|
options.chainCode,
|
|
@@ -13767,7 +13956,7 @@ var Sphere = class _Sphere {
|
|
|
13767
13956
|
options.basePath,
|
|
13768
13957
|
options.derivationMode
|
|
13769
13958
|
);
|
|
13770
|
-
|
|
13959
|
+
logger.debug("Sphere", "Initializing identity from master key...");
|
|
13771
13960
|
await sphere.initializeIdentityFromMasterKey(
|
|
13772
13961
|
options.masterKey,
|
|
13773
13962
|
options.chainCode,
|
|
@@ -13775,38 +13964,38 @@ var Sphere = class _Sphere {
|
|
|
13775
13964
|
);
|
|
13776
13965
|
}
|
|
13777
13966
|
progress?.({ step: "initializing", message: "Initializing wallet..." });
|
|
13778
|
-
|
|
13967
|
+
logger.debug("Sphere", "Initializing providers...");
|
|
13779
13968
|
await sphere.initializeProviders();
|
|
13780
|
-
|
|
13969
|
+
logger.debug("Sphere", "Providers initialized. Initializing modules...");
|
|
13781
13970
|
await sphere.initializeModules();
|
|
13782
|
-
|
|
13971
|
+
logger.debug("Sphere", "Modules initialized");
|
|
13783
13972
|
if (!options.nametag) {
|
|
13784
13973
|
progress?.({ step: "recovering_nametag", message: "Recovering nametag..." });
|
|
13785
|
-
|
|
13974
|
+
logger.debug("Sphere", "Recovering nametag from transport...");
|
|
13786
13975
|
await sphere.recoverNametagFromTransport();
|
|
13787
|
-
|
|
13976
|
+
logger.debug("Sphere", "Nametag recovery done");
|
|
13788
13977
|
progress?.({ step: "syncing_identity", message: "Publishing identity..." });
|
|
13789
13978
|
await sphere.syncIdentityWithTransport();
|
|
13790
13979
|
}
|
|
13791
13980
|
progress?.({ step: "finalizing", message: "Finalizing wallet..." });
|
|
13792
|
-
|
|
13981
|
+
logger.debug("Sphere", "Finalizing wallet creation...");
|
|
13793
13982
|
await sphere.finalizeWalletCreation();
|
|
13794
13983
|
sphere._initialized = true;
|
|
13795
13984
|
_Sphere.instance = sphere;
|
|
13796
|
-
|
|
13985
|
+
logger.debug("Sphere", "Tracking address 0...");
|
|
13797
13986
|
await sphere.ensureAddressTracked(0);
|
|
13798
13987
|
if (options.nametag) {
|
|
13799
13988
|
progress?.({ step: "registering_nametag", message: "Registering nametag..." });
|
|
13800
|
-
|
|
13989
|
+
logger.debug("Sphere", "Registering nametag...");
|
|
13801
13990
|
await sphere.registerNametag(options.nametag);
|
|
13802
13991
|
}
|
|
13803
13992
|
if (sphere._tokenStorageProviders.size > 0) {
|
|
13804
13993
|
progress?.({ step: "syncing_tokens", message: "Syncing tokens..." });
|
|
13805
13994
|
try {
|
|
13806
13995
|
const syncResult = await sphere._payments.sync();
|
|
13807
|
-
|
|
13996
|
+
logger.debug("Sphere", `Auto-sync: +${syncResult.added} -${syncResult.removed}`);
|
|
13808
13997
|
} catch (err) {
|
|
13809
|
-
|
|
13998
|
+
logger.warn("Sphere", "Auto-sync failed (non-fatal):", err);
|
|
13810
13999
|
}
|
|
13811
14000
|
}
|
|
13812
14001
|
if (options.discoverAddresses !== false && sphere._transport.discoverAddresses) {
|
|
@@ -13815,14 +14004,14 @@ var Sphere = class _Sphere {
|
|
|
13815
14004
|
const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
|
|
13816
14005
|
const result = await sphere.discoverAddresses(discoverOpts);
|
|
13817
14006
|
if (result.addresses.length > 0) {
|
|
13818
|
-
|
|
14007
|
+
logger.debug("Sphere", `Address discovery: found ${result.addresses.length} address(es)`);
|
|
13819
14008
|
}
|
|
13820
14009
|
} catch (err) {
|
|
13821
|
-
|
|
14010
|
+
logger.warn("Sphere", "Address discovery failed (non-fatal):", err);
|
|
13822
14011
|
}
|
|
13823
14012
|
}
|
|
13824
14013
|
progress?.({ step: "complete", message: "Import complete" });
|
|
13825
|
-
|
|
14014
|
+
logger.debug("Sphere", "Import complete");
|
|
13826
14015
|
return sphere;
|
|
13827
14016
|
}
|
|
13828
14017
|
/**
|
|
@@ -13848,26 +14037,26 @@ var Sphere = class _Sphere {
|
|
|
13848
14037
|
const storage = "get" in storageOrOptions ? storageOrOptions : storageOrOptions.storage;
|
|
13849
14038
|
const tokenStorage = "get" in storageOrOptions ? void 0 : storageOrOptions.tokenStorage;
|
|
13850
14039
|
if (_Sphere.instance) {
|
|
13851
|
-
|
|
14040
|
+
logger.debug("Sphere", "Destroying Sphere instance...");
|
|
13852
14041
|
await _Sphere.instance.destroy();
|
|
13853
|
-
|
|
14042
|
+
logger.debug("Sphere", "Sphere instance destroyed");
|
|
13854
14043
|
}
|
|
13855
|
-
|
|
14044
|
+
logger.debug("Sphere", "Clearing L1 vesting cache...");
|
|
13856
14045
|
await vestingClassifier.destroy();
|
|
13857
|
-
|
|
14046
|
+
logger.debug("Sphere", "Yielding 50ms for IDB transaction settlement...");
|
|
13858
14047
|
await new Promise((r) => setTimeout(r, 50));
|
|
13859
14048
|
if (tokenStorage?.clear) {
|
|
13860
|
-
|
|
14049
|
+
logger.debug("Sphere", "Clearing token storage...");
|
|
13861
14050
|
try {
|
|
13862
14051
|
await tokenStorage.clear();
|
|
13863
|
-
|
|
14052
|
+
logger.debug("Sphere", "Token storage cleared");
|
|
13864
14053
|
} catch (err) {
|
|
13865
|
-
|
|
14054
|
+
logger.warn("Sphere", "Token storage clear failed:", err);
|
|
13866
14055
|
}
|
|
13867
14056
|
} else {
|
|
13868
|
-
|
|
14057
|
+
logger.debug("Sphere", "No token storage provider to clear");
|
|
13869
14058
|
}
|
|
13870
|
-
|
|
14059
|
+
logger.debug("Sphere", "Clearing KV storage...");
|
|
13871
14060
|
if (!storage.isConnected()) {
|
|
13872
14061
|
try {
|
|
13873
14062
|
await storage.connect();
|
|
@@ -13876,11 +14065,11 @@ var Sphere = class _Sphere {
|
|
|
13876
14065
|
}
|
|
13877
14066
|
if (storage.isConnected()) {
|
|
13878
14067
|
await storage.clear();
|
|
13879
|
-
|
|
14068
|
+
logger.debug("Sphere", "KV storage cleared");
|
|
13880
14069
|
} else {
|
|
13881
|
-
|
|
14070
|
+
logger.debug("Sphere", "KV storage not connected, skipping");
|
|
13882
14071
|
}
|
|
13883
|
-
|
|
14072
|
+
logger.debug("Sphere", "Done");
|
|
13884
14073
|
}
|
|
13885
14074
|
/**
|
|
13886
14075
|
* Get current instance
|
|
@@ -13972,7 +14161,7 @@ var Sphere = class _Sphere {
|
|
|
13972
14161
|
*/
|
|
13973
14162
|
async addTokenStorageProvider(provider) {
|
|
13974
14163
|
if (this._tokenStorageProviders.has(provider.id)) {
|
|
13975
|
-
throw new
|
|
14164
|
+
throw new SphereError(`Token storage provider '${provider.id}' already exists`, "INVALID_CONFIG");
|
|
13976
14165
|
}
|
|
13977
14166
|
if (this._identity) {
|
|
13978
14167
|
provider.setIdentity(this._identity);
|
|
@@ -14092,7 +14281,7 @@ var Sphere = class _Sphere {
|
|
|
14092
14281
|
exportToJSON(options = {}) {
|
|
14093
14282
|
this.ensureReady();
|
|
14094
14283
|
if (!this._masterKey && !this._identity) {
|
|
14095
|
-
throw new
|
|
14284
|
+
throw new SphereError("Wallet not initialized", "NOT_INITIALIZED");
|
|
14096
14285
|
}
|
|
14097
14286
|
const addressCount = options.addressCount || 1;
|
|
14098
14287
|
const addresses = [];
|
|
@@ -14172,7 +14361,7 @@ var Sphere = class _Sphere {
|
|
|
14172
14361
|
exportToTxt(options = {}) {
|
|
14173
14362
|
this.ensureReady();
|
|
14174
14363
|
if (!this._masterKey && !this._identity) {
|
|
14175
|
-
throw new
|
|
14364
|
+
throw new SphereError("Wallet not initialized", "NOT_INITIALIZED");
|
|
14176
14365
|
}
|
|
14177
14366
|
const addressCount = options.addressCount || 1;
|
|
14178
14367
|
const addresses = [];
|
|
@@ -14611,7 +14800,7 @@ var Sphere = class _Sphere {
|
|
|
14611
14800
|
this.ensureReady();
|
|
14612
14801
|
const entry = this._trackedAddresses.get(index);
|
|
14613
14802
|
if (!entry) {
|
|
14614
|
-
throw new
|
|
14803
|
+
throw new SphereError(`Address at index ${index} is not tracked. Switch to it first.`, "INVALID_CONFIG");
|
|
14615
14804
|
}
|
|
14616
14805
|
if (entry.hidden === hidden) return;
|
|
14617
14806
|
entry.hidden = hidden;
|
|
@@ -14641,14 +14830,14 @@ var Sphere = class _Sphere {
|
|
|
14641
14830
|
async switchToAddress(index, options) {
|
|
14642
14831
|
this.ensureReady();
|
|
14643
14832
|
if (!this._masterKey) {
|
|
14644
|
-
throw new
|
|
14833
|
+
throw new SphereError("HD derivation requires master key with chain code. Cannot switch addresses.", "INVALID_CONFIG");
|
|
14645
14834
|
}
|
|
14646
14835
|
if (index < 0) {
|
|
14647
|
-
throw new
|
|
14836
|
+
throw new SphereError("Address index must be non-negative", "INVALID_CONFIG");
|
|
14648
14837
|
}
|
|
14649
14838
|
const newNametag = options?.nametag ? this.cleanNametag(options.nametag) : void 0;
|
|
14650
14839
|
if (newNametag && !isValidNametag(newNametag)) {
|
|
14651
|
-
throw new
|
|
14840
|
+
throw new SphereError("Invalid nametag format. Use lowercase alphanumeric, underscore, or hyphen (3-20 chars), or a valid phone number.", "VALIDATION_ERROR");
|
|
14652
14841
|
}
|
|
14653
14842
|
const addressInfo = this.deriveAddress(index, false);
|
|
14654
14843
|
const ipnsHash = sha256(addressInfo.publicKey, "hex").slice(0, 40);
|
|
@@ -14658,7 +14847,7 @@ var Sphere = class _Sphere {
|
|
|
14658
14847
|
if (newNametag) {
|
|
14659
14848
|
const existing = await this._transport.resolveNametag?.(newNametag);
|
|
14660
14849
|
if (existing) {
|
|
14661
|
-
throw new
|
|
14850
|
+
throw new SphereError(`Nametag @${newNametag} is already taken`, "VALIDATION_ERROR");
|
|
14662
14851
|
}
|
|
14663
14852
|
let nametags = this._addressNametags.get(addressId);
|
|
14664
14853
|
if (!nametags) {
|
|
@@ -14681,12 +14870,12 @@ var Sphere = class _Sphere {
|
|
|
14681
14870
|
await this._storage.set(STORAGE_KEYS_GLOBAL.CURRENT_ADDRESS_INDEX, index.toString());
|
|
14682
14871
|
this._storage.setIdentity(this._identity);
|
|
14683
14872
|
await this._transport.setIdentity(this._identity);
|
|
14684
|
-
|
|
14873
|
+
logger.debug("Sphere", `switchToAddress(${index}): re-initializing ${this._tokenStorageProviders.size} token storage provider(s)`);
|
|
14685
14874
|
for (const [providerId, provider] of this._tokenStorageProviders.entries()) {
|
|
14686
|
-
|
|
14875
|
+
logger.debug("Sphere", `switchToAddress(${index}): shutdown provider=${providerId}`);
|
|
14687
14876
|
await provider.shutdown();
|
|
14688
14877
|
provider.setIdentity(this._identity);
|
|
14689
|
-
|
|
14878
|
+
logger.debug("Sphere", `switchToAddress(${index}): initialize provider=${providerId}`);
|
|
14690
14879
|
await provider.initialize();
|
|
14691
14880
|
}
|
|
14692
14881
|
await this.reinitializeModulesForNewAddress();
|
|
@@ -14697,9 +14886,9 @@ var Sphere = class _Sphere {
|
|
|
14697
14886
|
nametag: this._identity.nametag,
|
|
14698
14887
|
addressIndex: index
|
|
14699
14888
|
});
|
|
14700
|
-
|
|
14889
|
+
logger.debug("Sphere", `Switched to address ${index}:`, this._identity.l1Address);
|
|
14701
14890
|
this.postSwitchSync(index, newNametag).catch((err) => {
|
|
14702
|
-
|
|
14891
|
+
logger.warn("Sphere", `Post-switch sync failed for address ${index}:`, err);
|
|
14703
14892
|
});
|
|
14704
14893
|
}
|
|
14705
14894
|
/**
|
|
@@ -14713,16 +14902,16 @@ var Sphere = class _Sphere {
|
|
|
14713
14902
|
if (newNametag) {
|
|
14714
14903
|
await this.persistAddressNametags();
|
|
14715
14904
|
if (!this._payments.hasNametag()) {
|
|
14716
|
-
|
|
14905
|
+
logger.debug("Sphere", `Minting nametag token for @${newNametag}...`);
|
|
14717
14906
|
try {
|
|
14718
14907
|
const result = await this.mintNametag(newNametag);
|
|
14719
14908
|
if (result.success) {
|
|
14720
|
-
|
|
14909
|
+
logger.debug("Sphere", `Nametag token minted successfully`);
|
|
14721
14910
|
} else {
|
|
14722
|
-
|
|
14911
|
+
logger.warn("Sphere", `Could not mint nametag token: ${result.error}`);
|
|
14723
14912
|
}
|
|
14724
14913
|
} catch (err) {
|
|
14725
|
-
|
|
14914
|
+
logger.warn("Sphere", `Nametag token mint failed:`, err);
|
|
14726
14915
|
}
|
|
14727
14916
|
}
|
|
14728
14917
|
this.emitEvent("nametag:registered", {
|
|
@@ -14730,16 +14919,16 @@ var Sphere = class _Sphere {
|
|
|
14730
14919
|
addressIndex: index
|
|
14731
14920
|
});
|
|
14732
14921
|
} else if (this._identity?.nametag && !this._payments.hasNametag()) {
|
|
14733
|
-
|
|
14922
|
+
logger.debug("Sphere", `Nametag @${this._identity.nametag} has no token after switch, minting...`);
|
|
14734
14923
|
try {
|
|
14735
14924
|
const result = await this.mintNametag(this._identity.nametag);
|
|
14736
14925
|
if (result.success) {
|
|
14737
|
-
|
|
14926
|
+
logger.debug("Sphere", `Nametag token minted successfully after switch`);
|
|
14738
14927
|
} else {
|
|
14739
|
-
|
|
14928
|
+
logger.warn("Sphere", `Could not mint nametag token after switch: ${result.error}`);
|
|
14740
14929
|
}
|
|
14741
14930
|
} catch (err) {
|
|
14742
|
-
|
|
14931
|
+
logger.warn("Sphere", `Nametag token mint failed after switch:`, err);
|
|
14743
14932
|
}
|
|
14744
14933
|
}
|
|
14745
14934
|
}
|
|
@@ -14778,7 +14967,7 @@ var Sphere = class _Sphere {
|
|
|
14778
14967
|
await this._groupChat?.load();
|
|
14779
14968
|
await this._market?.load();
|
|
14780
14969
|
this._payments.sync().catch((err) => {
|
|
14781
|
-
|
|
14970
|
+
logger.warn("Sphere", "Post-switch sync failed:", err);
|
|
14782
14971
|
});
|
|
14783
14972
|
}
|
|
14784
14973
|
/**
|
|
@@ -14812,7 +15001,7 @@ var Sphere = class _Sphere {
|
|
|
14812
15001
|
*/
|
|
14813
15002
|
_deriveAddressInternal(index, isChange = false) {
|
|
14814
15003
|
if (!this._masterKey) {
|
|
14815
|
-
throw new
|
|
15004
|
+
throw new SphereError("HD derivation requires master key with chain code", "INVALID_CONFIG");
|
|
14816
15005
|
}
|
|
14817
15006
|
if (this._derivationMode === "wif_hmac") {
|
|
14818
15007
|
return generateAddressFromMasterKey(this._masterKey.privateKey, index);
|
|
@@ -14842,7 +15031,7 @@ var Sphere = class _Sphere {
|
|
|
14842
15031
|
deriveAddressAtPath(path) {
|
|
14843
15032
|
this.ensureReady();
|
|
14844
15033
|
if (!this._masterKey) {
|
|
14845
|
-
throw new
|
|
15034
|
+
throw new SphereError("HD derivation requires master key with chain code", "INVALID_CONFIG");
|
|
14846
15035
|
}
|
|
14847
15036
|
const match = path.match(/\/(\d+)$/);
|
|
14848
15037
|
const index = match ? parseInt(match[1], 10) : 0;
|
|
@@ -14909,13 +15098,14 @@ var Sphere = class _Sphere {
|
|
|
14909
15098
|
async scanAddresses(options = {}) {
|
|
14910
15099
|
this.ensureReady();
|
|
14911
15100
|
if (!this._masterKey) {
|
|
14912
|
-
throw new
|
|
15101
|
+
throw new SphereError("Address scanning requires HD master key", "INVALID_CONFIG");
|
|
14913
15102
|
}
|
|
14914
15103
|
const resolveNametag = options.resolveNametag ?? (this._transport.resolveAddressInfo ? async (l1Address) => {
|
|
14915
15104
|
try {
|
|
14916
15105
|
const info = await this._transport.resolveAddressInfo(l1Address);
|
|
14917
15106
|
return info?.nametag ?? null;
|
|
14918
|
-
} catch {
|
|
15107
|
+
} catch (err) {
|
|
15108
|
+
logger.debug("Sphere", "Nametag resolution failed during scan", err);
|
|
14919
15109
|
return null;
|
|
14920
15110
|
}
|
|
14921
15111
|
} : void 0);
|
|
@@ -14966,10 +15156,10 @@ var Sphere = class _Sphere {
|
|
|
14966
15156
|
async discoverAddresses(options = {}) {
|
|
14967
15157
|
this.ensureReady();
|
|
14968
15158
|
if (!this._masterKey) {
|
|
14969
|
-
throw new
|
|
15159
|
+
throw new SphereError("Address discovery requires HD master key", "INVALID_CONFIG");
|
|
14970
15160
|
}
|
|
14971
15161
|
if (!this._transport.discoverAddresses) {
|
|
14972
|
-
throw new
|
|
15162
|
+
throw new SphereError("Transport provider does not support address discovery", "INVALID_CONFIG");
|
|
14973
15163
|
}
|
|
14974
15164
|
const includeL1Scan = options.includeL1Scan ?? true;
|
|
14975
15165
|
const transportResult = await discoverAddressesImpl(
|
|
@@ -15025,7 +15215,7 @@ var Sphere = class _Sphere {
|
|
|
15025
15215
|
}
|
|
15026
15216
|
transportResult.addresses.sort((a, b) => a.index - b.index);
|
|
15027
15217
|
} catch (err) {
|
|
15028
|
-
|
|
15218
|
+
logger.warn("Sphere", "L1 scan failed during discovery (non-fatal):", err);
|
|
15029
15219
|
}
|
|
15030
15220
|
}
|
|
15031
15221
|
if (options.autoTrack && transportResult.addresses.length > 0) {
|
|
@@ -15123,7 +15313,7 @@ var Sphere = class _Sphere {
|
|
|
15123
15313
|
*/
|
|
15124
15314
|
async disableProvider(providerId) {
|
|
15125
15315
|
if (providerId === this._storage.id) {
|
|
15126
|
-
throw new
|
|
15316
|
+
throw new SphereError("Cannot disable the main storage provider", "INVALID_CONFIG");
|
|
15127
15317
|
}
|
|
15128
15318
|
const provider = this.findProviderById(providerId);
|
|
15129
15319
|
if (!provider) return false;
|
|
@@ -15326,10 +15516,10 @@ var Sphere = class _Sphere {
|
|
|
15326
15516
|
this.ensureReady();
|
|
15327
15517
|
const cleanNametag = this.cleanNametag(nametag);
|
|
15328
15518
|
if (!isValidNametag(cleanNametag)) {
|
|
15329
|
-
throw new
|
|
15519
|
+
throw new SphereError("Invalid nametag format. Use lowercase alphanumeric, underscore, or hyphen (3-20 chars), or a valid phone number.", "VALIDATION_ERROR");
|
|
15330
15520
|
}
|
|
15331
15521
|
if (this._identity?.nametag) {
|
|
15332
|
-
throw new
|
|
15522
|
+
throw new SphereError(`Nametag already registered for address ${this._currentAddressIndex}: @${this._identity.nametag}`, "ALREADY_INITIALIZED");
|
|
15333
15523
|
}
|
|
15334
15524
|
if (this._transport.publishIdentityBinding) {
|
|
15335
15525
|
const success = await this._transport.publishIdentityBinding(
|
|
@@ -15339,7 +15529,7 @@ var Sphere = class _Sphere {
|
|
|
15339
15529
|
cleanNametag
|
|
15340
15530
|
);
|
|
15341
15531
|
if (!success) {
|
|
15342
|
-
throw new
|
|
15532
|
+
throw new SphereError("Failed to register nametag. It may already be taken.", "VALIDATION_ERROR");
|
|
15343
15533
|
}
|
|
15344
15534
|
}
|
|
15345
15535
|
this._identity.nametag = cleanNametag;
|
|
@@ -15355,19 +15545,19 @@ var Sphere = class _Sphere {
|
|
|
15355
15545
|
}
|
|
15356
15546
|
await this.persistAddressNametags();
|
|
15357
15547
|
if (!this._payments.hasNametag()) {
|
|
15358
|
-
|
|
15548
|
+
logger.debug("Sphere", `Minting nametag token for @${cleanNametag}...`);
|
|
15359
15549
|
const result = await this.mintNametag(cleanNametag);
|
|
15360
15550
|
if (!result.success) {
|
|
15361
|
-
|
|
15551
|
+
logger.warn("Sphere", `Failed to mint nametag token: ${result.error}`);
|
|
15362
15552
|
} else {
|
|
15363
|
-
|
|
15553
|
+
logger.debug("Sphere", `Nametag token minted successfully`);
|
|
15364
15554
|
}
|
|
15365
15555
|
}
|
|
15366
15556
|
this.emitEvent("nametag:registered", {
|
|
15367
15557
|
nametag: cleanNametag,
|
|
15368
15558
|
addressIndex: this._currentAddressIndex
|
|
15369
15559
|
});
|
|
15370
|
-
|
|
15560
|
+
logger.debug("Sphere", `Nametag registered for address ${this._currentAddressIndex}:`, cleanNametag);
|
|
15371
15561
|
}
|
|
15372
15562
|
/**
|
|
15373
15563
|
* Persist tracked addresses to storage (only minimal fields via StorageProvider)
|
|
@@ -15607,13 +15797,13 @@ var Sphere = class _Sphere {
|
|
|
15607
15797
|
this._identity.directAddress || "",
|
|
15608
15798
|
recoveredNametag
|
|
15609
15799
|
);
|
|
15610
|
-
|
|
15800
|
+
logger.debug("Sphere", `Migrated legacy binding with nametag @${recoveredNametag}`);
|
|
15611
15801
|
return;
|
|
15612
15802
|
}
|
|
15613
15803
|
}
|
|
15614
15804
|
const needsUpdate = !existing.directAddress || !existing.l1Address || !existing.chainPubkey || this._identity?.nametag && !existing.nametag;
|
|
15615
15805
|
if (needsUpdate) {
|
|
15616
|
-
|
|
15806
|
+
logger.debug("Sphere", "Existing binding incomplete, re-publishing with full data");
|
|
15617
15807
|
await this._transport.publishIdentityBinding(
|
|
15618
15808
|
this._identity.chainPubkey,
|
|
15619
15809
|
this._identity.l1Address,
|
|
@@ -15622,11 +15812,11 @@ var Sphere = class _Sphere {
|
|
|
15622
15812
|
);
|
|
15623
15813
|
return;
|
|
15624
15814
|
}
|
|
15625
|
-
|
|
15815
|
+
logger.debug("Sphere", "Existing binding found, skipping re-publish");
|
|
15626
15816
|
return;
|
|
15627
15817
|
}
|
|
15628
15818
|
} catch (e) {
|
|
15629
|
-
|
|
15819
|
+
logger.warn("Sphere", "resolve() failed, skipping publish to avoid overwrite", e);
|
|
15630
15820
|
return;
|
|
15631
15821
|
}
|
|
15632
15822
|
}
|
|
@@ -15638,12 +15828,12 @@ var Sphere = class _Sphere {
|
|
|
15638
15828
|
nametag || void 0
|
|
15639
15829
|
);
|
|
15640
15830
|
if (success) {
|
|
15641
|
-
|
|
15831
|
+
logger.debug("Sphere", `Identity binding published${nametag ? ` with nametag @${nametag}` : ""}`);
|
|
15642
15832
|
} else if (nametag) {
|
|
15643
|
-
|
|
15833
|
+
logger.warn("Sphere", `Nametag @${nametag} is taken by another pubkey`);
|
|
15644
15834
|
}
|
|
15645
15835
|
} catch (error) {
|
|
15646
|
-
|
|
15836
|
+
logger.warn("Sphere", `Identity binding sync failed:`, error);
|
|
15647
15837
|
}
|
|
15648
15838
|
}
|
|
15649
15839
|
/**
|
|
@@ -15796,7 +15986,7 @@ var Sphere = class _Sphere {
|
|
|
15796
15986
|
if (encryptedMnemonic) {
|
|
15797
15987
|
const mnemonic = this.decrypt(encryptedMnemonic);
|
|
15798
15988
|
if (!mnemonic) {
|
|
15799
|
-
throw new
|
|
15989
|
+
throw new SphereError("Failed to decrypt mnemonic", "STORAGE_ERROR");
|
|
15800
15990
|
}
|
|
15801
15991
|
this._mnemonic = mnemonic;
|
|
15802
15992
|
this._source = "mnemonic";
|
|
@@ -15804,7 +15994,7 @@ var Sphere = class _Sphere {
|
|
|
15804
15994
|
} else if (encryptedMasterKey) {
|
|
15805
15995
|
const masterKey = this.decrypt(encryptedMasterKey);
|
|
15806
15996
|
if (!masterKey) {
|
|
15807
|
-
throw new
|
|
15997
|
+
throw new SphereError("Failed to decrypt master key", "STORAGE_ERROR");
|
|
15808
15998
|
}
|
|
15809
15999
|
this._mnemonic = null;
|
|
15810
16000
|
if (this._source === "unknown") {
|
|
@@ -15816,7 +16006,7 @@ var Sphere = class _Sphere {
|
|
|
15816
16006
|
derivationPath ?? void 0
|
|
15817
16007
|
);
|
|
15818
16008
|
} else {
|
|
15819
|
-
throw new
|
|
16009
|
+
throw new SphereError("No wallet data found in storage", "NOT_INITIALIZED");
|
|
15820
16010
|
}
|
|
15821
16011
|
if (this._identity) {
|
|
15822
16012
|
this._storage.setIdentity(this._identity);
|
|
@@ -15838,7 +16028,7 @@ var Sphere = class _Sphere {
|
|
|
15838
16028
|
nametag
|
|
15839
16029
|
};
|
|
15840
16030
|
this._storage.setIdentity(this._identity);
|
|
15841
|
-
|
|
16031
|
+
logger.debug("Sphere", `Restored to address ${this._currentAddressIndex}:`, this._identity.l1Address);
|
|
15842
16032
|
} else if (this._identity && nametag) {
|
|
15843
16033
|
this._identity.nametag = nametag;
|
|
15844
16034
|
}
|
|
@@ -16029,7 +16219,7 @@ var Sphere = class _Sphere {
|
|
|
16029
16219
|
// ===========================================================================
|
|
16030
16220
|
ensureReady() {
|
|
16031
16221
|
if (!this._initialized) {
|
|
16032
|
-
throw new
|
|
16222
|
+
throw new SphereError("Sphere not initialized", "NOT_INITIALIZED");
|
|
16033
16223
|
}
|
|
16034
16224
|
}
|
|
16035
16225
|
emitEvent(type, data) {
|
|
@@ -16039,7 +16229,7 @@ var Sphere = class _Sphere {
|
|
|
16039
16229
|
try {
|
|
16040
16230
|
handler(data);
|
|
16041
16231
|
} catch (error) {
|
|
16042
|
-
|
|
16232
|
+
logger.error("Sphere", "Event handler error:", error);
|
|
16043
16233
|
}
|
|
16044
16234
|
}
|
|
16045
16235
|
}
|
|
@@ -16076,6 +16266,7 @@ var getSphere = Sphere.getInstance.bind(Sphere);
|
|
|
16076
16266
|
var sphereExists = Sphere.exists.bind(Sphere);
|
|
16077
16267
|
|
|
16078
16268
|
// core/currency.ts
|
|
16269
|
+
init_logger();
|
|
16079
16270
|
var DEFAULT_TOKEN_DECIMALS = 18;
|
|
16080
16271
|
function toSmallestUnit(amount, decimals = DEFAULT_TOKEN_DECIMALS) {
|
|
16081
16272
|
if (!amount) return 0n;
|
|
@@ -16084,7 +16275,8 @@ function toSmallestUnit(amount, decimals = DEFAULT_TOKEN_DECIMALS) {
|
|
|
16084
16275
|
const [integer, fraction = ""] = str.split(".");
|
|
16085
16276
|
const paddedFraction = fraction.padEnd(decimals, "0").slice(0, decimals);
|
|
16086
16277
|
return BigInt(integer + paddedFraction);
|
|
16087
|
-
} catch {
|
|
16278
|
+
} catch (err) {
|
|
16279
|
+
logger.debug("Currency", "toSmallestUnit conversion failed", err);
|
|
16088
16280
|
return 0n;
|
|
16089
16281
|
}
|
|
16090
16282
|
}
|
|
@@ -16113,6 +16305,8 @@ var CurrencyUtils = {
|
|
|
16113
16305
|
|
|
16114
16306
|
// core/index.ts
|
|
16115
16307
|
init_bech32();
|
|
16308
|
+
init_logger();
|
|
16309
|
+
init_errors();
|
|
16116
16310
|
|
|
16117
16311
|
// core/network-health.ts
|
|
16118
16312
|
init_constants();
|
|
@@ -16307,6 +16501,7 @@ async function runCustomCheck(name, checkFn, timeoutMs) {
|
|
|
16307
16501
|
DEFAULT_DERIVATION_PATH,
|
|
16308
16502
|
DEFAULT_TOKEN_DECIMALS,
|
|
16309
16503
|
Sphere,
|
|
16504
|
+
SphereError,
|
|
16310
16505
|
base58Decode,
|
|
16311
16506
|
base58Encode,
|
|
16312
16507
|
bytesToHex,
|
|
@@ -16353,10 +16548,12 @@ async function runCustomCheck(name, checkFn, timeoutMs) {
|
|
|
16353
16548
|
importSphere,
|
|
16354
16549
|
initSphere,
|
|
16355
16550
|
isEncryptedData,
|
|
16551
|
+
isSphereError,
|
|
16356
16552
|
isValidBech32,
|
|
16357
16553
|
isValidNametag,
|
|
16358
16554
|
isValidPrivateKey,
|
|
16359
16555
|
loadSphere,
|
|
16556
|
+
logger,
|
|
16360
16557
|
mnemonicToEntropy,
|
|
16361
16558
|
mnemonicToSeed,
|
|
16362
16559
|
mnemonicToSeedSync,
|