@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.
- package/dist/index.d.mts +62 -37
- package/dist/index.d.ts +62 -37
- package/dist/index.js +347 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +347 -60
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +33 -8
- package/dist/react/index.d.ts +33 -8
- package/dist/react/index.js +358 -33
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +358 -34
- package/dist/react/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import EventEmitter from 'eventemitter3';
|
|
2
|
+
import { ChainType as ChainType$1 } from '@enclave-hq/chain-utils';
|
|
2
3
|
import { isAddress, getAddress, createWalletClient, custom, createPublicClient, http, verifyMessage } from 'viem';
|
|
3
4
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
4
5
|
|
|
@@ -31,15 +32,7 @@ var TypedEventEmitter = class {
|
|
|
31
32
|
return this;
|
|
32
33
|
}
|
|
33
34
|
};
|
|
34
|
-
|
|
35
|
-
// src/core/types.ts
|
|
36
|
-
var ChainType = /* @__PURE__ */ ((ChainType4) => {
|
|
37
|
-
ChainType4["EVM"] = "evm";
|
|
38
|
-
ChainType4["TRON"] = "tron";
|
|
39
|
-
ChainType4["SOLANA"] = "solana";
|
|
40
|
-
ChainType4["COSMOS"] = "cosmos";
|
|
41
|
-
return ChainType4;
|
|
42
|
-
})(ChainType || {});
|
|
35
|
+
var ChainType = ChainType$1;
|
|
43
36
|
var WalletType = /* @__PURE__ */ ((WalletType3) => {
|
|
44
37
|
WalletType3["METAMASK"] = "metamask";
|
|
45
38
|
WalletType3["WALLETCONNECT"] = "walletconnect";
|
|
@@ -303,14 +296,15 @@ function shortenAddress(address, chars = 4) {
|
|
|
303
296
|
const formatted = getAddress(address);
|
|
304
297
|
return `${formatted.substring(0, chars + 2)}...${formatted.substring(42 - chars)}`;
|
|
305
298
|
}
|
|
306
|
-
|
|
307
|
-
// src/utils/chain-info.ts
|
|
308
299
|
var CHAIN_INFO = {
|
|
309
300
|
// EVM Mainnet
|
|
310
301
|
1: {
|
|
311
302
|
id: 1,
|
|
303
|
+
slip44: 60,
|
|
304
|
+
// Ethereum SLIP-44
|
|
312
305
|
name: "Ethereum Mainnet",
|
|
313
|
-
chainType:
|
|
306
|
+
chainType: ChainType$1.EVM,
|
|
307
|
+
symbol: "ETH",
|
|
314
308
|
nativeCurrency: {
|
|
315
309
|
name: "Ether",
|
|
316
310
|
symbol: "ETH",
|
|
@@ -323,7 +317,8 @@ var CHAIN_INFO = {
|
|
|
323
317
|
11155111: {
|
|
324
318
|
id: 11155111,
|
|
325
319
|
name: "Sepolia Testnet",
|
|
326
|
-
chainType:
|
|
320
|
+
chainType: ChainType$1.EVM,
|
|
321
|
+
symbol: "ETH",
|
|
327
322
|
nativeCurrency: {
|
|
328
323
|
name: "Sepolia Ether",
|
|
329
324
|
symbol: "ETH",
|
|
@@ -335,8 +330,11 @@ var CHAIN_INFO = {
|
|
|
335
330
|
// Binance Smart Chain
|
|
336
331
|
56: {
|
|
337
332
|
id: 56,
|
|
333
|
+
slip44: 714,
|
|
334
|
+
// BSC SLIP-44
|
|
338
335
|
name: "BNB Smart Chain",
|
|
339
|
-
chainType:
|
|
336
|
+
chainType: ChainType$1.EVM,
|
|
337
|
+
symbol: "BNB",
|
|
340
338
|
nativeCurrency: {
|
|
341
339
|
name: "BNB",
|
|
342
340
|
symbol: "BNB",
|
|
@@ -348,7 +346,8 @@ var CHAIN_INFO = {
|
|
|
348
346
|
97: {
|
|
349
347
|
id: 97,
|
|
350
348
|
name: "BNB Smart Chain Testnet",
|
|
351
|
-
chainType:
|
|
349
|
+
chainType: ChainType$1.EVM,
|
|
350
|
+
symbol: "BNB",
|
|
352
351
|
nativeCurrency: {
|
|
353
352
|
name: "BNB",
|
|
354
353
|
symbol: "BNB",
|
|
@@ -360,8 +359,11 @@ var CHAIN_INFO = {
|
|
|
360
359
|
// Polygon
|
|
361
360
|
137: {
|
|
362
361
|
id: 137,
|
|
362
|
+
slip44: 966,
|
|
363
|
+
// Polygon SLIP-44
|
|
363
364
|
name: "Polygon Mainnet",
|
|
364
|
-
chainType:
|
|
365
|
+
chainType: ChainType$1.EVM,
|
|
366
|
+
symbol: "MATIC",
|
|
365
367
|
nativeCurrency: {
|
|
366
368
|
name: "MATIC",
|
|
367
369
|
symbol: "MATIC",
|
|
@@ -373,7 +375,8 @@ var CHAIN_INFO = {
|
|
|
373
375
|
80002: {
|
|
374
376
|
id: 80002,
|
|
375
377
|
name: "Polygon Amoy Testnet",
|
|
376
|
-
chainType:
|
|
378
|
+
chainType: ChainType$1.EVM,
|
|
379
|
+
symbol: "MATIC",
|
|
377
380
|
nativeCurrency: {
|
|
378
381
|
name: "MATIC",
|
|
379
382
|
symbol: "MATIC",
|
|
@@ -385,8 +388,11 @@ var CHAIN_INFO = {
|
|
|
385
388
|
// Tron
|
|
386
389
|
195: {
|
|
387
390
|
id: 195,
|
|
391
|
+
slip44: 195,
|
|
392
|
+
// Tron SLIP-44
|
|
388
393
|
name: "Tron Mainnet",
|
|
389
|
-
chainType:
|
|
394
|
+
chainType: ChainType$1.TRON,
|
|
395
|
+
symbol: "TRX",
|
|
390
396
|
nativeCurrency: {
|
|
391
397
|
name: "TRX",
|
|
392
398
|
symbol: "TRX",
|
|
@@ -398,8 +404,11 @@ var CHAIN_INFO = {
|
|
|
398
404
|
// Arbitrum
|
|
399
405
|
42161: {
|
|
400
406
|
id: 42161,
|
|
407
|
+
slip44: 1042161,
|
|
408
|
+
// Custom SLIP-44 (1000000 + 42161)
|
|
401
409
|
name: "Arbitrum One",
|
|
402
|
-
chainType:
|
|
410
|
+
chainType: ChainType$1.EVM,
|
|
411
|
+
symbol: "ETH",
|
|
403
412
|
nativeCurrency: {
|
|
404
413
|
name: "Ether",
|
|
405
414
|
symbol: "ETH",
|
|
@@ -411,8 +420,11 @@ var CHAIN_INFO = {
|
|
|
411
420
|
// Optimism
|
|
412
421
|
10: {
|
|
413
422
|
id: 10,
|
|
423
|
+
slip44: 1000010,
|
|
424
|
+
// Custom SLIP-44 (1000000 + 10)
|
|
414
425
|
name: "Optimism",
|
|
415
|
-
chainType:
|
|
426
|
+
chainType: ChainType$1.EVM,
|
|
427
|
+
symbol: "ETH",
|
|
416
428
|
nativeCurrency: {
|
|
417
429
|
name: "Ether",
|
|
418
430
|
symbol: "ETH",
|
|
@@ -424,8 +436,11 @@ var CHAIN_INFO = {
|
|
|
424
436
|
// Avalanche
|
|
425
437
|
43114: {
|
|
426
438
|
id: 43114,
|
|
439
|
+
slip44: 9e3,
|
|
440
|
+
// Avalanche SLIP-44
|
|
427
441
|
name: "Avalanche C-Chain",
|
|
428
|
-
chainType:
|
|
442
|
+
chainType: ChainType$1.EVM,
|
|
443
|
+
symbol: "AVAX",
|
|
429
444
|
nativeCurrency: {
|
|
430
445
|
name: "AVAX",
|
|
431
446
|
symbol: "AVAX",
|
|
@@ -442,10 +457,10 @@ function getChainType(chainId) {
|
|
|
442
457
|
return CHAIN_INFO[chainId]?.chainType;
|
|
443
458
|
}
|
|
444
459
|
function isEVMChain(chainId) {
|
|
445
|
-
return getChainType(chainId) ===
|
|
460
|
+
return getChainType(chainId) === ChainType$1.EVM;
|
|
446
461
|
}
|
|
447
462
|
function isTronChain(chainId) {
|
|
448
|
-
return getChainType(chainId) ===
|
|
463
|
+
return getChainType(chainId) === ChainType$1.TRON;
|
|
449
464
|
}
|
|
450
465
|
|
|
451
466
|
// src/adapters/evm/metamask.ts
|
|
@@ -453,26 +468,34 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
453
468
|
constructor() {
|
|
454
469
|
super(...arguments);
|
|
455
470
|
this.type = "metamask" /* METAMASK */;
|
|
456
|
-
this.chainType =
|
|
471
|
+
this.chainType = ChainType.EVM;
|
|
457
472
|
this.name = "MetaMask";
|
|
458
473
|
this.icon = "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg";
|
|
459
474
|
this.walletClient = null;
|
|
460
475
|
this.publicClient = null;
|
|
461
476
|
/**
|
|
462
477
|
* 处理账户变化
|
|
478
|
+
*
|
|
479
|
+
* 注意:MetaMask 的行为
|
|
480
|
+
* - 切换到已连接的账户:触发事件,返回新账户 ['0xNewAddress']
|
|
481
|
+
* - 切换到未连接的账户:不触发事件(用户需要手动断开和重新连接)
|
|
482
|
+
* - 锁定钱包:触发事件,返回空数组 []
|
|
463
483
|
*/
|
|
464
484
|
this.handleAccountsChanged = (accounts) => {
|
|
485
|
+
console.log("[MetaMask] accountsChanged event triggered:", accounts);
|
|
465
486
|
if (accounts.length === 0) {
|
|
487
|
+
console.log("[MetaMask] Disconnecting: wallet locked or manually disconnected");
|
|
466
488
|
this.setState("disconnected" /* DISCONNECTED */);
|
|
467
489
|
this.setAccount(null);
|
|
468
490
|
this.emitAccountChanged(null);
|
|
469
491
|
} else {
|
|
470
492
|
const address = formatEVMAddress(accounts[0]);
|
|
493
|
+
console.log("[MetaMask] Account changed to:", address);
|
|
471
494
|
const account = {
|
|
472
495
|
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
473
496
|
nativeAddress: address,
|
|
474
497
|
chainId: this.currentAccount.chainId,
|
|
475
|
-
chainType:
|
|
498
|
+
chainType: ChainType.EVM,
|
|
476
499
|
isActive: true
|
|
477
500
|
};
|
|
478
501
|
this.setAccount(account);
|
|
@@ -524,21 +547,23 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
524
547
|
if (chainId && chainId !== parsedChainId) {
|
|
525
548
|
await this.switchChain(chainId);
|
|
526
549
|
}
|
|
550
|
+
const finalChainId = chainId || parsedChainId;
|
|
551
|
+
const viemChain = this.getViemChain(finalChainId);
|
|
527
552
|
this.walletClient = createWalletClient({
|
|
528
553
|
account: accounts[0],
|
|
554
|
+
chain: viemChain,
|
|
529
555
|
transport: custom(provider)
|
|
530
556
|
});
|
|
531
|
-
const finalChainId = chainId || parsedChainId;
|
|
532
557
|
this.publicClient = createPublicClient({
|
|
533
|
-
chain:
|
|
534
|
-
transport:
|
|
558
|
+
chain: viemChain,
|
|
559
|
+
transport: custom(provider)
|
|
535
560
|
});
|
|
536
561
|
const address = formatEVMAddress(accounts[0]);
|
|
537
562
|
const account = {
|
|
538
563
|
universalAddress: createUniversalAddress(finalChainId, address),
|
|
539
564
|
nativeAddress: address,
|
|
540
565
|
chainId: finalChainId,
|
|
541
|
-
chainType:
|
|
566
|
+
chainType: ChainType.EVM,
|
|
542
567
|
isActive: true
|
|
543
568
|
};
|
|
544
569
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -592,6 +617,40 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
592
617
|
throw error;
|
|
593
618
|
}
|
|
594
619
|
}
|
|
620
|
+
/**
|
|
621
|
+
* 签名交易
|
|
622
|
+
*
|
|
623
|
+
* Note: This signs a raw transaction without sending it.
|
|
624
|
+
* The transaction can be broadcast later using the returned signature.
|
|
625
|
+
*/
|
|
626
|
+
async signTransaction(transaction) {
|
|
627
|
+
this.ensureConnected();
|
|
628
|
+
try {
|
|
629
|
+
const provider = this.getBrowserProvider();
|
|
630
|
+
const tx = {
|
|
631
|
+
from: this.currentAccount.nativeAddress,
|
|
632
|
+
to: transaction.to,
|
|
633
|
+
value: transaction.value ? `0x${BigInt(transaction.value).toString(16)}` : void 0,
|
|
634
|
+
data: transaction.data || "0x",
|
|
635
|
+
gas: transaction.gas ? `0x${BigInt(transaction.gas).toString(16)}` : void 0,
|
|
636
|
+
gasPrice: transaction.gasPrice ? `0x${BigInt(transaction.gasPrice).toString(16)}` : void 0,
|
|
637
|
+
maxFeePerGas: transaction.maxFeePerGas ? `0x${BigInt(transaction.maxFeePerGas).toString(16)}` : void 0,
|
|
638
|
+
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ? `0x${BigInt(transaction.maxPriorityFeePerGas).toString(16)}` : void 0,
|
|
639
|
+
nonce: transaction.nonce !== void 0 ? `0x${transaction.nonce.toString(16)}` : void 0,
|
|
640
|
+
chainId: transaction.chainId || this.currentAccount.chainId
|
|
641
|
+
};
|
|
642
|
+
const signature = await provider.request({
|
|
643
|
+
method: "eth_signTransaction",
|
|
644
|
+
params: [tx]
|
|
645
|
+
});
|
|
646
|
+
return signature;
|
|
647
|
+
} catch (error) {
|
|
648
|
+
if (error.code === 4001) {
|
|
649
|
+
throw new SignatureRejectedError("Transaction signature was rejected by user");
|
|
650
|
+
}
|
|
651
|
+
throw error;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
595
654
|
/**
|
|
596
655
|
* 切换链
|
|
597
656
|
*/
|
|
@@ -822,9 +881,14 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
822
881
|
constructor() {
|
|
823
882
|
super(...arguments);
|
|
824
883
|
this.type = "tronlink" /* TRONLINK */;
|
|
825
|
-
this.chainType =
|
|
884
|
+
this.chainType = ChainType.TRON;
|
|
826
885
|
this.name = "TronLink";
|
|
827
886
|
this.icon = "https://www.tronlink.org/static/logoIcon.svg";
|
|
887
|
+
/**
|
|
888
|
+
* 轮询检测账户变化(备用方案)
|
|
889
|
+
*/
|
|
890
|
+
this.pollingInterval = null;
|
|
891
|
+
this.lastKnownAddress = null;
|
|
828
892
|
/**
|
|
829
893
|
* 处理账户变化
|
|
830
894
|
*/
|
|
@@ -839,7 +903,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
839
903
|
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
840
904
|
nativeAddress: address,
|
|
841
905
|
chainId: this.currentAccount.chainId,
|
|
842
|
-
chainType:
|
|
906
|
+
chainType: ChainType.TRON,
|
|
843
907
|
isActive: true
|
|
844
908
|
};
|
|
845
909
|
this.setAccount(account);
|
|
@@ -878,7 +942,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
878
942
|
universalAddress: createUniversalAddress(tronChainId, address),
|
|
879
943
|
nativeAddress: address,
|
|
880
944
|
chainId: tronChainId,
|
|
881
|
-
chainType:
|
|
945
|
+
chainType: ChainType.TRON,
|
|
882
946
|
isActive: true
|
|
883
947
|
};
|
|
884
948
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -896,20 +960,177 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
896
960
|
}
|
|
897
961
|
/**
|
|
898
962
|
* 签名消息
|
|
963
|
+
*
|
|
964
|
+
* Note: TronLink supports two signing methods:
|
|
965
|
+
* - trx.sign(): Signs a transaction object
|
|
966
|
+
* - trx.signMessageV2(): Signs a plain text message (what we use here)
|
|
899
967
|
*/
|
|
900
968
|
async signMessage(message) {
|
|
901
969
|
this.ensureConnected();
|
|
902
970
|
try {
|
|
903
971
|
const tronWeb = this.getTronWeb();
|
|
904
|
-
|
|
905
|
-
|
|
972
|
+
if (typeof tronWeb.trx.signMessageV2 === "function") {
|
|
973
|
+
const signature = await tronWeb.trx.signMessageV2(message);
|
|
974
|
+
return signature;
|
|
975
|
+
} else {
|
|
976
|
+
console.warn("[TronLink] signMessageV2 not available, falling back to sign()");
|
|
977
|
+
const signature = await tronWeb.trx.sign(message);
|
|
978
|
+
return signature;
|
|
979
|
+
}
|
|
906
980
|
} catch (error) {
|
|
907
981
|
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
908
982
|
throw new SignatureRejectedError();
|
|
909
983
|
}
|
|
984
|
+
if (error.message?.includes("Invalid transaction")) {
|
|
985
|
+
throw new Error("Invalid message format. For transaction signing, use signTransaction() instead.");
|
|
986
|
+
}
|
|
910
987
|
throw error;
|
|
911
988
|
}
|
|
912
989
|
}
|
|
990
|
+
/**
|
|
991
|
+
* 签名交易
|
|
992
|
+
*
|
|
993
|
+
* Note: This uses trx.sign() which is specifically for signing transaction objects.
|
|
994
|
+
* For plain text message signing, use signMessage() instead.
|
|
995
|
+
*/
|
|
996
|
+
async signTransaction(transaction) {
|
|
997
|
+
this.ensureConnected();
|
|
998
|
+
try {
|
|
999
|
+
const tronWeb = this.getTronWeb();
|
|
1000
|
+
const signature = await tronWeb.trx.sign(transaction);
|
|
1001
|
+
return signature;
|
|
1002
|
+
} catch (error) {
|
|
1003
|
+
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
1004
|
+
throw new SignatureRejectedError("Transaction signature was rejected by user");
|
|
1005
|
+
}
|
|
1006
|
+
if (error.message?.includes("Invalid transaction")) {
|
|
1007
|
+
throw new Error("Invalid transaction format. Please provide a properly formatted Tron transaction object.");
|
|
1008
|
+
}
|
|
1009
|
+
throw error;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* 读取合约
|
|
1014
|
+
*/
|
|
1015
|
+
async readContract(params) {
|
|
1016
|
+
this.ensureConnected();
|
|
1017
|
+
try {
|
|
1018
|
+
const tronWeb = this.getTronWeb();
|
|
1019
|
+
const contract = await tronWeb.contract(params.abi, params.address);
|
|
1020
|
+
const result = await contract[params.functionName](...params.args || []).call();
|
|
1021
|
+
return result;
|
|
1022
|
+
} catch (error) {
|
|
1023
|
+
console.error("Read contract error:", error);
|
|
1024
|
+
throw new Error(`Failed to read contract: ${error.message}`);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
/**
|
|
1028
|
+
* 写入合约
|
|
1029
|
+
*/
|
|
1030
|
+
async writeContract(params) {
|
|
1031
|
+
this.ensureConnected();
|
|
1032
|
+
try {
|
|
1033
|
+
const tronWeb = this.getTronWeb();
|
|
1034
|
+
console.log("[TronLink] writeContract params:", {
|
|
1035
|
+
address: params.address,
|
|
1036
|
+
functionName: params.functionName,
|
|
1037
|
+
args: params.args,
|
|
1038
|
+
value: params.value,
|
|
1039
|
+
gas: params.gas
|
|
1040
|
+
});
|
|
1041
|
+
if (!params.args || params.args.length === 0) {
|
|
1042
|
+
throw new Error("Contract function arguments are required");
|
|
1043
|
+
}
|
|
1044
|
+
const hasUndefined = params.args.some((arg) => arg === void 0 || arg === null);
|
|
1045
|
+
if (hasUndefined) {
|
|
1046
|
+
console.error("[TronLink] Invalid args detected:", params.args);
|
|
1047
|
+
throw new Error(`Invalid contract arguments: some arguments are undefined or null`);
|
|
1048
|
+
}
|
|
1049
|
+
const functionAbi = params.abi.find(
|
|
1050
|
+
(item) => item.name === params.functionName && item.type === "function"
|
|
1051
|
+
);
|
|
1052
|
+
if (!functionAbi) {
|
|
1053
|
+
throw new Error(`Function ${params.functionName} not found in ABI`);
|
|
1054
|
+
}
|
|
1055
|
+
console.log("[TronLink] Function ABI:", functionAbi);
|
|
1056
|
+
console.log("[TronLink] Calling with args:", params.args);
|
|
1057
|
+
const options = {
|
|
1058
|
+
feeLimit: params.gas || 1e8,
|
|
1059
|
+
// 默认 100 TRX 的能量限制
|
|
1060
|
+
callValue: params.value || 0
|
|
1061
|
+
// 发送的 TRX 数量(单位:SUN)
|
|
1062
|
+
};
|
|
1063
|
+
const parameter = functionAbi.inputs.map((input, index) => ({
|
|
1064
|
+
type: input.type,
|
|
1065
|
+
value: params.args[index]
|
|
1066
|
+
}));
|
|
1067
|
+
console.log("[TronLink] Transaction options:", options);
|
|
1068
|
+
console.log("[TronLink] Parameters:", parameter);
|
|
1069
|
+
const transaction = await tronWeb.transactionBuilder.triggerSmartContract(
|
|
1070
|
+
params.address,
|
|
1071
|
+
params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")",
|
|
1072
|
+
options,
|
|
1073
|
+
parameter,
|
|
1074
|
+
this.currentAccount.nativeAddress
|
|
1075
|
+
);
|
|
1076
|
+
console.log("[TronLink] Transaction built:", transaction);
|
|
1077
|
+
if (!transaction || !transaction.transaction) {
|
|
1078
|
+
throw new Error("Failed to build transaction");
|
|
1079
|
+
}
|
|
1080
|
+
const signedTx = await tronWeb.trx.sign(transaction.transaction);
|
|
1081
|
+
const broadcast = await tronWeb.trx.sendRawTransaction(signedTx);
|
|
1082
|
+
console.log("[TronLink] Broadcast result:", broadcast);
|
|
1083
|
+
if (!broadcast.result) {
|
|
1084
|
+
throw new Error(broadcast.message || "Transaction broadcast failed");
|
|
1085
|
+
}
|
|
1086
|
+
const txHash = broadcast.txid || broadcast.transaction?.txID;
|
|
1087
|
+
console.log("[TronLink] Transaction hash:", txHash);
|
|
1088
|
+
return txHash || "";
|
|
1089
|
+
} catch (error) {
|
|
1090
|
+
console.error("Write contract error:", error);
|
|
1091
|
+
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
1092
|
+
throw new SignatureRejectedError("Transaction was rejected by user");
|
|
1093
|
+
}
|
|
1094
|
+
throw new Error(`Failed to write contract: ${error.message}`);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* 等待交易确认
|
|
1099
|
+
*/
|
|
1100
|
+
async waitForTransaction(txHash, _confirmations = 1) {
|
|
1101
|
+
try {
|
|
1102
|
+
const tronWeb = this.getTronWeb();
|
|
1103
|
+
let attempts = 0;
|
|
1104
|
+
const maxAttempts = 60;
|
|
1105
|
+
while (attempts < maxAttempts) {
|
|
1106
|
+
try {
|
|
1107
|
+
const txInfo = await tronWeb.trx.getTransactionInfo(txHash);
|
|
1108
|
+
if (txInfo && txInfo.id) {
|
|
1109
|
+
const receipt = {
|
|
1110
|
+
transactionHash: txHash,
|
|
1111
|
+
blockNumber: txInfo.blockNumber || 0,
|
|
1112
|
+
blockHash: txInfo.blockHash || "",
|
|
1113
|
+
from: this.currentAccount.nativeAddress,
|
|
1114
|
+
to: txInfo.contract_address || "",
|
|
1115
|
+
status: txInfo.receipt?.result === "SUCCESS" ? "success" : "failed",
|
|
1116
|
+
gasUsed: (txInfo.receipt?.energy_usage_total || 0).toString(),
|
|
1117
|
+
logs: txInfo.log || []
|
|
1118
|
+
};
|
|
1119
|
+
if (receipt.status === "failed") {
|
|
1120
|
+
throw new TransactionFailedError(txHash, "Transaction failed on Tron network");
|
|
1121
|
+
}
|
|
1122
|
+
return receipt;
|
|
1123
|
+
}
|
|
1124
|
+
} catch (error) {
|
|
1125
|
+
}
|
|
1126
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1127
|
+
attempts++;
|
|
1128
|
+
}
|
|
1129
|
+
throw new Error("Transaction confirmation timeout");
|
|
1130
|
+
} catch (error) {
|
|
1131
|
+
throw new Error(`Failed to wait for transaction: ${error.message}`);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
913
1134
|
/**
|
|
914
1135
|
* 获取 Provider
|
|
915
1136
|
*/
|
|
@@ -948,9 +1169,16 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
948
1169
|
setupEventListeners() {
|
|
949
1170
|
if (typeof window === "undefined") return;
|
|
950
1171
|
const w = window;
|
|
951
|
-
|
|
952
|
-
w.tronLink.on
|
|
953
|
-
|
|
1172
|
+
try {
|
|
1173
|
+
if (w.tronLink && typeof w.tronLink.on === "function") {
|
|
1174
|
+
w.tronLink.on("accountsChanged", this.handleAccountsChanged);
|
|
1175
|
+
w.tronLink.on("disconnect", this.handleDisconnect);
|
|
1176
|
+
} else if (w.tronWeb && w.tronWeb.eventServer) {
|
|
1177
|
+
this.startPolling();
|
|
1178
|
+
}
|
|
1179
|
+
} catch (error) {
|
|
1180
|
+
console.warn("TronLink event listener setup failed:", error);
|
|
1181
|
+
this.startPolling();
|
|
954
1182
|
}
|
|
955
1183
|
}
|
|
956
1184
|
/**
|
|
@@ -959,9 +1187,38 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
959
1187
|
removeEventListeners() {
|
|
960
1188
|
if (typeof window === "undefined") return;
|
|
961
1189
|
const w = window;
|
|
962
|
-
|
|
963
|
-
w.tronLink.off
|
|
964
|
-
|
|
1190
|
+
try {
|
|
1191
|
+
if (w.tronLink && typeof w.tronLink.off === "function") {
|
|
1192
|
+
w.tronLink.off("accountsChanged", this.handleAccountsChanged);
|
|
1193
|
+
w.tronLink.off("disconnect", this.handleDisconnect);
|
|
1194
|
+
}
|
|
1195
|
+
} catch (error) {
|
|
1196
|
+
console.warn("TronLink event listener removal failed:", error);
|
|
1197
|
+
}
|
|
1198
|
+
this.stopPolling();
|
|
1199
|
+
}
|
|
1200
|
+
startPolling() {
|
|
1201
|
+
if (this.pollingInterval) return;
|
|
1202
|
+
this.lastKnownAddress = this.currentAccount?.nativeAddress || null;
|
|
1203
|
+
this.pollingInterval = setInterval(async () => {
|
|
1204
|
+
try {
|
|
1205
|
+
const tronWeb = this.getTronWeb();
|
|
1206
|
+
const currentAddress = tronWeb.defaultAddress?.base58;
|
|
1207
|
+
if (currentAddress && currentAddress !== this.lastKnownAddress) {
|
|
1208
|
+
this.lastKnownAddress = currentAddress;
|
|
1209
|
+
this.handleAccountsChanged({ address: { base58: currentAddress } });
|
|
1210
|
+
} else if (!currentAddress && this.lastKnownAddress) {
|
|
1211
|
+
this.lastKnownAddress = null;
|
|
1212
|
+
this.handleAccountsChanged(null);
|
|
1213
|
+
}
|
|
1214
|
+
} catch (error) {
|
|
1215
|
+
}
|
|
1216
|
+
}, 2e3);
|
|
1217
|
+
}
|
|
1218
|
+
stopPolling() {
|
|
1219
|
+
if (this.pollingInterval) {
|
|
1220
|
+
clearInterval(this.pollingInterval);
|
|
1221
|
+
this.pollingInterval = null;
|
|
965
1222
|
}
|
|
966
1223
|
}
|
|
967
1224
|
};
|
|
@@ -972,7 +1229,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
972
1229
|
constructor() {
|
|
973
1230
|
super(...arguments);
|
|
974
1231
|
this.type = "private-key" /* PRIVATE_KEY */;
|
|
975
|
-
this.chainType =
|
|
1232
|
+
this.chainType = ChainType.EVM;
|
|
976
1233
|
this.name = "Private Key (EVM)";
|
|
977
1234
|
this.privateKey = null;
|
|
978
1235
|
this.walletClient = null;
|
|
@@ -1002,7 +1259,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
1002
1259
|
universalAddress: createUniversalAddress(chainId, address),
|
|
1003
1260
|
nativeAddress: address,
|
|
1004
1261
|
chainId,
|
|
1005
|
-
chainType:
|
|
1262
|
+
chainType: ChainType.EVM,
|
|
1006
1263
|
isActive: true
|
|
1007
1264
|
};
|
|
1008
1265
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -1352,9 +1609,10 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1352
1609
|
if (!this.primaryWallet) {
|
|
1353
1610
|
return;
|
|
1354
1611
|
}
|
|
1612
|
+
const chainType = this.primaryWallet.chainType;
|
|
1355
1613
|
await this.primaryWallet.disconnect();
|
|
1356
1614
|
this.removeAdapterListeners(this.primaryWallet);
|
|
1357
|
-
this.connectedWallets.delete(
|
|
1615
|
+
this.connectedWallets.delete(chainType);
|
|
1358
1616
|
this.primaryWallet = null;
|
|
1359
1617
|
if (this.config.enableStorage) {
|
|
1360
1618
|
this.saveToStorage();
|
|
@@ -1459,6 +1717,34 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1459
1717
|
}
|
|
1460
1718
|
return adapter.signTypedData(typedData);
|
|
1461
1719
|
}
|
|
1720
|
+
/**
|
|
1721
|
+
* 签名交易(使用主钱包)
|
|
1722
|
+
*/
|
|
1723
|
+
async signTransaction(transaction) {
|
|
1724
|
+
if (!this.primaryWallet) {
|
|
1725
|
+
throw new WalletNotConnectedError();
|
|
1726
|
+
}
|
|
1727
|
+
if (!this.primaryWallet.signTransaction) {
|
|
1728
|
+
throw new Error(`signTransaction not supported by ${this.primaryWallet.type}`);
|
|
1729
|
+
}
|
|
1730
|
+
return this.primaryWallet.signTransaction(transaction);
|
|
1731
|
+
}
|
|
1732
|
+
/**
|
|
1733
|
+
* 使用指定链类型的钱包签名交易
|
|
1734
|
+
*/
|
|
1735
|
+
async signTransactionWithChainType(transaction, chainType) {
|
|
1736
|
+
if (!chainType) {
|
|
1737
|
+
return this.signTransaction(transaction);
|
|
1738
|
+
}
|
|
1739
|
+
const adapter = this.connectedWallets.get(chainType);
|
|
1740
|
+
if (!adapter) {
|
|
1741
|
+
throw new WalletNotConnectedError(`Wallet for chain type ${chainType}`);
|
|
1742
|
+
}
|
|
1743
|
+
if (!adapter.signTransaction) {
|
|
1744
|
+
throw new Error(`signTransaction not supported by ${adapter.type}`);
|
|
1745
|
+
}
|
|
1746
|
+
return adapter.signTransaction(transaction);
|
|
1747
|
+
}
|
|
1462
1748
|
// ===== 链切换 =====
|
|
1463
1749
|
/**
|
|
1464
1750
|
* 请求切换链(仅 EVM)
|
|
@@ -1619,6 +1905,7 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1619
1905
|
* 移除适配器事件监听
|
|
1620
1906
|
*/
|
|
1621
1907
|
removeAdapterListeners(adapter) {
|
|
1908
|
+
if (!adapter) return;
|
|
1622
1909
|
adapter.removeAllListeners();
|
|
1623
1910
|
}
|
|
1624
1911
|
// ===== 存储 =====
|
|
@@ -1692,7 +1979,7 @@ var AuthMessageGenerator = class {
|
|
|
1692
1979
|
*/
|
|
1693
1980
|
generateAuthMessage(chainType, nonce, chainId, timestamp = Date.now(), statement) {
|
|
1694
1981
|
switch (chainType) {
|
|
1695
|
-
case
|
|
1982
|
+
case ChainType.EVM:
|
|
1696
1983
|
return this.generateEIP191Message({
|
|
1697
1984
|
domain: this.domain,
|
|
1698
1985
|
nonce,
|
|
@@ -1700,7 +1987,7 @@ var AuthMessageGenerator = class {
|
|
|
1700
1987
|
timestamp,
|
|
1701
1988
|
statement
|
|
1702
1989
|
});
|
|
1703
|
-
case
|
|
1990
|
+
case ChainType.TRON:
|
|
1704
1991
|
return this.generateTIP191Message({
|
|
1705
1992
|
domain: this.domain,
|
|
1706
1993
|
nonce,
|
|
@@ -1763,9 +2050,9 @@ var SignatureVerifier = class {
|
|
|
1763
2050
|
*/
|
|
1764
2051
|
async verifySignature(message, signature, expectedAddress, chainType) {
|
|
1765
2052
|
switch (chainType) {
|
|
1766
|
-
case
|
|
2053
|
+
case ChainType.EVM:
|
|
1767
2054
|
return this.verifyEIP191Signature(message, signature, expectedAddress);
|
|
1768
|
-
case
|
|
2055
|
+
case ChainType.TRON:
|
|
1769
2056
|
return this.verifyTIP191Signature(message, signature, expectedAddress);
|
|
1770
2057
|
default:
|
|
1771
2058
|
throw new Error(`Unsupported chain type: ${chainType}`);
|
|
@@ -1803,7 +2090,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1803
2090
|
["metamask" /* METAMASK */]: {
|
|
1804
2091
|
type: "metamask" /* METAMASK */,
|
|
1805
2092
|
name: "MetaMask",
|
|
1806
|
-
chainType:
|
|
2093
|
+
chainType: ChainType.EVM,
|
|
1807
2094
|
icon: "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg",
|
|
1808
2095
|
downloadUrl: "https://metamask.io/download/",
|
|
1809
2096
|
description: "The most popular Ethereum wallet"
|
|
@@ -1811,7 +2098,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1811
2098
|
["walletconnect" /* WALLETCONNECT */]: {
|
|
1812
2099
|
type: "walletconnect" /* WALLETCONNECT */,
|
|
1813
2100
|
name: "WalletConnect",
|
|
1814
|
-
chainType:
|
|
2101
|
+
chainType: ChainType.EVM,
|
|
1815
2102
|
icon: "https://avatars.githubusercontent.com/u/37784886",
|
|
1816
2103
|
downloadUrl: "https://walletconnect.com/",
|
|
1817
2104
|
description: "Connect to 170+ wallets"
|
|
@@ -1819,7 +2106,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1819
2106
|
["coinbase-wallet" /* COINBASE_WALLET */]: {
|
|
1820
2107
|
type: "coinbase-wallet" /* COINBASE_WALLET */,
|
|
1821
2108
|
name: "Coinbase Wallet",
|
|
1822
|
-
chainType:
|
|
2109
|
+
chainType: ChainType.EVM,
|
|
1823
2110
|
icon: "https://www.coinbase.com/img/favicon/favicon-96x96.png",
|
|
1824
2111
|
downloadUrl: "https://www.coinbase.com/wallet",
|
|
1825
2112
|
description: "Coinbase self-custody wallet"
|
|
@@ -1827,7 +2114,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1827
2114
|
["tronlink" /* TRONLINK */]: {
|
|
1828
2115
|
type: "tronlink" /* TRONLINK */,
|
|
1829
2116
|
name: "TronLink",
|
|
1830
|
-
chainType:
|
|
2117
|
+
chainType: ChainType.TRON,
|
|
1831
2118
|
icon: "https://www.tronlink.org/static/logoIcon.svg",
|
|
1832
2119
|
downloadUrl: "https://www.tronlink.org/",
|
|
1833
2120
|
description: "The official Tron wallet"
|
|
@@ -1835,14 +2122,14 @@ var SUPPORTED_WALLETS = {
|
|
|
1835
2122
|
["walletconnect-tron" /* WALLETCONNECT_TRON */]: {
|
|
1836
2123
|
type: "walletconnect-tron" /* WALLETCONNECT_TRON */,
|
|
1837
2124
|
name: "WalletConnect (Tron)",
|
|
1838
|
-
chainType:
|
|
2125
|
+
chainType: ChainType.TRON,
|
|
1839
2126
|
downloadUrl: "https://walletconnect.com/",
|
|
1840
2127
|
description: "WalletConnect for Tron"
|
|
1841
2128
|
},
|
|
1842
2129
|
["private-key" /* PRIVATE_KEY */]: {
|
|
1843
2130
|
type: "private-key" /* PRIVATE_KEY */,
|
|
1844
2131
|
name: "Private Key",
|
|
1845
|
-
chainType:
|
|
2132
|
+
chainType: ChainType.EVM,
|
|
1846
2133
|
// 可以用于任何链
|
|
1847
2134
|
description: "Import wallet using private key (for development)"
|
|
1848
2135
|
}
|
|
@@ -1852,12 +2139,12 @@ function getWalletMetadata(type) {
|
|
|
1852
2139
|
}
|
|
1853
2140
|
function getEVMWallets() {
|
|
1854
2141
|
return Object.values(SUPPORTED_WALLETS).filter(
|
|
1855
|
-
(wallet) => wallet.chainType ===
|
|
2142
|
+
(wallet) => wallet.chainType === ChainType.EVM
|
|
1856
2143
|
);
|
|
1857
2144
|
}
|
|
1858
2145
|
function getTronWallets() {
|
|
1859
2146
|
return Object.values(SUPPORTED_WALLETS).filter(
|
|
1860
|
-
(wallet) => wallet.chainType ===
|
|
2147
|
+
(wallet) => wallet.chainType === ChainType.TRON
|
|
1861
2148
|
);
|
|
1862
2149
|
}
|
|
1863
2150
|
|
|
@@ -1884,7 +2171,7 @@ var WalletDetector = class {
|
|
|
1884
2171
|
if (!metadata) {
|
|
1885
2172
|
return {
|
|
1886
2173
|
walletType,
|
|
1887
|
-
chainType:
|
|
2174
|
+
chainType: ChainType.EVM,
|
|
1888
2175
|
// 默认
|
|
1889
2176
|
isAvailable: false,
|
|
1890
2177
|
detected: false
|
|
@@ -1992,9 +2279,9 @@ function shortenTronAddress(address, chars = 4) {
|
|
|
1992
2279
|
// src/utils/validation.ts
|
|
1993
2280
|
function validateAddress(address, chainType) {
|
|
1994
2281
|
switch (chainType) {
|
|
1995
|
-
case
|
|
2282
|
+
case ChainType.EVM:
|
|
1996
2283
|
return isValidEVMAddress(address);
|
|
1997
|
-
case
|
|
2284
|
+
case ChainType.TRON:
|
|
1998
2285
|
return isValidTronAddress(address);
|
|
1999
2286
|
default:
|
|
2000
2287
|
return false;
|
|
@@ -2015,9 +2302,9 @@ function isValidSignature(signature) {
|
|
|
2015
2302
|
}
|
|
2016
2303
|
function isValidTransactionHash(txHash, chainType) {
|
|
2017
2304
|
switch (chainType) {
|
|
2018
|
-
case
|
|
2305
|
+
case ChainType.EVM:
|
|
2019
2306
|
return /^0x[0-9a-fA-F]{64}$/.test(txHash);
|
|
2020
|
-
case
|
|
2307
|
+
case ChainType.TRON:
|
|
2021
2308
|
return /^[0-9a-fA-F]{64}$/.test(txHash);
|
|
2022
2309
|
default:
|
|
2023
2310
|
return false;
|