@enclave-hq/wallet-sdk 1.0.0 → 1.0.1

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.
@@ -2,6 +2,7 @@
2
2
 
3
3
  var React = require('react');
4
4
  var EventEmitter = require('eventemitter3');
5
+ var chainUtils = require('@enclave-hq/chain-utils');
5
6
  var viem = require('viem');
6
7
  var accounts = require('viem/accounts');
7
8
 
@@ -39,6 +40,7 @@ var TypedEventEmitter = class {
39
40
  return this;
40
41
  }
41
42
  };
43
+ var ChainType = chainUtils.ChainType;
42
44
 
43
45
  // src/core/errors.ts
44
46
  var WalletSDKError = class _WalletSDKError extends Error {
@@ -219,14 +221,15 @@ function formatEVMAddress(address) {
219
221
  }
220
222
  return viem.getAddress(address);
221
223
  }
222
-
223
- // src/utils/chain-info.ts
224
224
  var CHAIN_INFO = {
225
225
  // EVM Mainnet
226
226
  1: {
227
227
  id: 1,
228
+ slip44: 60,
229
+ // Ethereum SLIP-44
228
230
  name: "Ethereum Mainnet",
229
- chainType: "evm" /* EVM */,
231
+ chainType: chainUtils.ChainType.EVM,
232
+ symbol: "ETH",
230
233
  nativeCurrency: {
231
234
  name: "Ether",
232
235
  symbol: "ETH",
@@ -239,7 +242,8 @@ var CHAIN_INFO = {
239
242
  11155111: {
240
243
  id: 11155111,
241
244
  name: "Sepolia Testnet",
242
- chainType: "evm" /* EVM */,
245
+ chainType: chainUtils.ChainType.EVM,
246
+ symbol: "ETH",
243
247
  nativeCurrency: {
244
248
  name: "Sepolia Ether",
245
249
  symbol: "ETH",
@@ -251,8 +255,11 @@ var CHAIN_INFO = {
251
255
  // Binance Smart Chain
252
256
  56: {
253
257
  id: 56,
258
+ slip44: 714,
259
+ // BSC SLIP-44
254
260
  name: "BNB Smart Chain",
255
- chainType: "evm" /* EVM */,
261
+ chainType: chainUtils.ChainType.EVM,
262
+ symbol: "BNB",
256
263
  nativeCurrency: {
257
264
  name: "BNB",
258
265
  symbol: "BNB",
@@ -264,7 +271,8 @@ var CHAIN_INFO = {
264
271
  97: {
265
272
  id: 97,
266
273
  name: "BNB Smart Chain Testnet",
267
- chainType: "evm" /* EVM */,
274
+ chainType: chainUtils.ChainType.EVM,
275
+ symbol: "BNB",
268
276
  nativeCurrency: {
269
277
  name: "BNB",
270
278
  symbol: "BNB",
@@ -276,8 +284,11 @@ var CHAIN_INFO = {
276
284
  // Polygon
277
285
  137: {
278
286
  id: 137,
287
+ slip44: 966,
288
+ // Polygon SLIP-44
279
289
  name: "Polygon Mainnet",
280
- chainType: "evm" /* EVM */,
290
+ chainType: chainUtils.ChainType.EVM,
291
+ symbol: "MATIC",
281
292
  nativeCurrency: {
282
293
  name: "MATIC",
283
294
  symbol: "MATIC",
@@ -289,7 +300,8 @@ var CHAIN_INFO = {
289
300
  80002: {
290
301
  id: 80002,
291
302
  name: "Polygon Amoy Testnet",
292
- chainType: "evm" /* EVM */,
303
+ chainType: chainUtils.ChainType.EVM,
304
+ symbol: "MATIC",
293
305
  nativeCurrency: {
294
306
  name: "MATIC",
295
307
  symbol: "MATIC",
@@ -301,8 +313,11 @@ var CHAIN_INFO = {
301
313
  // Tron
302
314
  195: {
303
315
  id: 195,
316
+ slip44: 195,
317
+ // Tron SLIP-44
304
318
  name: "Tron Mainnet",
305
- chainType: "tron" /* TRON */,
319
+ chainType: chainUtils.ChainType.TRON,
320
+ symbol: "TRX",
306
321
  nativeCurrency: {
307
322
  name: "TRX",
308
323
  symbol: "TRX",
@@ -314,8 +329,11 @@ var CHAIN_INFO = {
314
329
  // Arbitrum
315
330
  42161: {
316
331
  id: 42161,
332
+ slip44: 1042161,
333
+ // Custom SLIP-44 (1000000 + 42161)
317
334
  name: "Arbitrum One",
318
- chainType: "evm" /* EVM */,
335
+ chainType: chainUtils.ChainType.EVM,
336
+ symbol: "ETH",
319
337
  nativeCurrency: {
320
338
  name: "Ether",
321
339
  symbol: "ETH",
@@ -327,8 +345,11 @@ var CHAIN_INFO = {
327
345
  // Optimism
328
346
  10: {
329
347
  id: 10,
348
+ slip44: 1000010,
349
+ // Custom SLIP-44 (1000000 + 10)
330
350
  name: "Optimism",
331
- chainType: "evm" /* EVM */,
351
+ chainType: chainUtils.ChainType.EVM,
352
+ symbol: "ETH",
332
353
  nativeCurrency: {
333
354
  name: "Ether",
334
355
  symbol: "ETH",
@@ -340,8 +361,11 @@ var CHAIN_INFO = {
340
361
  // Avalanche
341
362
  43114: {
342
363
  id: 43114,
364
+ slip44: 9e3,
365
+ // Avalanche SLIP-44
343
366
  name: "Avalanche C-Chain",
344
- chainType: "evm" /* EVM */,
367
+ chainType: chainUtils.ChainType.EVM,
368
+ symbol: "AVAX",
345
369
  nativeCurrency: {
346
370
  name: "AVAX",
347
371
  symbol: "AVAX",
@@ -360,26 +384,34 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
360
384
  constructor() {
361
385
  super(...arguments);
362
386
  this.type = "metamask" /* METAMASK */;
363
- this.chainType = "evm" /* EVM */;
387
+ this.chainType = ChainType.EVM;
364
388
  this.name = "MetaMask";
365
389
  this.icon = "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg";
366
390
  this.walletClient = null;
367
391
  this.publicClient = null;
368
392
  /**
369
393
  * 处理账户变化
394
+ *
395
+ * 注意:MetaMask 的行为
396
+ * - 切换到已连接的账户:触发事件,返回新账户 ['0xNewAddress']
397
+ * - 切换到未连接的账户:不触发事件(用户需要手动断开和重新连接)
398
+ * - 锁定钱包:触发事件,返回空数组 []
370
399
  */
371
400
  this.handleAccountsChanged = (accounts) => {
401
+ console.log("[MetaMask] accountsChanged event triggered:", accounts);
372
402
  if (accounts.length === 0) {
403
+ console.log("[MetaMask] Disconnecting: wallet locked or manually disconnected");
373
404
  this.setState("disconnected" /* DISCONNECTED */);
374
405
  this.setAccount(null);
375
406
  this.emitAccountChanged(null);
376
407
  } else {
377
408
  const address = formatEVMAddress(accounts[0]);
409
+ console.log("[MetaMask] Account changed to:", address);
378
410
  const account = {
379
411
  universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
380
412
  nativeAddress: address,
381
413
  chainId: this.currentAccount.chainId,
382
- chainType: "evm" /* EVM */,
414
+ chainType: ChainType.EVM,
383
415
  isActive: true
384
416
  };
385
417
  this.setAccount(account);
@@ -431,21 +463,23 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
431
463
  if (chainId && chainId !== parsedChainId) {
432
464
  await this.switchChain(chainId);
433
465
  }
466
+ const finalChainId = chainId || parsedChainId;
467
+ const viemChain = this.getViemChain(finalChainId);
434
468
  this.walletClient = viem.createWalletClient({
435
469
  account: accounts[0],
470
+ chain: viemChain,
436
471
  transport: viem.custom(provider)
437
472
  });
438
- const finalChainId = chainId || parsedChainId;
439
473
  this.publicClient = viem.createPublicClient({
440
- chain: this.getViemChain(finalChainId),
441
- transport: viem.http()
474
+ chain: viemChain,
475
+ transport: viem.custom(provider)
442
476
  });
443
477
  const address = formatEVMAddress(accounts[0]);
444
478
  const account = {
445
479
  universalAddress: createUniversalAddress(finalChainId, address),
446
480
  nativeAddress: address,
447
481
  chainId: finalChainId,
448
- chainType: "evm" /* EVM */,
482
+ chainType: ChainType.EVM,
449
483
  isActive: true
450
484
  };
451
485
  this.setState("connected" /* CONNECTED */);
@@ -499,6 +533,40 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
499
533
  throw error;
500
534
  }
501
535
  }
536
+ /**
537
+ * 签名交易
538
+ *
539
+ * Note: This signs a raw transaction without sending it.
540
+ * The transaction can be broadcast later using the returned signature.
541
+ */
542
+ async signTransaction(transaction) {
543
+ this.ensureConnected();
544
+ try {
545
+ const provider = this.getBrowserProvider();
546
+ const tx = {
547
+ from: this.currentAccount.nativeAddress,
548
+ to: transaction.to,
549
+ value: transaction.value ? `0x${BigInt(transaction.value).toString(16)}` : void 0,
550
+ data: transaction.data || "0x",
551
+ gas: transaction.gas ? `0x${BigInt(transaction.gas).toString(16)}` : void 0,
552
+ gasPrice: transaction.gasPrice ? `0x${BigInt(transaction.gasPrice).toString(16)}` : void 0,
553
+ maxFeePerGas: transaction.maxFeePerGas ? `0x${BigInt(transaction.maxFeePerGas).toString(16)}` : void 0,
554
+ maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ? `0x${BigInt(transaction.maxPriorityFeePerGas).toString(16)}` : void 0,
555
+ nonce: transaction.nonce !== void 0 ? `0x${transaction.nonce.toString(16)}` : void 0,
556
+ chainId: transaction.chainId || this.currentAccount.chainId
557
+ };
558
+ const signature = await provider.request({
559
+ method: "eth_signTransaction",
560
+ params: [tx]
561
+ });
562
+ return signature;
563
+ } catch (error) {
564
+ if (error.code === 4001) {
565
+ throw new SignatureRejectedError("Transaction signature was rejected by user");
566
+ }
567
+ throw error;
568
+ }
569
+ }
502
570
  /**
503
571
  * 切换链
504
572
  */
@@ -729,9 +797,14 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
729
797
  constructor() {
730
798
  super(...arguments);
731
799
  this.type = "tronlink" /* TRONLINK */;
732
- this.chainType = "tron" /* TRON */;
800
+ this.chainType = ChainType.TRON;
733
801
  this.name = "TronLink";
734
802
  this.icon = "https://www.tronlink.org/static/logoIcon.svg";
803
+ /**
804
+ * 轮询检测账户变化(备用方案)
805
+ */
806
+ this.pollingInterval = null;
807
+ this.lastKnownAddress = null;
735
808
  /**
736
809
  * 处理账户变化
737
810
  */
@@ -746,7 +819,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
746
819
  universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
747
820
  nativeAddress: address,
748
821
  chainId: this.currentAccount.chainId,
749
- chainType: "tron" /* TRON */,
822
+ chainType: ChainType.TRON,
750
823
  isActive: true
751
824
  };
752
825
  this.setAccount(account);
@@ -785,7 +858,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
785
858
  universalAddress: createUniversalAddress(tronChainId, address),
786
859
  nativeAddress: address,
787
860
  chainId: tronChainId,
788
- chainType: "tron" /* TRON */,
861
+ chainType: ChainType.TRON,
789
862
  isActive: true
790
863
  };
791
864
  this.setState("connected" /* CONNECTED */);
@@ -803,20 +876,177 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
803
876
  }
804
877
  /**
805
878
  * 签名消息
879
+ *
880
+ * Note: TronLink supports two signing methods:
881
+ * - trx.sign(): Signs a transaction object
882
+ * - trx.signMessageV2(): Signs a plain text message (what we use here)
806
883
  */
807
884
  async signMessage(message) {
808
885
  this.ensureConnected();
809
886
  try {
810
887
  const tronWeb = this.getTronWeb();
811
- const signature = await tronWeb.trx.sign(message);
812
- return signature;
888
+ if (typeof tronWeb.trx.signMessageV2 === "function") {
889
+ const signature = await tronWeb.trx.signMessageV2(message);
890
+ return signature;
891
+ } else {
892
+ console.warn("[TronLink] signMessageV2 not available, falling back to sign()");
893
+ const signature = await tronWeb.trx.sign(message);
894
+ return signature;
895
+ }
813
896
  } catch (error) {
814
897
  if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
815
898
  throw new SignatureRejectedError();
816
899
  }
900
+ if (error.message?.includes("Invalid transaction")) {
901
+ throw new Error("Invalid message format. For transaction signing, use signTransaction() instead.");
902
+ }
817
903
  throw error;
818
904
  }
819
905
  }
906
+ /**
907
+ * 签名交易
908
+ *
909
+ * Note: This uses trx.sign() which is specifically for signing transaction objects.
910
+ * For plain text message signing, use signMessage() instead.
911
+ */
912
+ async signTransaction(transaction) {
913
+ this.ensureConnected();
914
+ try {
915
+ const tronWeb = this.getTronWeb();
916
+ const signature = await tronWeb.trx.sign(transaction);
917
+ return signature;
918
+ } catch (error) {
919
+ if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
920
+ throw new SignatureRejectedError("Transaction signature was rejected by user");
921
+ }
922
+ if (error.message?.includes("Invalid transaction")) {
923
+ throw new Error("Invalid transaction format. Please provide a properly formatted Tron transaction object.");
924
+ }
925
+ throw error;
926
+ }
927
+ }
928
+ /**
929
+ * 读取合约
930
+ */
931
+ async readContract(params) {
932
+ this.ensureConnected();
933
+ try {
934
+ const tronWeb = this.getTronWeb();
935
+ const contract = await tronWeb.contract(params.abi, params.address);
936
+ const result = await contract[params.functionName](...params.args || []).call();
937
+ return result;
938
+ } catch (error) {
939
+ console.error("Read contract error:", error);
940
+ throw new Error(`Failed to read contract: ${error.message}`);
941
+ }
942
+ }
943
+ /**
944
+ * 写入合约
945
+ */
946
+ async writeContract(params) {
947
+ this.ensureConnected();
948
+ try {
949
+ const tronWeb = this.getTronWeb();
950
+ console.log("[TronLink] writeContract params:", {
951
+ address: params.address,
952
+ functionName: params.functionName,
953
+ args: params.args,
954
+ value: params.value,
955
+ gas: params.gas
956
+ });
957
+ if (!params.args || params.args.length === 0) {
958
+ throw new Error("Contract function arguments are required");
959
+ }
960
+ const hasUndefined = params.args.some((arg) => arg === void 0 || arg === null);
961
+ if (hasUndefined) {
962
+ console.error("[TronLink] Invalid args detected:", params.args);
963
+ throw new Error(`Invalid contract arguments: some arguments are undefined or null`);
964
+ }
965
+ const functionAbi = params.abi.find(
966
+ (item) => item.name === params.functionName && item.type === "function"
967
+ );
968
+ if (!functionAbi) {
969
+ throw new Error(`Function ${params.functionName} not found in ABI`);
970
+ }
971
+ console.log("[TronLink] Function ABI:", functionAbi);
972
+ console.log("[TronLink] Calling with args:", params.args);
973
+ const options = {
974
+ feeLimit: params.gas || 1e8,
975
+ // 默认 100 TRX 的能量限制
976
+ callValue: params.value || 0
977
+ // 发送的 TRX 数量(单位:SUN)
978
+ };
979
+ const parameter = functionAbi.inputs.map((input, index) => ({
980
+ type: input.type,
981
+ value: params.args[index]
982
+ }));
983
+ console.log("[TronLink] Transaction options:", options);
984
+ console.log("[TronLink] Parameters:", parameter);
985
+ const transaction = await tronWeb.transactionBuilder.triggerSmartContract(
986
+ params.address,
987
+ params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")",
988
+ options,
989
+ parameter,
990
+ this.currentAccount.nativeAddress
991
+ );
992
+ console.log("[TronLink] Transaction built:", transaction);
993
+ if (!transaction || !transaction.transaction) {
994
+ throw new Error("Failed to build transaction");
995
+ }
996
+ const signedTx = await tronWeb.trx.sign(transaction.transaction);
997
+ const broadcast = await tronWeb.trx.sendRawTransaction(signedTx);
998
+ console.log("[TronLink] Broadcast result:", broadcast);
999
+ if (!broadcast.result) {
1000
+ throw new Error(broadcast.message || "Transaction broadcast failed");
1001
+ }
1002
+ const txHash = broadcast.txid || broadcast.transaction?.txID;
1003
+ console.log("[TronLink] Transaction hash:", txHash);
1004
+ return txHash || "";
1005
+ } catch (error) {
1006
+ console.error("Write contract error:", error);
1007
+ if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
1008
+ throw new SignatureRejectedError("Transaction was rejected by user");
1009
+ }
1010
+ throw new Error(`Failed to write contract: ${error.message}`);
1011
+ }
1012
+ }
1013
+ /**
1014
+ * 等待交易确认
1015
+ */
1016
+ async waitForTransaction(txHash, _confirmations = 1) {
1017
+ try {
1018
+ const tronWeb = this.getTronWeb();
1019
+ let attempts = 0;
1020
+ const maxAttempts = 60;
1021
+ while (attempts < maxAttempts) {
1022
+ try {
1023
+ const txInfo = await tronWeb.trx.getTransactionInfo(txHash);
1024
+ if (txInfo && txInfo.id) {
1025
+ const receipt = {
1026
+ transactionHash: txHash,
1027
+ blockNumber: txInfo.blockNumber || 0,
1028
+ blockHash: txInfo.blockHash || "",
1029
+ from: this.currentAccount.nativeAddress,
1030
+ to: txInfo.contract_address || "",
1031
+ status: txInfo.receipt?.result === "SUCCESS" ? "success" : "failed",
1032
+ gasUsed: (txInfo.receipt?.energy_usage_total || 0).toString(),
1033
+ logs: txInfo.log || []
1034
+ };
1035
+ if (receipt.status === "failed") {
1036
+ throw new TransactionFailedError(txHash, "Transaction failed on Tron network");
1037
+ }
1038
+ return receipt;
1039
+ }
1040
+ } catch (error) {
1041
+ }
1042
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
1043
+ attempts++;
1044
+ }
1045
+ throw new Error("Transaction confirmation timeout");
1046
+ } catch (error) {
1047
+ throw new Error(`Failed to wait for transaction: ${error.message}`);
1048
+ }
1049
+ }
820
1050
  /**
821
1051
  * 获取 Provider
822
1052
  */
@@ -855,9 +1085,16 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
855
1085
  setupEventListeners() {
856
1086
  if (typeof window === "undefined") return;
857
1087
  const w = window;
858
- if (w.tronLink) {
859
- w.tronLink.on("accountsChanged", this.handleAccountsChanged);
860
- w.tronLink.on("disconnect", this.handleDisconnect);
1088
+ try {
1089
+ if (w.tronLink && typeof w.tronLink.on === "function") {
1090
+ w.tronLink.on("accountsChanged", this.handleAccountsChanged);
1091
+ w.tronLink.on("disconnect", this.handleDisconnect);
1092
+ } else if (w.tronWeb && w.tronWeb.eventServer) {
1093
+ this.startPolling();
1094
+ }
1095
+ } catch (error) {
1096
+ console.warn("TronLink event listener setup failed:", error);
1097
+ this.startPolling();
861
1098
  }
862
1099
  }
863
1100
  /**
@@ -866,9 +1103,38 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
866
1103
  removeEventListeners() {
867
1104
  if (typeof window === "undefined") return;
868
1105
  const w = window;
869
- if (w.tronLink) {
870
- w.tronLink.off("accountsChanged", this.handleAccountsChanged);
871
- w.tronLink.off("disconnect", this.handleDisconnect);
1106
+ try {
1107
+ if (w.tronLink && typeof w.tronLink.off === "function") {
1108
+ w.tronLink.off("accountsChanged", this.handleAccountsChanged);
1109
+ w.tronLink.off("disconnect", this.handleDisconnect);
1110
+ }
1111
+ } catch (error) {
1112
+ console.warn("TronLink event listener removal failed:", error);
1113
+ }
1114
+ this.stopPolling();
1115
+ }
1116
+ startPolling() {
1117
+ if (this.pollingInterval) return;
1118
+ this.lastKnownAddress = this.currentAccount?.nativeAddress || null;
1119
+ this.pollingInterval = setInterval(async () => {
1120
+ try {
1121
+ const tronWeb = this.getTronWeb();
1122
+ const currentAddress = tronWeb.defaultAddress?.base58;
1123
+ if (currentAddress && currentAddress !== this.lastKnownAddress) {
1124
+ this.lastKnownAddress = currentAddress;
1125
+ this.handleAccountsChanged({ address: { base58: currentAddress } });
1126
+ } else if (!currentAddress && this.lastKnownAddress) {
1127
+ this.lastKnownAddress = null;
1128
+ this.handleAccountsChanged(null);
1129
+ }
1130
+ } catch (error) {
1131
+ }
1132
+ }, 2e3);
1133
+ }
1134
+ stopPolling() {
1135
+ if (this.pollingInterval) {
1136
+ clearInterval(this.pollingInterval);
1137
+ this.pollingInterval = null;
872
1138
  }
873
1139
  }
874
1140
  };
@@ -879,7 +1145,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
879
1145
  constructor() {
880
1146
  super(...arguments);
881
1147
  this.type = "private-key" /* PRIVATE_KEY */;
882
- this.chainType = "evm" /* EVM */;
1148
+ this.chainType = ChainType.EVM;
883
1149
  this.name = "Private Key (EVM)";
884
1150
  this.privateKey = null;
885
1151
  this.walletClient = null;
@@ -909,7 +1175,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
909
1175
  universalAddress: createUniversalAddress(chainId, address),
910
1176
  nativeAddress: address,
911
1177
  chainId,
912
- chainType: "evm" /* EVM */,
1178
+ chainType: ChainType.EVM,
913
1179
  isActive: true
914
1180
  };
915
1181
  this.setState("connected" /* CONNECTED */);
@@ -1259,9 +1525,10 @@ var WalletManager = class extends TypedEventEmitter {
1259
1525
  if (!this.primaryWallet) {
1260
1526
  return;
1261
1527
  }
1528
+ const chainType = this.primaryWallet.chainType;
1262
1529
  await this.primaryWallet.disconnect();
1263
1530
  this.removeAdapterListeners(this.primaryWallet);
1264
- this.connectedWallets.delete(this.primaryWallet.chainType);
1531
+ this.connectedWallets.delete(chainType);
1265
1532
  this.primaryWallet = null;
1266
1533
  if (this.config.enableStorage) {
1267
1534
  this.saveToStorage();
@@ -1366,6 +1633,34 @@ var WalletManager = class extends TypedEventEmitter {
1366
1633
  }
1367
1634
  return adapter.signTypedData(typedData);
1368
1635
  }
1636
+ /**
1637
+ * 签名交易(使用主钱包)
1638
+ */
1639
+ async signTransaction(transaction) {
1640
+ if (!this.primaryWallet) {
1641
+ throw new WalletNotConnectedError();
1642
+ }
1643
+ if (!this.primaryWallet.signTransaction) {
1644
+ throw new Error(`signTransaction not supported by ${this.primaryWallet.type}`);
1645
+ }
1646
+ return this.primaryWallet.signTransaction(transaction);
1647
+ }
1648
+ /**
1649
+ * 使用指定链类型的钱包签名交易
1650
+ */
1651
+ async signTransactionWithChainType(transaction, chainType) {
1652
+ if (!chainType) {
1653
+ return this.signTransaction(transaction);
1654
+ }
1655
+ const adapter = this.connectedWallets.get(chainType);
1656
+ if (!adapter) {
1657
+ throw new WalletNotConnectedError(`Wallet for chain type ${chainType}`);
1658
+ }
1659
+ if (!adapter.signTransaction) {
1660
+ throw new Error(`signTransaction not supported by ${adapter.type}`);
1661
+ }
1662
+ return adapter.signTransaction(transaction);
1663
+ }
1369
1664
  // ===== 链切换 =====
1370
1665
  /**
1371
1666
  * 请求切换链(仅 EVM)
@@ -1526,6 +1821,7 @@ var WalletManager = class extends TypedEventEmitter {
1526
1821
  * 移除适配器事件监听
1527
1822
  */
1528
1823
  removeAdapterListeners(adapter) {
1824
+ if (!adapter) return;
1529
1825
  adapter.removeAllListeners();
1530
1826
  }
1531
1827
  // ===== 存储 =====
@@ -1623,6 +1919,9 @@ function WalletProvider({ children, walletManager: externalWalletManager }) {
1623
1919
  const signMessage = React.useCallback(async (message) => {
1624
1920
  return walletManager.signMessage(message);
1625
1921
  }, [walletManager]);
1922
+ const signTransaction = React.useCallback(async (transaction) => {
1923
+ return walletManager.signTransaction(transaction);
1924
+ }, [walletManager]);
1626
1925
  React.useEffect(() => {
1627
1926
  const handleAccountChanged = (newAccount) => {
1628
1927
  setAccount(newAccount);
@@ -1662,7 +1961,8 @@ function WalletProvider({ children, walletManager: externalWalletManager }) {
1662
1961
  connectAdditional,
1663
1962
  disconnect,
1664
1963
  switchPrimaryWallet,
1665
- signMessage
1964
+ signMessage,
1965
+ signTransaction
1666
1966
  };
1667
1967
  return /* @__PURE__ */ React__default.default.createElement(WalletContext.Provider, { value }, children);
1668
1968
  }
@@ -1771,12 +2071,37 @@ function useSignMessage() {
1771
2071
  error
1772
2072
  };
1773
2073
  }
2074
+ function useSignTransaction() {
2075
+ const { signTransaction: contextSignTransaction } = useWallet();
2076
+ const [isSigning, setIsSigning] = React.useState(false);
2077
+ const [error, setError] = React.useState(null);
2078
+ const signTransaction = async (transaction) => {
2079
+ setIsSigning(true);
2080
+ setError(null);
2081
+ try {
2082
+ const signature = await contextSignTransaction(transaction);
2083
+ return signature;
2084
+ } catch (err) {
2085
+ const error2 = err instanceof Error ? err : new Error(String(err));
2086
+ setError(error2);
2087
+ throw error2;
2088
+ } finally {
2089
+ setIsSigning(false);
2090
+ }
2091
+ };
2092
+ return {
2093
+ signTransaction,
2094
+ isSigning,
2095
+ error
2096
+ };
2097
+ }
1774
2098
 
1775
2099
  exports.WalletProvider = WalletProvider;
1776
2100
  exports.useAccount = useAccount;
1777
2101
  exports.useConnect = useConnect;
1778
2102
  exports.useDisconnect = useDisconnect;
1779
2103
  exports.useSignMessage = useSignMessage;
2104
+ exports.useSignTransaction = useSignTransaction;
1780
2105
  exports.useWallet = useWallet;
1781
2106
  //# sourceMappingURL=index.js.map
1782
2107
  //# sourceMappingURL=index.js.map