@t402/wdk 2.0.0 → 2.3.0
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/README.md +117 -112
- package/dist/cjs/index.d.ts +384 -11
- package/dist/cjs/index.js +803 -173
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.d.mts +384 -11
- package/dist/esm/index.mjs +786 -178
- package/dist/esm/index.mjs.map +1 -1
- package/package.json +48 -22
package/dist/cjs/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -30,7 +40,10 @@ __export(index_exports, {
|
|
|
30
40
|
DEFAULT_CHAINS: () => DEFAULT_CHAINS,
|
|
31
41
|
DEFAULT_RETRY_CONFIG: () => DEFAULT_RETRY_CONFIG,
|
|
32
42
|
DEFAULT_RPC_ENDPOINTS: () => DEFAULT_RPC_ENDPOINTS,
|
|
43
|
+
HardwareWalletError: () => HardwareWalletError,
|
|
44
|
+
HardwareWalletErrorCode: () => HardwareWalletErrorCode,
|
|
33
45
|
LAYERZERO_ENDPOINT_IDS: () => import_evm3.LAYERZERO_ENDPOINT_IDS,
|
|
46
|
+
LedgerSigner: () => LedgerSigner,
|
|
34
47
|
MockWDKSigner: () => MockWDKSigner,
|
|
35
48
|
RPCError: () => RPCError,
|
|
36
49
|
SignerError: () => SignerError,
|
|
@@ -38,6 +51,7 @@ __export(index_exports, {
|
|
|
38
51
|
T402WDK: () => T402WDK,
|
|
39
52
|
TTLCache: () => TTLCache,
|
|
40
53
|
TransactionError: () => TransactionError,
|
|
54
|
+
TrezorSigner: () => TrezorSigner,
|
|
41
55
|
USDC_ADDRESSES: () => USDC_ADDRESSES,
|
|
42
56
|
USDT0_ADDRESSES: () => USDT0_ADDRESSES,
|
|
43
57
|
USDT0_OFT_ADDRESSES: () => import_evm3.USDT0_OFT_ADDRESSES,
|
|
@@ -49,7 +63,10 @@ __export(index_exports, {
|
|
|
49
63
|
WDKSigner: () => WDKSigner,
|
|
50
64
|
WdkBridge: () => WdkBridge,
|
|
51
65
|
createDirectBridge: () => createDirectBridge,
|
|
66
|
+
createLedgerSigner: () => createLedgerSigner,
|
|
67
|
+
createTrezorSigner: () => createTrezorSigner,
|
|
52
68
|
createWDKSigner: () => createWDKSigner,
|
|
69
|
+
detectHardwareWalletSupport: () => detectHardwareWalletSupport,
|
|
53
70
|
getBridgeableChains: () => import_evm3.getBridgeableChains,
|
|
54
71
|
getChainFromNetwork: () => getChainFromNetwork,
|
|
55
72
|
getChainId: () => getChainId,
|
|
@@ -57,6 +74,7 @@ __export(index_exports, {
|
|
|
57
74
|
getPreferredToken: () => getPreferredToken,
|
|
58
75
|
getUsdt0Chains: () => getUsdt0Chains,
|
|
59
76
|
hasErrorCode: () => hasErrorCode,
|
|
77
|
+
isHardwareWalletSupported: () => isHardwareWalletSupported,
|
|
60
78
|
isWDKError: () => isWDKError,
|
|
61
79
|
normalizeChainConfig: () => normalizeChainConfig,
|
|
62
80
|
supportsBridging: () => import_evm3.supportsBridging,
|
|
@@ -74,9 +92,10 @@ var DEFAULT_CACHE_CONFIG = {
|
|
|
74
92
|
refreshOnAccess: false
|
|
75
93
|
};
|
|
76
94
|
var TTLCache = class {
|
|
95
|
+
_cache = /* @__PURE__ */ new Map();
|
|
96
|
+
_config;
|
|
97
|
+
_cleanupInterval = null;
|
|
77
98
|
constructor(config = {}) {
|
|
78
|
-
this._cache = /* @__PURE__ */ new Map();
|
|
79
|
-
this._cleanupInterval = null;
|
|
80
99
|
this._config = { ...DEFAULT_CACHE_CONFIG, ...config };
|
|
81
100
|
if (this._config.maxSize > 0) {
|
|
82
101
|
this._startCleanup();
|
|
@@ -344,6 +363,9 @@ var DEFAULT_BALANCE_CACHE_CONFIG = {
|
|
|
344
363
|
maxSize: 500
|
|
345
364
|
};
|
|
346
365
|
var BalanceCache = class {
|
|
366
|
+
_cache;
|
|
367
|
+
_aggregatedCache;
|
|
368
|
+
_config;
|
|
347
369
|
constructor(config = {}) {
|
|
348
370
|
this._config = { ...DEFAULT_BALANCE_CACHE_CONFIG, ...config };
|
|
349
371
|
this._cache = new TTLCache({
|
|
@@ -752,6 +774,9 @@ var WDKErrorCode = /* @__PURE__ */ ((WDKErrorCode2) => {
|
|
|
752
774
|
return WDKErrorCode2;
|
|
753
775
|
})(WDKErrorCode || {});
|
|
754
776
|
var WDKError = class _WDKError extends Error {
|
|
777
|
+
code;
|
|
778
|
+
cause;
|
|
779
|
+
context;
|
|
755
780
|
constructor(code, message, options) {
|
|
756
781
|
super(message);
|
|
757
782
|
this.name = "WDKError";
|
|
@@ -796,6 +821,7 @@ var WDKInitializationError = class extends WDKError {
|
|
|
796
821
|
}
|
|
797
822
|
};
|
|
798
823
|
var ChainError = class extends WDKError {
|
|
824
|
+
chain;
|
|
799
825
|
constructor(code, message, options) {
|
|
800
826
|
super(code, message, {
|
|
801
827
|
cause: options?.cause,
|
|
@@ -806,6 +832,8 @@ var ChainError = class extends WDKError {
|
|
|
806
832
|
}
|
|
807
833
|
};
|
|
808
834
|
var SignerError = class extends WDKError {
|
|
835
|
+
chain;
|
|
836
|
+
address;
|
|
809
837
|
constructor(code, message, options) {
|
|
810
838
|
super(code, message, {
|
|
811
839
|
cause: options?.cause,
|
|
@@ -817,6 +845,7 @@ var SignerError = class extends WDKError {
|
|
|
817
845
|
}
|
|
818
846
|
};
|
|
819
847
|
var SigningError = class extends WDKError {
|
|
848
|
+
operation;
|
|
820
849
|
constructor(code, message, options) {
|
|
821
850
|
super(code, message, {
|
|
822
851
|
cause: options.cause,
|
|
@@ -827,6 +856,8 @@ var SigningError = class extends WDKError {
|
|
|
827
856
|
}
|
|
828
857
|
};
|
|
829
858
|
var BalanceError = class extends WDKError {
|
|
859
|
+
chain;
|
|
860
|
+
token;
|
|
830
861
|
constructor(code, message, options) {
|
|
831
862
|
super(code, message, {
|
|
832
863
|
cause: options?.cause,
|
|
@@ -838,6 +869,8 @@ var BalanceError = class extends WDKError {
|
|
|
838
869
|
}
|
|
839
870
|
};
|
|
840
871
|
var TransactionError = class extends WDKError {
|
|
872
|
+
chain;
|
|
873
|
+
txHash;
|
|
841
874
|
constructor(code, message, options) {
|
|
842
875
|
super(code, message, {
|
|
843
876
|
cause: options?.cause,
|
|
@@ -849,6 +882,8 @@ var TransactionError = class extends WDKError {
|
|
|
849
882
|
}
|
|
850
883
|
};
|
|
851
884
|
var BridgeError = class extends WDKError {
|
|
885
|
+
fromChain;
|
|
886
|
+
toChain;
|
|
852
887
|
constructor(code, message, options) {
|
|
853
888
|
super(code, message, {
|
|
854
889
|
cause: options?.cause,
|
|
@@ -864,6 +899,8 @@ var BridgeError = class extends WDKError {
|
|
|
864
899
|
}
|
|
865
900
|
};
|
|
866
901
|
var RPCError = class extends WDKError {
|
|
902
|
+
endpoint;
|
|
903
|
+
rpcCode;
|
|
867
904
|
constructor(code, message, options) {
|
|
868
905
|
super(code, message, {
|
|
869
906
|
cause: options?.cause,
|
|
@@ -891,11 +928,10 @@ function wrapError(error, defaultCode = 9999 /* UNKNOWN_ERROR */, defaultMessage
|
|
|
891
928
|
});
|
|
892
929
|
}
|
|
893
930
|
if (msg.includes("rate limit") || msg.includes("too many requests") || msg.includes("429")) {
|
|
894
|
-
return new RPCError(
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
);
|
|
931
|
+
return new RPCError(8003 /* RPC_RATE_LIMITED */, `Rate limited: ${error.message}`, {
|
|
932
|
+
cause: error,
|
|
933
|
+
context
|
|
934
|
+
});
|
|
899
935
|
}
|
|
900
936
|
if (msg.includes("connection") || msg.includes("network") || msg.includes("econnrefused") || msg.includes("enotfound")) {
|
|
901
937
|
return new RPCError(
|
|
@@ -973,12 +1009,7 @@ async function withTimeout(promise, timeoutMs, operation = "Operation") {
|
|
|
973
1009
|
let timeoutId;
|
|
974
1010
|
const timeoutPromise = new Promise((_, reject) => {
|
|
975
1011
|
timeoutId = setTimeout(() => {
|
|
976
|
-
reject(
|
|
977
|
-
new RPCError(
|
|
978
|
-
8002 /* RPC_TIMEOUT */,
|
|
979
|
-
`${operation} timed out after ${timeoutMs}ms`
|
|
980
|
-
)
|
|
981
|
-
);
|
|
1012
|
+
reject(new RPCError(8002 /* RPC_TIMEOUT */, `${operation} timed out after ${timeoutMs}ms`));
|
|
982
1013
|
}, timeoutMs);
|
|
983
1014
|
});
|
|
984
1015
|
try {
|
|
@@ -995,6 +1026,12 @@ var DEFAULT_BALANCE_RETRY = {
|
|
|
995
1026
|
baseDelay: 500
|
|
996
1027
|
};
|
|
997
1028
|
var WDKSigner = class {
|
|
1029
|
+
_wdk;
|
|
1030
|
+
_chain;
|
|
1031
|
+
_accountIndex;
|
|
1032
|
+
_account = null;
|
|
1033
|
+
_address = null;
|
|
1034
|
+
_timeoutMs;
|
|
998
1035
|
/**
|
|
999
1036
|
* Create a new WDK signer
|
|
1000
1037
|
*
|
|
@@ -1004,14 +1041,8 @@ var WDKSigner = class {
|
|
|
1004
1041
|
* @param timeoutMs - Timeout for operations in milliseconds (default: 30000)
|
|
1005
1042
|
*/
|
|
1006
1043
|
constructor(wdk, chain, accountIndex = 0, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
1007
|
-
this._account = null;
|
|
1008
|
-
this._address = null;
|
|
1009
1044
|
if (!wdk) {
|
|
1010
|
-
throw new SignerError(
|
|
1011
|
-
1002 /* WDK_NOT_INITIALIZED */,
|
|
1012
|
-
"WDK instance is required",
|
|
1013
|
-
{ chain }
|
|
1014
|
-
);
|
|
1045
|
+
throw new SignerError(1002 /* WDK_NOT_INITIALIZED */, "WDK instance is required", { chain });
|
|
1015
1046
|
}
|
|
1016
1047
|
if (!chain || typeof chain !== "string") {
|
|
1017
1048
|
throw new SignerError(
|
|
@@ -1152,11 +1183,7 @@ var WDKSigner = class {
|
|
|
1152
1183
|
primaryType: message.primaryType,
|
|
1153
1184
|
message: message.message
|
|
1154
1185
|
});
|
|
1155
|
-
const signature = await withTimeout(
|
|
1156
|
-
signPromise,
|
|
1157
|
-
this._timeoutMs,
|
|
1158
|
-
"Signing typed data"
|
|
1159
|
-
);
|
|
1186
|
+
const signature = await withTimeout(signPromise, this._timeoutMs, "Signing typed data");
|
|
1160
1187
|
if (!signature || !signature.startsWith("0x")) {
|
|
1161
1188
|
throw new SigningError(
|
|
1162
1189
|
4001 /* SIGN_TYPED_DATA_FAILED */,
|
|
@@ -1169,19 +1196,20 @@ var WDKSigner = class {
|
|
|
1169
1196
|
if (error instanceof SigningError) {
|
|
1170
1197
|
throw error;
|
|
1171
1198
|
}
|
|
1172
|
-
const wrapped = wrapError(
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
throw new SigningError(
|
|
1177
|
-
wrapped.code,
|
|
1178
|
-
wrapped.message,
|
|
1199
|
+
const wrapped = wrapError(
|
|
1200
|
+
error,
|
|
1201
|
+
4001 /* SIGN_TYPED_DATA_FAILED */,
|
|
1202
|
+
"Failed to sign typed data",
|
|
1179
1203
|
{
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
context: wrapped.context
|
|
1204
|
+
chain: this._chain,
|
|
1205
|
+
primaryType: message.primaryType
|
|
1183
1206
|
}
|
|
1184
1207
|
);
|
|
1208
|
+
throw new SigningError(wrapped.code, wrapped.message, {
|
|
1209
|
+
operation: "signTypedData",
|
|
1210
|
+
cause: wrapped.cause,
|
|
1211
|
+
context: wrapped.context
|
|
1212
|
+
});
|
|
1185
1213
|
}
|
|
1186
1214
|
}
|
|
1187
1215
|
/**
|
|
@@ -1191,11 +1219,10 @@ var WDKSigner = class {
|
|
|
1191
1219
|
*/
|
|
1192
1220
|
async signMessage(message) {
|
|
1193
1221
|
if (message === void 0 || message === null) {
|
|
1194
|
-
throw new SigningError(
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
);
|
|
1222
|
+
throw new SigningError(4004 /* INVALID_MESSAGE */, "Message is required for signing", {
|
|
1223
|
+
operation: "signMessage",
|
|
1224
|
+
context: { chain: this._chain }
|
|
1225
|
+
});
|
|
1199
1226
|
}
|
|
1200
1227
|
if (typeof message !== "string" && !(message instanceof Uint8Array)) {
|
|
1201
1228
|
throw new SigningError(
|
|
@@ -1208,11 +1235,7 @@ var WDKSigner = class {
|
|
|
1208
1235
|
const account = await this.getAccount();
|
|
1209
1236
|
const messageStr = typeof message === "string" ? message : Buffer.from(message).toString("utf-8");
|
|
1210
1237
|
const signPromise = account.signMessage(messageStr);
|
|
1211
|
-
const signature = await withTimeout(
|
|
1212
|
-
signPromise,
|
|
1213
|
-
this._timeoutMs,
|
|
1214
|
-
"Signing message"
|
|
1215
|
-
);
|
|
1238
|
+
const signature = await withTimeout(signPromise, this._timeoutMs, "Signing message");
|
|
1216
1239
|
if (!signature || !signature.startsWith("0x")) {
|
|
1217
1240
|
throw new SigningError(
|
|
1218
1241
|
4002 /* SIGN_MESSAGE_FAILED */,
|
|
@@ -1228,15 +1251,11 @@ var WDKSigner = class {
|
|
|
1228
1251
|
const wrapped = wrapError(error, 4002 /* SIGN_MESSAGE_FAILED */, "Failed to sign message", {
|
|
1229
1252
|
chain: this._chain
|
|
1230
1253
|
});
|
|
1231
|
-
throw new SigningError(
|
|
1232
|
-
|
|
1233
|
-
wrapped.
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
cause: wrapped.cause,
|
|
1237
|
-
context: wrapped.context
|
|
1238
|
-
}
|
|
1239
|
-
);
|
|
1254
|
+
throw new SigningError(wrapped.code, wrapped.message, {
|
|
1255
|
+
operation: "signMessage",
|
|
1256
|
+
cause: wrapped.cause,
|
|
1257
|
+
context: wrapped.context
|
|
1258
|
+
});
|
|
1240
1259
|
}
|
|
1241
1260
|
}
|
|
1242
1261
|
/**
|
|
@@ -1265,13 +1284,10 @@ var WDKSigner = class {
|
|
|
1265
1284
|
async getBalance() {
|
|
1266
1285
|
try {
|
|
1267
1286
|
const account = await this.getAccount();
|
|
1268
|
-
return await withRetry(
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
},
|
|
1273
|
-
DEFAULT_BALANCE_RETRY
|
|
1274
|
-
);
|
|
1287
|
+
return await withRetry(async () => {
|
|
1288
|
+
const balancePromise = account.getBalance();
|
|
1289
|
+
return withTimeout(balancePromise, this._timeoutMs, "Fetching native balance");
|
|
1290
|
+
}, DEFAULT_BALANCE_RETRY);
|
|
1275
1291
|
} catch (error) {
|
|
1276
1292
|
if (error instanceof BalanceError) {
|
|
1277
1293
|
throw error;
|
|
@@ -1301,13 +1317,10 @@ var WDKSigner = class {
|
|
|
1301
1317
|
}
|
|
1302
1318
|
try {
|
|
1303
1319
|
const account = await this.getAccount();
|
|
1304
|
-
return await withRetry(
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
},
|
|
1309
|
-
DEFAULT_BALANCE_RETRY
|
|
1310
|
-
);
|
|
1320
|
+
return await withRetry(async () => {
|
|
1321
|
+
const balancePromise = account.getTokenBalance(tokenAddress);
|
|
1322
|
+
return withTimeout(balancePromise, this._timeoutMs, "Fetching token balance");
|
|
1323
|
+
}, DEFAULT_BALANCE_RETRY);
|
|
1311
1324
|
} catch (error) {
|
|
1312
1325
|
if (error instanceof BalanceError) {
|
|
1313
1326
|
throw error;
|
|
@@ -1338,17 +1351,14 @@ var WDKSigner = class {
|
|
|
1338
1351
|
}
|
|
1339
1352
|
try {
|
|
1340
1353
|
const account = await this.getAccount();
|
|
1341
|
-
return await withRetry(
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
},
|
|
1350
|
-
DEFAULT_BALANCE_RETRY
|
|
1351
|
-
);
|
|
1354
|
+
return await withRetry(async () => {
|
|
1355
|
+
const estimatePromise = account.estimateGas({
|
|
1356
|
+
to: params.to,
|
|
1357
|
+
value: params.value,
|
|
1358
|
+
data: params.data
|
|
1359
|
+
});
|
|
1360
|
+
return withTimeout(estimatePromise, this._timeoutMs, "Estimating gas");
|
|
1361
|
+
}, DEFAULT_BALANCE_RETRY);
|
|
1352
1362
|
} catch (error) {
|
|
1353
1363
|
if (error instanceof TransactionError) {
|
|
1354
1364
|
throw error;
|
|
@@ -1406,15 +1416,11 @@ var WDKSigner = class {
|
|
|
1406
1416
|
chain: this._chain,
|
|
1407
1417
|
to: params.to
|
|
1408
1418
|
});
|
|
1409
|
-
throw new TransactionError(
|
|
1410
|
-
|
|
1411
|
-
wrapped.
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
cause: wrapped.cause,
|
|
1415
|
-
context: wrapped.context
|
|
1416
|
-
}
|
|
1417
|
-
);
|
|
1419
|
+
throw new TransactionError(wrapped.code, wrapped.message, {
|
|
1420
|
+
chain: this._chain,
|
|
1421
|
+
cause: wrapped.cause,
|
|
1422
|
+
context: wrapped.context
|
|
1423
|
+
});
|
|
1418
1424
|
}
|
|
1419
1425
|
}
|
|
1420
1426
|
};
|
|
@@ -1424,9 +1430,9 @@ async function createWDKSigner(wdk, chain, accountIndex = 0, timeoutMs = DEFAULT
|
|
|
1424
1430
|
return signer;
|
|
1425
1431
|
}
|
|
1426
1432
|
var MockWDKSigner = class {
|
|
1427
|
-
|
|
1433
|
+
address;
|
|
1434
|
+
constructor(address, _privateKey) {
|
|
1428
1435
|
this.address = address;
|
|
1429
|
-
this._privateKey = privateKey;
|
|
1430
1436
|
}
|
|
1431
1437
|
async signTypedData(_message) {
|
|
1432
1438
|
return "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
|
|
@@ -1438,53 +1444,17 @@ var MockWDKSigner = class {
|
|
|
1438
1444
|
|
|
1439
1445
|
// src/t402wdk.ts
|
|
1440
1446
|
var import_evm = require("@t402/evm");
|
|
1441
|
-
var
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
this._normalizedChains = /* @__PURE__ */ new Map();
|
|
1453
|
-
this._signerCache = /* @__PURE__ */ new Map();
|
|
1454
|
-
this._initializationError = null;
|
|
1455
|
-
if (!seedPhrase || typeof seedPhrase !== "string") {
|
|
1456
|
-
throw new WDKInitializationError("Seed phrase is required and must be a string");
|
|
1457
|
-
}
|
|
1458
|
-
const words = seedPhrase.trim().split(/\s+/);
|
|
1459
|
-
const validWordCounts = [12, 15, 18, 21, 24];
|
|
1460
|
-
if (!validWordCounts.includes(words.length)) {
|
|
1461
|
-
throw new WDKInitializationError(
|
|
1462
|
-
`Invalid seed phrase: expected 12, 15, 18, 21, or 24 words, got ${words.length}`,
|
|
1463
|
-
{ context: { wordCount: words.length } }
|
|
1464
|
-
);
|
|
1465
|
-
}
|
|
1466
|
-
this._seedPhrase = seedPhrase;
|
|
1467
|
-
this._config = config;
|
|
1468
|
-
this._options = options;
|
|
1469
|
-
this._balanceCache = new BalanceCache(options.cache);
|
|
1470
|
-
for (const [chain, chainConfig] of Object.entries(config)) {
|
|
1471
|
-
if (chainConfig) {
|
|
1472
|
-
try {
|
|
1473
|
-
this._normalizedChains.set(chain, normalizeChainConfig(chain, chainConfig));
|
|
1474
|
-
} catch (error) {
|
|
1475
|
-
throw new ChainError(
|
|
1476
|
-
2003 /* INVALID_CHAIN_CONFIG */,
|
|
1477
|
-
`Invalid configuration for chain "${chain}": ${error instanceof Error ? error.message : String(error)}`,
|
|
1478
|
-
{ chain, cause: error instanceof Error ? error : void 0 }
|
|
1479
|
-
);
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
this._addDefaultChainsIfNeeded();
|
|
1484
|
-
if (_T402WDK._WDK) {
|
|
1485
|
-
this._initializeWDK();
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1447
|
+
var T402WDK = class _T402WDK {
|
|
1448
|
+
_wdk = null;
|
|
1449
|
+
_normalizedChains = /* @__PURE__ */ new Map();
|
|
1450
|
+
_seedPhrase;
|
|
1451
|
+
_signerCache = /* @__PURE__ */ new Map();
|
|
1452
|
+
_balanceCache;
|
|
1453
|
+
_initializationError = null;
|
|
1454
|
+
// WDK module references (set via registerWDK)
|
|
1455
|
+
static _WDK = null;
|
|
1456
|
+
static _WalletManagerEvm = null;
|
|
1457
|
+
static _BridgeUsdt0Evm = null;
|
|
1488
1458
|
/**
|
|
1489
1459
|
* Register the Tether WDK modules
|
|
1490
1460
|
*
|
|
@@ -1552,6 +1522,46 @@ var _T402WDK = class _T402WDK {
|
|
|
1552
1522
|
);
|
|
1553
1523
|
}
|
|
1554
1524
|
}
|
|
1525
|
+
/**
|
|
1526
|
+
* Create a new T402WDK instance
|
|
1527
|
+
*
|
|
1528
|
+
* @param seedPhrase - BIP-39 mnemonic seed phrase
|
|
1529
|
+
* @param config - Chain configuration (RPC endpoints)
|
|
1530
|
+
* @param options - Additional options (cache configuration, etc.)
|
|
1531
|
+
* @throws {WDKInitializationError} If seed phrase is invalid
|
|
1532
|
+
*/
|
|
1533
|
+
constructor(seedPhrase, config = {}, options = {}) {
|
|
1534
|
+
if (!seedPhrase || typeof seedPhrase !== "string") {
|
|
1535
|
+
throw new WDKInitializationError("Seed phrase is required and must be a string");
|
|
1536
|
+
}
|
|
1537
|
+
const words = seedPhrase.trim().split(/\s+/);
|
|
1538
|
+
const validWordCounts = [12, 15, 18, 21, 24];
|
|
1539
|
+
if (!validWordCounts.includes(words.length)) {
|
|
1540
|
+
throw new WDKInitializationError(
|
|
1541
|
+
`Invalid seed phrase: expected 12, 15, 18, 21, or 24 words, got ${words.length}`,
|
|
1542
|
+
{ context: { wordCount: words.length } }
|
|
1543
|
+
);
|
|
1544
|
+
}
|
|
1545
|
+
this._seedPhrase = seedPhrase;
|
|
1546
|
+
this._balanceCache = new BalanceCache(options.cache);
|
|
1547
|
+
for (const [chain, chainConfig] of Object.entries(config)) {
|
|
1548
|
+
if (chainConfig) {
|
|
1549
|
+
try {
|
|
1550
|
+
this._normalizedChains.set(chain, normalizeChainConfig(chain, chainConfig));
|
|
1551
|
+
} catch (error) {
|
|
1552
|
+
throw new ChainError(
|
|
1553
|
+
2003 /* INVALID_CHAIN_CONFIG */,
|
|
1554
|
+
`Invalid configuration for chain "${chain}": ${error instanceof Error ? error.message : String(error)}`,
|
|
1555
|
+
{ chain, cause: error instanceof Error ? error : void 0 }
|
|
1556
|
+
);
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
this._addDefaultChainsIfNeeded();
|
|
1561
|
+
if (_T402WDK._WDK) {
|
|
1562
|
+
this._initializeWDK();
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1555
1565
|
/**
|
|
1556
1566
|
* Add default chain configurations for common chains
|
|
1557
1567
|
*/
|
|
@@ -1559,10 +1569,7 @@ var _T402WDK = class _T402WDK {
|
|
|
1559
1569
|
if (this._normalizedChains.size === 0) {
|
|
1560
1570
|
const defaultEndpoint = DEFAULT_RPC_ENDPOINTS.arbitrum;
|
|
1561
1571
|
if (defaultEndpoint) {
|
|
1562
|
-
this._normalizedChains.set(
|
|
1563
|
-
"arbitrum",
|
|
1564
|
-
normalizeChainConfig("arbitrum", defaultEndpoint)
|
|
1565
|
-
);
|
|
1572
|
+
this._normalizedChains.set("arbitrum", normalizeChainConfig("arbitrum", defaultEndpoint));
|
|
1566
1573
|
}
|
|
1567
1574
|
}
|
|
1568
1575
|
}
|
|
@@ -1793,11 +1800,9 @@ var _T402WDK = class _T402WDK {
|
|
|
1793
1800
|
async getChainBalances(chain, accountIndex = 0) {
|
|
1794
1801
|
const config = this._normalizedChains.get(chain);
|
|
1795
1802
|
if (!config) {
|
|
1796
|
-
throw new ChainError(
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
{ chain }
|
|
1800
|
-
);
|
|
1803
|
+
throw new ChainError(2001 /* CHAIN_NOT_CONFIGURED */, `Chain "${chain}" not configured`, {
|
|
1804
|
+
chain
|
|
1805
|
+
});
|
|
1801
1806
|
}
|
|
1802
1807
|
try {
|
|
1803
1808
|
const signer = await this.getSigner(chain, accountIndex);
|
|
@@ -1947,7 +1952,10 @@ var _T402WDK = class _T402WDK {
|
|
|
1947
1952
|
throw new BalanceError(
|
|
1948
1953
|
5001 /* BALANCE_FETCH_FAILED */,
|
|
1949
1954
|
`Failed to find best chain for payment: ${error instanceof Error ? error.message : String(error)}`,
|
|
1950
|
-
{
|
|
1955
|
+
{
|
|
1956
|
+
cause: error instanceof Error ? error : void 0,
|
|
1957
|
+
context: { amount: amount.toString() }
|
|
1958
|
+
}
|
|
1951
1959
|
);
|
|
1952
1960
|
}
|
|
1953
1961
|
}
|
|
@@ -1969,25 +1977,23 @@ var _T402WDK = class _T402WDK {
|
|
|
1969
1977
|
);
|
|
1970
1978
|
}
|
|
1971
1979
|
if (!params.fromChain || !params.toChain) {
|
|
1972
|
-
throw new BridgeError(
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
);
|
|
1980
|
+
throw new BridgeError(7003 /* BRIDGE_FAILED */, "Both fromChain and toChain are required", {
|
|
1981
|
+
fromChain: params.fromChain,
|
|
1982
|
+
toChain: params.toChain
|
|
1983
|
+
});
|
|
1977
1984
|
}
|
|
1978
1985
|
if (params.fromChain === params.toChain) {
|
|
1979
|
-
throw new BridgeError(
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
);
|
|
1986
|
+
throw new BridgeError(7002 /* BRIDGE_NOT_SUPPORTED */, "Cannot bridge to the same chain", {
|
|
1987
|
+
fromChain: params.fromChain,
|
|
1988
|
+
toChain: params.toChain
|
|
1989
|
+
});
|
|
1984
1990
|
}
|
|
1985
1991
|
if (!params.amount || params.amount <= 0n) {
|
|
1986
|
-
throw new BridgeError(
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
);
|
|
1992
|
+
throw new BridgeError(7003 /* BRIDGE_FAILED */, "Amount must be greater than 0", {
|
|
1993
|
+
fromChain: params.fromChain,
|
|
1994
|
+
toChain: params.toChain,
|
|
1995
|
+
context: { amount: params.amount?.toString() }
|
|
1996
|
+
});
|
|
1991
1997
|
}
|
|
1992
1998
|
if (!this.canBridge(params.fromChain, params.toChain)) {
|
|
1993
1999
|
throw new BridgeError(
|
|
@@ -2116,11 +2122,6 @@ var _T402WDK = class _T402WDK {
|
|
|
2116
2122
|
this._signerCache.clear();
|
|
2117
2123
|
}
|
|
2118
2124
|
};
|
|
2119
|
-
// WDK module references (set via registerWDK)
|
|
2120
|
-
_T402WDK._WDK = null;
|
|
2121
|
-
_T402WDK._WalletManagerEvm = null;
|
|
2122
|
-
_T402WDK._BridgeUsdt0Evm = null;
|
|
2123
|
-
var T402WDK = _T402WDK;
|
|
2124
2125
|
function formatTokenAmount(amount, decimals) {
|
|
2125
2126
|
if (amount === 0n) {
|
|
2126
2127
|
return "0";
|
|
@@ -2139,26 +2140,24 @@ function formatTokenAmount(amount, decimals) {
|
|
|
2139
2140
|
// src/bridge.ts
|
|
2140
2141
|
var import_evm2 = require("@t402/evm");
|
|
2141
2142
|
var WdkBridge = class {
|
|
2142
|
-
|
|
2143
|
-
this.bridges = /* @__PURE__ */ new Map();
|
|
2144
|
-
}
|
|
2143
|
+
bridges = /* @__PURE__ */ new Map();
|
|
2145
2144
|
/**
|
|
2146
2145
|
* Create bridge signer adapter from WDK signer
|
|
2147
2146
|
*/
|
|
2148
2147
|
createBridgeSigner(signer) {
|
|
2149
2148
|
return {
|
|
2150
2149
|
address: signer.address,
|
|
2151
|
-
readContract: async (
|
|
2150
|
+
readContract: async (_args) => {
|
|
2152
2151
|
throw new Error(
|
|
2153
2152
|
"readContract not available on WDKSigner. Use T402WDK.bridgeUsdt0() instead."
|
|
2154
2153
|
);
|
|
2155
2154
|
},
|
|
2156
|
-
writeContract: async (
|
|
2155
|
+
writeContract: async (_args) => {
|
|
2157
2156
|
throw new Error(
|
|
2158
2157
|
"writeContract not available on WDKSigner. Use T402WDK.bridgeUsdt0() instead."
|
|
2159
2158
|
);
|
|
2160
2159
|
},
|
|
2161
|
-
waitForTransactionReceipt: async (
|
|
2160
|
+
waitForTransactionReceipt: async (_args) => {
|
|
2162
2161
|
throw new Error(
|
|
2163
2162
|
"waitForTransactionReceipt not available on WDKSigner. Use T402WDK.bridgeUsdt0() instead."
|
|
2164
2163
|
);
|
|
@@ -2203,6 +2202,629 @@ function createDirectBridge(signer, chain) {
|
|
|
2203
2202
|
|
|
2204
2203
|
// src/index.ts
|
|
2205
2204
|
var import_evm3 = require("@t402/evm");
|
|
2205
|
+
|
|
2206
|
+
// src/hardware/types.ts
|
|
2207
|
+
var HardwareWalletErrorCode = /* @__PURE__ */ ((HardwareWalletErrorCode2) => {
|
|
2208
|
+
HardwareWalletErrorCode2["DEVICE_NOT_FOUND"] = "DEVICE_NOT_FOUND";
|
|
2209
|
+
HardwareWalletErrorCode2["CONNECTION_FAILED"] = "CONNECTION_FAILED";
|
|
2210
|
+
HardwareWalletErrorCode2["DEVICE_LOCKED"] = "DEVICE_LOCKED";
|
|
2211
|
+
HardwareWalletErrorCode2["APP_NOT_OPEN"] = "APP_NOT_OPEN";
|
|
2212
|
+
HardwareWalletErrorCode2["TRANSPORT_ERROR"] = "TRANSPORT_ERROR";
|
|
2213
|
+
HardwareWalletErrorCode2["USER_REJECTED"] = "USER_REJECTED";
|
|
2214
|
+
HardwareWalletErrorCode2["SIGNING_FAILED"] = "SIGNING_FAILED";
|
|
2215
|
+
HardwareWalletErrorCode2["INVALID_DATA"] = "INVALID_DATA";
|
|
2216
|
+
HardwareWalletErrorCode2["NOT_SUPPORTED"] = "NOT_SUPPORTED";
|
|
2217
|
+
HardwareWalletErrorCode2["TIMEOUT"] = "TIMEOUT";
|
|
2218
|
+
HardwareWalletErrorCode2["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
|
|
2219
|
+
return HardwareWalletErrorCode2;
|
|
2220
|
+
})(HardwareWalletErrorCode || {});
|
|
2221
|
+
var HardwareWalletError = class extends Error {
|
|
2222
|
+
code;
|
|
2223
|
+
walletType;
|
|
2224
|
+
cause;
|
|
2225
|
+
constructor(code, message, walletType, cause) {
|
|
2226
|
+
super(message);
|
|
2227
|
+
this.name = "HardwareWalletError";
|
|
2228
|
+
this.code = code;
|
|
2229
|
+
this.walletType = walletType;
|
|
2230
|
+
this.cause = cause;
|
|
2231
|
+
}
|
|
2232
|
+
};
|
|
2233
|
+
|
|
2234
|
+
// src/hardware/ledger.ts
|
|
2235
|
+
var DEFAULT_DERIVATION_PATH = "m/44'/60'/0'/0";
|
|
2236
|
+
var LedgerSigner = class {
|
|
2237
|
+
walletType = "ledger";
|
|
2238
|
+
_address = null;
|
|
2239
|
+
_transport = null;
|
|
2240
|
+
_eth = null;
|
|
2241
|
+
_options;
|
|
2242
|
+
_status = "disconnected";
|
|
2243
|
+
_deviceInfo;
|
|
2244
|
+
constructor(options = {}) {
|
|
2245
|
+
this._options = {
|
|
2246
|
+
transport: options.transport ?? "webusb",
|
|
2247
|
+
accountIndex: options.accountIndex ?? 0,
|
|
2248
|
+
derivationPath: options.derivationPath ?? `${DEFAULT_DERIVATION_PATH}/${options.accountIndex ?? 0}`,
|
|
2249
|
+
timeout: options.timeout ?? 3e4,
|
|
2250
|
+
scrambleKey: options.scrambleKey ?? true,
|
|
2251
|
+
appName: options.appName ?? "Ethereum"
|
|
2252
|
+
};
|
|
2253
|
+
this._deviceInfo = {
|
|
2254
|
+
type: "ledger",
|
|
2255
|
+
isLocked: true,
|
|
2256
|
+
status: "disconnected"
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
/**
|
|
2260
|
+
* Get the wallet address
|
|
2261
|
+
*/
|
|
2262
|
+
get address() {
|
|
2263
|
+
if (!this._address) {
|
|
2264
|
+
throw new HardwareWalletError(
|
|
2265
|
+
"CONNECTION_FAILED" /* CONNECTION_FAILED */,
|
|
2266
|
+
"Ledger not connected. Call connect() first.",
|
|
2267
|
+
"ledger"
|
|
2268
|
+
);
|
|
2269
|
+
}
|
|
2270
|
+
return this._address;
|
|
2271
|
+
}
|
|
2272
|
+
/**
|
|
2273
|
+
* Get device info
|
|
2274
|
+
*/
|
|
2275
|
+
get deviceInfo() {
|
|
2276
|
+
return { ...this._deviceInfo };
|
|
2277
|
+
}
|
|
2278
|
+
/**
|
|
2279
|
+
* Check if connected
|
|
2280
|
+
*/
|
|
2281
|
+
get isConnected() {
|
|
2282
|
+
return this._status === "ready" && this._transport !== null;
|
|
2283
|
+
}
|
|
2284
|
+
/**
|
|
2285
|
+
* Get the derivation path
|
|
2286
|
+
*/
|
|
2287
|
+
get derivationPath() {
|
|
2288
|
+
return this._options.derivationPath;
|
|
2289
|
+
}
|
|
2290
|
+
/**
|
|
2291
|
+
* Connect to the Ledger device
|
|
2292
|
+
*/
|
|
2293
|
+
async connect() {
|
|
2294
|
+
if (this.isConnected) {
|
|
2295
|
+
return;
|
|
2296
|
+
}
|
|
2297
|
+
this._status = "connecting";
|
|
2298
|
+
this._deviceInfo.status = "connecting";
|
|
2299
|
+
try {
|
|
2300
|
+
const TransportModule = await this._getTransportModule();
|
|
2301
|
+
const EthModule = await import("@ledgerhq/hw-app-eth");
|
|
2302
|
+
this._transport = await TransportModule.default.create();
|
|
2303
|
+
this._status = "connected";
|
|
2304
|
+
this._deviceInfo.status = "connected";
|
|
2305
|
+
this._eth = new EthModule.default(this._transport);
|
|
2306
|
+
try {
|
|
2307
|
+
const appConfig = await this._eth.getAppConfiguration();
|
|
2308
|
+
this._deviceInfo.firmwareVersion = appConfig.version;
|
|
2309
|
+
} catch {
|
|
2310
|
+
}
|
|
2311
|
+
const result = await this._eth.getAddress(this._options.derivationPath, false);
|
|
2312
|
+
this._address = result.address;
|
|
2313
|
+
this._status = "ready";
|
|
2314
|
+
this._deviceInfo.status = "ready";
|
|
2315
|
+
this._deviceInfo.isLocked = false;
|
|
2316
|
+
} catch (error) {
|
|
2317
|
+
this._status = "disconnected";
|
|
2318
|
+
this._deviceInfo.status = "disconnected";
|
|
2319
|
+
this._transport = null;
|
|
2320
|
+
this._eth = null;
|
|
2321
|
+
throw this._wrapError(error);
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
/**
|
|
2325
|
+
* Disconnect from the Ledger device
|
|
2326
|
+
*/
|
|
2327
|
+
async disconnect() {
|
|
2328
|
+
if (this._transport) {
|
|
2329
|
+
try {
|
|
2330
|
+
await this._transport.close();
|
|
2331
|
+
} catch {
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
this._transport = null;
|
|
2335
|
+
this._eth = null;
|
|
2336
|
+
this._address = null;
|
|
2337
|
+
this._status = "disconnected";
|
|
2338
|
+
this._deviceInfo.status = "disconnected";
|
|
2339
|
+
this._deviceInfo.isLocked = true;
|
|
2340
|
+
}
|
|
2341
|
+
/**
|
|
2342
|
+
* Sign EIP-712 typed data
|
|
2343
|
+
*
|
|
2344
|
+
* Note: Requires Ethereum app version 1.6.0+ for EIP-712 support
|
|
2345
|
+
*/
|
|
2346
|
+
async signTypedData(params) {
|
|
2347
|
+
if (!this.isConnected || !this._eth) {
|
|
2348
|
+
throw new HardwareWalletError(
|
|
2349
|
+
"CONNECTION_FAILED" /* CONNECTION_FAILED */,
|
|
2350
|
+
"Ledger not connected",
|
|
2351
|
+
"ledger"
|
|
2352
|
+
);
|
|
2353
|
+
}
|
|
2354
|
+
try {
|
|
2355
|
+
const result = await this._eth.signEIP712Message(this._options.derivationPath, {
|
|
2356
|
+
domain: params.domain,
|
|
2357
|
+
types: params.types,
|
|
2358
|
+
primaryType: params.primaryType,
|
|
2359
|
+
message: params.message
|
|
2360
|
+
});
|
|
2361
|
+
const r = result.r.padStart(64, "0");
|
|
2362
|
+
const s = result.s.padStart(64, "0");
|
|
2363
|
+
const v = result.v.toString(16).padStart(2, "0");
|
|
2364
|
+
return `0x${r}${s}${v}`;
|
|
2365
|
+
} catch (error) {
|
|
2366
|
+
throw this._wrapError(error);
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
/**
|
|
2370
|
+
* Sign a personal message
|
|
2371
|
+
*/
|
|
2372
|
+
async signMessage(message) {
|
|
2373
|
+
if (!this.isConnected || !this._eth) {
|
|
2374
|
+
throw new HardwareWalletError(
|
|
2375
|
+
"CONNECTION_FAILED" /* CONNECTION_FAILED */,
|
|
2376
|
+
"Ledger not connected",
|
|
2377
|
+
"ledger"
|
|
2378
|
+
);
|
|
2379
|
+
}
|
|
2380
|
+
try {
|
|
2381
|
+
const messageHex = typeof message === "string" ? Buffer.from(message).toString("hex") : Buffer.from(message).toString("hex");
|
|
2382
|
+
const result = await this._eth.signPersonalMessage(this._options.derivationPath, messageHex);
|
|
2383
|
+
const r = result.r.padStart(64, "0");
|
|
2384
|
+
const s = result.s.padStart(64, "0");
|
|
2385
|
+
const v = result.v.toString(16).padStart(2, "0");
|
|
2386
|
+
return `0x${r}${s}${v}`;
|
|
2387
|
+
} catch (error) {
|
|
2388
|
+
throw this._wrapError(error);
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
/**
|
|
2392
|
+
* Get multiple addresses for account selection
|
|
2393
|
+
*/
|
|
2394
|
+
async getAddresses(count = 5, startIndex = 0) {
|
|
2395
|
+
if (!this.isConnected || !this._eth) {
|
|
2396
|
+
throw new HardwareWalletError(
|
|
2397
|
+
"CONNECTION_FAILED" /* CONNECTION_FAILED */,
|
|
2398
|
+
"Ledger not connected",
|
|
2399
|
+
"ledger"
|
|
2400
|
+
);
|
|
2401
|
+
}
|
|
2402
|
+
const addresses = [];
|
|
2403
|
+
for (let i = startIndex; i < startIndex + count; i++) {
|
|
2404
|
+
const path = `${DEFAULT_DERIVATION_PATH}/${i}`;
|
|
2405
|
+
const result = await this._eth.getAddress(path, false);
|
|
2406
|
+
addresses.push(result.address);
|
|
2407
|
+
}
|
|
2408
|
+
return addresses;
|
|
2409
|
+
}
|
|
2410
|
+
/**
|
|
2411
|
+
* Get the appropriate transport module based on options
|
|
2412
|
+
*/
|
|
2413
|
+
async _getTransportModule() {
|
|
2414
|
+
switch (this._options.transport) {
|
|
2415
|
+
case "webhid":
|
|
2416
|
+
return import("@ledgerhq/hw-transport-webhid");
|
|
2417
|
+
case "bluetooth":
|
|
2418
|
+
return import("@ledgerhq/hw-transport-web-ble");
|
|
2419
|
+
case "webusb":
|
|
2420
|
+
default:
|
|
2421
|
+
return import("@ledgerhq/hw-transport-webusb");
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
/**
|
|
2425
|
+
* Wrap errors in HardwareWalletError
|
|
2426
|
+
*/
|
|
2427
|
+
_wrapError(error) {
|
|
2428
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
2429
|
+
const message = err.message.toLowerCase();
|
|
2430
|
+
if (message.includes("denied") || message.includes("rejected")) {
|
|
2431
|
+
return new HardwareWalletError(
|
|
2432
|
+
"USER_REJECTED" /* USER_REJECTED */,
|
|
2433
|
+
"User rejected the action on the Ledger device",
|
|
2434
|
+
"ledger",
|
|
2435
|
+
err
|
|
2436
|
+
);
|
|
2437
|
+
}
|
|
2438
|
+
if (message.includes("locked")) {
|
|
2439
|
+
return new HardwareWalletError(
|
|
2440
|
+
"DEVICE_LOCKED" /* DEVICE_LOCKED */,
|
|
2441
|
+
"Ledger device is locked. Please unlock it.",
|
|
2442
|
+
"ledger",
|
|
2443
|
+
err
|
|
2444
|
+
);
|
|
2445
|
+
}
|
|
2446
|
+
if (message.includes("no device") || message.includes("not found")) {
|
|
2447
|
+
return new HardwareWalletError(
|
|
2448
|
+
"DEVICE_NOT_FOUND" /* DEVICE_NOT_FOUND */,
|
|
2449
|
+
"Ledger device not found. Please connect your device.",
|
|
2450
|
+
"ledger",
|
|
2451
|
+
err
|
|
2452
|
+
);
|
|
2453
|
+
}
|
|
2454
|
+
if (message.includes("app") || message.includes("ethereum")) {
|
|
2455
|
+
return new HardwareWalletError(
|
|
2456
|
+
"APP_NOT_OPEN" /* APP_NOT_OPEN */,
|
|
2457
|
+
"Please open the Ethereum app on your Ledger device.",
|
|
2458
|
+
"ledger",
|
|
2459
|
+
err
|
|
2460
|
+
);
|
|
2461
|
+
}
|
|
2462
|
+
if (message.includes("timeout")) {
|
|
2463
|
+
return new HardwareWalletError(
|
|
2464
|
+
"TIMEOUT" /* TIMEOUT */,
|
|
2465
|
+
"Connection timed out",
|
|
2466
|
+
"ledger",
|
|
2467
|
+
err
|
|
2468
|
+
);
|
|
2469
|
+
}
|
|
2470
|
+
return new HardwareWalletError(
|
|
2471
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
2472
|
+
err.message,
|
|
2473
|
+
"ledger",
|
|
2474
|
+
err
|
|
2475
|
+
);
|
|
2476
|
+
}
|
|
2477
|
+
};
|
|
2478
|
+
async function createLedgerSigner(options) {
|
|
2479
|
+
const signer = new LedgerSigner(options);
|
|
2480
|
+
await signer.connect();
|
|
2481
|
+
return signer;
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
// src/hardware/trezor.ts
|
|
2485
|
+
var DEFAULT_DERIVATION_PATH2 = "m/44'/60'/0'/0";
|
|
2486
|
+
var TrezorConnect = null;
|
|
2487
|
+
var TrezorSigner = class {
|
|
2488
|
+
walletType = "trezor";
|
|
2489
|
+
_address = null;
|
|
2490
|
+
_options;
|
|
2491
|
+
_status = "disconnected";
|
|
2492
|
+
_deviceInfo;
|
|
2493
|
+
_initialized = false;
|
|
2494
|
+
constructor(options) {
|
|
2495
|
+
if (!options.manifest) {
|
|
2496
|
+
throw new HardwareWalletError(
|
|
2497
|
+
"INVALID_DATA" /* INVALID_DATA */,
|
|
2498
|
+
"Trezor manifest is required (email and appUrl)",
|
|
2499
|
+
"trezor"
|
|
2500
|
+
);
|
|
2501
|
+
}
|
|
2502
|
+
this._options = {
|
|
2503
|
+
manifest: options.manifest,
|
|
2504
|
+
transport: options.transport ?? "webusb",
|
|
2505
|
+
accountIndex: options.accountIndex ?? 0,
|
|
2506
|
+
derivationPath: options.derivationPath ?? `${DEFAULT_DERIVATION_PATH2}/${options.accountIndex ?? 0}`,
|
|
2507
|
+
timeout: options.timeout ?? 3e4,
|
|
2508
|
+
popup: options.popup ?? true,
|
|
2509
|
+
debug: options.debug ?? false
|
|
2510
|
+
};
|
|
2511
|
+
this._deviceInfo = {
|
|
2512
|
+
type: "trezor",
|
|
2513
|
+
isLocked: true,
|
|
2514
|
+
status: "disconnected"
|
|
2515
|
+
};
|
|
2516
|
+
}
|
|
2517
|
+
/**
|
|
2518
|
+
* Get the wallet address
|
|
2519
|
+
*/
|
|
2520
|
+
get address() {
|
|
2521
|
+
if (!this._address) {
|
|
2522
|
+
throw new HardwareWalletError(
|
|
2523
|
+
"CONNECTION_FAILED" /* CONNECTION_FAILED */,
|
|
2524
|
+
"Trezor not connected. Call connect() first.",
|
|
2525
|
+
"trezor"
|
|
2526
|
+
);
|
|
2527
|
+
}
|
|
2528
|
+
return this._address;
|
|
2529
|
+
}
|
|
2530
|
+
/**
|
|
2531
|
+
* Get device info
|
|
2532
|
+
*/
|
|
2533
|
+
get deviceInfo() {
|
|
2534
|
+
return { ...this._deviceInfo };
|
|
2535
|
+
}
|
|
2536
|
+
/**
|
|
2537
|
+
* Check if connected
|
|
2538
|
+
*/
|
|
2539
|
+
get isConnected() {
|
|
2540
|
+
return this._status === "ready" && this._address !== null;
|
|
2541
|
+
}
|
|
2542
|
+
/**
|
|
2543
|
+
* Get the derivation path
|
|
2544
|
+
*/
|
|
2545
|
+
get derivationPath() {
|
|
2546
|
+
return this._options.derivationPath;
|
|
2547
|
+
}
|
|
2548
|
+
/**
|
|
2549
|
+
* Initialize Trezor Connect
|
|
2550
|
+
*/
|
|
2551
|
+
async _initTrezorConnect() {
|
|
2552
|
+
if (this._initialized && TrezorConnect) {
|
|
2553
|
+
return;
|
|
2554
|
+
}
|
|
2555
|
+
try {
|
|
2556
|
+
const module2 = await import("@trezor/connect");
|
|
2557
|
+
TrezorConnect = module2.default;
|
|
2558
|
+
await TrezorConnect.init({
|
|
2559
|
+
manifest: {
|
|
2560
|
+
email: this._options.manifest.email,
|
|
2561
|
+
appUrl: this._options.manifest.appUrl,
|
|
2562
|
+
appName: "T402 WDK"
|
|
2563
|
+
},
|
|
2564
|
+
popup: this._options.popup,
|
|
2565
|
+
debug: this._options.debug
|
|
2566
|
+
});
|
|
2567
|
+
this._initialized = true;
|
|
2568
|
+
} catch (error) {
|
|
2569
|
+
throw new HardwareWalletError(
|
|
2570
|
+
"CONNECTION_FAILED" /* CONNECTION_FAILED */,
|
|
2571
|
+
`Failed to initialize Trezor Connect: ${error instanceof Error ? error.message : String(error)}`,
|
|
2572
|
+
"trezor",
|
|
2573
|
+
error instanceof Error ? error : void 0
|
|
2574
|
+
);
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* Connect to the Trezor device
|
|
2579
|
+
*/
|
|
2580
|
+
async connect() {
|
|
2581
|
+
if (this.isConnected) {
|
|
2582
|
+
return;
|
|
2583
|
+
}
|
|
2584
|
+
this._status = "connecting";
|
|
2585
|
+
this._deviceInfo.status = "connecting";
|
|
2586
|
+
try {
|
|
2587
|
+
await this._initTrezorConnect();
|
|
2588
|
+
if (!TrezorConnect) {
|
|
2589
|
+
throw new Error("TrezorConnect not initialized");
|
|
2590
|
+
}
|
|
2591
|
+
const featuresResult = await TrezorConnect.getFeatures();
|
|
2592
|
+
if (featuresResult.success) {
|
|
2593
|
+
const features = featuresResult.payload;
|
|
2594
|
+
this._deviceInfo.model = features.model;
|
|
2595
|
+
this._deviceInfo.firmwareVersion = `${features.major_version}.${features.minor_version}.${features.patch_version}`;
|
|
2596
|
+
}
|
|
2597
|
+
const result = await TrezorConnect.ethereumGetAddress({
|
|
2598
|
+
path: this._options.derivationPath,
|
|
2599
|
+
showOnTrezor: false
|
|
2600
|
+
});
|
|
2601
|
+
if (!result.success) {
|
|
2602
|
+
throw new Error(result.payload.error || "Failed to get address");
|
|
2603
|
+
}
|
|
2604
|
+
this._address = result.payload.address;
|
|
2605
|
+
this._status = "ready";
|
|
2606
|
+
this._deviceInfo.status = "ready";
|
|
2607
|
+
this._deviceInfo.isLocked = false;
|
|
2608
|
+
} catch (error) {
|
|
2609
|
+
this._status = "disconnected";
|
|
2610
|
+
this._deviceInfo.status = "disconnected";
|
|
2611
|
+
this._address = null;
|
|
2612
|
+
throw this._wrapError(error);
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
/**
|
|
2616
|
+
* Disconnect from the Trezor device
|
|
2617
|
+
*/
|
|
2618
|
+
async disconnect() {
|
|
2619
|
+
if (TrezorConnect) {
|
|
2620
|
+
try {
|
|
2621
|
+
TrezorConnect.dispose();
|
|
2622
|
+
} catch {
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
this._address = null;
|
|
2626
|
+
this._status = "disconnected";
|
|
2627
|
+
this._deviceInfo.status = "disconnected";
|
|
2628
|
+
this._deviceInfo.isLocked = true;
|
|
2629
|
+
this._initialized = false;
|
|
2630
|
+
TrezorConnect = null;
|
|
2631
|
+
}
|
|
2632
|
+
/**
|
|
2633
|
+
* Sign EIP-712 typed data
|
|
2634
|
+
*/
|
|
2635
|
+
async signTypedData(params) {
|
|
2636
|
+
if (!this.isConnected) {
|
|
2637
|
+
throw new HardwareWalletError(
|
|
2638
|
+
"CONNECTION_FAILED" /* CONNECTION_FAILED */,
|
|
2639
|
+
"Trezor not connected",
|
|
2640
|
+
"trezor"
|
|
2641
|
+
);
|
|
2642
|
+
}
|
|
2643
|
+
await this._initTrezorConnect();
|
|
2644
|
+
if (!TrezorConnect) {
|
|
2645
|
+
throw new Error("TrezorConnect not initialized");
|
|
2646
|
+
}
|
|
2647
|
+
try {
|
|
2648
|
+
const trezorTypes = this._convertTypesToTrezorFormat(params.types);
|
|
2649
|
+
if (!trezorTypes.EIP712Domain) {
|
|
2650
|
+
trezorTypes.EIP712Domain = [
|
|
2651
|
+
{ name: "name", type: "string" },
|
|
2652
|
+
{ name: "version", type: "string" },
|
|
2653
|
+
{ name: "chainId", type: "uint256" },
|
|
2654
|
+
{ name: "verifyingContract", type: "address" }
|
|
2655
|
+
];
|
|
2656
|
+
}
|
|
2657
|
+
const result = await TrezorConnect.ethereumSignTypedData({
|
|
2658
|
+
path: this._options.derivationPath,
|
|
2659
|
+
data: {
|
|
2660
|
+
domain: params.domain,
|
|
2661
|
+
types: trezorTypes,
|
|
2662
|
+
primaryType: params.primaryType,
|
|
2663
|
+
message: params.message
|
|
2664
|
+
},
|
|
2665
|
+
metamask_v4_compat: true
|
|
2666
|
+
});
|
|
2667
|
+
if (!result.success) {
|
|
2668
|
+
throw new Error(result.payload.error || "Failed to sign typed data");
|
|
2669
|
+
}
|
|
2670
|
+
return result.payload.signature;
|
|
2671
|
+
} catch (error) {
|
|
2672
|
+
throw this._wrapError(error);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
/**
|
|
2676
|
+
* Sign a personal message
|
|
2677
|
+
*/
|
|
2678
|
+
async signMessage(message) {
|
|
2679
|
+
if (!this.isConnected) {
|
|
2680
|
+
throw new HardwareWalletError(
|
|
2681
|
+
"CONNECTION_FAILED" /* CONNECTION_FAILED */,
|
|
2682
|
+
"Trezor not connected",
|
|
2683
|
+
"trezor"
|
|
2684
|
+
);
|
|
2685
|
+
}
|
|
2686
|
+
await this._initTrezorConnect();
|
|
2687
|
+
if (!TrezorConnect) {
|
|
2688
|
+
throw new Error("TrezorConnect not initialized");
|
|
2689
|
+
}
|
|
2690
|
+
try {
|
|
2691
|
+
const messageHex = typeof message === "string" ? `0x${Buffer.from(message).toString("hex")}` : `0x${Buffer.from(message).toString("hex")}`;
|
|
2692
|
+
const result = await TrezorConnect.ethereumSignMessage({
|
|
2693
|
+
path: this._options.derivationPath,
|
|
2694
|
+
message: messageHex,
|
|
2695
|
+
hex: true
|
|
2696
|
+
});
|
|
2697
|
+
if (!result.success) {
|
|
2698
|
+
throw new Error(result.payload.error || "Failed to sign message");
|
|
2699
|
+
}
|
|
2700
|
+
return `0x${result.payload.signature}`;
|
|
2701
|
+
} catch (error) {
|
|
2702
|
+
throw this._wrapError(error);
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
/**
|
|
2706
|
+
* Get multiple addresses for account selection
|
|
2707
|
+
*/
|
|
2708
|
+
async getAddresses(count = 5, startIndex = 0) {
|
|
2709
|
+
if (!this.isConnected) {
|
|
2710
|
+
throw new HardwareWalletError(
|
|
2711
|
+
"CONNECTION_FAILED" /* CONNECTION_FAILED */,
|
|
2712
|
+
"Trezor not connected",
|
|
2713
|
+
"trezor"
|
|
2714
|
+
);
|
|
2715
|
+
}
|
|
2716
|
+
await this._initTrezorConnect();
|
|
2717
|
+
if (!TrezorConnect) {
|
|
2718
|
+
throw new Error("TrezorConnect not initialized");
|
|
2719
|
+
}
|
|
2720
|
+
const addresses = [];
|
|
2721
|
+
const bundle = [];
|
|
2722
|
+
for (let i = startIndex; i < startIndex + count; i++) {
|
|
2723
|
+
bundle.push({
|
|
2724
|
+
path: `${DEFAULT_DERIVATION_PATH2}/${i}`,
|
|
2725
|
+
showOnTrezor: false
|
|
2726
|
+
});
|
|
2727
|
+
}
|
|
2728
|
+
const result = await TrezorConnect.ethereumGetAddress({ bundle });
|
|
2729
|
+
if (!result.success) {
|
|
2730
|
+
throw this._wrapError(new Error(result.payload.error || "Failed to get addresses"));
|
|
2731
|
+
}
|
|
2732
|
+
for (const item of result.payload) {
|
|
2733
|
+
addresses.push(item.address);
|
|
2734
|
+
}
|
|
2735
|
+
return addresses;
|
|
2736
|
+
}
|
|
2737
|
+
/**
|
|
2738
|
+
* Convert EIP-712 types to Trezor format
|
|
2739
|
+
*/
|
|
2740
|
+
_convertTypesToTrezorFormat(types) {
|
|
2741
|
+
const result = {};
|
|
2742
|
+
for (const [typeName, fields] of Object.entries(types)) {
|
|
2743
|
+
if (Array.isArray(fields)) {
|
|
2744
|
+
result[typeName] = fields.map((field) => ({
|
|
2745
|
+
name: String(field.name),
|
|
2746
|
+
type: String(field.type)
|
|
2747
|
+
}));
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
return result;
|
|
2751
|
+
}
|
|
2752
|
+
/**
|
|
2753
|
+
* Wrap errors in HardwareWalletError
|
|
2754
|
+
*/
|
|
2755
|
+
_wrapError(error) {
|
|
2756
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
2757
|
+
const message = err.message.toLowerCase();
|
|
2758
|
+
if (message.includes("cancelled") || message.includes("rejected") || message.includes("denied")) {
|
|
2759
|
+
return new HardwareWalletError(
|
|
2760
|
+
"USER_REJECTED" /* USER_REJECTED */,
|
|
2761
|
+
"User cancelled the action on the Trezor device",
|
|
2762
|
+
"trezor",
|
|
2763
|
+
err
|
|
2764
|
+
);
|
|
2765
|
+
}
|
|
2766
|
+
if (message.includes("pin")) {
|
|
2767
|
+
return new HardwareWalletError(
|
|
2768
|
+
"DEVICE_LOCKED" /* DEVICE_LOCKED */,
|
|
2769
|
+
"Trezor device requires PIN entry",
|
|
2770
|
+
"trezor",
|
|
2771
|
+
err
|
|
2772
|
+
);
|
|
2773
|
+
}
|
|
2774
|
+
if (message.includes("passphrase")) {
|
|
2775
|
+
return new HardwareWalletError(
|
|
2776
|
+
"DEVICE_LOCKED" /* DEVICE_LOCKED */,
|
|
2777
|
+
"Trezor device requires passphrase entry",
|
|
2778
|
+
"trezor",
|
|
2779
|
+
err
|
|
2780
|
+
);
|
|
2781
|
+
}
|
|
2782
|
+
if (message.includes("device") && message.includes("not found")) {
|
|
2783
|
+
return new HardwareWalletError(
|
|
2784
|
+
"DEVICE_NOT_FOUND" /* DEVICE_NOT_FOUND */,
|
|
2785
|
+
"Trezor device not found. Please connect your device.",
|
|
2786
|
+
"trezor",
|
|
2787
|
+
err
|
|
2788
|
+
);
|
|
2789
|
+
}
|
|
2790
|
+
if (message.includes("timeout")) {
|
|
2791
|
+
return new HardwareWalletError(
|
|
2792
|
+
"TIMEOUT" /* TIMEOUT */,
|
|
2793
|
+
"Connection timed out",
|
|
2794
|
+
"trezor",
|
|
2795
|
+
err
|
|
2796
|
+
);
|
|
2797
|
+
}
|
|
2798
|
+
return new HardwareWalletError(
|
|
2799
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
2800
|
+
err.message,
|
|
2801
|
+
"trezor",
|
|
2802
|
+
err
|
|
2803
|
+
);
|
|
2804
|
+
}
|
|
2805
|
+
};
|
|
2806
|
+
async function createTrezorSigner(options) {
|
|
2807
|
+
const signer = new TrezorSigner(options);
|
|
2808
|
+
await signer.connect();
|
|
2809
|
+
return signer;
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
// src/hardware/index.ts
|
|
2813
|
+
function detectHardwareWalletSupport() {
|
|
2814
|
+
const hasNavigator = typeof navigator !== "undefined";
|
|
2815
|
+
return {
|
|
2816
|
+
ledger: {
|
|
2817
|
+
webusb: hasNavigator && "usb" in navigator,
|
|
2818
|
+
webhid: hasNavigator && "hid" in navigator,
|
|
2819
|
+
bluetooth: hasNavigator && "bluetooth" in navigator
|
|
2820
|
+
},
|
|
2821
|
+
trezor: hasNavigator && "usb" in navigator
|
|
2822
|
+
};
|
|
2823
|
+
}
|
|
2824
|
+
function isHardwareWalletSupported() {
|
|
2825
|
+
const support = detectHardwareWalletSupport();
|
|
2826
|
+
return support.ledger.webusb || support.ledger.webhid || support.ledger.bluetooth || support.trezor;
|
|
2827
|
+
}
|
|
2206
2828
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2207
2829
|
0 && (module.exports = {
|
|
2208
2830
|
BalanceCache,
|
|
@@ -2215,7 +2837,10 @@ var import_evm3 = require("@t402/evm");
|
|
|
2215
2837
|
DEFAULT_CHAINS,
|
|
2216
2838
|
DEFAULT_RETRY_CONFIG,
|
|
2217
2839
|
DEFAULT_RPC_ENDPOINTS,
|
|
2840
|
+
HardwareWalletError,
|
|
2841
|
+
HardwareWalletErrorCode,
|
|
2218
2842
|
LAYERZERO_ENDPOINT_IDS,
|
|
2843
|
+
LedgerSigner,
|
|
2219
2844
|
MockWDKSigner,
|
|
2220
2845
|
RPCError,
|
|
2221
2846
|
SignerError,
|
|
@@ -2223,6 +2848,7 @@ var import_evm3 = require("@t402/evm");
|
|
|
2223
2848
|
T402WDK,
|
|
2224
2849
|
TTLCache,
|
|
2225
2850
|
TransactionError,
|
|
2851
|
+
TrezorSigner,
|
|
2226
2852
|
USDC_ADDRESSES,
|
|
2227
2853
|
USDT0_ADDRESSES,
|
|
2228
2854
|
USDT0_OFT_ADDRESSES,
|
|
@@ -2234,7 +2860,10 @@ var import_evm3 = require("@t402/evm");
|
|
|
2234
2860
|
WDKSigner,
|
|
2235
2861
|
WdkBridge,
|
|
2236
2862
|
createDirectBridge,
|
|
2863
|
+
createLedgerSigner,
|
|
2864
|
+
createTrezorSigner,
|
|
2237
2865
|
createWDKSigner,
|
|
2866
|
+
detectHardwareWalletSupport,
|
|
2238
2867
|
getBridgeableChains,
|
|
2239
2868
|
getChainFromNetwork,
|
|
2240
2869
|
getChainId,
|
|
@@ -2242,6 +2871,7 @@ var import_evm3 = require("@t402/evm");
|
|
|
2242
2871
|
getPreferredToken,
|
|
2243
2872
|
getUsdt0Chains,
|
|
2244
2873
|
hasErrorCode,
|
|
2874
|
+
isHardwareWalletSupported,
|
|
2245
2875
|
isWDKError,
|
|
2246
2876
|
normalizeChainConfig,
|
|
2247
2877
|
supportsBridging,
|