@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.cjs +181 -197
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +181 -197
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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,
|
|
1736
|
+
async save(key, value, expiryEpochMs) {
|
|
1737
1737
|
try {
|
|
1738
1738
|
const item = {
|
|
1739
1739
|
value,
|
|
1740
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
104150
|
-
*
|
|
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(
|
|
104316
|
-
|
|
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([
|
|
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
|
-
*
|
|
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([
|
|
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
|
-
|
|
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
|
|
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
|
|
104675
|
-
|
|
104676
|
-
|
|
104677
|
-
|
|
104678
|
-
|
|
104679
|
-
|
|
104680
|
-
|
|
104681
|
-
|
|
104682
|
-
|
|
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) ===
|
|
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
|
|
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
|
-
|
|
104751
|
-
|
|
104752
|
-
|
|
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
|
-
|
|
104763
|
-
|
|
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
|
|
104919
|
+
await this.safeReadErrorDetails(response)
|
|
104936
104920
|
);
|
|
104937
104921
|
}
|
|
104938
|
-
if (response.status ===
|
|
104939
|
-
|
|
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 {
|