@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.
@@ -1,5 +1,6 @@
1
1
  import React, { createContext, useState, useCallback, useEffect, useContext } from 'react';
2
2
  import EventEmitter from 'eventemitter3';
3
+ import { ChainType as ChainType$1 } from '@enclave-hq/chain-utils';
3
4
  import { createWalletClient, http, createPublicClient, custom, isAddress, getAddress } from 'viem';
4
5
  import { privateKeyToAccount } from 'viem/accounts';
5
6
 
@@ -32,6 +33,7 @@ var TypedEventEmitter = class {
32
33
  return this;
33
34
  }
34
35
  };
36
+ var ChainType = ChainType$1;
35
37
 
36
38
  // src/core/errors.ts
37
39
  var WalletSDKError = class _WalletSDKError extends Error {
@@ -212,14 +214,15 @@ function formatEVMAddress(address) {
212
214
  }
213
215
  return getAddress(address);
214
216
  }
215
-
216
- // src/utils/chain-info.ts
217
217
  var CHAIN_INFO = {
218
218
  // EVM Mainnet
219
219
  1: {
220
220
  id: 1,
221
+ slip44: 60,
222
+ // Ethereum SLIP-44
221
223
  name: "Ethereum Mainnet",
222
- chainType: "evm" /* EVM */,
224
+ chainType: ChainType$1.EVM,
225
+ symbol: "ETH",
223
226
  nativeCurrency: {
224
227
  name: "Ether",
225
228
  symbol: "ETH",
@@ -232,7 +235,8 @@ var CHAIN_INFO = {
232
235
  11155111: {
233
236
  id: 11155111,
234
237
  name: "Sepolia Testnet",
235
- chainType: "evm" /* EVM */,
238
+ chainType: ChainType$1.EVM,
239
+ symbol: "ETH",
236
240
  nativeCurrency: {
237
241
  name: "Sepolia Ether",
238
242
  symbol: "ETH",
@@ -244,8 +248,11 @@ var CHAIN_INFO = {
244
248
  // Binance Smart Chain
245
249
  56: {
246
250
  id: 56,
251
+ slip44: 714,
252
+ // BSC SLIP-44
247
253
  name: "BNB Smart Chain",
248
- chainType: "evm" /* EVM */,
254
+ chainType: ChainType$1.EVM,
255
+ symbol: "BNB",
249
256
  nativeCurrency: {
250
257
  name: "BNB",
251
258
  symbol: "BNB",
@@ -257,7 +264,8 @@ var CHAIN_INFO = {
257
264
  97: {
258
265
  id: 97,
259
266
  name: "BNB Smart Chain Testnet",
260
- chainType: "evm" /* EVM */,
267
+ chainType: ChainType$1.EVM,
268
+ symbol: "BNB",
261
269
  nativeCurrency: {
262
270
  name: "BNB",
263
271
  symbol: "BNB",
@@ -269,8 +277,11 @@ var CHAIN_INFO = {
269
277
  // Polygon
270
278
  137: {
271
279
  id: 137,
280
+ slip44: 966,
281
+ // Polygon SLIP-44
272
282
  name: "Polygon Mainnet",
273
- chainType: "evm" /* EVM */,
283
+ chainType: ChainType$1.EVM,
284
+ symbol: "MATIC",
274
285
  nativeCurrency: {
275
286
  name: "MATIC",
276
287
  symbol: "MATIC",
@@ -282,7 +293,8 @@ var CHAIN_INFO = {
282
293
  80002: {
283
294
  id: 80002,
284
295
  name: "Polygon Amoy Testnet",
285
- chainType: "evm" /* EVM */,
296
+ chainType: ChainType$1.EVM,
297
+ symbol: "MATIC",
286
298
  nativeCurrency: {
287
299
  name: "MATIC",
288
300
  symbol: "MATIC",
@@ -294,8 +306,11 @@ var CHAIN_INFO = {
294
306
  // Tron
295
307
  195: {
296
308
  id: 195,
309
+ slip44: 195,
310
+ // Tron SLIP-44
297
311
  name: "Tron Mainnet",
298
- chainType: "tron" /* TRON */,
312
+ chainType: ChainType$1.TRON,
313
+ symbol: "TRX",
299
314
  nativeCurrency: {
300
315
  name: "TRX",
301
316
  symbol: "TRX",
@@ -307,8 +322,11 @@ var CHAIN_INFO = {
307
322
  // Arbitrum
308
323
  42161: {
309
324
  id: 42161,
325
+ slip44: 1042161,
326
+ // Custom SLIP-44 (1000000 + 42161)
310
327
  name: "Arbitrum One",
311
- chainType: "evm" /* EVM */,
328
+ chainType: ChainType$1.EVM,
329
+ symbol: "ETH",
312
330
  nativeCurrency: {
313
331
  name: "Ether",
314
332
  symbol: "ETH",
@@ -320,8 +338,11 @@ var CHAIN_INFO = {
320
338
  // Optimism
321
339
  10: {
322
340
  id: 10,
341
+ slip44: 1000010,
342
+ // Custom SLIP-44 (1000000 + 10)
323
343
  name: "Optimism",
324
- chainType: "evm" /* EVM */,
344
+ chainType: ChainType$1.EVM,
345
+ symbol: "ETH",
325
346
  nativeCurrency: {
326
347
  name: "Ether",
327
348
  symbol: "ETH",
@@ -333,8 +354,11 @@ var CHAIN_INFO = {
333
354
  // Avalanche
334
355
  43114: {
335
356
  id: 43114,
357
+ slip44: 9e3,
358
+ // Avalanche SLIP-44
336
359
  name: "Avalanche C-Chain",
337
- chainType: "evm" /* EVM */,
360
+ chainType: ChainType$1.EVM,
361
+ symbol: "AVAX",
338
362
  nativeCurrency: {
339
363
  name: "AVAX",
340
364
  symbol: "AVAX",
@@ -353,26 +377,34 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
353
377
  constructor() {
354
378
  super(...arguments);
355
379
  this.type = "metamask" /* METAMASK */;
356
- this.chainType = "evm" /* EVM */;
380
+ this.chainType = ChainType.EVM;
357
381
  this.name = "MetaMask";
358
382
  this.icon = "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg";
359
383
  this.walletClient = null;
360
384
  this.publicClient = null;
361
385
  /**
362
386
  * 处理账户变化
387
+ *
388
+ * 注意:MetaMask 的行为
389
+ * - 切换到已连接的账户:触发事件,返回新账户 ['0xNewAddress']
390
+ * - 切换到未连接的账户:不触发事件(用户需要手动断开和重新连接)
391
+ * - 锁定钱包:触发事件,返回空数组 []
363
392
  */
364
393
  this.handleAccountsChanged = (accounts) => {
394
+ console.log("[MetaMask] accountsChanged event triggered:", accounts);
365
395
  if (accounts.length === 0) {
396
+ console.log("[MetaMask] Disconnecting: wallet locked or manually disconnected");
366
397
  this.setState("disconnected" /* DISCONNECTED */);
367
398
  this.setAccount(null);
368
399
  this.emitAccountChanged(null);
369
400
  } else {
370
401
  const address = formatEVMAddress(accounts[0]);
402
+ console.log("[MetaMask] Account changed to:", address);
371
403
  const account = {
372
404
  universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
373
405
  nativeAddress: address,
374
406
  chainId: this.currentAccount.chainId,
375
- chainType: "evm" /* EVM */,
407
+ chainType: ChainType.EVM,
376
408
  isActive: true
377
409
  };
378
410
  this.setAccount(account);
@@ -424,21 +456,23 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
424
456
  if (chainId && chainId !== parsedChainId) {
425
457
  await this.switchChain(chainId);
426
458
  }
459
+ const finalChainId = chainId || parsedChainId;
460
+ const viemChain = this.getViemChain(finalChainId);
427
461
  this.walletClient = createWalletClient({
428
462
  account: accounts[0],
463
+ chain: viemChain,
429
464
  transport: custom(provider)
430
465
  });
431
- const finalChainId = chainId || parsedChainId;
432
466
  this.publicClient = createPublicClient({
433
- chain: this.getViemChain(finalChainId),
434
- transport: http()
467
+ chain: viemChain,
468
+ transport: custom(provider)
435
469
  });
436
470
  const address = formatEVMAddress(accounts[0]);
437
471
  const account = {
438
472
  universalAddress: createUniversalAddress(finalChainId, address),
439
473
  nativeAddress: address,
440
474
  chainId: finalChainId,
441
- chainType: "evm" /* EVM */,
475
+ chainType: ChainType.EVM,
442
476
  isActive: true
443
477
  };
444
478
  this.setState("connected" /* CONNECTED */);
@@ -492,6 +526,40 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
492
526
  throw error;
493
527
  }
494
528
  }
529
+ /**
530
+ * 签名交易
531
+ *
532
+ * Note: This signs a raw transaction without sending it.
533
+ * The transaction can be broadcast later using the returned signature.
534
+ */
535
+ async signTransaction(transaction) {
536
+ this.ensureConnected();
537
+ try {
538
+ const provider = this.getBrowserProvider();
539
+ const tx = {
540
+ from: this.currentAccount.nativeAddress,
541
+ to: transaction.to,
542
+ value: transaction.value ? `0x${BigInt(transaction.value).toString(16)}` : void 0,
543
+ data: transaction.data || "0x",
544
+ gas: transaction.gas ? `0x${BigInt(transaction.gas).toString(16)}` : void 0,
545
+ gasPrice: transaction.gasPrice ? `0x${BigInt(transaction.gasPrice).toString(16)}` : void 0,
546
+ maxFeePerGas: transaction.maxFeePerGas ? `0x${BigInt(transaction.maxFeePerGas).toString(16)}` : void 0,
547
+ maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ? `0x${BigInt(transaction.maxPriorityFeePerGas).toString(16)}` : void 0,
548
+ nonce: transaction.nonce !== void 0 ? `0x${transaction.nonce.toString(16)}` : void 0,
549
+ chainId: transaction.chainId || this.currentAccount.chainId
550
+ };
551
+ const signature = await provider.request({
552
+ method: "eth_signTransaction",
553
+ params: [tx]
554
+ });
555
+ return signature;
556
+ } catch (error) {
557
+ if (error.code === 4001) {
558
+ throw new SignatureRejectedError("Transaction signature was rejected by user");
559
+ }
560
+ throw error;
561
+ }
562
+ }
495
563
  /**
496
564
  * 切换链
497
565
  */
@@ -722,9 +790,14 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
722
790
  constructor() {
723
791
  super(...arguments);
724
792
  this.type = "tronlink" /* TRONLINK */;
725
- this.chainType = "tron" /* TRON */;
793
+ this.chainType = ChainType.TRON;
726
794
  this.name = "TronLink";
727
795
  this.icon = "https://www.tronlink.org/static/logoIcon.svg";
796
+ /**
797
+ * 轮询检测账户变化(备用方案)
798
+ */
799
+ this.pollingInterval = null;
800
+ this.lastKnownAddress = null;
728
801
  /**
729
802
  * 处理账户变化
730
803
  */
@@ -739,7 +812,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
739
812
  universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
740
813
  nativeAddress: address,
741
814
  chainId: this.currentAccount.chainId,
742
- chainType: "tron" /* TRON */,
815
+ chainType: ChainType.TRON,
743
816
  isActive: true
744
817
  };
745
818
  this.setAccount(account);
@@ -778,7 +851,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
778
851
  universalAddress: createUniversalAddress(tronChainId, address),
779
852
  nativeAddress: address,
780
853
  chainId: tronChainId,
781
- chainType: "tron" /* TRON */,
854
+ chainType: ChainType.TRON,
782
855
  isActive: true
783
856
  };
784
857
  this.setState("connected" /* CONNECTED */);
@@ -796,20 +869,177 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
796
869
  }
797
870
  /**
798
871
  * 签名消息
872
+ *
873
+ * Note: TronLink supports two signing methods:
874
+ * - trx.sign(): Signs a transaction object
875
+ * - trx.signMessageV2(): Signs a plain text message (what we use here)
799
876
  */
800
877
  async signMessage(message) {
801
878
  this.ensureConnected();
802
879
  try {
803
880
  const tronWeb = this.getTronWeb();
804
- const signature = await tronWeb.trx.sign(message);
805
- return signature;
881
+ if (typeof tronWeb.trx.signMessageV2 === "function") {
882
+ const signature = await tronWeb.trx.signMessageV2(message);
883
+ return signature;
884
+ } else {
885
+ console.warn("[TronLink] signMessageV2 not available, falling back to sign()");
886
+ const signature = await tronWeb.trx.sign(message);
887
+ return signature;
888
+ }
806
889
  } catch (error) {
807
890
  if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
808
891
  throw new SignatureRejectedError();
809
892
  }
893
+ if (error.message?.includes("Invalid transaction")) {
894
+ throw new Error("Invalid message format. For transaction signing, use signTransaction() instead.");
895
+ }
810
896
  throw error;
811
897
  }
812
898
  }
899
+ /**
900
+ * 签名交易
901
+ *
902
+ * Note: This uses trx.sign() which is specifically for signing transaction objects.
903
+ * For plain text message signing, use signMessage() instead.
904
+ */
905
+ async signTransaction(transaction) {
906
+ this.ensureConnected();
907
+ try {
908
+ const tronWeb = this.getTronWeb();
909
+ const signature = await tronWeb.trx.sign(transaction);
910
+ return signature;
911
+ } catch (error) {
912
+ if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
913
+ throw new SignatureRejectedError("Transaction signature was rejected by user");
914
+ }
915
+ if (error.message?.includes("Invalid transaction")) {
916
+ throw new Error("Invalid transaction format. Please provide a properly formatted Tron transaction object.");
917
+ }
918
+ throw error;
919
+ }
920
+ }
921
+ /**
922
+ * 读取合约
923
+ */
924
+ async readContract(params) {
925
+ this.ensureConnected();
926
+ try {
927
+ const tronWeb = this.getTronWeb();
928
+ const contract = await tronWeb.contract(params.abi, params.address);
929
+ const result = await contract[params.functionName](...params.args || []).call();
930
+ return result;
931
+ } catch (error) {
932
+ console.error("Read contract error:", error);
933
+ throw new Error(`Failed to read contract: ${error.message}`);
934
+ }
935
+ }
936
+ /**
937
+ * 写入合约
938
+ */
939
+ async writeContract(params) {
940
+ this.ensureConnected();
941
+ try {
942
+ const tronWeb = this.getTronWeb();
943
+ console.log("[TronLink] writeContract params:", {
944
+ address: params.address,
945
+ functionName: params.functionName,
946
+ args: params.args,
947
+ value: params.value,
948
+ gas: params.gas
949
+ });
950
+ if (!params.args || params.args.length === 0) {
951
+ throw new Error("Contract function arguments are required");
952
+ }
953
+ const hasUndefined = params.args.some((arg) => arg === void 0 || arg === null);
954
+ if (hasUndefined) {
955
+ console.error("[TronLink] Invalid args detected:", params.args);
956
+ throw new Error(`Invalid contract arguments: some arguments are undefined or null`);
957
+ }
958
+ const functionAbi = params.abi.find(
959
+ (item) => item.name === params.functionName && item.type === "function"
960
+ );
961
+ if (!functionAbi) {
962
+ throw new Error(`Function ${params.functionName} not found in ABI`);
963
+ }
964
+ console.log("[TronLink] Function ABI:", functionAbi);
965
+ console.log("[TronLink] Calling with args:", params.args);
966
+ const options = {
967
+ feeLimit: params.gas || 1e8,
968
+ // 默认 100 TRX 的能量限制
969
+ callValue: params.value || 0
970
+ // 发送的 TRX 数量(单位:SUN)
971
+ };
972
+ const parameter = functionAbi.inputs.map((input, index) => ({
973
+ type: input.type,
974
+ value: params.args[index]
975
+ }));
976
+ console.log("[TronLink] Transaction options:", options);
977
+ console.log("[TronLink] Parameters:", parameter);
978
+ const transaction = await tronWeb.transactionBuilder.triggerSmartContract(
979
+ params.address,
980
+ params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")",
981
+ options,
982
+ parameter,
983
+ this.currentAccount.nativeAddress
984
+ );
985
+ console.log("[TronLink] Transaction built:", transaction);
986
+ if (!transaction || !transaction.transaction) {
987
+ throw new Error("Failed to build transaction");
988
+ }
989
+ const signedTx = await tronWeb.trx.sign(transaction.transaction);
990
+ const broadcast = await tronWeb.trx.sendRawTransaction(signedTx);
991
+ console.log("[TronLink] Broadcast result:", broadcast);
992
+ if (!broadcast.result) {
993
+ throw new Error(broadcast.message || "Transaction broadcast failed");
994
+ }
995
+ const txHash = broadcast.txid || broadcast.transaction?.txID;
996
+ console.log("[TronLink] Transaction hash:", txHash);
997
+ return txHash || "";
998
+ } catch (error) {
999
+ console.error("Write contract error:", error);
1000
+ if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
1001
+ throw new SignatureRejectedError("Transaction was rejected by user");
1002
+ }
1003
+ throw new Error(`Failed to write contract: ${error.message}`);
1004
+ }
1005
+ }
1006
+ /**
1007
+ * 等待交易确认
1008
+ */
1009
+ async waitForTransaction(txHash, _confirmations = 1) {
1010
+ try {
1011
+ const tronWeb = this.getTronWeb();
1012
+ let attempts = 0;
1013
+ const maxAttempts = 60;
1014
+ while (attempts < maxAttempts) {
1015
+ try {
1016
+ const txInfo = await tronWeb.trx.getTransactionInfo(txHash);
1017
+ if (txInfo && txInfo.id) {
1018
+ const receipt = {
1019
+ transactionHash: txHash,
1020
+ blockNumber: txInfo.blockNumber || 0,
1021
+ blockHash: txInfo.blockHash || "",
1022
+ from: this.currentAccount.nativeAddress,
1023
+ to: txInfo.contract_address || "",
1024
+ status: txInfo.receipt?.result === "SUCCESS" ? "success" : "failed",
1025
+ gasUsed: (txInfo.receipt?.energy_usage_total || 0).toString(),
1026
+ logs: txInfo.log || []
1027
+ };
1028
+ if (receipt.status === "failed") {
1029
+ throw new TransactionFailedError(txHash, "Transaction failed on Tron network");
1030
+ }
1031
+ return receipt;
1032
+ }
1033
+ } catch (error) {
1034
+ }
1035
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
1036
+ attempts++;
1037
+ }
1038
+ throw new Error("Transaction confirmation timeout");
1039
+ } catch (error) {
1040
+ throw new Error(`Failed to wait for transaction: ${error.message}`);
1041
+ }
1042
+ }
813
1043
  /**
814
1044
  * 获取 Provider
815
1045
  */
@@ -848,9 +1078,16 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
848
1078
  setupEventListeners() {
849
1079
  if (typeof window === "undefined") return;
850
1080
  const w = window;
851
- if (w.tronLink) {
852
- w.tronLink.on("accountsChanged", this.handleAccountsChanged);
853
- w.tronLink.on("disconnect", this.handleDisconnect);
1081
+ try {
1082
+ if (w.tronLink && typeof w.tronLink.on === "function") {
1083
+ w.tronLink.on("accountsChanged", this.handleAccountsChanged);
1084
+ w.tronLink.on("disconnect", this.handleDisconnect);
1085
+ } else if (w.tronWeb && w.tronWeb.eventServer) {
1086
+ this.startPolling();
1087
+ }
1088
+ } catch (error) {
1089
+ console.warn("TronLink event listener setup failed:", error);
1090
+ this.startPolling();
854
1091
  }
855
1092
  }
856
1093
  /**
@@ -859,9 +1096,38 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
859
1096
  removeEventListeners() {
860
1097
  if (typeof window === "undefined") return;
861
1098
  const w = window;
862
- if (w.tronLink) {
863
- w.tronLink.off("accountsChanged", this.handleAccountsChanged);
864
- w.tronLink.off("disconnect", this.handleDisconnect);
1099
+ try {
1100
+ if (w.tronLink && typeof w.tronLink.off === "function") {
1101
+ w.tronLink.off("accountsChanged", this.handleAccountsChanged);
1102
+ w.tronLink.off("disconnect", this.handleDisconnect);
1103
+ }
1104
+ } catch (error) {
1105
+ console.warn("TronLink event listener removal failed:", error);
1106
+ }
1107
+ this.stopPolling();
1108
+ }
1109
+ startPolling() {
1110
+ if (this.pollingInterval) return;
1111
+ this.lastKnownAddress = this.currentAccount?.nativeAddress || null;
1112
+ this.pollingInterval = setInterval(async () => {
1113
+ try {
1114
+ const tronWeb = this.getTronWeb();
1115
+ const currentAddress = tronWeb.defaultAddress?.base58;
1116
+ if (currentAddress && currentAddress !== this.lastKnownAddress) {
1117
+ this.lastKnownAddress = currentAddress;
1118
+ this.handleAccountsChanged({ address: { base58: currentAddress } });
1119
+ } else if (!currentAddress && this.lastKnownAddress) {
1120
+ this.lastKnownAddress = null;
1121
+ this.handleAccountsChanged(null);
1122
+ }
1123
+ } catch (error) {
1124
+ }
1125
+ }, 2e3);
1126
+ }
1127
+ stopPolling() {
1128
+ if (this.pollingInterval) {
1129
+ clearInterval(this.pollingInterval);
1130
+ this.pollingInterval = null;
865
1131
  }
866
1132
  }
867
1133
  };
@@ -872,7 +1138,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
872
1138
  constructor() {
873
1139
  super(...arguments);
874
1140
  this.type = "private-key" /* PRIVATE_KEY */;
875
- this.chainType = "evm" /* EVM */;
1141
+ this.chainType = ChainType.EVM;
876
1142
  this.name = "Private Key (EVM)";
877
1143
  this.privateKey = null;
878
1144
  this.walletClient = null;
@@ -902,7 +1168,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
902
1168
  universalAddress: createUniversalAddress(chainId, address),
903
1169
  nativeAddress: address,
904
1170
  chainId,
905
- chainType: "evm" /* EVM */,
1171
+ chainType: ChainType.EVM,
906
1172
  isActive: true
907
1173
  };
908
1174
  this.setState("connected" /* CONNECTED */);
@@ -1252,9 +1518,10 @@ var WalletManager = class extends TypedEventEmitter {
1252
1518
  if (!this.primaryWallet) {
1253
1519
  return;
1254
1520
  }
1521
+ const chainType = this.primaryWallet.chainType;
1255
1522
  await this.primaryWallet.disconnect();
1256
1523
  this.removeAdapterListeners(this.primaryWallet);
1257
- this.connectedWallets.delete(this.primaryWallet.chainType);
1524
+ this.connectedWallets.delete(chainType);
1258
1525
  this.primaryWallet = null;
1259
1526
  if (this.config.enableStorage) {
1260
1527
  this.saveToStorage();
@@ -1359,6 +1626,34 @@ var WalletManager = class extends TypedEventEmitter {
1359
1626
  }
1360
1627
  return adapter.signTypedData(typedData);
1361
1628
  }
1629
+ /**
1630
+ * 签名交易(使用主钱包)
1631
+ */
1632
+ async signTransaction(transaction) {
1633
+ if (!this.primaryWallet) {
1634
+ throw new WalletNotConnectedError();
1635
+ }
1636
+ if (!this.primaryWallet.signTransaction) {
1637
+ throw new Error(`signTransaction not supported by ${this.primaryWallet.type}`);
1638
+ }
1639
+ return this.primaryWallet.signTransaction(transaction);
1640
+ }
1641
+ /**
1642
+ * 使用指定链类型的钱包签名交易
1643
+ */
1644
+ async signTransactionWithChainType(transaction, chainType) {
1645
+ if (!chainType) {
1646
+ return this.signTransaction(transaction);
1647
+ }
1648
+ const adapter = this.connectedWallets.get(chainType);
1649
+ if (!adapter) {
1650
+ throw new WalletNotConnectedError(`Wallet for chain type ${chainType}`);
1651
+ }
1652
+ if (!adapter.signTransaction) {
1653
+ throw new Error(`signTransaction not supported by ${adapter.type}`);
1654
+ }
1655
+ return adapter.signTransaction(transaction);
1656
+ }
1362
1657
  // ===== 链切换 =====
1363
1658
  /**
1364
1659
  * 请求切换链(仅 EVM)
@@ -1519,6 +1814,7 @@ var WalletManager = class extends TypedEventEmitter {
1519
1814
  * 移除适配器事件监听
1520
1815
  */
1521
1816
  removeAdapterListeners(adapter) {
1817
+ if (!adapter) return;
1522
1818
  adapter.removeAllListeners();
1523
1819
  }
1524
1820
  // ===== 存储 =====
@@ -1616,6 +1912,9 @@ function WalletProvider({ children, walletManager: externalWalletManager }) {
1616
1912
  const signMessage = useCallback(async (message) => {
1617
1913
  return walletManager.signMessage(message);
1618
1914
  }, [walletManager]);
1915
+ const signTransaction = useCallback(async (transaction) => {
1916
+ return walletManager.signTransaction(transaction);
1917
+ }, [walletManager]);
1619
1918
  useEffect(() => {
1620
1919
  const handleAccountChanged = (newAccount) => {
1621
1920
  setAccount(newAccount);
@@ -1655,7 +1954,8 @@ function WalletProvider({ children, walletManager: externalWalletManager }) {
1655
1954
  connectAdditional,
1656
1955
  disconnect,
1657
1956
  switchPrimaryWallet,
1658
- signMessage
1957
+ signMessage,
1958
+ signTransaction
1659
1959
  };
1660
1960
  return /* @__PURE__ */ React.createElement(WalletContext.Provider, { value }, children);
1661
1961
  }
@@ -1764,7 +2064,31 @@ function useSignMessage() {
1764
2064
  error
1765
2065
  };
1766
2066
  }
2067
+ function useSignTransaction() {
2068
+ const { signTransaction: contextSignTransaction } = useWallet();
2069
+ const [isSigning, setIsSigning] = useState(false);
2070
+ const [error, setError] = useState(null);
2071
+ const signTransaction = async (transaction) => {
2072
+ setIsSigning(true);
2073
+ setError(null);
2074
+ try {
2075
+ const signature = await contextSignTransaction(transaction);
2076
+ return signature;
2077
+ } catch (err) {
2078
+ const error2 = err instanceof Error ? err : new Error(String(err));
2079
+ setError(error2);
2080
+ throw error2;
2081
+ } finally {
2082
+ setIsSigning(false);
2083
+ }
2084
+ };
2085
+ return {
2086
+ signTransaction,
2087
+ isSigning,
2088
+ error
2089
+ };
2090
+ }
1767
2091
 
1768
- export { WalletProvider, useAccount, useConnect, useDisconnect, useSignMessage, useWallet };
2092
+ export { WalletProvider, useAccount, useConnect, useDisconnect, useSignMessage, useSignTransaction, useWallet };
1769
2093
  //# sourceMappingURL=index.mjs.map
1770
2094
  //# sourceMappingURL=index.mjs.map