@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.
@@ -773,6 +773,7 @@ __export(core_exports, {
773
773
  CurrencyUtils: () => CurrencyUtils,
774
774
  DEFAULT_DERIVATION_PATH: () => DEFAULT_DERIVATION_PATH2,
775
775
  DEFAULT_TOKEN_DECIMALS: () => DEFAULT_TOKEN_DECIMALS,
776
+ SIGN_MESSAGE_PREFIX: () => SIGN_MESSAGE_PREFIX,
776
777
  Sphere: () => Sphere,
777
778
  SphereError: () => SphereError,
778
779
  base58Decode: () => base58Decode,
@@ -815,6 +816,7 @@ __export(core_exports, {
815
816
  getSphere: () => getSphere,
816
817
  hash160: () => hash160,
817
818
  hash160ToBytes: () => hash160ToBytes,
819
+ hashSignMessage: () => hashSignMessage,
818
820
  hexToBytes: () => hexToBytes,
819
821
  identityFromMnemonic: () => identityFromMnemonic,
820
822
  identityFromMnemonicSync: () => identityFromMnemonicSync,
@@ -839,11 +841,13 @@ __export(core_exports, {
839
841
  scanAddressesImpl: () => scanAddressesImpl,
840
842
  serializeEncrypted: () => serializeEncrypted,
841
843
  sha256: () => sha256,
844
+ signMessage: () => signMessage,
842
845
  sleep: () => sleep,
843
846
  sphereExists: () => sphereExists,
844
847
  toHumanReadable: () => toHumanReadable,
845
848
  toSmallestUnit: () => toSmallestUnit,
846
- validateMnemonic: () => validateMnemonic2
849
+ validateMnemonic: () => validateMnemonic2,
850
+ verifySignedMessage: () => verifySignedMessage
847
851
  });
848
852
  module.exports = __toCommonJS(core_exports);
849
853
 
@@ -1053,6 +1057,73 @@ function generateAddressInfo(privateKey, index, path, prefix = "alpha") {
1053
1057
  index
1054
1058
  };
1055
1059
  }
1060
+ var SIGN_MESSAGE_PREFIX = "Sphere Signed Message:\n";
1061
+ function varint(n) {
1062
+ if (n < 253) return new Uint8Array([n]);
1063
+ const buf = new Uint8Array(3);
1064
+ buf[0] = 253;
1065
+ buf[1] = n & 255;
1066
+ buf[2] = n >> 8 & 255;
1067
+ return buf;
1068
+ }
1069
+ function hashSignMessage(message) {
1070
+ const prefix = new TextEncoder().encode(SIGN_MESSAGE_PREFIX);
1071
+ const msg = new TextEncoder().encode(message);
1072
+ const prefixLen = varint(prefix.length);
1073
+ const msgLen = varint(msg.length);
1074
+ const full = new Uint8Array(prefixLen.length + prefix.length + msgLen.length + msg.length);
1075
+ let off = 0;
1076
+ full.set(prefixLen, off);
1077
+ off += prefixLen.length;
1078
+ full.set(prefix, off);
1079
+ off += prefix.length;
1080
+ full.set(msgLen, off);
1081
+ off += msgLen.length;
1082
+ full.set(msg, off);
1083
+ const hex = Array.from(full).map((b) => b.toString(16).padStart(2, "0")).join("");
1084
+ const h1 = import_crypto_js2.default.SHA256(import_crypto_js2.default.enc.Hex.parse(hex)).toString();
1085
+ return import_crypto_js2.default.SHA256(import_crypto_js2.default.enc.Hex.parse(h1)).toString();
1086
+ }
1087
+ function signMessage(privateKeyHex, message) {
1088
+ const keyPair = ec.keyFromPrivate(privateKeyHex, "hex");
1089
+ const hashHex = hashSignMessage(message);
1090
+ const hashBytes = Buffer.from(hashHex, "hex");
1091
+ const sig = keyPair.sign(hashBytes, { canonical: true });
1092
+ const pub = keyPair.getPublic();
1093
+ let recoveryParam = -1;
1094
+ for (let i = 0; i < 4; i++) {
1095
+ try {
1096
+ if (ec.recoverPubKey(hashBytes, sig, i).eq(pub)) {
1097
+ recoveryParam = i;
1098
+ break;
1099
+ }
1100
+ } catch {
1101
+ }
1102
+ }
1103
+ if (recoveryParam === -1) {
1104
+ throw new SphereError("Could not find recovery parameter", "SIGNING_ERROR");
1105
+ }
1106
+ const v = (31 + recoveryParam).toString(16).padStart(2, "0");
1107
+ const r = sig.r.toString("hex").padStart(64, "0");
1108
+ const s = sig.s.toString("hex").padStart(64, "0");
1109
+ return v + r + s;
1110
+ }
1111
+ function verifySignedMessage(message, signature, expectedPubkey) {
1112
+ if (signature.length !== 130) return false;
1113
+ const v = parseInt(signature.slice(0, 2), 16) - 31;
1114
+ const r = signature.slice(2, 66);
1115
+ const s = signature.slice(66, 130);
1116
+ if (v < 0 || v > 3) return false;
1117
+ const hashHex = hashSignMessage(message);
1118
+ const hashBytes = Buffer.from(hashHex, "hex");
1119
+ try {
1120
+ const recovered = ec.recoverPubKey(hashBytes, { r, s }, v);
1121
+ const recoveredHex = recovered.encode("hex", true);
1122
+ return recoveredHex === expectedPubkey;
1123
+ } catch {
1124
+ return false;
1125
+ }
1126
+ }
1056
1127
 
1057
1128
  // l1/crypto.ts
1058
1129
  var import_crypto_js3 = __toESM(require("crypto-js"), 1);
@@ -8983,13 +9054,16 @@ var GroupChatModule = class {
8983
9054
  logger.error("GroupChat", "Max reconnection attempts reached");
8984
9055
  return;
8985
9056
  }
9057
+ const maxDelay = this.config.reconnectDelayMs * 16;
9058
+ const delay = Math.min(this.config.reconnectDelayMs * Math.pow(2, this.reconnectAttempts), maxDelay);
8986
9059
  this.reconnectAttempts++;
9060
+ logger.debug("GroupChat", `Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.config.maxReconnectAttempts})`);
8987
9061
  this.reconnectTimer = setTimeout(() => {
8988
9062
  this.reconnectTimer = null;
8989
9063
  if (this.deps) {
8990
9064
  this.connect().catch((err) => logger.error("GroupChat", "Reconnect failed:", err));
8991
9065
  }
8992
- }, this.config.reconnectDelayMs);
9066
+ }, delay);
8993
9067
  }
8994
9068
  // ===========================================================================
8995
9069
  // Subscription Management
@@ -12326,6 +12400,7 @@ var secp256k1 = /* @__PURE__ */ ecdsa(Pointk1, sha2564);
12326
12400
 
12327
12401
  // modules/market/MarketModule.ts
12328
12402
  init_errors();
12403
+ init_logger();
12329
12404
  var DEFAULT_MARKET_API_URL = "https://market-api.unicity.network";
12330
12405
  function hexToBytes3(hex) {
12331
12406
  const len = hex.length >> 1;
@@ -12498,16 +12573,54 @@ var MarketModule = class {
12498
12573
  */
12499
12574
  subscribeFeed(listener) {
12500
12575
  const wsUrl = this.apiUrl.replace(/^http/, "ws") + "/ws/feed";
12501
- const ws2 = new WebSocket(wsUrl);
12502
- ws2.onmessage = (event) => {
12503
- try {
12504
- const raw = JSON.parse(typeof event.data === "string" ? event.data : event.data.toString());
12505
- listener(mapFeedMessage(raw));
12506
- } catch {
12576
+ const BASE_DELAY2 = 2e3;
12577
+ const MAX_DELAY2 = 3e4;
12578
+ const MAX_ATTEMPTS = 10;
12579
+ let ws2 = null;
12580
+ let reconnectAttempts2 = 0;
12581
+ let reconnectTimer = null;
12582
+ let destroyed = false;
12583
+ function connect2() {
12584
+ if (destroyed) return;
12585
+ ws2 = new WebSocket(wsUrl);
12586
+ ws2.onopen = () => {
12587
+ reconnectAttempts2 = 0;
12588
+ logger.debug("Market", "Feed WebSocket connected");
12589
+ };
12590
+ ws2.onmessage = (event) => {
12591
+ try {
12592
+ const raw = JSON.parse(typeof event.data === "string" ? event.data : event.data.toString());
12593
+ listener(mapFeedMessage(raw));
12594
+ } catch {
12595
+ }
12596
+ };
12597
+ ws2.onclose = () => {
12598
+ if (destroyed) return;
12599
+ scheduleReconnect();
12600
+ };
12601
+ ws2.onerror = () => {
12602
+ };
12603
+ }
12604
+ function scheduleReconnect() {
12605
+ if (destroyed) return;
12606
+ if (reconnectAttempts2 >= MAX_ATTEMPTS) {
12607
+ logger.warn("Market", `Feed WebSocket: gave up after ${MAX_ATTEMPTS} reconnect attempts`);
12608
+ return;
12507
12609
  }
12508
- };
12610
+ const delay = Math.min(BASE_DELAY2 * Math.pow(2, reconnectAttempts2), MAX_DELAY2);
12611
+ reconnectAttempts2++;
12612
+ logger.debug("Market", `Feed WebSocket reconnecting in ${delay}ms (attempt ${reconnectAttempts2}/${MAX_ATTEMPTS})`);
12613
+ reconnectTimer = setTimeout(connect2, delay);
12614
+ }
12615
+ connect2();
12509
12616
  return () => {
12510
- ws2.close();
12617
+ destroyed = true;
12618
+ if (reconnectTimer) {
12619
+ clearTimeout(reconnectTimer);
12620
+ reconnectTimer = null;
12621
+ }
12622
+ ws2?.close();
12623
+ ws2 = null;
12511
12624
  };
12512
12625
  }
12513
12626
  // ---------------------------------------------------------------------------
@@ -14136,6 +14249,23 @@ var Sphere = class _Sphere {
14136
14249
  return this._initialized;
14137
14250
  }
14138
14251
  // ===========================================================================
14252
+ // Public Methods - Signing
14253
+ // ===========================================================================
14254
+ /**
14255
+ * Sign a plaintext message with the wallet's secp256k1 private key.
14256
+ *
14257
+ * Returns a 130-character hex string: v (2) + r (64) + s (64).
14258
+ * The private key never leaves the SDK boundary.
14259
+ *
14260
+ * @throws SphereError if the wallet is not initialized or identity is missing
14261
+ */
14262
+ signMessage(message) {
14263
+ if (!this._identity?.privateKey) {
14264
+ throw new SphereError("Wallet not initialized \u2014 cannot sign", "NOT_INITIALIZED");
14265
+ }
14266
+ return signMessage(this._identity.privateKey, message);
14267
+ }
14268
+ // ===========================================================================
14139
14269
  // Public Methods - Providers Access
14140
14270
  // ===========================================================================
14141
14271
  getStorage() {
@@ -16500,6 +16630,7 @@ async function runCustomCheck(name, checkFn, timeoutMs) {
16500
16630
  CurrencyUtils,
16501
16631
  DEFAULT_DERIVATION_PATH,
16502
16632
  DEFAULT_TOKEN_DECIMALS,
16633
+ SIGN_MESSAGE_PREFIX,
16503
16634
  Sphere,
16504
16635
  SphereError,
16505
16636
  base58Decode,
@@ -16542,6 +16673,7 @@ async function runCustomCheck(name, checkFn, timeoutMs) {
16542
16673
  getSphere,
16543
16674
  hash160,
16544
16675
  hash160ToBytes,
16676
+ hashSignMessage,
16545
16677
  hexToBytes,
16546
16678
  identityFromMnemonic,
16547
16679
  identityFromMnemonicSync,
@@ -16566,11 +16698,13 @@ async function runCustomCheck(name, checkFn, timeoutMs) {
16566
16698
  scanAddressesImpl,
16567
16699
  serializeEncrypted,
16568
16700
  sha256,
16701
+ signMessage,
16569
16702
  sleep,
16570
16703
  sphereExists,
16571
16704
  toHumanReadable,
16572
16705
  toSmallestUnit,
16573
- validateMnemonic
16706
+ validateMnemonic,
16707
+ verifySignedMessage
16574
16708
  });
16575
16709
  /*! Bundled license information:
16576
16710