@enclave-hq/wallet-sdk 1.0.0 → 1.0.2
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 +360 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +360 -63
- 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 +369 -34
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +369 -35
- 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 && transaction.gasPrice !== "auto" ? `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
|
*/
|
|
@@ -680,6 +739,16 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
680
739
|
throw new Error("Wallet client not initialized");
|
|
681
740
|
}
|
|
682
741
|
try {
|
|
742
|
+
console.log("\u{1F50D} [MetaMask writeContract] params.gasPrice:", params.gasPrice, "type:", typeof params.gasPrice);
|
|
743
|
+
let processedGasPrice;
|
|
744
|
+
if (!params.gasPrice) {
|
|
745
|
+
processedGasPrice = void 0;
|
|
746
|
+
} else if (params.gasPrice === "auto") {
|
|
747
|
+
processedGasPrice = void 0;
|
|
748
|
+
} else {
|
|
749
|
+
processedGasPrice = BigInt(params.gasPrice);
|
|
750
|
+
}
|
|
751
|
+
console.log("\u{1F50D} [MetaMask writeContract] processedGasPrice:", processedGasPrice);
|
|
683
752
|
const txHash = await this.walletClient.writeContract({
|
|
684
753
|
address: params.address,
|
|
685
754
|
abi: params.abi,
|
|
@@ -687,7 +756,7 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
687
756
|
...params.args ? { args: params.args } : {},
|
|
688
757
|
value: params.value ? BigInt(params.value) : void 0,
|
|
689
758
|
gas: params.gas ? BigInt(params.gas) : void 0,
|
|
690
|
-
gasPrice:
|
|
759
|
+
gasPrice: processedGasPrice
|
|
691
760
|
});
|
|
692
761
|
return txHash;
|
|
693
762
|
} catch (error) {
|
|
@@ -830,9 +899,14 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
830
899
|
constructor() {
|
|
831
900
|
super(...arguments);
|
|
832
901
|
this.type = "tronlink" /* TRONLINK */;
|
|
833
|
-
this.chainType =
|
|
902
|
+
this.chainType = ChainType.TRON;
|
|
834
903
|
this.name = "TronLink";
|
|
835
904
|
this.icon = "https://www.tronlink.org/static/logoIcon.svg";
|
|
905
|
+
/**
|
|
906
|
+
* 轮询检测账户变化(备用方案)
|
|
907
|
+
*/
|
|
908
|
+
this.pollingInterval = null;
|
|
909
|
+
this.lastKnownAddress = null;
|
|
836
910
|
/**
|
|
837
911
|
* 处理账户变化
|
|
838
912
|
*/
|
|
@@ -847,7 +921,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
847
921
|
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
848
922
|
nativeAddress: address,
|
|
849
923
|
chainId: this.currentAccount.chainId,
|
|
850
|
-
chainType:
|
|
924
|
+
chainType: ChainType.TRON,
|
|
851
925
|
isActive: true
|
|
852
926
|
};
|
|
853
927
|
this.setAccount(account);
|
|
@@ -886,7 +960,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
886
960
|
universalAddress: createUniversalAddress(tronChainId, address),
|
|
887
961
|
nativeAddress: address,
|
|
888
962
|
chainId: tronChainId,
|
|
889
|
-
chainType:
|
|
963
|
+
chainType: ChainType.TRON,
|
|
890
964
|
isActive: true
|
|
891
965
|
};
|
|
892
966
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -904,20 +978,177 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
904
978
|
}
|
|
905
979
|
/**
|
|
906
980
|
* 签名消息
|
|
981
|
+
*
|
|
982
|
+
* Note: TronLink supports two signing methods:
|
|
983
|
+
* - trx.sign(): Signs a transaction object
|
|
984
|
+
* - trx.signMessageV2(): Signs a plain text message (what we use here)
|
|
907
985
|
*/
|
|
908
986
|
async signMessage(message) {
|
|
909
987
|
this.ensureConnected();
|
|
910
988
|
try {
|
|
911
989
|
const tronWeb = this.getTronWeb();
|
|
912
|
-
|
|
913
|
-
|
|
990
|
+
if (typeof tronWeb.trx.signMessageV2 === "function") {
|
|
991
|
+
const signature = await tronWeb.trx.signMessageV2(message);
|
|
992
|
+
return signature;
|
|
993
|
+
} else {
|
|
994
|
+
console.warn("[TronLink] signMessageV2 not available, falling back to sign()");
|
|
995
|
+
const signature = await tronWeb.trx.sign(message);
|
|
996
|
+
return signature;
|
|
997
|
+
}
|
|
914
998
|
} catch (error) {
|
|
915
999
|
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
916
1000
|
throw new SignatureRejectedError();
|
|
917
1001
|
}
|
|
1002
|
+
if (error.message?.includes("Invalid transaction")) {
|
|
1003
|
+
throw new Error("Invalid message format. For transaction signing, use signTransaction() instead.");
|
|
1004
|
+
}
|
|
1005
|
+
throw error;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* 签名交易
|
|
1010
|
+
*
|
|
1011
|
+
* Note: This uses trx.sign() which is specifically for signing transaction objects.
|
|
1012
|
+
* For plain text message signing, use signMessage() instead.
|
|
1013
|
+
*/
|
|
1014
|
+
async signTransaction(transaction) {
|
|
1015
|
+
this.ensureConnected();
|
|
1016
|
+
try {
|
|
1017
|
+
const tronWeb = this.getTronWeb();
|
|
1018
|
+
const signature = await tronWeb.trx.sign(transaction);
|
|
1019
|
+
return signature;
|
|
1020
|
+
} catch (error) {
|
|
1021
|
+
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
1022
|
+
throw new SignatureRejectedError("Transaction signature was rejected by user");
|
|
1023
|
+
}
|
|
1024
|
+
if (error.message?.includes("Invalid transaction")) {
|
|
1025
|
+
throw new Error("Invalid transaction format. Please provide a properly formatted Tron transaction object.");
|
|
1026
|
+
}
|
|
918
1027
|
throw error;
|
|
919
1028
|
}
|
|
920
1029
|
}
|
|
1030
|
+
/**
|
|
1031
|
+
* 读取合约
|
|
1032
|
+
*/
|
|
1033
|
+
async readContract(params) {
|
|
1034
|
+
this.ensureConnected();
|
|
1035
|
+
try {
|
|
1036
|
+
const tronWeb = this.getTronWeb();
|
|
1037
|
+
const contract = await tronWeb.contract(params.abi, params.address);
|
|
1038
|
+
const result = await contract[params.functionName](...params.args || []).call();
|
|
1039
|
+
return result;
|
|
1040
|
+
} catch (error) {
|
|
1041
|
+
console.error("Read contract error:", error);
|
|
1042
|
+
throw new Error(`Failed to read contract: ${error.message}`);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* 写入合约
|
|
1047
|
+
*/
|
|
1048
|
+
async writeContract(params) {
|
|
1049
|
+
this.ensureConnected();
|
|
1050
|
+
try {
|
|
1051
|
+
const tronWeb = this.getTronWeb();
|
|
1052
|
+
console.log("[TronLink] writeContract params:", {
|
|
1053
|
+
address: params.address,
|
|
1054
|
+
functionName: params.functionName,
|
|
1055
|
+
args: params.args,
|
|
1056
|
+
value: params.value,
|
|
1057
|
+
gas: params.gas
|
|
1058
|
+
});
|
|
1059
|
+
if (!params.args || params.args.length === 0) {
|
|
1060
|
+
throw new Error("Contract function arguments are required");
|
|
1061
|
+
}
|
|
1062
|
+
const hasUndefined = params.args.some((arg) => arg === void 0 || arg === null);
|
|
1063
|
+
if (hasUndefined) {
|
|
1064
|
+
console.error("[TronLink] Invalid args detected:", params.args);
|
|
1065
|
+
throw new Error(`Invalid contract arguments: some arguments are undefined or null`);
|
|
1066
|
+
}
|
|
1067
|
+
const functionAbi = params.abi.find(
|
|
1068
|
+
(item) => item.name === params.functionName && item.type === "function"
|
|
1069
|
+
);
|
|
1070
|
+
if (!functionAbi) {
|
|
1071
|
+
throw new Error(`Function ${params.functionName} not found in ABI`);
|
|
1072
|
+
}
|
|
1073
|
+
console.log("[TronLink] Function ABI:", functionAbi);
|
|
1074
|
+
console.log("[TronLink] Calling with args:", params.args);
|
|
1075
|
+
const options = {
|
|
1076
|
+
feeLimit: params.gas || 1e8,
|
|
1077
|
+
// 默认 100 TRX 的能量限制
|
|
1078
|
+
callValue: params.value || 0
|
|
1079
|
+
// 发送的 TRX 数量(单位:SUN)
|
|
1080
|
+
};
|
|
1081
|
+
const parameter = functionAbi.inputs.map((input, index) => ({
|
|
1082
|
+
type: input.type,
|
|
1083
|
+
value: params.args[index]
|
|
1084
|
+
}));
|
|
1085
|
+
console.log("[TronLink] Transaction options:", options);
|
|
1086
|
+
console.log("[TronLink] Parameters:", parameter);
|
|
1087
|
+
const transaction = await tronWeb.transactionBuilder.triggerSmartContract(
|
|
1088
|
+
params.address,
|
|
1089
|
+
params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")",
|
|
1090
|
+
options,
|
|
1091
|
+
parameter,
|
|
1092
|
+
this.currentAccount.nativeAddress
|
|
1093
|
+
);
|
|
1094
|
+
console.log("[TronLink] Transaction built:", transaction);
|
|
1095
|
+
if (!transaction || !transaction.transaction) {
|
|
1096
|
+
throw new Error("Failed to build transaction");
|
|
1097
|
+
}
|
|
1098
|
+
const signedTx = await tronWeb.trx.sign(transaction.transaction);
|
|
1099
|
+
const broadcast = await tronWeb.trx.sendRawTransaction(signedTx);
|
|
1100
|
+
console.log("[TronLink] Broadcast result:", broadcast);
|
|
1101
|
+
if (!broadcast.result) {
|
|
1102
|
+
throw new Error(broadcast.message || "Transaction broadcast failed");
|
|
1103
|
+
}
|
|
1104
|
+
const txHash = broadcast.txid || broadcast.transaction?.txID;
|
|
1105
|
+
console.log("[TronLink] Transaction hash:", txHash);
|
|
1106
|
+
return txHash || "";
|
|
1107
|
+
} catch (error) {
|
|
1108
|
+
console.error("Write contract error:", error);
|
|
1109
|
+
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
1110
|
+
throw new SignatureRejectedError("Transaction was rejected by user");
|
|
1111
|
+
}
|
|
1112
|
+
throw new Error(`Failed to write contract: ${error.message}`);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* 等待交易确认
|
|
1117
|
+
*/
|
|
1118
|
+
async waitForTransaction(txHash, _confirmations = 1) {
|
|
1119
|
+
try {
|
|
1120
|
+
const tronWeb = this.getTronWeb();
|
|
1121
|
+
let attempts = 0;
|
|
1122
|
+
const maxAttempts = 60;
|
|
1123
|
+
while (attempts < maxAttempts) {
|
|
1124
|
+
try {
|
|
1125
|
+
const txInfo = await tronWeb.trx.getTransactionInfo(txHash);
|
|
1126
|
+
if (txInfo && txInfo.id) {
|
|
1127
|
+
const receipt = {
|
|
1128
|
+
transactionHash: txHash,
|
|
1129
|
+
blockNumber: txInfo.blockNumber || 0,
|
|
1130
|
+
blockHash: txInfo.blockHash || "",
|
|
1131
|
+
from: this.currentAccount.nativeAddress,
|
|
1132
|
+
to: txInfo.contract_address || "",
|
|
1133
|
+
status: txInfo.receipt?.result === "SUCCESS" ? "success" : "failed",
|
|
1134
|
+
gasUsed: (txInfo.receipt?.energy_usage_total || 0).toString(),
|
|
1135
|
+
logs: txInfo.log || []
|
|
1136
|
+
};
|
|
1137
|
+
if (receipt.status === "failed") {
|
|
1138
|
+
throw new TransactionFailedError(txHash, "Transaction failed on Tron network");
|
|
1139
|
+
}
|
|
1140
|
+
return receipt;
|
|
1141
|
+
}
|
|
1142
|
+
} catch (error) {
|
|
1143
|
+
}
|
|
1144
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1145
|
+
attempts++;
|
|
1146
|
+
}
|
|
1147
|
+
throw new Error("Transaction confirmation timeout");
|
|
1148
|
+
} catch (error) {
|
|
1149
|
+
throw new Error(`Failed to wait for transaction: ${error.message}`);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
921
1152
|
/**
|
|
922
1153
|
* 获取 Provider
|
|
923
1154
|
*/
|
|
@@ -956,9 +1187,16 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
956
1187
|
setupEventListeners() {
|
|
957
1188
|
if (typeof window === "undefined") return;
|
|
958
1189
|
const w = window;
|
|
959
|
-
|
|
960
|
-
w.tronLink.on
|
|
961
|
-
|
|
1190
|
+
try {
|
|
1191
|
+
if (w.tronLink && typeof w.tronLink.on === "function") {
|
|
1192
|
+
w.tronLink.on("accountsChanged", this.handleAccountsChanged);
|
|
1193
|
+
w.tronLink.on("disconnect", this.handleDisconnect);
|
|
1194
|
+
} else if (w.tronWeb && w.tronWeb.eventServer) {
|
|
1195
|
+
this.startPolling();
|
|
1196
|
+
}
|
|
1197
|
+
} catch (error) {
|
|
1198
|
+
console.warn("TronLink event listener setup failed:", error);
|
|
1199
|
+
this.startPolling();
|
|
962
1200
|
}
|
|
963
1201
|
}
|
|
964
1202
|
/**
|
|
@@ -967,9 +1205,38 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
967
1205
|
removeEventListeners() {
|
|
968
1206
|
if (typeof window === "undefined") return;
|
|
969
1207
|
const w = window;
|
|
970
|
-
|
|
971
|
-
w.tronLink.off
|
|
972
|
-
|
|
1208
|
+
try {
|
|
1209
|
+
if (w.tronLink && typeof w.tronLink.off === "function") {
|
|
1210
|
+
w.tronLink.off("accountsChanged", this.handleAccountsChanged);
|
|
1211
|
+
w.tronLink.off("disconnect", this.handleDisconnect);
|
|
1212
|
+
}
|
|
1213
|
+
} catch (error) {
|
|
1214
|
+
console.warn("TronLink event listener removal failed:", error);
|
|
1215
|
+
}
|
|
1216
|
+
this.stopPolling();
|
|
1217
|
+
}
|
|
1218
|
+
startPolling() {
|
|
1219
|
+
if (this.pollingInterval) return;
|
|
1220
|
+
this.lastKnownAddress = this.currentAccount?.nativeAddress || null;
|
|
1221
|
+
this.pollingInterval = setInterval(async () => {
|
|
1222
|
+
try {
|
|
1223
|
+
const tronWeb = this.getTronWeb();
|
|
1224
|
+
const currentAddress = tronWeb.defaultAddress?.base58;
|
|
1225
|
+
if (currentAddress && currentAddress !== this.lastKnownAddress) {
|
|
1226
|
+
this.lastKnownAddress = currentAddress;
|
|
1227
|
+
this.handleAccountsChanged({ address: { base58: currentAddress } });
|
|
1228
|
+
} else if (!currentAddress && this.lastKnownAddress) {
|
|
1229
|
+
this.lastKnownAddress = null;
|
|
1230
|
+
this.handleAccountsChanged(null);
|
|
1231
|
+
}
|
|
1232
|
+
} catch (error) {
|
|
1233
|
+
}
|
|
1234
|
+
}, 2e3);
|
|
1235
|
+
}
|
|
1236
|
+
stopPolling() {
|
|
1237
|
+
if (this.pollingInterval) {
|
|
1238
|
+
clearInterval(this.pollingInterval);
|
|
1239
|
+
this.pollingInterval = null;
|
|
973
1240
|
}
|
|
974
1241
|
}
|
|
975
1242
|
};
|
|
@@ -980,7 +1247,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
980
1247
|
constructor() {
|
|
981
1248
|
super(...arguments);
|
|
982
1249
|
this.type = "private-key" /* PRIVATE_KEY */;
|
|
983
|
-
this.chainType =
|
|
1250
|
+
this.chainType = ChainType.EVM;
|
|
984
1251
|
this.name = "Private Key (EVM)";
|
|
985
1252
|
this.privateKey = null;
|
|
986
1253
|
this.walletClient = null;
|
|
@@ -1010,7 +1277,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
1010
1277
|
universalAddress: createUniversalAddress(chainId, address),
|
|
1011
1278
|
nativeAddress: address,
|
|
1012
1279
|
chainId,
|
|
1013
|
-
chainType:
|
|
1280
|
+
chainType: ChainType.EVM,
|
|
1014
1281
|
isActive: true
|
|
1015
1282
|
};
|
|
1016
1283
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -1360,9 +1627,10 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1360
1627
|
if (!this.primaryWallet) {
|
|
1361
1628
|
return;
|
|
1362
1629
|
}
|
|
1630
|
+
const chainType = this.primaryWallet.chainType;
|
|
1363
1631
|
await this.primaryWallet.disconnect();
|
|
1364
1632
|
this.removeAdapterListeners(this.primaryWallet);
|
|
1365
|
-
this.connectedWallets.delete(
|
|
1633
|
+
this.connectedWallets.delete(chainType);
|
|
1366
1634
|
this.primaryWallet = null;
|
|
1367
1635
|
if (this.config.enableStorage) {
|
|
1368
1636
|
this.saveToStorage();
|
|
@@ -1467,6 +1735,34 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1467
1735
|
}
|
|
1468
1736
|
return adapter.signTypedData(typedData);
|
|
1469
1737
|
}
|
|
1738
|
+
/**
|
|
1739
|
+
* 签名交易(使用主钱包)
|
|
1740
|
+
*/
|
|
1741
|
+
async signTransaction(transaction) {
|
|
1742
|
+
if (!this.primaryWallet) {
|
|
1743
|
+
throw new WalletNotConnectedError();
|
|
1744
|
+
}
|
|
1745
|
+
if (!this.primaryWallet.signTransaction) {
|
|
1746
|
+
throw new Error(`signTransaction not supported by ${this.primaryWallet.type}`);
|
|
1747
|
+
}
|
|
1748
|
+
return this.primaryWallet.signTransaction(transaction);
|
|
1749
|
+
}
|
|
1750
|
+
/**
|
|
1751
|
+
* 使用指定链类型的钱包签名交易
|
|
1752
|
+
*/
|
|
1753
|
+
async signTransactionWithChainType(transaction, chainType) {
|
|
1754
|
+
if (!chainType) {
|
|
1755
|
+
return this.signTransaction(transaction);
|
|
1756
|
+
}
|
|
1757
|
+
const adapter = this.connectedWallets.get(chainType);
|
|
1758
|
+
if (!adapter) {
|
|
1759
|
+
throw new WalletNotConnectedError(`Wallet for chain type ${chainType}`);
|
|
1760
|
+
}
|
|
1761
|
+
if (!adapter.signTransaction) {
|
|
1762
|
+
throw new Error(`signTransaction not supported by ${adapter.type}`);
|
|
1763
|
+
}
|
|
1764
|
+
return adapter.signTransaction(transaction);
|
|
1765
|
+
}
|
|
1470
1766
|
// ===== 链切换 =====
|
|
1471
1767
|
/**
|
|
1472
1768
|
* 请求切换链(仅 EVM)
|
|
@@ -1627,6 +1923,7 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1627
1923
|
* 移除适配器事件监听
|
|
1628
1924
|
*/
|
|
1629
1925
|
removeAdapterListeners(adapter) {
|
|
1926
|
+
if (!adapter) return;
|
|
1630
1927
|
adapter.removeAllListeners();
|
|
1631
1928
|
}
|
|
1632
1929
|
// ===== 存储 =====
|
|
@@ -1700,7 +1997,7 @@ var AuthMessageGenerator = class {
|
|
|
1700
1997
|
*/
|
|
1701
1998
|
generateAuthMessage(chainType, nonce, chainId, timestamp = Date.now(), statement) {
|
|
1702
1999
|
switch (chainType) {
|
|
1703
|
-
case
|
|
2000
|
+
case ChainType.EVM:
|
|
1704
2001
|
return this.generateEIP191Message({
|
|
1705
2002
|
domain: this.domain,
|
|
1706
2003
|
nonce,
|
|
@@ -1708,7 +2005,7 @@ var AuthMessageGenerator = class {
|
|
|
1708
2005
|
timestamp,
|
|
1709
2006
|
statement
|
|
1710
2007
|
});
|
|
1711
|
-
case
|
|
2008
|
+
case ChainType.TRON:
|
|
1712
2009
|
return this.generateTIP191Message({
|
|
1713
2010
|
domain: this.domain,
|
|
1714
2011
|
nonce,
|
|
@@ -1771,9 +2068,9 @@ var SignatureVerifier = class {
|
|
|
1771
2068
|
*/
|
|
1772
2069
|
async verifySignature(message, signature, expectedAddress, chainType) {
|
|
1773
2070
|
switch (chainType) {
|
|
1774
|
-
case
|
|
2071
|
+
case ChainType.EVM:
|
|
1775
2072
|
return this.verifyEIP191Signature(message, signature, expectedAddress);
|
|
1776
|
-
case
|
|
2073
|
+
case ChainType.TRON:
|
|
1777
2074
|
return this.verifyTIP191Signature(message, signature, expectedAddress);
|
|
1778
2075
|
default:
|
|
1779
2076
|
throw new Error(`Unsupported chain type: ${chainType}`);
|
|
@@ -1811,7 +2108,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1811
2108
|
["metamask" /* METAMASK */]: {
|
|
1812
2109
|
type: "metamask" /* METAMASK */,
|
|
1813
2110
|
name: "MetaMask",
|
|
1814
|
-
chainType:
|
|
2111
|
+
chainType: ChainType.EVM,
|
|
1815
2112
|
icon: "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg",
|
|
1816
2113
|
downloadUrl: "https://metamask.io/download/",
|
|
1817
2114
|
description: "The most popular Ethereum wallet"
|
|
@@ -1819,7 +2116,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1819
2116
|
["walletconnect" /* WALLETCONNECT */]: {
|
|
1820
2117
|
type: "walletconnect" /* WALLETCONNECT */,
|
|
1821
2118
|
name: "WalletConnect",
|
|
1822
|
-
chainType:
|
|
2119
|
+
chainType: ChainType.EVM,
|
|
1823
2120
|
icon: "https://avatars.githubusercontent.com/u/37784886",
|
|
1824
2121
|
downloadUrl: "https://walletconnect.com/",
|
|
1825
2122
|
description: "Connect to 170+ wallets"
|
|
@@ -1827,7 +2124,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1827
2124
|
["coinbase-wallet" /* COINBASE_WALLET */]: {
|
|
1828
2125
|
type: "coinbase-wallet" /* COINBASE_WALLET */,
|
|
1829
2126
|
name: "Coinbase Wallet",
|
|
1830
|
-
chainType:
|
|
2127
|
+
chainType: ChainType.EVM,
|
|
1831
2128
|
icon: "https://www.coinbase.com/img/favicon/favicon-96x96.png",
|
|
1832
2129
|
downloadUrl: "https://www.coinbase.com/wallet",
|
|
1833
2130
|
description: "Coinbase self-custody wallet"
|
|
@@ -1835,7 +2132,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1835
2132
|
["tronlink" /* TRONLINK */]: {
|
|
1836
2133
|
type: "tronlink" /* TRONLINK */,
|
|
1837
2134
|
name: "TronLink",
|
|
1838
|
-
chainType:
|
|
2135
|
+
chainType: ChainType.TRON,
|
|
1839
2136
|
icon: "https://www.tronlink.org/static/logoIcon.svg",
|
|
1840
2137
|
downloadUrl: "https://www.tronlink.org/",
|
|
1841
2138
|
description: "The official Tron wallet"
|
|
@@ -1843,14 +2140,14 @@ var SUPPORTED_WALLETS = {
|
|
|
1843
2140
|
["walletconnect-tron" /* WALLETCONNECT_TRON */]: {
|
|
1844
2141
|
type: "walletconnect-tron" /* WALLETCONNECT_TRON */,
|
|
1845
2142
|
name: "WalletConnect (Tron)",
|
|
1846
|
-
chainType:
|
|
2143
|
+
chainType: ChainType.TRON,
|
|
1847
2144
|
downloadUrl: "https://walletconnect.com/",
|
|
1848
2145
|
description: "WalletConnect for Tron"
|
|
1849
2146
|
},
|
|
1850
2147
|
["private-key" /* PRIVATE_KEY */]: {
|
|
1851
2148
|
type: "private-key" /* PRIVATE_KEY */,
|
|
1852
2149
|
name: "Private Key",
|
|
1853
|
-
chainType:
|
|
2150
|
+
chainType: ChainType.EVM,
|
|
1854
2151
|
// 可以用于任何链
|
|
1855
2152
|
description: "Import wallet using private key (for development)"
|
|
1856
2153
|
}
|
|
@@ -1860,12 +2157,12 @@ function getWalletMetadata(type) {
|
|
|
1860
2157
|
}
|
|
1861
2158
|
function getEVMWallets() {
|
|
1862
2159
|
return Object.values(SUPPORTED_WALLETS).filter(
|
|
1863
|
-
(wallet) => wallet.chainType ===
|
|
2160
|
+
(wallet) => wallet.chainType === ChainType.EVM
|
|
1864
2161
|
);
|
|
1865
2162
|
}
|
|
1866
2163
|
function getTronWallets() {
|
|
1867
2164
|
return Object.values(SUPPORTED_WALLETS).filter(
|
|
1868
|
-
(wallet) => wallet.chainType ===
|
|
2165
|
+
(wallet) => wallet.chainType === ChainType.TRON
|
|
1869
2166
|
);
|
|
1870
2167
|
}
|
|
1871
2168
|
|
|
@@ -1892,7 +2189,7 @@ var WalletDetector = class {
|
|
|
1892
2189
|
if (!metadata) {
|
|
1893
2190
|
return {
|
|
1894
2191
|
walletType,
|
|
1895
|
-
chainType:
|
|
2192
|
+
chainType: ChainType.EVM,
|
|
1896
2193
|
// 默认
|
|
1897
2194
|
isAvailable: false,
|
|
1898
2195
|
detected: false
|
|
@@ -1931,11 +2228,11 @@ var WalletDetector = class {
|
|
|
1931
2228
|
}
|
|
1932
2229
|
}
|
|
1933
2230
|
/**
|
|
1934
|
-
* 检测 MetaMask
|
|
2231
|
+
* 检测 MetaMask(现在支持所有 window.ethereum 钱包)
|
|
1935
2232
|
*/
|
|
1936
2233
|
isMetaMaskAvailable() {
|
|
1937
2234
|
const w = window;
|
|
1938
|
-
return !!
|
|
2235
|
+
return !!w.ethereum;
|
|
1939
2236
|
}
|
|
1940
2237
|
/**
|
|
1941
2238
|
* 检测 TronLink
|
|
@@ -2000,9 +2297,9 @@ function shortenTronAddress(address, chars = 4) {
|
|
|
2000
2297
|
// src/utils/validation.ts
|
|
2001
2298
|
function validateAddress(address, chainType) {
|
|
2002
2299
|
switch (chainType) {
|
|
2003
|
-
case
|
|
2300
|
+
case ChainType.EVM:
|
|
2004
2301
|
return isValidEVMAddress(address);
|
|
2005
|
-
case
|
|
2302
|
+
case ChainType.TRON:
|
|
2006
2303
|
return isValidTronAddress(address);
|
|
2007
2304
|
default:
|
|
2008
2305
|
return false;
|
|
@@ -2023,9 +2320,9 @@ function isValidSignature(signature) {
|
|
|
2023
2320
|
}
|
|
2024
2321
|
function isValidTransactionHash(txHash, chainType) {
|
|
2025
2322
|
switch (chainType) {
|
|
2026
|
-
case
|
|
2323
|
+
case ChainType.EVM:
|
|
2027
2324
|
return /^0x[0-9a-fA-F]{64}$/.test(txHash);
|
|
2028
|
-
case
|
|
2325
|
+
case ChainType.TRON:
|
|
2029
2326
|
return /^[0-9a-fA-F]{64}$/.test(txHash);
|
|
2030
2327
|
default:
|
|
2031
2328
|
return false;
|