@weblock-wallet/sdk 0.1.43 → 0.1.44

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
@@ -104035,6 +104035,8 @@ var SDKErrorCode = /* @__PURE__ */ ((SDKErrorCode2) => {
104035
104035
  SDKErrorCode2["WALLET_ALREADY_EXISTS"] = "WALLET_ALREADY_EXISTS";
104036
104036
  SDKErrorCode2["WALLET_CREATION_FAILED"] = "WALLET_CREATION_FAILED";
104037
104037
  SDKErrorCode2["INVALID_PASSWORD"] = "INVALID_PASSWORD";
104038
+ SDKErrorCode2["RECOVERY_NOT_AVAILABLE"] = "RECOVERY_NOT_AVAILABLE";
104039
+ SDKErrorCode2["PIN_RESET_FAILED"] = "PIN_RESET_FAILED";
104038
104040
  SDKErrorCode2["ASSET_NOT_FOUND"] = "ASSET_NOT_FOUND";
104039
104041
  SDKErrorCode2["INSUFFICIENT_BALANCE"] = "INSUFFICIENT_BALANCE";
104040
104042
  SDKErrorCode2["TRANSFER_FAILED"] = "TRANSFER_FAILED";
@@ -104151,6 +104153,16 @@ var ERC20_ABI = [
104151
104153
  "function decimals() view returns (uint8)",
104152
104154
  "function symbol() view returns (string)"
104153
104155
  ];
104156
+ var STORAGE_KEYS = {
104157
+ walletAddress: (orgHost) => `${orgHost}:walletAddress`,
104158
+ share2: (orgHost) => `${orgHost}:share2`,
104159
+ encryptedShare2: (orgHost) => `${orgHost}:encryptedShare2`,
104160
+ encryptedShare2Device: (orgHost) => `${orgHost}:encryptedShare2_device`,
104161
+ deviceSecret: (orgHost) => `${orgHost}:deviceSecret`,
104162
+ firebaseId: (orgHost) => `${orgHost}:firebaseId`,
104163
+ accessToken: (orgHost) => `${orgHost}:accessToken`,
104164
+ isNewUser: (orgHost) => `${orgHost}:isNewUser`
104165
+ };
104154
104166
  var WalletService = class {
104155
104167
  constructor(walletClient, rpcClient, orgHost, networkService) {
104156
104168
  this.walletClient = walletClient;
@@ -104159,13 +104171,53 @@ var WalletService = class {
104159
104171
  this.networkService = networkService;
104160
104172
  this.walletAddress = null;
104161
104173
  }
104174
+ /**
104175
+ * Wallet PIN/password mismatch handling.
104176
+ */
104177
+ isInvalidPasswordError(error) {
104178
+ if (!error) return false;
104179
+ if (error instanceof Error) {
104180
+ const msg = (error.message || "").toLowerCase();
104181
+ return msg.includes("wrong password") || msg.includes("unable to decrypt") || msg.includes("bad decrypt") || msg.includes("invalid key");
104182
+ }
104183
+ try {
104184
+ const msg = String(error?.message ?? "").toLowerCase();
104185
+ return msg.includes("wrong password") || msg.includes("unable to decrypt") || msg.includes("bad decrypt") || msg.includes("invalid key");
104186
+ } catch {
104187
+ return false;
104188
+ }
104189
+ }
104190
+ isSixDigitPin(pin) {
104191
+ return /^[0-9]{6}$/.test(pin);
104192
+ }
104193
+ /**
104194
+ * deviceSecret은 "PIN과 무관한 로컬 복구용 비밀값"입니다.
104195
+ * - 같은 디바이스에서만 PIN reset이 가능하도록 하는 역할
104196
+ * - 서버에는 절대 전달하지 않습니다.
104197
+ */
104198
+ async getOrCreateDeviceSecret() {
104199
+ const key = STORAGE_KEYS.deviceSecret(this.orgHost);
104200
+ const existing = await LocalForage.get(key);
104201
+ if (existing) return existing;
104202
+ const secret = randomBytes(32).toString("hex");
104203
+ await LocalForage.save(key, secret);
104204
+ return secret;
104205
+ }
104206
+ async ensureDeviceEncryptedShare2(share2Plain, firebaseId) {
104207
+ const encryptedKey = STORAGE_KEYS.encryptedShare2Device(this.orgHost);
104208
+ const existing = await LocalForage.get(encryptedKey);
104209
+ if (existing) return;
104210
+ const deviceSecret = await this.getOrCreateDeviceSecret();
104211
+ const encrypted = Crypto.encryptShare(share2Plain, deviceSecret, firebaseId);
104212
+ await LocalForage.save(encryptedKey, encrypted);
104213
+ }
104162
104214
  async getAddress() {
104163
104215
  try {
104164
104216
  if (this.walletAddress) {
104165
104217
  return this.walletAddress;
104166
104218
  }
104167
104219
  const savedAddress = await LocalForage.get(
104168
- `${this.orgHost}:walletAddress`
104220
+ STORAGE_KEYS.walletAddress(this.orgHost)
104169
104221
  );
104170
104222
  if (savedAddress) {
104171
104223
  this.walletAddress = savedAddress;
@@ -104175,7 +104227,7 @@ var WalletService = class {
104175
104227
  if (walletInfo?.address) {
104176
104228
  this.walletAddress = walletInfo.address;
104177
104229
  await LocalForage.save(
104178
- `${this.orgHost}:walletAddress`,
104230
+ STORAGE_KEYS.walletAddress(this.orgHost),
104179
104231
  walletInfo.address
104180
104232
  );
104181
104233
  return walletInfo.address;
@@ -104192,7 +104244,7 @@ var WalletService = class {
104192
104244
  async create(password) {
104193
104245
  try {
104194
104246
  const firebaseId = await LocalForage.get(
104195
- `${this.orgHost}:firebaseId`
104247
+ STORAGE_KEYS.firebaseId(this.orgHost)
104196
104248
  );
104197
104249
  console.log("1. FirebaseId:", firebaseId);
104198
104250
  if (!firebaseId) {
@@ -104201,8 +104253,14 @@ var WalletService = class {
104201
104253
  if (!password) {
104202
104254
  throw new SDKError("Password is required", "INVALID_PARAMS" /* INVALID_PARAMS */);
104203
104255
  }
104256
+ if (!this.isSixDigitPin(password)) {
104257
+ throw new SDKError(
104258
+ "PIN must be a 6-digit number",
104259
+ "INVALID_PARAMS" /* INVALID_PARAMS */
104260
+ );
104261
+ }
104204
104262
  const isNewUser = await LocalForage.get(
104205
- `${this.orgHost}:isNewUser`
104263
+ STORAGE_KEYS.isNewUser(this.orgHost)
104206
104264
  );
104207
104265
  if (!isNewUser) {
104208
104266
  throw new SDKError(
@@ -104221,21 +104279,15 @@ var WalletService = class {
104221
104279
  console.log("4. Splitting private key...");
104222
104280
  const shares = await Secrets.split(wallet.privateKey, 3, 2);
104223
104281
  const [share1, share2, share3] = shares;
104224
- console.log("5. Shares created:", {
104225
- share1Length: share1.length,
104226
- share2Length: share2.length,
104227
- share3Length: share3.length
104228
- });
104229
104282
  console.log("6. Encrypting shares...");
104230
104283
  const encryptedShare2 = Crypto.encryptShare(share2, password, firebaseId);
104231
104284
  const encryptedShare3 = Crypto.encryptShare(share3, password, firebaseId);
104232
- console.log("7. Shares encrypted:", {
104233
- encryptedShare2Length: encryptedShare2.length,
104234
- encryptedShare3Length: encryptedShare3.length
104235
- });
104236
104285
  console.log("8. Saving encryptedShare2 to LocalForage...");
104237
- await LocalForage.save(`${this.orgHost}:encryptedShare2`, encryptedShare2);
104238
- console.log("9. encryptedShare2 saved");
104286
+ await LocalForage.save(
104287
+ STORAGE_KEYS.encryptedShare2(this.orgHost),
104288
+ encryptedShare2
104289
+ );
104290
+ await this.ensureDeviceEncryptedShare2(share2, firebaseId);
104239
104291
  console.log("10. Creating wallet on server...");
104240
104292
  await this.walletClient.createWallet({
104241
104293
  address: wallet.address,
@@ -104243,9 +104295,11 @@ var WalletService = class {
104243
104295
  share1,
104244
104296
  encryptedShare3
104245
104297
  });
104246
- console.log("11. Wallet created on server");
104247
104298
  this.walletAddress = wallet.address;
104248
- await LocalForage.save(`${this.orgHost}:walletAddress`, wallet.address);
104299
+ await LocalForage.save(
104300
+ STORAGE_KEYS.walletAddress(this.orgHost),
104301
+ wallet.address
104302
+ );
104249
104303
  return wallet.address;
104250
104304
  } catch (error) {
104251
104305
  console.error("Error in create wallet:", error);
@@ -104260,44 +104314,54 @@ var WalletService = class {
104260
104314
  async retrieveWallet(password) {
104261
104315
  try {
104262
104316
  const accessToken = await LocalForage.get(
104263
- `${this.orgHost}:accessToken`
104317
+ STORAGE_KEYS.accessToken(this.orgHost)
104264
104318
  );
104265
104319
  if (!accessToken) {
104266
104320
  throw new SDKError("Access token not found", "AUTH_REQUIRED" /* AUTH_REQUIRED */);
104267
104321
  }
104268
- console.log("1. Checking login status...");
104269
104322
  const firebaseId = await LocalForage.get(
104270
- `${this.orgHost}:firebaseId`
104323
+ STORAGE_KEYS.firebaseId(this.orgHost)
104271
104324
  );
104272
104325
  if (!firebaseId) {
104273
104326
  throw new SDKError("Not logged in", "AUTH_REQUIRED" /* AUTH_REQUIRED */);
104274
104327
  }
104275
- console.log("2. Getting wallet info from server...");
104328
+ if (!this.isSixDigitPin(password)) {
104329
+ throw new SDKError(
104330
+ "PIN must be a 6-digit number",
104331
+ "INVALID_PARAMS" /* INVALID_PARAMS */
104332
+ );
104333
+ }
104334
+ const decryptShareOrThrow = (encryptedShare) => {
104335
+ try {
104336
+ return Crypto.decryptShare(encryptedShare, password, firebaseId);
104337
+ } catch (e7) {
104338
+ if (this.isInvalidPasswordError(e7)) {
104339
+ throw new SDKError(
104340
+ "Incorrect PIN code",
104341
+ "INVALID_PASSWORD" /* INVALID_PASSWORD */,
104342
+ e7
104343
+ );
104344
+ }
104345
+ throw e7;
104346
+ }
104347
+ };
104276
104348
  const walletInfo = await this.walletClient.getWallet();
104277
- console.log("3. Wallet info received:", { address: walletInfo.address });
104278
- let share2 = await LocalForage.get(`${this.orgHost}:share2`);
104349
+ let share2 = await LocalForage.get(
104350
+ STORAGE_KEYS.share2(this.orgHost)
104351
+ );
104279
104352
  if (!share2) {
104280
104353
  const encryptedShare2 = await LocalForage.get(
104281
- `${this.orgHost}:encryptedShare2`
104354
+ STORAGE_KEYS.encryptedShare2(this.orgHost)
104282
104355
  );
104283
104356
  if (encryptedShare2) {
104284
- share2 = Crypto.decryptShare(encryptedShare2, password, firebaseId);
104285
- await LocalForage.save(`${this.orgHost}:share2`, share2);
104357
+ share2 = decryptShareOrThrow(encryptedShare2);
104358
+ await LocalForage.save(STORAGE_KEYS.share2(this.orgHost), share2);
104286
104359
  } else {
104287
- console.log("8. No encryptedShare2, recovering using share3...");
104288
- const share3 = Crypto.decryptShare(
104289
- walletInfo.encryptedShare3,
104290
- password,
104291
- firebaseId
104292
- );
104293
- console.log("9. Share3 decrypted, combining with share1...");
104360
+ const share3 = decryptShareOrThrow(walletInfo.encryptedShare3);
104294
104361
  const privateKey2 = await Secrets.combine([walletInfo.share1, share3]);
104295
104362
  const wallet2 = new import_ethers2.Wallet(privateKey2);
104296
- console.log("10. Generating new shares...");
104297
104363
  const newShares = await Secrets.split(wallet2.privateKey, 3, 2);
104298
104364
  const [newShare1, newShare2, newShare3] = newShares;
104299
- console.log("11. New shares generated");
104300
- console.log("12. Updating wallet keys on server...");
104301
104365
  await this.walletClient.updateWalletKey({
104302
104366
  share1: newShare1,
104303
104367
  encryptedShare3: Crypto.encryptShare(
@@ -104306,28 +104370,34 @@ var WalletService = class {
104306
104370
  firebaseId
104307
104371
  )
104308
104372
  });
104309
- console.log("13. Saving new shares locally...");
104310
- await LocalForage.save(`${this.orgHost}:share2`, newShare2);
104373
+ await LocalForage.save(STORAGE_KEYS.share2(this.orgHost), newShare2);
104311
104374
  await LocalForage.save(
104312
- `${this.orgHost}:encryptedShare2`,
104375
+ STORAGE_KEYS.encryptedShare2(this.orgHost),
104313
104376
  Crypto.encryptShare(newShare2, password, firebaseId)
104314
104377
  );
104315
- console.log("14. Wallet recovered with share3:", wallet2.address);
104378
+ await this.ensureDeviceEncryptedShare2(newShare2, firebaseId);
104316
104379
  this.walletAddress = wallet2.address;
104317
- console.log("15. Wallet address set:", this.walletAddress);
104380
+ await LocalForage.save(
104381
+ STORAGE_KEYS.walletAddress(this.orgHost),
104382
+ wallet2.address
104383
+ );
104384
+ await LocalForage.delete(STORAGE_KEYS.share2(this.orgHost));
104318
104385
  return wallet2.address;
104319
104386
  }
104320
104387
  }
104321
- console.log("15. Combining share1 and share2...");
104322
104388
  const privateKey = await Secrets.combine([walletInfo.share1, share2]);
104323
104389
  const wallet = new import_ethers2.Wallet(privateKey);
104390
+ await this.ensureDeviceEncryptedShare2(share2, firebaseId);
104324
104391
  this.walletAddress = wallet.address;
104325
- await LocalForage.save(`${this.orgHost}:walletAddress`, wallet.address);
104326
- await LocalForage.delete(`${this.orgHost}:share2`);
104392
+ await LocalForage.save(
104393
+ STORAGE_KEYS.walletAddress(this.orgHost),
104394
+ wallet.address
104395
+ );
104396
+ await LocalForage.delete(STORAGE_KEYS.share2(this.orgHost));
104327
104397
  return wallet.address;
104328
104398
  } catch (error) {
104329
104399
  this.walletAddress = null;
104330
- await LocalForage.delete(`${this.orgHost}:share2`);
104400
+ await LocalForage.delete(STORAGE_KEYS.share2(this.orgHost));
104331
104401
  console.error("Error in retrieveWallet:", error);
104332
104402
  if (error instanceof SDKError) throw error;
104333
104403
  throw new SDKError(
@@ -104337,11 +104407,109 @@ var WalletService = class {
104337
104407
  );
104338
104408
  }
104339
104409
  }
104410
+ /**
104411
+ * NEW: PIN reset (프라이빗키/주소 유지)
104412
+ * - 같은 디바이스에 남아있는 encryptedShare2_device를 이용
104413
+ * - 서버는 PATCH /v1/wallets/keys 로 share1 / encryptedShare3 만 업데이트
104414
+ */
104415
+ async resetPin(newPassword) {
104416
+ try {
104417
+ const accessToken = await LocalForage.get(
104418
+ STORAGE_KEYS.accessToken(this.orgHost)
104419
+ );
104420
+ if (!accessToken) {
104421
+ throw new SDKError("Access token not found", "AUTH_REQUIRED" /* AUTH_REQUIRED */);
104422
+ }
104423
+ const firebaseId = await LocalForage.get(
104424
+ STORAGE_KEYS.firebaseId(this.orgHost)
104425
+ );
104426
+ if (!firebaseId) {
104427
+ throw new SDKError("Not logged in", "AUTH_REQUIRED" /* AUTH_REQUIRED */);
104428
+ }
104429
+ if (!newPassword || !this.isSixDigitPin(newPassword)) {
104430
+ throw new SDKError(
104431
+ "PIN must be a 6-digit number",
104432
+ "INVALID_PARAMS" /* INVALID_PARAMS */
104433
+ );
104434
+ }
104435
+ const encryptedDevice = await LocalForage.get(
104436
+ STORAGE_KEYS.encryptedShare2Device(this.orgHost)
104437
+ );
104438
+ if (!encryptedDevice) {
104439
+ throw new SDKError(
104440
+ "PIN reset is not available on this device",
104441
+ "RECOVERY_NOT_AVAILABLE" /* RECOVERY_NOT_AVAILABLE */
104442
+ );
104443
+ }
104444
+ const deviceSecret = await LocalForage.get(
104445
+ STORAGE_KEYS.deviceSecret(this.orgHost)
104446
+ );
104447
+ if (!deviceSecret) {
104448
+ throw new SDKError(
104449
+ "PIN reset is not available on this device",
104450
+ "RECOVERY_NOT_AVAILABLE" /* RECOVERY_NOT_AVAILABLE */
104451
+ );
104452
+ }
104453
+ let share2;
104454
+ try {
104455
+ share2 = Crypto.decryptShare(encryptedDevice, deviceSecret, firebaseId);
104456
+ } catch (e7) {
104457
+ throw new SDKError(
104458
+ "PIN reset is not available on this device",
104459
+ "RECOVERY_NOT_AVAILABLE" /* RECOVERY_NOT_AVAILABLE */,
104460
+ e7
104461
+ );
104462
+ }
104463
+ const walletInfo = await this.walletClient.getWallet();
104464
+ const privateKey = await Secrets.combine([walletInfo.share1, share2]);
104465
+ const wallet = new import_ethers2.Wallet(privateKey);
104466
+ const newShares = await Secrets.split(wallet.privateKey, 3, 2);
104467
+ const [newShare1, newShare2, newShare3] = newShares;
104468
+ await this.walletClient.updateWalletKey({
104469
+ share1: newShare1,
104470
+ encryptedShare3: Crypto.encryptShare(
104471
+ newShare3,
104472
+ newPassword,
104473
+ firebaseId
104474
+ )
104475
+ });
104476
+ await LocalForage.save(
104477
+ STORAGE_KEYS.encryptedShare2(this.orgHost),
104478
+ Crypto.encryptShare(newShare2, newPassword, firebaseId)
104479
+ );
104480
+ const newEncryptedDevice = Crypto.encryptShare(
104481
+ newShare2,
104482
+ deviceSecret,
104483
+ firebaseId
104484
+ );
104485
+ await LocalForage.save(
104486
+ STORAGE_KEYS.encryptedShare2Device(this.orgHost),
104487
+ newEncryptedDevice
104488
+ );
104489
+ this.walletAddress = wallet.address;
104490
+ await LocalForage.save(
104491
+ STORAGE_KEYS.walletAddress(this.orgHost),
104492
+ wallet.address
104493
+ );
104494
+ await LocalForage.delete(STORAGE_KEYS.share2(this.orgHost));
104495
+ return wallet.address;
104496
+ } catch (error) {
104497
+ console.error("Error in resetPin:", error);
104498
+ if (error instanceof SDKError) throw error;
104499
+ throw new SDKError(
104500
+ "Failed to reset PIN",
104501
+ "PIN_RESET_FAILED" /* PIN_RESET_FAILED */,
104502
+ error
104503
+ );
104504
+ }
104505
+ }
104340
104506
  async clearWalletState() {
104341
104507
  this.walletAddress = null;
104342
- await LocalForage.delete(`${this.orgHost}:walletAddress`);
104343
- await LocalForage.delete(`${this.orgHost}:share2`);
104344
- await LocalForage.delete(`${this.orgHost}:encryptedShare2`);
104508
+ await LocalForage.delete(STORAGE_KEYS.walletAddress(this.orgHost));
104509
+ await LocalForage.delete(STORAGE_KEYS.share2(this.orgHost));
104510
+ await LocalForage.delete(STORAGE_KEYS.encryptedShare2(this.orgHost));
104511
+ await LocalForage.delete(STORAGE_KEYS.encryptedShare2Device(this.orgHost));
104512
+ await LocalForage.delete(STORAGE_KEYS.deviceSecret(this.orgHost));
104345
104513
  }
104346
104514
  async getBalance(address, chainId) {
104347
104515
  const response = await this.rpcClient.sendRpc({
@@ -104498,7 +104666,7 @@ var WalletService = class {
104498
104666
  }
104499
104667
  const [share1, share2] = await Promise.all([
104500
104668
  this.walletClient.getWallet().then((wallet2) => wallet2.share1),
104501
- LocalForage.get(`${this.orgHost}:share2`)
104669
+ LocalForage.get(STORAGE_KEYS.share2(this.orgHost))
104502
104670
  ]);
104503
104671
  if (!share1 || !share2) {
104504
104672
  throw new SDKError(
@@ -105990,6 +106158,7 @@ var InternalCoreImpl = class {
105990
106158
  getAddress: () => this.walletService.getAddress(),
105991
106159
  create: (password) => this.walletService.create(password),
105992
106160
  retrieveWallet: (password) => this.walletService.retrieveWallet(password),
106161
+ resetPin: (newPassword) => this.walletService.resetPin(newPassword),
105993
106162
  getBalance: (address, chainId) => this.walletService.getBalance(address, chainId),
105994
106163
  getTokenBalance: (tokenAddress, walletAddress, chainId) => this.walletService.getTokenBalance(tokenAddress, walletAddress, chainId),
105995
106164
  sendTransaction: (params) => this.walletService.sendTransaction(params),
@@ -106011,21 +106180,20 @@ var InternalCoreImpl = class {
106011
106180
  };
106012
106181
  this.asset = {
106013
106182
  transfer: (params) => this.assetService.transfer(params),
106014
- addToken: (params) => this.assetService.addToken(params),
106015
- // New ERC20 methods
106183
+ /**
106184
+ * 타입 정합성:
106185
+ * - InternalCore는 decimals?: number
106186
+ * - 기존 AssetService 내부 구현이 decimals를 string으로 받는 경우가 있어,
106187
+ * 여기서 안전하게 string으로 변환해서 전달합니다.
106188
+ */
106189
+ addToken: (params) => this.assetService.addToken({
106190
+ ...params,
106191
+ decimals: typeof params.decimals === "number" ? String(params.decimals) : void 0
106192
+ }),
106016
106193
  getTokenBalance: (params) => this.assetService.getTokenBalance(params),
106017
106194
  approveToken: (params) => this.assetService.approveToken(params),
106018
106195
  getAllowance: (params) => this.assetService.getAllowance(params),
106019
- // getTokenInfo: (params: TokenInfoParams) =>
106020
- // this.assetService.getTokenInfo(params),
106021
106196
  addNFTCollection: (params) => this.assetService.addNFTCollection(params),
106022
- // checkSecurityTokenCompliance: (params: {
106023
- // networkId: string
106024
- // tokenAddress: string
106025
- // from: string
106026
- // to: string
106027
- // amount: string
106028
- // }) => this.assetService.checkSecurityTokenCompliance(params),
106029
106197
  on: (event, listener) => this.assetService.on(event, listener),
106030
106198
  off: (event, listener) => this.assetService.off(event, listener),
106031
106199
  getTokenInfo: (params) => this.assetService.getTokenInfo(params),
@@ -106114,6 +106282,18 @@ var UserModule = class {
106114
106282
  const wallet = await this.walletModule.getInfo();
106115
106283
  return { wallet };
106116
106284
  }
106285
+ /**
106286
+ * PIN을 모르는 상태에서 같은 디바이스에 남아있는 복구용 share2(encryptedShare2_device)로
106287
+ * PIN을 재설정합니다. (프라이빗키/주소 유지)
106288
+ */
106289
+ async resetPin(newPassword) {
106290
+ if (!newPassword) {
106291
+ throw new SDKError("Password is required", "INVALID_PARAMS" /* INVALID_PARAMS */);
106292
+ }
106293
+ await this.core.wallet.resetPin(newPassword);
106294
+ const wallet = await this.walletModule.getInfo();
106295
+ return { wallet };
106296
+ }
106117
106297
  async signOut() {
106118
106298
  return this.core.auth.signOut();
106119
106299
  }