@weblock-wallet/sdk 0.1.66 → 0.1.68

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.js CHANGED
@@ -1733,11 +1733,11 @@ var storage = localforage.createInstance({
1733
1733
  description: "WeBlock Wallet SDK Secure Storage"
1734
1734
  });
1735
1735
  var LocalForage = {
1736
- async save(key, value, expiry) {
1736
+ async save(key, value, expiryEpochMs) {
1737
1737
  try {
1738
1738
  const item = {
1739
1739
  value,
1740
- expiry
1740
+ expiryEpochMs
1741
1741
  };
1742
1742
  await storage.setItem(key, item);
1743
1743
  } catch (err) {
@@ -1747,10 +1747,8 @@ var LocalForage = {
1747
1747
  async get(key) {
1748
1748
  try {
1749
1749
  const item = await storage.getItem(key);
1750
- if (!item) {
1751
- return null;
1752
- }
1753
- if (item.expiry && Date.now() > item.expiry * 1e3) {
1750
+ if (!item) return null;
1751
+ if (item.expiryEpochMs && Date.now() > item.expiryEpochMs) {
1754
1752
  await storage.removeItem(key);
1755
1753
  return null;
1756
1754
  }
@@ -1893,26 +1891,6 @@ var AuthService = class {
1893
1891
  import { Wallet, Interface, Transaction as EthersTx } from "ethers";
1894
1892
  import { generateMnemonic, mnemonicToSeed } from "bip39";
1895
1893
 
1896
- // src/utils/secrets.ts
1897
- import { split, combine } from "shamir-secret-sharing";
1898
- var Secrets = {
1899
- async split(secret, total, threshold) {
1900
- if (secret.startsWith("0x")) {
1901
- secret = secret.substring(2);
1902
- }
1903
- const array = await split(
1904
- new Uint8Array(Buffer.from(secret, "hex")),
1905
- total,
1906
- threshold
1907
- );
1908
- return array.map((item) => Buffer.from(item).toString("hex"));
1909
- },
1910
- async combine(shares) {
1911
- const array = shares.map((item) => new Uint8Array(Buffer.from(item, "hex")));
1912
- return `0x${Buffer.from(await combine(array)).toString("hex")}`;
1913
- }
1914
- };
1915
-
1916
1894
  // node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/chunk-CcCWfKp1.js
1917
1895
  var exports$22 = {};
1918
1896
  var _dewExec$12 = false;
@@ -103928,6 +103906,26 @@ var webcrypto = exports11.webcrypto;
103928
103906
  var getRandomValues = exports11.getRandomValues;
103929
103907
  var randomUUID = exports11.randomUUID;
103930
103908
 
103909
+ // src/utils/secrets.ts
103910
+ import { split, combine } from "shamir-secret-sharing";
103911
+ var Secrets = {
103912
+ async split(secret, total, threshold) {
103913
+ if (secret.startsWith("0x")) {
103914
+ secret = secret.substring(2);
103915
+ }
103916
+ const array = await split(
103917
+ new Uint8Array(Buffer.from(secret, "hex")),
103918
+ total,
103919
+ threshold
103920
+ );
103921
+ return array.map((item) => Buffer.from(item).toString("hex"));
103922
+ },
103923
+ async combine(shares) {
103924
+ const array = shares.map((item) => new Uint8Array(Buffer.from(item, "hex")));
103925
+ return `0x${Buffer.from(await combine(array)).toString("hex")}`;
103926
+ }
103927
+ };
103928
+
103931
103929
  // src/utils/crypto.ts
103932
103930
  import * as ed from "@noble/ed25519";
103933
103931
  function urlEncode(pemKey) {
@@ -103975,6 +103973,65 @@ var Crypto = {
103975
103973
  }
103976
103974
  };
103977
103975
 
103976
+ // src/utils/numbers.ts
103977
+ import { parseUnits, formatUnits } from "ethers";
103978
+ var TokenAmount = class {
103979
+ /**
103980
+ * Wei 단위의 값을 사용자가 읽을 수 있는 형태로 변환
103981
+ * @param value - Wei 단위의 값 (hex string 또는 decimal string)
103982
+ * @param decimals - 토큰의 소수점 자리수
103983
+ * @returns 변환된 문자열
103984
+ */
103985
+ static fromWei(value, decimals) {
103986
+ try {
103987
+ return formatUnits(value, decimals);
103988
+ } catch (error) {
103989
+ console.error("Error converting from wei:", error);
103990
+ return "0.0";
103991
+ }
103992
+ }
103993
+ /**
103994
+ * 사용자 입력값을 Wei 단위로 변환
103995
+ * @param value - 사용자 입력값 (예: "1.5")
103996
+ * @param decimals - 토큰의 소수점 자리수
103997
+ * @returns Wei 단위의 값
103998
+ */
103999
+ static toWei(value, decimals) {
104000
+ try {
104001
+ return parseUnits(value, decimals).toString();
104002
+ } catch (error) {
104003
+ console.error("Error converting to wei:", error);
104004
+ return "0";
104005
+ }
104006
+ }
104007
+ /**
104008
+ * 표시용 포맷으로 변환
104009
+ * @param value - Wei 단위의 값
104010
+ * @param decimals - 토큰의 소수점 자리수
104011
+ * @param maxDecimals - 최대 표시할 소수점 자리수 (기본값: 4)
104012
+ * @returns 포맷된 문자열
104013
+ */
104014
+ static format(value, decimals, maxDecimals = 4) {
104015
+ const fullNumber = this.fromWei(value, decimals);
104016
+ const [beforeDecimal, afterDecimal = ""] = fullNumber.split(".");
104017
+ return `${beforeDecimal}.${afterDecimal.slice(0, maxDecimals)}`;
104018
+ }
104019
+ /**
104020
+ * 값이 유효한지 검증
104021
+ * @param value - 검증할 값
104022
+ * @returns 유효성 여부
104023
+ */
104024
+ static isValid(value) {
104025
+ return /^\d*\.?\d*$/.test(value) && value !== "";
104026
+ }
104027
+ };
104028
+ var DECIMALS = {
104029
+ ETH: 18,
104030
+ USDC: 6,
104031
+ USDT: 6,
104032
+ DAI: 18
104033
+ };
104034
+
103978
104035
  // src/types/error.ts
103979
104036
  var SDKErrorCode = /* @__PURE__ */ ((SDKErrorCode2) => {
103980
104037
  SDKErrorCode2["NOT_INITIALIZED"] = "NOT_INITIALIZED";
@@ -104043,65 +104100,6 @@ var SignInStatus = /* @__PURE__ */ ((SignInStatus2) => {
104043
104100
  return SignInStatus2;
104044
104101
  })(SignInStatus || {});
104045
104102
 
104046
- // src/utils/numbers.ts
104047
- import { parseUnits, formatUnits } from "ethers";
104048
- var TokenAmount = class {
104049
- /**
104050
- * Wei 단위의 값을 사용자가 읽을 수 있는 형태로 변환
104051
- * @param value - Wei 단위의 값 (hex string 또는 decimal string)
104052
- * @param decimals - 토큰의 소수점 자리수
104053
- * @returns 변환된 문자열
104054
- */
104055
- static fromWei(value, decimals) {
104056
- try {
104057
- return formatUnits(value, decimals);
104058
- } catch (error) {
104059
- console.error("Error converting from wei:", error);
104060
- return "0.0";
104061
- }
104062
- }
104063
- /**
104064
- * 사용자 입력값을 Wei 단위로 변환
104065
- * @param value - 사용자 입력값 (예: "1.5")
104066
- * @param decimals - 토큰의 소수점 자리수
104067
- * @returns Wei 단위의 값
104068
- */
104069
- static toWei(value, decimals) {
104070
- try {
104071
- return parseUnits(value, decimals).toString();
104072
- } catch (error) {
104073
- console.error("Error converting to wei:", error);
104074
- return "0";
104075
- }
104076
- }
104077
- /**
104078
- * 표시용 포맷으로 변환
104079
- * @param value - Wei 단위의 값
104080
- * @param decimals - 토큰의 소수점 자리수
104081
- * @param maxDecimals - 최대 표시할 소수점 자리수 (기본값: 4)
104082
- * @returns 포맷된 문자열
104083
- */
104084
- static format(value, decimals, maxDecimals = 4) {
104085
- const fullNumber = this.fromWei(value, decimals);
104086
- const [beforeDecimal, afterDecimal = ""] = fullNumber.split(".");
104087
- return `${beforeDecimal}.${afterDecimal.slice(0, maxDecimals)}`;
104088
- }
104089
- /**
104090
- * 값이 유효한지 검증
104091
- * @param value - 검증할 값
104092
- * @returns 유효성 여부
104093
- */
104094
- static isValid(value) {
104095
- return /^\d*\.?\d*$/.test(value) && value !== "";
104096
- }
104097
- };
104098
- var DECIMALS = {
104099
- ETH: 18,
104100
- USDC: 6,
104101
- USDT: 6,
104102
- DAI: 18
104103
- };
104104
-
104105
104103
  // src/core/services/wallet.ts
104106
104104
  var ERC20_ABI = [
104107
104105
  "function balanceOf(address owner) view returns (uint256)",
@@ -104127,7 +104125,7 @@ var WalletService = class {
104127
104125
  this.walletAddress = null;
104128
104126
  }
104129
104127
  /**
104130
- * Wallet PIN/password mismatch handling.
104128
+ * Password/PIN mismatch detection for decrypt errors.
104131
104129
  */
104132
104130
  isInvalidPasswordError(error) {
104133
104131
  if (!error) return false;
@@ -104146,9 +104144,8 @@ var WalletService = class {
104146
104144
  return /^[0-9]{6}$/.test(pin);
104147
104145
  }
104148
104146
  /**
104149
- * deviceSecret "PIN과 무관한 로컬 복구용 비밀값"입니다.
104150
- * - 같은 디바이스에서만 PIN reset이 가능하도록 하는 역할
104151
- * - 서버에는 절대 전달하지 않습니다.
104147
+ * deviceSecret: local-only secret for device recovery material.
104148
+ * This must never be sent to server.
104152
104149
  */
104153
104150
  async getOrCreateDeviceSecret() {
104154
104151
  const key = STORAGE_KEYS.deviceSecret(this.orgHost);
@@ -104158,19 +104155,20 @@ var WalletService = class {
104158
104155
  await LocalForage.save(key, secret);
104159
104156
  return secret;
104160
104157
  }
104158
+ /**
104159
+ * PATCH APPLIED:
104160
+ * Always overwrite encryptedShare2_device when we have a fresh share2.
104161
+ * Keeping an old device share causes (share1 new + share2 old) => different derived wallet.
104162
+ */
104161
104163
  async ensureDeviceEncryptedShare2(share2Plain, firebaseId) {
104162
104164
  const encryptedKey = STORAGE_KEYS.encryptedShare2Device(this.orgHost);
104163
- const existing = await LocalForage.get(encryptedKey);
104164
- if (existing) return;
104165
104165
  const deviceSecret = await this.getOrCreateDeviceSecret();
104166
104166
  const encrypted = Crypto.encryptShare(share2Plain, deviceSecret, firebaseId);
104167
104167
  await LocalForage.save(encryptedKey, encrypted);
104168
104168
  }
104169
104169
  async getAddress() {
104170
104170
  try {
104171
- if (this.walletAddress) {
104172
- return this.walletAddress;
104173
- }
104171
+ if (this.walletAddress) return this.walletAddress;
104174
104172
  const savedAddress = await LocalForage.get(
104175
104173
  STORAGE_KEYS.walletAddress(this.orgHost)
104176
104174
  );
@@ -104201,7 +104199,6 @@ var WalletService = class {
104201
104199
  const firebaseId = await LocalForage.get(
104202
104200
  STORAGE_KEYS.firebaseId(this.orgHost)
104203
104201
  );
104204
- console.log("1. FirebaseId:", firebaseId);
104205
104202
  if (!firebaseId) {
104206
104203
  throw new SDKError("Not logged in", "AUTH_REQUIRED" /* AUTH_REQUIRED */);
104207
104204
  }
@@ -104223,27 +104220,18 @@ var WalletService = class {
104223
104220
  "WALLET_ALREADY_EXISTS" /* WALLET_ALREADY_EXISTS */
104224
104221
  );
104225
104222
  }
104226
- console.log("2. Generating wallet...");
104227
104223
  const mnemonic = generateMnemonic();
104228
104224
  const seed = await mnemonicToSeed(mnemonic);
104229
104225
  const wallet = new Wallet(seed.slice(0, 32).toString("hex"));
104230
- console.log("3. Wallet created:", {
104231
- address: wallet.address,
104232
- publicKey: wallet.signingKey.publicKey
104233
- });
104234
- console.log("4. Splitting private key...");
104235
104226
  const shares = await Secrets.split(wallet.privateKey, 3, 2);
104236
104227
  const [share1, share2, share3] = shares;
104237
- console.log("6. Encrypting shares...");
104238
104228
  const encryptedShare2 = Crypto.encryptShare(share2, password, firebaseId);
104239
104229
  const encryptedShare3 = Crypto.encryptShare(share3, password, firebaseId);
104240
- console.log("8. Saving encryptedShare2 to LocalForage...");
104241
104230
  await LocalForage.save(
104242
104231
  STORAGE_KEYS.encryptedShare2(this.orgHost),
104243
104232
  encryptedShare2
104244
104233
  );
104245
104234
  await this.ensureDeviceEncryptedShare2(share2, firebaseId);
104246
- console.log("10. Creating wallet on server...");
104247
104235
  await this.walletClient.createWallet({
104248
104236
  address: wallet.address,
104249
104237
  publicKey: wallet.signingKey.publicKey,
@@ -104257,7 +104245,6 @@ var WalletService = class {
104257
104245
  );
104258
104246
  return wallet.address;
104259
104247
  } catch (error) {
104260
- console.error("Error in create wallet:", error);
104261
104248
  if (error instanceof SDKError) throw error;
104262
104249
  throw new SDKError(
104263
104250
  "Failed to create wallet",
@@ -104312,8 +104299,13 @@ var WalletService = class {
104312
104299
  share2 = decryptShareOrThrow(encryptedShare2);
104313
104300
  await LocalForage.save(STORAGE_KEYS.share2(this.orgHost), share2);
104314
104301
  } else {
104315
- const share3 = decryptShareOrThrow(walletInfo.encryptedShare3);
104316
- const privateKey2 = await Secrets.combine([walletInfo.share1, share3]);
104302
+ const share3 = decryptShareOrThrow(
104303
+ walletInfo.encryptedShare3
104304
+ );
104305
+ const privateKey2 = await Secrets.combine([
104306
+ walletInfo.share1,
104307
+ share3
104308
+ ]);
104317
104309
  const wallet2 = new Wallet(privateKey2);
104318
104310
  const newShares = await Secrets.split(wallet2.privateKey, 3, 2);
104319
104311
  const [newShare1, newShare2, newShare3] = newShares;
@@ -104340,7 +104332,10 @@ var WalletService = class {
104340
104332
  return wallet2.address;
104341
104333
  }
104342
104334
  }
104343
- const privateKey = await Secrets.combine([walletInfo.share1, share2]);
104335
+ const privateKey = await Secrets.combine([
104336
+ walletInfo.share1,
104337
+ share2
104338
+ ]);
104344
104339
  const wallet = new Wallet(privateKey);
104345
104340
  await this.ensureDeviceEncryptedShare2(share2, firebaseId);
104346
104341
  this.walletAddress = wallet.address;
@@ -104353,7 +104348,6 @@ var WalletService = class {
104353
104348
  } catch (error) {
104354
104349
  this.walletAddress = null;
104355
104350
  await LocalForage.delete(STORAGE_KEYS.share2(this.orgHost));
104356
- console.error("Error in retrieveWallet:", error);
104357
104351
  if (error instanceof SDKError) throw error;
104358
104352
  throw new SDKError(
104359
104353
  "Failed to retrieve wallet",
@@ -104363,9 +104357,7 @@ var WalletService = class {
104363
104357
  }
104364
104358
  }
104365
104359
  /**
104366
- * NEW: PIN reset (프라이빗키/주소 유지)
104367
- * - 같은 디바이스에 남아있는 encryptedShare2_device를 이용
104368
- * - 서버는 PATCH /v1/wallets/keys 로 share1 / encryptedShare3 만 업데이트
104360
+ * PIN reset (same private key/address) using encryptedShare2_device.
104369
104361
  */
104370
104362
  async resetPin(newPassword) {
104371
104363
  try {
@@ -104390,16 +104382,10 @@ var WalletService = class {
104390
104382
  const encryptedDevice = await LocalForage.get(
104391
104383
  STORAGE_KEYS.encryptedShare2Device(this.orgHost)
104392
104384
  );
104393
- if (!encryptedDevice) {
104394
- throw new SDKError(
104395
- "PIN reset is not available on this device",
104396
- "RECOVERY_NOT_AVAILABLE" /* RECOVERY_NOT_AVAILABLE */
104397
- );
104398
- }
104399
104385
  const deviceSecret = await LocalForage.get(
104400
104386
  STORAGE_KEYS.deviceSecret(this.orgHost)
104401
104387
  );
104402
- if (!deviceSecret) {
104388
+ if (!encryptedDevice || !deviceSecret) {
104403
104389
  throw new SDKError(
104404
104390
  "PIN reset is not available on this device",
104405
104391
  "RECOVERY_NOT_AVAILABLE" /* RECOVERY_NOT_AVAILABLE */
@@ -104416,7 +104402,10 @@ var WalletService = class {
104416
104402
  );
104417
104403
  }
104418
104404
  const walletInfo = await this.walletClient.getWallet();
104419
- const privateKey = await Secrets.combine([walletInfo.share1, share2]);
104405
+ const privateKey = await Secrets.combine([
104406
+ walletInfo.share1,
104407
+ share2
104408
+ ]);
104420
104409
  const wallet = new Wallet(privateKey);
104421
104410
  const newShares = await Secrets.split(wallet.privateKey, 3, 2);
104422
104411
  const [newShare1, newShare2, newShare3] = newShares;
@@ -104432,15 +104421,7 @@ var WalletService = class {
104432
104421
  STORAGE_KEYS.encryptedShare2(this.orgHost),
104433
104422
  Crypto.encryptShare(newShare2, newPassword, firebaseId)
104434
104423
  );
104435
- const newEncryptedDevice = Crypto.encryptShare(
104436
- newShare2,
104437
- deviceSecret,
104438
- firebaseId
104439
- );
104440
- await LocalForage.save(
104441
- STORAGE_KEYS.encryptedShare2Device(this.orgHost),
104442
- newEncryptedDevice
104443
- );
104424
+ await this.ensureDeviceEncryptedShare2(newShare2, firebaseId);
104444
104425
  this.walletAddress = wallet.address;
104445
104426
  await LocalForage.save(
104446
104427
  STORAGE_KEYS.walletAddress(this.orgHost),
@@ -104449,7 +104430,6 @@ var WalletService = class {
104449
104430
  await LocalForage.delete(STORAGE_KEYS.share2(this.orgHost));
104450
104431
  return wallet.address;
104451
104432
  } catch (error) {
104452
- console.error("Error in resetPin:", error);
104453
104433
  if (error instanceof SDKError) throw error;
104454
104434
  throw new SDKError(
104455
104435
  "Failed to reset PIN",
@@ -104487,38 +104467,20 @@ var WalletService = class {
104487
104467
  const rawBalance = await this.rpcClient.sendRpc({
104488
104468
  chainId,
104489
104469
  method: "eth_call" /* ETH_CALL */,
104490
- params: [
104491
- {
104492
- to: tokenAddress,
104493
- data
104494
- },
104495
- "latest"
104496
- ]
104470
+ params: [{ to: tokenAddress, data }, "latest"]
104497
104471
  });
104498
104472
  const decimalsData = erc20.encodeFunctionData("decimals", []);
104499
104473
  const decimalsRes = await this.rpcClient.sendRpc({
104500
104474
  chainId,
104501
104475
  method: "eth_call" /* ETH_CALL */,
104502
- params: [
104503
- {
104504
- to: tokenAddress,
104505
- data: decimalsData
104506
- },
104507
- "latest"
104508
- ]
104476
+ params: [{ to: tokenAddress, data: decimalsData }, "latest"]
104509
104477
  });
104510
104478
  const decimals = parseInt(decimalsRes.result, 16);
104511
104479
  const symbolData = erc20.encodeFunctionData("symbol", []);
104512
104480
  const symbolRes = await this.rpcClient.sendRpc({
104513
104481
  chainId,
104514
104482
  method: "eth_call" /* ETH_CALL */,
104515
- params: [
104516
- {
104517
- to: tokenAddress,
104518
- data: symbolData
104519
- },
104520
- "latest"
104521
- ]
104483
+ params: [{ to: tokenAddress, data: symbolData }, "latest"]
104522
104484
  });
104523
104485
  const symbol = erc20.decodeFunctionResult("symbol", symbolRes.result)[0];
104524
104486
  return {
@@ -104607,34 +104569,36 @@ var WalletService = class {
104607
104569
  method: "eth_getTransactionCount" /* ETH_GET_TRANSACTION_COUNT */,
104608
104570
  params: [address, "latest"]
104609
104571
  });
104610
- if (!nonce.result || nonce.result === "0x0") {
104611
- return void 0;
104612
- }
104572
+ if (!nonce.result || nonce.result === "0x0") return void 0;
104613
104573
  return {
104614
104574
  hash: "",
104615
104575
  status: "SUCCESS" /* SUCCESS */,
104616
104576
  timestamp: Date.now(),
104617
104577
  value: "0"
104618
104578
  };
104619
- } catch (error) {
104620
- console.error("Failed to get latest transaction:", error);
104579
+ } catch {
104621
104580
  return void 0;
104622
104581
  }
104623
104582
  }
104583
+ /**
104584
+ * PATCH APPLIED (critical):
104585
+ * - Never overwrite cached walletAddress with derived signer address.
104586
+ * - If server/cached address != derived address => throw WALLET_RECOVERY_FAILED.
104587
+ */
104624
104588
  async sendTransaction(params) {
104589
+ const toHexQuantity = (v5) => {
104590
+ if (v5 === void 0 || v5 === null) return "0x0";
104591
+ const s5 = String(v5).trim();
104592
+ if (!s5) return "0x0";
104593
+ if (s5.startsWith("0x") || s5.startsWith("0X")) return s5;
104594
+ try {
104595
+ const bi = BigInt(s5);
104596
+ return "0x" + bi.toString(16);
104597
+ } catch {
104598
+ return s5;
104599
+ }
104600
+ };
104625
104601
  try {
104626
- const toHexQuantity = (v5) => {
104627
- if (v5 === void 0 || v5 === null) return "0x0";
104628
- const s5 = String(v5).trim();
104629
- if (!s5) return "0x0";
104630
- if (s5.startsWith("0x") || s5.startsWith("0X")) return s5;
104631
- try {
104632
- const bi = BigInt(s5);
104633
- return "0x" + bi.toString(16);
104634
- } catch {
104635
- return s5;
104636
- }
104637
- };
104638
104602
  const walletInfo = await this.walletClient.getWallet();
104639
104603
  const share1 = walletInfo?.share1;
104640
104604
  let share2 = await LocalForage.get(
@@ -104671,25 +104635,25 @@ var WalletService = class {
104671
104635
  const privateKey = await Secrets.combine([share1, share2]);
104672
104636
  const wallet = new Wallet(privateKey);
104673
104637
  const from = wallet.address;
104674
- const cachedAddress = await LocalForage.get(
104675
- STORAGE_KEYS.walletAddress(this.orgHost)
104676
- );
104677
- if (cachedAddress && cachedAddress.toLowerCase() !== from.toLowerCase()) {
104678
- console.warn(
104679
- "[WalletService] walletAddress mismatch detected. cached=",
104680
- cachedAddress,
104681
- "derived=",
104682
- from
104638
+ const serverAddress = String(walletInfo?.address ?? "").trim();
104639
+ const cachedAddress = String(
104640
+ await LocalForage.get(
104641
+ STORAGE_KEYS.walletAddress(this.orgHost)
104642
+ ) ?? ""
104643
+ ).trim();
104644
+ const mismatch = (a5, b4) => a5 && b4 && a5.toLowerCase() !== b4.toLowerCase();
104645
+ if (mismatch(serverAddress, from) || mismatch(cachedAddress, from)) {
104646
+ throw new SDKError(
104647
+ `Wallet share mismatch detected. server=${serverAddress || "N/A"} cached=${cachedAddress || "N/A"} derived=${from}. Please re-enter PIN (retrieveWallet/resetPin) to refresh shares.`,
104648
+ "WALLET_RECOVERY_FAILED" /* WALLET_RECOVERY_FAILED */
104683
104649
  );
104684
- this.walletAddress = from;
104685
- await LocalForage.save(STORAGE_KEYS.walletAddress(this.orgHost), from);
104686
104650
  }
104687
104651
  const nativeBal = await this.rpcClient.sendRpc({
104688
104652
  chainId: params.chainId,
104689
104653
  method: "eth_getBalance" /* ETH_GET_BALANCE */,
104690
104654
  params: [from, "latest"]
104691
104655
  });
104692
- if (!nativeBal?.result || BigInt(nativeBal.result) === BigInt(0)) {
104656
+ if (!nativeBal?.result || BigInt(nativeBal.result) === 0n) {
104693
104657
  throw new SDKError(
104694
104658
  `Insufficient native balance for gas. sender=${from} balance=${nativeBal?.result ?? "0x0"}`,
104695
104659
  "TRANSACTION_FAILED" /* TRANSACTION_FAILED */
@@ -104725,17 +104689,16 @@ var WalletService = class {
104725
104689
  );
104726
104690
  const buffered = Math.max(21e3, Math.ceil(est * 1.2));
104727
104691
  gasLimit = "0x" + buffered.toString(16);
104728
- } catch (e7) {
104692
+ } catch {
104729
104693
  const data = (params.data || "0x").toLowerCase();
104730
104694
  const isApprove = data.startsWith("0x095ea7b3");
104731
104695
  const fallback = isApprove ? 12e4 : data !== "0x" ? 8e5 : 21e3;
104732
104696
  gasLimit = "0x" + fallback.toString(16);
104733
104697
  }
104734
104698
  }
104735
- const value = params.value ?? "0";
104736
104699
  const signedTx = await wallet.signTransaction({
104737
104700
  to: params.to,
104738
- value,
104701
+ value: params.value ?? "0",
104739
104702
  data: params.data || "0x",
104740
104703
  chainId: params.chainId,
104741
104704
  nonce,
@@ -104746,12 +104709,10 @@ var WalletService = class {
104746
104709
  const parsed = EthersTx.from(signedTx);
104747
104710
  const derivedFrom = parsed?.from;
104748
104711
  if (derivedFrom && String(derivedFrom).toLowerCase() !== from.toLowerCase()) {
104749
- console.warn(
104750
- "[WalletService] signedTx sender mismatch. wallet=",
104751
- from,
104752
- "txFrom=",
104753
- derivedFrom
104754
- );
104712
+ console.warn("[WalletService] signedTx sender mismatch.", {
104713
+ walletFrom: from,
104714
+ txFrom: derivedFrom
104715
+ });
104755
104716
  }
104756
104717
  } catch {
104757
104718
  }
@@ -104759,9 +104720,8 @@ var WalletService = class {
104759
104720
  await LocalForage.delete(STORAGE_KEYS.share2(this.orgHost));
104760
104721
  return txHash;
104761
104722
  } catch (error) {
104762
- if (error instanceof SDKError) {
104763
- throw error;
104764
- }
104723
+ await LocalForage.delete(STORAGE_KEYS.share2(this.orgHost));
104724
+ if (error instanceof SDKError) throw error;
104765
104725
  const msg = (() => {
104766
104726
  try {
104767
104727
  const anyErr = error;
@@ -104910,10 +104870,26 @@ var HttpClient = class {
104910
104870
  if (!accessToken) {
104911
104871
  throw new SDKError("No access token found", "AUTH_REQUIRED" /* AUTH_REQUIRED */);
104912
104872
  }
104873
+ ;
104913
104874
  headers["Authorization"] = `Bearer ${accessToken}`;
104914
104875
  }
104915
104876
  return headers;
104916
104877
  }
104878
+ async safeReadErrorDetails(response) {
104879
+ const contentType = response.headers.get("content-type") || "";
104880
+ try {
104881
+ if (contentType.includes("application/json")) {
104882
+ return await response.json();
104883
+ }
104884
+ } catch {
104885
+ }
104886
+ try {
104887
+ const text = await response.text();
104888
+ return text || void 0;
104889
+ } catch {
104890
+ return void 0;
104891
+ }
104892
+ }
104917
104893
  async request(method, path, data, config2 = {}) {
104918
104894
  const headers = await this.getHeaders(config2.needsAccessToken);
104919
104895
  const requestInit = {
@@ -104924,20 +104900,28 @@ var HttpClient = class {
104924
104900
  },
104925
104901
  credentials: config2.credentials
104926
104902
  };
104927
- if (data) {
104903
+ if (data !== void 0) {
104928
104904
  requestInit.body = JSON.stringify(data);
104929
104905
  }
104930
104906
  const response = await fetch(`${this.baseUrl}${path}`, requestInit);
104931
104907
  if (!response.ok) {
104908
+ if (config2.needsAccessToken && (response.status === 401 || response.status === 403)) {
104909
+ await LocalForage.delete(`${this.orgHost}:accessToken`);
104910
+ throw new SDKError(
104911
+ `Authentication required (status: ${response.status})`,
104912
+ "AUTH_REQUIRED" /* AUTH_REQUIRED */,
104913
+ await this.safeReadErrorDetails(response)
104914
+ );
104915
+ }
104932
104916
  throw new SDKError(
104933
104917
  `HTTP error! status: ${response.status}`,
104934
104918
  "REQUEST_FAILED" /* REQUEST_FAILED */,
104935
- await response.json()
104919
+ await this.safeReadErrorDetails(response)
104936
104920
  );
104937
104921
  }
104938
- if (response.status === 200 && response.headers.get("content-length") === "0") {
104939
- return void 0;
104940
- }
104922
+ if (response.status === 204) return void 0;
104923
+ const contentLength = response.headers.get("content-length");
104924
+ if (contentLength === "0") return void 0;
104941
104925
  try {
104942
104926
  return await response.json();
104943
104927
  } catch {