@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.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var EventEmitter = require('eventemitter3');
|
|
6
|
+
var chainUtils = require('@enclave-hq/chain-utils');
|
|
6
7
|
var viem = require('viem');
|
|
7
8
|
var accounts = require('viem/accounts');
|
|
8
9
|
|
|
@@ -39,15 +40,7 @@ var TypedEventEmitter = class {
|
|
|
39
40
|
return this;
|
|
40
41
|
}
|
|
41
42
|
};
|
|
42
|
-
|
|
43
|
-
// src/core/types.ts
|
|
44
|
-
var ChainType = /* @__PURE__ */ ((ChainType4) => {
|
|
45
|
-
ChainType4["EVM"] = "evm";
|
|
46
|
-
ChainType4["TRON"] = "tron";
|
|
47
|
-
ChainType4["SOLANA"] = "solana";
|
|
48
|
-
ChainType4["COSMOS"] = "cosmos";
|
|
49
|
-
return ChainType4;
|
|
50
|
-
})(ChainType || {});
|
|
43
|
+
var ChainType = chainUtils.ChainType;
|
|
51
44
|
var WalletType = /* @__PURE__ */ ((WalletType3) => {
|
|
52
45
|
WalletType3["METAMASK"] = "metamask";
|
|
53
46
|
WalletType3["WALLETCONNECT"] = "walletconnect";
|
|
@@ -311,14 +304,15 @@ function shortenAddress(address, chars = 4) {
|
|
|
311
304
|
const formatted = viem.getAddress(address);
|
|
312
305
|
return `${formatted.substring(0, chars + 2)}...${formatted.substring(42 - chars)}`;
|
|
313
306
|
}
|
|
314
|
-
|
|
315
|
-
// src/utils/chain-info.ts
|
|
316
307
|
var CHAIN_INFO = {
|
|
317
308
|
// EVM Mainnet
|
|
318
309
|
1: {
|
|
319
310
|
id: 1,
|
|
311
|
+
slip44: 60,
|
|
312
|
+
// Ethereum SLIP-44
|
|
320
313
|
name: "Ethereum Mainnet",
|
|
321
|
-
chainType:
|
|
314
|
+
chainType: chainUtils.ChainType.EVM,
|
|
315
|
+
symbol: "ETH",
|
|
322
316
|
nativeCurrency: {
|
|
323
317
|
name: "Ether",
|
|
324
318
|
symbol: "ETH",
|
|
@@ -331,7 +325,8 @@ var CHAIN_INFO = {
|
|
|
331
325
|
11155111: {
|
|
332
326
|
id: 11155111,
|
|
333
327
|
name: "Sepolia Testnet",
|
|
334
|
-
chainType:
|
|
328
|
+
chainType: chainUtils.ChainType.EVM,
|
|
329
|
+
symbol: "ETH",
|
|
335
330
|
nativeCurrency: {
|
|
336
331
|
name: "Sepolia Ether",
|
|
337
332
|
symbol: "ETH",
|
|
@@ -343,8 +338,11 @@ var CHAIN_INFO = {
|
|
|
343
338
|
// Binance Smart Chain
|
|
344
339
|
56: {
|
|
345
340
|
id: 56,
|
|
341
|
+
slip44: 714,
|
|
342
|
+
// BSC SLIP-44
|
|
346
343
|
name: "BNB Smart Chain",
|
|
347
|
-
chainType:
|
|
344
|
+
chainType: chainUtils.ChainType.EVM,
|
|
345
|
+
symbol: "BNB",
|
|
348
346
|
nativeCurrency: {
|
|
349
347
|
name: "BNB",
|
|
350
348
|
symbol: "BNB",
|
|
@@ -356,7 +354,8 @@ var CHAIN_INFO = {
|
|
|
356
354
|
97: {
|
|
357
355
|
id: 97,
|
|
358
356
|
name: "BNB Smart Chain Testnet",
|
|
359
|
-
chainType:
|
|
357
|
+
chainType: chainUtils.ChainType.EVM,
|
|
358
|
+
symbol: "BNB",
|
|
360
359
|
nativeCurrency: {
|
|
361
360
|
name: "BNB",
|
|
362
361
|
symbol: "BNB",
|
|
@@ -368,8 +367,11 @@ var CHAIN_INFO = {
|
|
|
368
367
|
// Polygon
|
|
369
368
|
137: {
|
|
370
369
|
id: 137,
|
|
370
|
+
slip44: 966,
|
|
371
|
+
// Polygon SLIP-44
|
|
371
372
|
name: "Polygon Mainnet",
|
|
372
|
-
chainType:
|
|
373
|
+
chainType: chainUtils.ChainType.EVM,
|
|
374
|
+
symbol: "MATIC",
|
|
373
375
|
nativeCurrency: {
|
|
374
376
|
name: "MATIC",
|
|
375
377
|
symbol: "MATIC",
|
|
@@ -381,7 +383,8 @@ var CHAIN_INFO = {
|
|
|
381
383
|
80002: {
|
|
382
384
|
id: 80002,
|
|
383
385
|
name: "Polygon Amoy Testnet",
|
|
384
|
-
chainType:
|
|
386
|
+
chainType: chainUtils.ChainType.EVM,
|
|
387
|
+
symbol: "MATIC",
|
|
385
388
|
nativeCurrency: {
|
|
386
389
|
name: "MATIC",
|
|
387
390
|
symbol: "MATIC",
|
|
@@ -393,8 +396,11 @@ var CHAIN_INFO = {
|
|
|
393
396
|
// Tron
|
|
394
397
|
195: {
|
|
395
398
|
id: 195,
|
|
399
|
+
slip44: 195,
|
|
400
|
+
// Tron SLIP-44
|
|
396
401
|
name: "Tron Mainnet",
|
|
397
|
-
chainType:
|
|
402
|
+
chainType: chainUtils.ChainType.TRON,
|
|
403
|
+
symbol: "TRX",
|
|
398
404
|
nativeCurrency: {
|
|
399
405
|
name: "TRX",
|
|
400
406
|
symbol: "TRX",
|
|
@@ -406,8 +412,11 @@ var CHAIN_INFO = {
|
|
|
406
412
|
// Arbitrum
|
|
407
413
|
42161: {
|
|
408
414
|
id: 42161,
|
|
415
|
+
slip44: 1042161,
|
|
416
|
+
// Custom SLIP-44 (1000000 + 42161)
|
|
409
417
|
name: "Arbitrum One",
|
|
410
|
-
chainType:
|
|
418
|
+
chainType: chainUtils.ChainType.EVM,
|
|
419
|
+
symbol: "ETH",
|
|
411
420
|
nativeCurrency: {
|
|
412
421
|
name: "Ether",
|
|
413
422
|
symbol: "ETH",
|
|
@@ -419,8 +428,11 @@ var CHAIN_INFO = {
|
|
|
419
428
|
// Optimism
|
|
420
429
|
10: {
|
|
421
430
|
id: 10,
|
|
431
|
+
slip44: 1000010,
|
|
432
|
+
// Custom SLIP-44 (1000000 + 10)
|
|
422
433
|
name: "Optimism",
|
|
423
|
-
chainType:
|
|
434
|
+
chainType: chainUtils.ChainType.EVM,
|
|
435
|
+
symbol: "ETH",
|
|
424
436
|
nativeCurrency: {
|
|
425
437
|
name: "Ether",
|
|
426
438
|
symbol: "ETH",
|
|
@@ -432,8 +444,11 @@ var CHAIN_INFO = {
|
|
|
432
444
|
// Avalanche
|
|
433
445
|
43114: {
|
|
434
446
|
id: 43114,
|
|
447
|
+
slip44: 9e3,
|
|
448
|
+
// Avalanche SLIP-44
|
|
435
449
|
name: "Avalanche C-Chain",
|
|
436
|
-
chainType:
|
|
450
|
+
chainType: chainUtils.ChainType.EVM,
|
|
451
|
+
symbol: "AVAX",
|
|
437
452
|
nativeCurrency: {
|
|
438
453
|
name: "AVAX",
|
|
439
454
|
symbol: "AVAX",
|
|
@@ -450,10 +465,10 @@ function getChainType(chainId) {
|
|
|
450
465
|
return CHAIN_INFO[chainId]?.chainType;
|
|
451
466
|
}
|
|
452
467
|
function isEVMChain(chainId) {
|
|
453
|
-
return getChainType(chainId) ===
|
|
468
|
+
return getChainType(chainId) === chainUtils.ChainType.EVM;
|
|
454
469
|
}
|
|
455
470
|
function isTronChain(chainId) {
|
|
456
|
-
return getChainType(chainId) ===
|
|
471
|
+
return getChainType(chainId) === chainUtils.ChainType.TRON;
|
|
457
472
|
}
|
|
458
473
|
|
|
459
474
|
// src/adapters/evm/metamask.ts
|
|
@@ -461,26 +476,34 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
461
476
|
constructor() {
|
|
462
477
|
super(...arguments);
|
|
463
478
|
this.type = "metamask" /* METAMASK */;
|
|
464
|
-
this.chainType =
|
|
479
|
+
this.chainType = ChainType.EVM;
|
|
465
480
|
this.name = "MetaMask";
|
|
466
481
|
this.icon = "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg";
|
|
467
482
|
this.walletClient = null;
|
|
468
483
|
this.publicClient = null;
|
|
469
484
|
/**
|
|
470
485
|
* 处理账户变化
|
|
486
|
+
*
|
|
487
|
+
* 注意:MetaMask 的行为
|
|
488
|
+
* - 切换到已连接的账户:触发事件,返回新账户 ['0xNewAddress']
|
|
489
|
+
* - 切换到未连接的账户:不触发事件(用户需要手动断开和重新连接)
|
|
490
|
+
* - 锁定钱包:触发事件,返回空数组 []
|
|
471
491
|
*/
|
|
472
492
|
this.handleAccountsChanged = (accounts) => {
|
|
493
|
+
console.log("[MetaMask] accountsChanged event triggered:", accounts);
|
|
473
494
|
if (accounts.length === 0) {
|
|
495
|
+
console.log("[MetaMask] Disconnecting: wallet locked or manually disconnected");
|
|
474
496
|
this.setState("disconnected" /* DISCONNECTED */);
|
|
475
497
|
this.setAccount(null);
|
|
476
498
|
this.emitAccountChanged(null);
|
|
477
499
|
} else {
|
|
478
500
|
const address = formatEVMAddress(accounts[0]);
|
|
501
|
+
console.log("[MetaMask] Account changed to:", address);
|
|
479
502
|
const account = {
|
|
480
503
|
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
481
504
|
nativeAddress: address,
|
|
482
505
|
chainId: this.currentAccount.chainId,
|
|
483
|
-
chainType:
|
|
506
|
+
chainType: ChainType.EVM,
|
|
484
507
|
isActive: true
|
|
485
508
|
};
|
|
486
509
|
this.setAccount(account);
|
|
@@ -532,21 +555,23 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
532
555
|
if (chainId && chainId !== parsedChainId) {
|
|
533
556
|
await this.switchChain(chainId);
|
|
534
557
|
}
|
|
558
|
+
const finalChainId = chainId || parsedChainId;
|
|
559
|
+
const viemChain = this.getViemChain(finalChainId);
|
|
535
560
|
this.walletClient = viem.createWalletClient({
|
|
536
561
|
account: accounts[0],
|
|
562
|
+
chain: viemChain,
|
|
537
563
|
transport: viem.custom(provider)
|
|
538
564
|
});
|
|
539
|
-
const finalChainId = chainId || parsedChainId;
|
|
540
565
|
this.publicClient = viem.createPublicClient({
|
|
541
|
-
chain:
|
|
542
|
-
transport: viem.
|
|
566
|
+
chain: viemChain,
|
|
567
|
+
transport: viem.custom(provider)
|
|
543
568
|
});
|
|
544
569
|
const address = formatEVMAddress(accounts[0]);
|
|
545
570
|
const account = {
|
|
546
571
|
universalAddress: createUniversalAddress(finalChainId, address),
|
|
547
572
|
nativeAddress: address,
|
|
548
573
|
chainId: finalChainId,
|
|
549
|
-
chainType:
|
|
574
|
+
chainType: ChainType.EVM,
|
|
550
575
|
isActive: true
|
|
551
576
|
};
|
|
552
577
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -600,6 +625,40 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
600
625
|
throw error;
|
|
601
626
|
}
|
|
602
627
|
}
|
|
628
|
+
/**
|
|
629
|
+
* 签名交易
|
|
630
|
+
*
|
|
631
|
+
* Note: This signs a raw transaction without sending it.
|
|
632
|
+
* The transaction can be broadcast later using the returned signature.
|
|
633
|
+
*/
|
|
634
|
+
async signTransaction(transaction) {
|
|
635
|
+
this.ensureConnected();
|
|
636
|
+
try {
|
|
637
|
+
const provider = this.getBrowserProvider();
|
|
638
|
+
const tx = {
|
|
639
|
+
from: this.currentAccount.nativeAddress,
|
|
640
|
+
to: transaction.to,
|
|
641
|
+
value: transaction.value ? `0x${BigInt(transaction.value).toString(16)}` : void 0,
|
|
642
|
+
data: transaction.data || "0x",
|
|
643
|
+
gas: transaction.gas ? `0x${BigInt(transaction.gas).toString(16)}` : void 0,
|
|
644
|
+
gasPrice: transaction.gasPrice ? `0x${BigInt(transaction.gasPrice).toString(16)}` : void 0,
|
|
645
|
+
maxFeePerGas: transaction.maxFeePerGas ? `0x${BigInt(transaction.maxFeePerGas).toString(16)}` : void 0,
|
|
646
|
+
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ? `0x${BigInt(transaction.maxPriorityFeePerGas).toString(16)}` : void 0,
|
|
647
|
+
nonce: transaction.nonce !== void 0 ? `0x${transaction.nonce.toString(16)}` : void 0,
|
|
648
|
+
chainId: transaction.chainId || this.currentAccount.chainId
|
|
649
|
+
};
|
|
650
|
+
const signature = await provider.request({
|
|
651
|
+
method: "eth_signTransaction",
|
|
652
|
+
params: [tx]
|
|
653
|
+
});
|
|
654
|
+
return signature;
|
|
655
|
+
} catch (error) {
|
|
656
|
+
if (error.code === 4001) {
|
|
657
|
+
throw new SignatureRejectedError("Transaction signature was rejected by user");
|
|
658
|
+
}
|
|
659
|
+
throw error;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
603
662
|
/**
|
|
604
663
|
* 切换链
|
|
605
664
|
*/
|
|
@@ -830,9 +889,14 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
830
889
|
constructor() {
|
|
831
890
|
super(...arguments);
|
|
832
891
|
this.type = "tronlink" /* TRONLINK */;
|
|
833
|
-
this.chainType =
|
|
892
|
+
this.chainType = ChainType.TRON;
|
|
834
893
|
this.name = "TronLink";
|
|
835
894
|
this.icon = "https://www.tronlink.org/static/logoIcon.svg";
|
|
895
|
+
/**
|
|
896
|
+
* 轮询检测账户变化(备用方案)
|
|
897
|
+
*/
|
|
898
|
+
this.pollingInterval = null;
|
|
899
|
+
this.lastKnownAddress = null;
|
|
836
900
|
/**
|
|
837
901
|
* 处理账户变化
|
|
838
902
|
*/
|
|
@@ -847,7 +911,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
847
911
|
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
848
912
|
nativeAddress: address,
|
|
849
913
|
chainId: this.currentAccount.chainId,
|
|
850
|
-
chainType:
|
|
914
|
+
chainType: ChainType.TRON,
|
|
851
915
|
isActive: true
|
|
852
916
|
};
|
|
853
917
|
this.setAccount(account);
|
|
@@ -886,7 +950,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
886
950
|
universalAddress: createUniversalAddress(tronChainId, address),
|
|
887
951
|
nativeAddress: address,
|
|
888
952
|
chainId: tronChainId,
|
|
889
|
-
chainType:
|
|
953
|
+
chainType: ChainType.TRON,
|
|
890
954
|
isActive: true
|
|
891
955
|
};
|
|
892
956
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -904,20 +968,177 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
904
968
|
}
|
|
905
969
|
/**
|
|
906
970
|
* 签名消息
|
|
971
|
+
*
|
|
972
|
+
* Note: TronLink supports two signing methods:
|
|
973
|
+
* - trx.sign(): Signs a transaction object
|
|
974
|
+
* - trx.signMessageV2(): Signs a plain text message (what we use here)
|
|
907
975
|
*/
|
|
908
976
|
async signMessage(message) {
|
|
909
977
|
this.ensureConnected();
|
|
910
978
|
try {
|
|
911
979
|
const tronWeb = this.getTronWeb();
|
|
912
|
-
|
|
913
|
-
|
|
980
|
+
if (typeof tronWeb.trx.signMessageV2 === "function") {
|
|
981
|
+
const signature = await tronWeb.trx.signMessageV2(message);
|
|
982
|
+
return signature;
|
|
983
|
+
} else {
|
|
984
|
+
console.warn("[TronLink] signMessageV2 not available, falling back to sign()");
|
|
985
|
+
const signature = await tronWeb.trx.sign(message);
|
|
986
|
+
return signature;
|
|
987
|
+
}
|
|
914
988
|
} catch (error) {
|
|
915
989
|
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
916
990
|
throw new SignatureRejectedError();
|
|
917
991
|
}
|
|
992
|
+
if (error.message?.includes("Invalid transaction")) {
|
|
993
|
+
throw new Error("Invalid message format. For transaction signing, use signTransaction() instead.");
|
|
994
|
+
}
|
|
918
995
|
throw error;
|
|
919
996
|
}
|
|
920
997
|
}
|
|
998
|
+
/**
|
|
999
|
+
* 签名交易
|
|
1000
|
+
*
|
|
1001
|
+
* Note: This uses trx.sign() which is specifically for signing transaction objects.
|
|
1002
|
+
* For plain text message signing, use signMessage() instead.
|
|
1003
|
+
*/
|
|
1004
|
+
async signTransaction(transaction) {
|
|
1005
|
+
this.ensureConnected();
|
|
1006
|
+
try {
|
|
1007
|
+
const tronWeb = this.getTronWeb();
|
|
1008
|
+
const signature = await tronWeb.trx.sign(transaction);
|
|
1009
|
+
return signature;
|
|
1010
|
+
} catch (error) {
|
|
1011
|
+
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
1012
|
+
throw new SignatureRejectedError("Transaction signature was rejected by user");
|
|
1013
|
+
}
|
|
1014
|
+
if (error.message?.includes("Invalid transaction")) {
|
|
1015
|
+
throw new Error("Invalid transaction format. Please provide a properly formatted Tron transaction object.");
|
|
1016
|
+
}
|
|
1017
|
+
throw error;
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* 读取合约
|
|
1022
|
+
*/
|
|
1023
|
+
async readContract(params) {
|
|
1024
|
+
this.ensureConnected();
|
|
1025
|
+
try {
|
|
1026
|
+
const tronWeb = this.getTronWeb();
|
|
1027
|
+
const contract = await tronWeb.contract(params.abi, params.address);
|
|
1028
|
+
const result = await contract[params.functionName](...params.args || []).call();
|
|
1029
|
+
return result;
|
|
1030
|
+
} catch (error) {
|
|
1031
|
+
console.error("Read contract error:", error);
|
|
1032
|
+
throw new Error(`Failed to read contract: ${error.message}`);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* 写入合约
|
|
1037
|
+
*/
|
|
1038
|
+
async writeContract(params) {
|
|
1039
|
+
this.ensureConnected();
|
|
1040
|
+
try {
|
|
1041
|
+
const tronWeb = this.getTronWeb();
|
|
1042
|
+
console.log("[TronLink] writeContract params:", {
|
|
1043
|
+
address: params.address,
|
|
1044
|
+
functionName: params.functionName,
|
|
1045
|
+
args: params.args,
|
|
1046
|
+
value: params.value,
|
|
1047
|
+
gas: params.gas
|
|
1048
|
+
});
|
|
1049
|
+
if (!params.args || params.args.length === 0) {
|
|
1050
|
+
throw new Error("Contract function arguments are required");
|
|
1051
|
+
}
|
|
1052
|
+
const hasUndefined = params.args.some((arg) => arg === void 0 || arg === null);
|
|
1053
|
+
if (hasUndefined) {
|
|
1054
|
+
console.error("[TronLink] Invalid args detected:", params.args);
|
|
1055
|
+
throw new Error(`Invalid contract arguments: some arguments are undefined or null`);
|
|
1056
|
+
}
|
|
1057
|
+
const functionAbi = params.abi.find(
|
|
1058
|
+
(item) => item.name === params.functionName && item.type === "function"
|
|
1059
|
+
);
|
|
1060
|
+
if (!functionAbi) {
|
|
1061
|
+
throw new Error(`Function ${params.functionName} not found in ABI`);
|
|
1062
|
+
}
|
|
1063
|
+
console.log("[TronLink] Function ABI:", functionAbi);
|
|
1064
|
+
console.log("[TronLink] Calling with args:", params.args);
|
|
1065
|
+
const options = {
|
|
1066
|
+
feeLimit: params.gas || 1e8,
|
|
1067
|
+
// 默认 100 TRX 的能量限制
|
|
1068
|
+
callValue: params.value || 0
|
|
1069
|
+
// 发送的 TRX 数量(单位:SUN)
|
|
1070
|
+
};
|
|
1071
|
+
const parameter = functionAbi.inputs.map((input, index) => ({
|
|
1072
|
+
type: input.type,
|
|
1073
|
+
value: params.args[index]
|
|
1074
|
+
}));
|
|
1075
|
+
console.log("[TronLink] Transaction options:", options);
|
|
1076
|
+
console.log("[TronLink] Parameters:", parameter);
|
|
1077
|
+
const transaction = await tronWeb.transactionBuilder.triggerSmartContract(
|
|
1078
|
+
params.address,
|
|
1079
|
+
params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")",
|
|
1080
|
+
options,
|
|
1081
|
+
parameter,
|
|
1082
|
+
this.currentAccount.nativeAddress
|
|
1083
|
+
);
|
|
1084
|
+
console.log("[TronLink] Transaction built:", transaction);
|
|
1085
|
+
if (!transaction || !transaction.transaction) {
|
|
1086
|
+
throw new Error("Failed to build transaction");
|
|
1087
|
+
}
|
|
1088
|
+
const signedTx = await tronWeb.trx.sign(transaction.transaction);
|
|
1089
|
+
const broadcast = await tronWeb.trx.sendRawTransaction(signedTx);
|
|
1090
|
+
console.log("[TronLink] Broadcast result:", broadcast);
|
|
1091
|
+
if (!broadcast.result) {
|
|
1092
|
+
throw new Error(broadcast.message || "Transaction broadcast failed");
|
|
1093
|
+
}
|
|
1094
|
+
const txHash = broadcast.txid || broadcast.transaction?.txID;
|
|
1095
|
+
console.log("[TronLink] Transaction hash:", txHash);
|
|
1096
|
+
return txHash || "";
|
|
1097
|
+
} catch (error) {
|
|
1098
|
+
console.error("Write contract error:", error);
|
|
1099
|
+
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
1100
|
+
throw new SignatureRejectedError("Transaction was rejected by user");
|
|
1101
|
+
}
|
|
1102
|
+
throw new Error(`Failed to write contract: ${error.message}`);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* 等待交易确认
|
|
1107
|
+
*/
|
|
1108
|
+
async waitForTransaction(txHash, _confirmations = 1) {
|
|
1109
|
+
try {
|
|
1110
|
+
const tronWeb = this.getTronWeb();
|
|
1111
|
+
let attempts = 0;
|
|
1112
|
+
const maxAttempts = 60;
|
|
1113
|
+
while (attempts < maxAttempts) {
|
|
1114
|
+
try {
|
|
1115
|
+
const txInfo = await tronWeb.trx.getTransactionInfo(txHash);
|
|
1116
|
+
if (txInfo && txInfo.id) {
|
|
1117
|
+
const receipt = {
|
|
1118
|
+
transactionHash: txHash,
|
|
1119
|
+
blockNumber: txInfo.blockNumber || 0,
|
|
1120
|
+
blockHash: txInfo.blockHash || "",
|
|
1121
|
+
from: this.currentAccount.nativeAddress,
|
|
1122
|
+
to: txInfo.contract_address || "",
|
|
1123
|
+
status: txInfo.receipt?.result === "SUCCESS" ? "success" : "failed",
|
|
1124
|
+
gasUsed: (txInfo.receipt?.energy_usage_total || 0).toString(),
|
|
1125
|
+
logs: txInfo.log || []
|
|
1126
|
+
};
|
|
1127
|
+
if (receipt.status === "failed") {
|
|
1128
|
+
throw new TransactionFailedError(txHash, "Transaction failed on Tron network");
|
|
1129
|
+
}
|
|
1130
|
+
return receipt;
|
|
1131
|
+
}
|
|
1132
|
+
} catch (error) {
|
|
1133
|
+
}
|
|
1134
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1135
|
+
attempts++;
|
|
1136
|
+
}
|
|
1137
|
+
throw new Error("Transaction confirmation timeout");
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
throw new Error(`Failed to wait for transaction: ${error.message}`);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
921
1142
|
/**
|
|
922
1143
|
* 获取 Provider
|
|
923
1144
|
*/
|
|
@@ -956,9 +1177,16 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
956
1177
|
setupEventListeners() {
|
|
957
1178
|
if (typeof window === "undefined") return;
|
|
958
1179
|
const w = window;
|
|
959
|
-
|
|
960
|
-
w.tronLink.on
|
|
961
|
-
|
|
1180
|
+
try {
|
|
1181
|
+
if (w.tronLink && typeof w.tronLink.on === "function") {
|
|
1182
|
+
w.tronLink.on("accountsChanged", this.handleAccountsChanged);
|
|
1183
|
+
w.tronLink.on("disconnect", this.handleDisconnect);
|
|
1184
|
+
} else if (w.tronWeb && w.tronWeb.eventServer) {
|
|
1185
|
+
this.startPolling();
|
|
1186
|
+
}
|
|
1187
|
+
} catch (error) {
|
|
1188
|
+
console.warn("TronLink event listener setup failed:", error);
|
|
1189
|
+
this.startPolling();
|
|
962
1190
|
}
|
|
963
1191
|
}
|
|
964
1192
|
/**
|
|
@@ -967,9 +1195,38 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
967
1195
|
removeEventListeners() {
|
|
968
1196
|
if (typeof window === "undefined") return;
|
|
969
1197
|
const w = window;
|
|
970
|
-
|
|
971
|
-
w.tronLink.off
|
|
972
|
-
|
|
1198
|
+
try {
|
|
1199
|
+
if (w.tronLink && typeof w.tronLink.off === "function") {
|
|
1200
|
+
w.tronLink.off("accountsChanged", this.handleAccountsChanged);
|
|
1201
|
+
w.tronLink.off("disconnect", this.handleDisconnect);
|
|
1202
|
+
}
|
|
1203
|
+
} catch (error) {
|
|
1204
|
+
console.warn("TronLink event listener removal failed:", error);
|
|
1205
|
+
}
|
|
1206
|
+
this.stopPolling();
|
|
1207
|
+
}
|
|
1208
|
+
startPolling() {
|
|
1209
|
+
if (this.pollingInterval) return;
|
|
1210
|
+
this.lastKnownAddress = this.currentAccount?.nativeAddress || null;
|
|
1211
|
+
this.pollingInterval = setInterval(async () => {
|
|
1212
|
+
try {
|
|
1213
|
+
const tronWeb = this.getTronWeb();
|
|
1214
|
+
const currentAddress = tronWeb.defaultAddress?.base58;
|
|
1215
|
+
if (currentAddress && currentAddress !== this.lastKnownAddress) {
|
|
1216
|
+
this.lastKnownAddress = currentAddress;
|
|
1217
|
+
this.handleAccountsChanged({ address: { base58: currentAddress } });
|
|
1218
|
+
} else if (!currentAddress && this.lastKnownAddress) {
|
|
1219
|
+
this.lastKnownAddress = null;
|
|
1220
|
+
this.handleAccountsChanged(null);
|
|
1221
|
+
}
|
|
1222
|
+
} catch (error) {
|
|
1223
|
+
}
|
|
1224
|
+
}, 2e3);
|
|
1225
|
+
}
|
|
1226
|
+
stopPolling() {
|
|
1227
|
+
if (this.pollingInterval) {
|
|
1228
|
+
clearInterval(this.pollingInterval);
|
|
1229
|
+
this.pollingInterval = null;
|
|
973
1230
|
}
|
|
974
1231
|
}
|
|
975
1232
|
};
|
|
@@ -980,7 +1237,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
980
1237
|
constructor() {
|
|
981
1238
|
super(...arguments);
|
|
982
1239
|
this.type = "private-key" /* PRIVATE_KEY */;
|
|
983
|
-
this.chainType =
|
|
1240
|
+
this.chainType = ChainType.EVM;
|
|
984
1241
|
this.name = "Private Key (EVM)";
|
|
985
1242
|
this.privateKey = null;
|
|
986
1243
|
this.walletClient = null;
|
|
@@ -1010,7 +1267,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
1010
1267
|
universalAddress: createUniversalAddress(chainId, address),
|
|
1011
1268
|
nativeAddress: address,
|
|
1012
1269
|
chainId,
|
|
1013
|
-
chainType:
|
|
1270
|
+
chainType: ChainType.EVM,
|
|
1014
1271
|
isActive: true
|
|
1015
1272
|
};
|
|
1016
1273
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -1360,9 +1617,10 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1360
1617
|
if (!this.primaryWallet) {
|
|
1361
1618
|
return;
|
|
1362
1619
|
}
|
|
1620
|
+
const chainType = this.primaryWallet.chainType;
|
|
1363
1621
|
await this.primaryWallet.disconnect();
|
|
1364
1622
|
this.removeAdapterListeners(this.primaryWallet);
|
|
1365
|
-
this.connectedWallets.delete(
|
|
1623
|
+
this.connectedWallets.delete(chainType);
|
|
1366
1624
|
this.primaryWallet = null;
|
|
1367
1625
|
if (this.config.enableStorage) {
|
|
1368
1626
|
this.saveToStorage();
|
|
@@ -1467,6 +1725,34 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1467
1725
|
}
|
|
1468
1726
|
return adapter.signTypedData(typedData);
|
|
1469
1727
|
}
|
|
1728
|
+
/**
|
|
1729
|
+
* 签名交易(使用主钱包)
|
|
1730
|
+
*/
|
|
1731
|
+
async signTransaction(transaction) {
|
|
1732
|
+
if (!this.primaryWallet) {
|
|
1733
|
+
throw new WalletNotConnectedError();
|
|
1734
|
+
}
|
|
1735
|
+
if (!this.primaryWallet.signTransaction) {
|
|
1736
|
+
throw new Error(`signTransaction not supported by ${this.primaryWallet.type}`);
|
|
1737
|
+
}
|
|
1738
|
+
return this.primaryWallet.signTransaction(transaction);
|
|
1739
|
+
}
|
|
1740
|
+
/**
|
|
1741
|
+
* 使用指定链类型的钱包签名交易
|
|
1742
|
+
*/
|
|
1743
|
+
async signTransactionWithChainType(transaction, chainType) {
|
|
1744
|
+
if (!chainType) {
|
|
1745
|
+
return this.signTransaction(transaction);
|
|
1746
|
+
}
|
|
1747
|
+
const adapter = this.connectedWallets.get(chainType);
|
|
1748
|
+
if (!adapter) {
|
|
1749
|
+
throw new WalletNotConnectedError(`Wallet for chain type ${chainType}`);
|
|
1750
|
+
}
|
|
1751
|
+
if (!adapter.signTransaction) {
|
|
1752
|
+
throw new Error(`signTransaction not supported by ${adapter.type}`);
|
|
1753
|
+
}
|
|
1754
|
+
return adapter.signTransaction(transaction);
|
|
1755
|
+
}
|
|
1470
1756
|
// ===== 链切换 =====
|
|
1471
1757
|
/**
|
|
1472
1758
|
* 请求切换链(仅 EVM)
|
|
@@ -1627,6 +1913,7 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1627
1913
|
* 移除适配器事件监听
|
|
1628
1914
|
*/
|
|
1629
1915
|
removeAdapterListeners(adapter) {
|
|
1916
|
+
if (!adapter) return;
|
|
1630
1917
|
adapter.removeAllListeners();
|
|
1631
1918
|
}
|
|
1632
1919
|
// ===== 存储 =====
|
|
@@ -1700,7 +1987,7 @@ var AuthMessageGenerator = class {
|
|
|
1700
1987
|
*/
|
|
1701
1988
|
generateAuthMessage(chainType, nonce, chainId, timestamp = Date.now(), statement) {
|
|
1702
1989
|
switch (chainType) {
|
|
1703
|
-
case
|
|
1990
|
+
case ChainType.EVM:
|
|
1704
1991
|
return this.generateEIP191Message({
|
|
1705
1992
|
domain: this.domain,
|
|
1706
1993
|
nonce,
|
|
@@ -1708,7 +1995,7 @@ var AuthMessageGenerator = class {
|
|
|
1708
1995
|
timestamp,
|
|
1709
1996
|
statement
|
|
1710
1997
|
});
|
|
1711
|
-
case
|
|
1998
|
+
case ChainType.TRON:
|
|
1712
1999
|
return this.generateTIP191Message({
|
|
1713
2000
|
domain: this.domain,
|
|
1714
2001
|
nonce,
|
|
@@ -1771,9 +2058,9 @@ var SignatureVerifier = class {
|
|
|
1771
2058
|
*/
|
|
1772
2059
|
async verifySignature(message, signature, expectedAddress, chainType) {
|
|
1773
2060
|
switch (chainType) {
|
|
1774
|
-
case
|
|
2061
|
+
case ChainType.EVM:
|
|
1775
2062
|
return this.verifyEIP191Signature(message, signature, expectedAddress);
|
|
1776
|
-
case
|
|
2063
|
+
case ChainType.TRON:
|
|
1777
2064
|
return this.verifyTIP191Signature(message, signature, expectedAddress);
|
|
1778
2065
|
default:
|
|
1779
2066
|
throw new Error(`Unsupported chain type: ${chainType}`);
|
|
@@ -1811,7 +2098,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1811
2098
|
["metamask" /* METAMASK */]: {
|
|
1812
2099
|
type: "metamask" /* METAMASK */,
|
|
1813
2100
|
name: "MetaMask",
|
|
1814
|
-
chainType:
|
|
2101
|
+
chainType: ChainType.EVM,
|
|
1815
2102
|
icon: "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg",
|
|
1816
2103
|
downloadUrl: "https://metamask.io/download/",
|
|
1817
2104
|
description: "The most popular Ethereum wallet"
|
|
@@ -1819,7 +2106,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1819
2106
|
["walletconnect" /* WALLETCONNECT */]: {
|
|
1820
2107
|
type: "walletconnect" /* WALLETCONNECT */,
|
|
1821
2108
|
name: "WalletConnect",
|
|
1822
|
-
chainType:
|
|
2109
|
+
chainType: ChainType.EVM,
|
|
1823
2110
|
icon: "https://avatars.githubusercontent.com/u/37784886",
|
|
1824
2111
|
downloadUrl: "https://walletconnect.com/",
|
|
1825
2112
|
description: "Connect to 170+ wallets"
|
|
@@ -1827,7 +2114,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1827
2114
|
["coinbase-wallet" /* COINBASE_WALLET */]: {
|
|
1828
2115
|
type: "coinbase-wallet" /* COINBASE_WALLET */,
|
|
1829
2116
|
name: "Coinbase Wallet",
|
|
1830
|
-
chainType:
|
|
2117
|
+
chainType: ChainType.EVM,
|
|
1831
2118
|
icon: "https://www.coinbase.com/img/favicon/favicon-96x96.png",
|
|
1832
2119
|
downloadUrl: "https://www.coinbase.com/wallet",
|
|
1833
2120
|
description: "Coinbase self-custody wallet"
|
|
@@ -1835,7 +2122,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1835
2122
|
["tronlink" /* TRONLINK */]: {
|
|
1836
2123
|
type: "tronlink" /* TRONLINK */,
|
|
1837
2124
|
name: "TronLink",
|
|
1838
|
-
chainType:
|
|
2125
|
+
chainType: ChainType.TRON,
|
|
1839
2126
|
icon: "https://www.tronlink.org/static/logoIcon.svg",
|
|
1840
2127
|
downloadUrl: "https://www.tronlink.org/",
|
|
1841
2128
|
description: "The official Tron wallet"
|
|
@@ -1843,14 +2130,14 @@ var SUPPORTED_WALLETS = {
|
|
|
1843
2130
|
["walletconnect-tron" /* WALLETCONNECT_TRON */]: {
|
|
1844
2131
|
type: "walletconnect-tron" /* WALLETCONNECT_TRON */,
|
|
1845
2132
|
name: "WalletConnect (Tron)",
|
|
1846
|
-
chainType:
|
|
2133
|
+
chainType: ChainType.TRON,
|
|
1847
2134
|
downloadUrl: "https://walletconnect.com/",
|
|
1848
2135
|
description: "WalletConnect for Tron"
|
|
1849
2136
|
},
|
|
1850
2137
|
["private-key" /* PRIVATE_KEY */]: {
|
|
1851
2138
|
type: "private-key" /* PRIVATE_KEY */,
|
|
1852
2139
|
name: "Private Key",
|
|
1853
|
-
chainType:
|
|
2140
|
+
chainType: ChainType.EVM,
|
|
1854
2141
|
// 可以用于任何链
|
|
1855
2142
|
description: "Import wallet using private key (for development)"
|
|
1856
2143
|
}
|
|
@@ -1860,12 +2147,12 @@ function getWalletMetadata(type) {
|
|
|
1860
2147
|
}
|
|
1861
2148
|
function getEVMWallets() {
|
|
1862
2149
|
return Object.values(SUPPORTED_WALLETS).filter(
|
|
1863
|
-
(wallet) => wallet.chainType ===
|
|
2150
|
+
(wallet) => wallet.chainType === ChainType.EVM
|
|
1864
2151
|
);
|
|
1865
2152
|
}
|
|
1866
2153
|
function getTronWallets() {
|
|
1867
2154
|
return Object.values(SUPPORTED_WALLETS).filter(
|
|
1868
|
-
(wallet) => wallet.chainType ===
|
|
2155
|
+
(wallet) => wallet.chainType === ChainType.TRON
|
|
1869
2156
|
);
|
|
1870
2157
|
}
|
|
1871
2158
|
|
|
@@ -1892,7 +2179,7 @@ var WalletDetector = class {
|
|
|
1892
2179
|
if (!metadata) {
|
|
1893
2180
|
return {
|
|
1894
2181
|
walletType,
|
|
1895
|
-
chainType:
|
|
2182
|
+
chainType: ChainType.EVM,
|
|
1896
2183
|
// 默认
|
|
1897
2184
|
isAvailable: false,
|
|
1898
2185
|
detected: false
|
|
@@ -2000,9 +2287,9 @@ function shortenTronAddress(address, chars = 4) {
|
|
|
2000
2287
|
// src/utils/validation.ts
|
|
2001
2288
|
function validateAddress(address, chainType) {
|
|
2002
2289
|
switch (chainType) {
|
|
2003
|
-
case
|
|
2290
|
+
case ChainType.EVM:
|
|
2004
2291
|
return isValidEVMAddress(address);
|
|
2005
|
-
case
|
|
2292
|
+
case ChainType.TRON:
|
|
2006
2293
|
return isValidTronAddress(address);
|
|
2007
2294
|
default:
|
|
2008
2295
|
return false;
|
|
@@ -2023,9 +2310,9 @@ function isValidSignature(signature) {
|
|
|
2023
2310
|
}
|
|
2024
2311
|
function isValidTransactionHash(txHash, chainType) {
|
|
2025
2312
|
switch (chainType) {
|
|
2026
|
-
case
|
|
2313
|
+
case ChainType.EVM:
|
|
2027
2314
|
return /^0x[0-9a-fA-F]{64}$/.test(txHash);
|
|
2028
|
-
case
|
|
2315
|
+
case ChainType.TRON:
|
|
2029
2316
|
return /^[0-9a-fA-F]{64}$/.test(txHash);
|
|
2030
2317
|
default:
|
|
2031
2318
|
return false;
|