@unicitylabs/sphere-sdk 0.5.6 → 0.5.8

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/dist/index.cjs CHANGED
@@ -846,6 +846,7 @@ __export(index_exports, {
846
846
  NIP29_KINDS: () => NIP29_KINDS,
847
847
  NOSTR_EVENT_KINDS: () => NOSTR_EVENT_KINDS,
848
848
  PaymentsModule: () => PaymentsModule,
849
+ SIGN_MESSAGE_PREFIX: () => SIGN_MESSAGE_PREFIX,
849
850
  STORAGE_KEYS: () => STORAGE_KEYS,
850
851
  STORAGE_KEYS_ADDRESS: () => STORAGE_KEYS_ADDRESS,
851
852
  STORAGE_KEYS_GLOBAL: () => STORAGE_KEYS_GLOBAL,
@@ -913,6 +914,7 @@ __export(index_exports, {
913
914
  hasValidTxfData: () => hasValidTxfData,
914
915
  hash160: () => hash160,
915
916
  hashNametag: () => import_nostr_js_sdk4.hashNametag,
917
+ hashSignMessage: () => hashSignMessage,
916
918
  hexToBytes: () => hexToBytes,
917
919
  identityFromMnemonicSync: () => identityFromMnemonicSync,
918
920
  initSphere: () => initSphere,
@@ -954,6 +956,7 @@ __export(index_exports, {
954
956
  randomUUID: () => randomUUID,
955
957
  ripemd160: () => ripemd160,
956
958
  sha256: () => sha256,
959
+ signMessage: () => signMessage,
957
960
  sleep: () => sleep,
958
961
  sphereExists: () => sphereExists,
959
962
  toHumanReadable: () => toHumanReadable,
@@ -962,7 +965,8 @@ __export(index_exports, {
962
965
  tokenIdFromKey: () => tokenIdFromKey,
963
966
  tokenToTxf: () => tokenToTxf,
964
967
  txfToToken: () => txfToToken,
965
- validateMnemonic: () => validateMnemonic2
968
+ validateMnemonic: () => validateMnemonic2,
969
+ verifySignedMessage: () => verifySignedMessage
966
970
  });
967
971
  module.exports = __toCommonJS(index_exports);
968
972
 
@@ -1238,6 +1242,73 @@ function generateAddressInfo(privateKey, index, path, prefix = "alpha") {
1238
1242
  index
1239
1243
  };
1240
1244
  }
1245
+ var SIGN_MESSAGE_PREFIX = "Sphere Signed Message:\n";
1246
+ function varint(n) {
1247
+ if (n < 253) return new Uint8Array([n]);
1248
+ const buf = new Uint8Array(3);
1249
+ buf[0] = 253;
1250
+ buf[1] = n & 255;
1251
+ buf[2] = n >> 8 & 255;
1252
+ return buf;
1253
+ }
1254
+ function hashSignMessage(message) {
1255
+ const prefix = new TextEncoder().encode(SIGN_MESSAGE_PREFIX);
1256
+ const msg = new TextEncoder().encode(message);
1257
+ const prefixLen = varint(prefix.length);
1258
+ const msgLen = varint(msg.length);
1259
+ const full = new Uint8Array(prefixLen.length + prefix.length + msgLen.length + msg.length);
1260
+ let off = 0;
1261
+ full.set(prefixLen, off);
1262
+ off += prefixLen.length;
1263
+ full.set(prefix, off);
1264
+ off += prefix.length;
1265
+ full.set(msgLen, off);
1266
+ off += msgLen.length;
1267
+ full.set(msg, off);
1268
+ const hex = Array.from(full).map((b) => b.toString(16).padStart(2, "0")).join("");
1269
+ const h1 = import_crypto_js2.default.SHA256(import_crypto_js2.default.enc.Hex.parse(hex)).toString();
1270
+ return import_crypto_js2.default.SHA256(import_crypto_js2.default.enc.Hex.parse(h1)).toString();
1271
+ }
1272
+ function signMessage(privateKeyHex, message) {
1273
+ const keyPair = ec.keyFromPrivate(privateKeyHex, "hex");
1274
+ const hashHex = hashSignMessage(message);
1275
+ const hashBytes = Buffer.from(hashHex, "hex");
1276
+ const sig = keyPair.sign(hashBytes, { canonical: true });
1277
+ const pub = keyPair.getPublic();
1278
+ let recoveryParam = -1;
1279
+ for (let i = 0; i < 4; i++) {
1280
+ try {
1281
+ if (ec.recoverPubKey(hashBytes, sig, i).eq(pub)) {
1282
+ recoveryParam = i;
1283
+ break;
1284
+ }
1285
+ } catch {
1286
+ }
1287
+ }
1288
+ if (recoveryParam === -1) {
1289
+ throw new SphereError("Could not find recovery parameter", "SIGNING_ERROR");
1290
+ }
1291
+ const v = (31 + recoveryParam).toString(16).padStart(2, "0");
1292
+ const r = sig.r.toString("hex").padStart(64, "0");
1293
+ const s = sig.s.toString("hex").padStart(64, "0");
1294
+ return v + r + s;
1295
+ }
1296
+ function verifySignedMessage(message, signature, expectedPubkey) {
1297
+ if (signature.length !== 130) return false;
1298
+ const v = parseInt(signature.slice(0, 2), 16) - 31;
1299
+ const r = signature.slice(2, 66);
1300
+ const s = signature.slice(66, 130);
1301
+ if (v < 0 || v > 3) return false;
1302
+ const hashHex = hashSignMessage(message);
1303
+ const hashBytes = Buffer.from(hashHex, "hex");
1304
+ try {
1305
+ const recovered = ec.recoverPubKey(hashBytes, { r, s }, v);
1306
+ const recoveredHex = recovered.encode("hex", true);
1307
+ return recoveredHex === expectedPubkey;
1308
+ } catch {
1309
+ return false;
1310
+ }
1311
+ }
1241
1312
 
1242
1313
  // l1/crypto.ts
1243
1314
  var import_crypto_js3 = __toESM(require("crypto-js"), 1);
@@ -9344,13 +9415,16 @@ var GroupChatModule = class {
9344
9415
  logger.error("GroupChat", "Max reconnection attempts reached");
9345
9416
  return;
9346
9417
  }
9418
+ const maxDelay = this.config.reconnectDelayMs * 16;
9419
+ const delay = Math.min(this.config.reconnectDelayMs * Math.pow(2, this.reconnectAttempts), maxDelay);
9347
9420
  this.reconnectAttempts++;
9421
+ logger.debug("GroupChat", `Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.config.maxReconnectAttempts})`);
9348
9422
  this.reconnectTimer = setTimeout(() => {
9349
9423
  this.reconnectTimer = null;
9350
9424
  if (this.deps) {
9351
9425
  this.connect().catch((err) => logger.error("GroupChat", "Reconnect failed:", err));
9352
9426
  }
9353
- }, this.config.reconnectDelayMs);
9427
+ }, delay);
9354
9428
  }
9355
9429
  // ===========================================================================
9356
9430
  // Subscription Management
@@ -12687,6 +12761,7 @@ var secp256k1 = /* @__PURE__ */ ecdsa(Pointk1, sha2564);
12687
12761
 
12688
12762
  // modules/market/MarketModule.ts
12689
12763
  init_errors();
12764
+ init_logger();
12690
12765
  var DEFAULT_MARKET_API_URL = "https://market-api.unicity.network";
12691
12766
  function hexToBytes3(hex) {
12692
12767
  const len = hex.length >> 1;
@@ -12859,16 +12934,54 @@ var MarketModule = class {
12859
12934
  */
12860
12935
  subscribeFeed(listener) {
12861
12936
  const wsUrl = this.apiUrl.replace(/^http/, "ws") + "/ws/feed";
12862
- const ws2 = new WebSocket(wsUrl);
12863
- ws2.onmessage = (event) => {
12864
- try {
12865
- const raw = JSON.parse(typeof event.data === "string" ? event.data : event.data.toString());
12866
- listener(mapFeedMessage(raw));
12867
- } catch {
12937
+ const BASE_DELAY2 = 2e3;
12938
+ const MAX_DELAY2 = 3e4;
12939
+ const MAX_ATTEMPTS = 10;
12940
+ let ws2 = null;
12941
+ let reconnectAttempts2 = 0;
12942
+ let reconnectTimer = null;
12943
+ let destroyed = false;
12944
+ function connect2() {
12945
+ if (destroyed) return;
12946
+ ws2 = new WebSocket(wsUrl);
12947
+ ws2.onopen = () => {
12948
+ reconnectAttempts2 = 0;
12949
+ logger.debug("Market", "Feed WebSocket connected");
12950
+ };
12951
+ ws2.onmessage = (event) => {
12952
+ try {
12953
+ const raw = JSON.parse(typeof event.data === "string" ? event.data : event.data.toString());
12954
+ listener(mapFeedMessage(raw));
12955
+ } catch {
12956
+ }
12957
+ };
12958
+ ws2.onclose = () => {
12959
+ if (destroyed) return;
12960
+ scheduleReconnect();
12961
+ };
12962
+ ws2.onerror = () => {
12963
+ };
12964
+ }
12965
+ function scheduleReconnect() {
12966
+ if (destroyed) return;
12967
+ if (reconnectAttempts2 >= MAX_ATTEMPTS) {
12968
+ logger.warn("Market", `Feed WebSocket: gave up after ${MAX_ATTEMPTS} reconnect attempts`);
12969
+ return;
12868
12970
  }
12869
- };
12971
+ const delay = Math.min(BASE_DELAY2 * Math.pow(2, reconnectAttempts2), MAX_DELAY2);
12972
+ reconnectAttempts2++;
12973
+ logger.debug("Market", `Feed WebSocket reconnecting in ${delay}ms (attempt ${reconnectAttempts2}/${MAX_ATTEMPTS})`);
12974
+ reconnectTimer = setTimeout(connect2, delay);
12975
+ }
12976
+ connect2();
12870
12977
  return () => {
12871
- ws2.close();
12978
+ destroyed = true;
12979
+ if (reconnectTimer) {
12980
+ clearTimeout(reconnectTimer);
12981
+ reconnectTimer = null;
12982
+ }
12983
+ ws2?.close();
12984
+ ws2 = null;
12872
12985
  };
12873
12986
  }
12874
12987
  // ---------------------------------------------------------------------------
@@ -14412,6 +14525,23 @@ var Sphere = class _Sphere {
14412
14525
  return this._initialized;
14413
14526
  }
14414
14527
  // ===========================================================================
14528
+ // Public Methods - Signing
14529
+ // ===========================================================================
14530
+ /**
14531
+ * Sign a plaintext message with the wallet's secp256k1 private key.
14532
+ *
14533
+ * Returns a 130-character hex string: v (2) + r (64) + s (64).
14534
+ * The private key never leaves the SDK boundary.
14535
+ *
14536
+ * @throws SphereError if the wallet is not initialized or identity is missing
14537
+ */
14538
+ signMessage(message) {
14539
+ if (!this._identity?.privateKey) {
14540
+ throw new SphereError("Wallet not initialized \u2014 cannot sign", "NOT_INITIALIZED");
14541
+ }
14542
+ return signMessage(this._identity.privateKey, message);
14543
+ }
14544
+ // ===========================================================================
14415
14545
  // Public Methods - Providers Access
14416
14546
  // ===========================================================================
14417
14547
  getStorage() {
@@ -17434,6 +17564,7 @@ function createPriceProvider(config) {
17434
17564
  NIP29_KINDS,
17435
17565
  NOSTR_EVENT_KINDS,
17436
17566
  PaymentsModule,
17567
+ SIGN_MESSAGE_PREFIX,
17437
17568
  STORAGE_KEYS,
17438
17569
  STORAGE_KEYS_ADDRESS,
17439
17570
  STORAGE_KEYS_GLOBAL,
@@ -17501,6 +17632,7 @@ function createPriceProvider(config) {
17501
17632
  hasValidTxfData,
17502
17633
  hash160,
17503
17634
  hashNametag,
17635
+ hashSignMessage,
17504
17636
  hexToBytes,
17505
17637
  identityFromMnemonicSync,
17506
17638
  initSphere,
@@ -17542,6 +17674,7 @@ function createPriceProvider(config) {
17542
17674
  randomUUID,
17543
17675
  ripemd160,
17544
17676
  sha256,
17677
+ signMessage,
17545
17678
  sleep,
17546
17679
  sphereExists,
17547
17680
  toHumanReadable,
@@ -17550,7 +17683,8 @@ function createPriceProvider(config) {
17550
17683
  tokenIdFromKey,
17551
17684
  tokenToTxf,
17552
17685
  txfToToken,
17553
- validateMnemonic
17686
+ validateMnemonic,
17687
+ verifySignedMessage
17554
17688
  });
17555
17689
  /*! Bundled license information:
17556
17690