@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.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 && transaction.gasPrice !== "auto" ? `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
|
*/
|
|
@@ -672,6 +731,16 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
672
731
|
throw new Error("Wallet client not initialized");
|
|
673
732
|
}
|
|
674
733
|
try {
|
|
734
|
+
console.log("\u{1F50D} [MetaMask writeContract] params.gasPrice:", params.gasPrice, "type:", typeof params.gasPrice);
|
|
735
|
+
let processedGasPrice;
|
|
736
|
+
if (!params.gasPrice) {
|
|
737
|
+
processedGasPrice = void 0;
|
|
738
|
+
} else if (params.gasPrice === "auto") {
|
|
739
|
+
processedGasPrice = void 0;
|
|
740
|
+
} else {
|
|
741
|
+
processedGasPrice = BigInt(params.gasPrice);
|
|
742
|
+
}
|
|
743
|
+
console.log("\u{1F50D} [MetaMask writeContract] processedGasPrice:", processedGasPrice);
|
|
675
744
|
const txHash = await this.walletClient.writeContract({
|
|
676
745
|
address: params.address,
|
|
677
746
|
abi: params.abi,
|
|
@@ -679,7 +748,7 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
679
748
|
...params.args ? { args: params.args } : {},
|
|
680
749
|
value: params.value ? BigInt(params.value) : void 0,
|
|
681
750
|
gas: params.gas ? BigInt(params.gas) : void 0,
|
|
682
|
-
gasPrice:
|
|
751
|
+
gasPrice: processedGasPrice
|
|
683
752
|
});
|
|
684
753
|
return txHash;
|
|
685
754
|
} catch (error) {
|
|
@@ -822,9 +891,14 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
822
891
|
constructor() {
|
|
823
892
|
super(...arguments);
|
|
824
893
|
this.type = "tronlink" /* TRONLINK */;
|
|
825
|
-
this.chainType =
|
|
894
|
+
this.chainType = ChainType.TRON;
|
|
826
895
|
this.name = "TronLink";
|
|
827
896
|
this.icon = "https://www.tronlink.org/static/logoIcon.svg";
|
|
897
|
+
/**
|
|
898
|
+
* 轮询检测账户变化(备用方案)
|
|
899
|
+
*/
|
|
900
|
+
this.pollingInterval = null;
|
|
901
|
+
this.lastKnownAddress = null;
|
|
828
902
|
/**
|
|
829
903
|
* 处理账户变化
|
|
830
904
|
*/
|
|
@@ -839,7 +913,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
839
913
|
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
840
914
|
nativeAddress: address,
|
|
841
915
|
chainId: this.currentAccount.chainId,
|
|
842
|
-
chainType:
|
|
916
|
+
chainType: ChainType.TRON,
|
|
843
917
|
isActive: true
|
|
844
918
|
};
|
|
845
919
|
this.setAccount(account);
|
|
@@ -878,7 +952,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
878
952
|
universalAddress: createUniversalAddress(tronChainId, address),
|
|
879
953
|
nativeAddress: address,
|
|
880
954
|
chainId: tronChainId,
|
|
881
|
-
chainType:
|
|
955
|
+
chainType: ChainType.TRON,
|
|
882
956
|
isActive: true
|
|
883
957
|
};
|
|
884
958
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -896,20 +970,177 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
896
970
|
}
|
|
897
971
|
/**
|
|
898
972
|
* 签名消息
|
|
973
|
+
*
|
|
974
|
+
* Note: TronLink supports two signing methods:
|
|
975
|
+
* - trx.sign(): Signs a transaction object
|
|
976
|
+
* - trx.signMessageV2(): Signs a plain text message (what we use here)
|
|
899
977
|
*/
|
|
900
978
|
async signMessage(message) {
|
|
901
979
|
this.ensureConnected();
|
|
902
980
|
try {
|
|
903
981
|
const tronWeb = this.getTronWeb();
|
|
904
|
-
|
|
905
|
-
|
|
982
|
+
if (typeof tronWeb.trx.signMessageV2 === "function") {
|
|
983
|
+
const signature = await tronWeb.trx.signMessageV2(message);
|
|
984
|
+
return signature;
|
|
985
|
+
} else {
|
|
986
|
+
console.warn("[TronLink] signMessageV2 not available, falling back to sign()");
|
|
987
|
+
const signature = await tronWeb.trx.sign(message);
|
|
988
|
+
return signature;
|
|
989
|
+
}
|
|
906
990
|
} catch (error) {
|
|
907
991
|
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
908
992
|
throw new SignatureRejectedError();
|
|
909
993
|
}
|
|
994
|
+
if (error.message?.includes("Invalid transaction")) {
|
|
995
|
+
throw new Error("Invalid message format. For transaction signing, use signTransaction() instead.");
|
|
996
|
+
}
|
|
997
|
+
throw error;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* 签名交易
|
|
1002
|
+
*
|
|
1003
|
+
* Note: This uses trx.sign() which is specifically for signing transaction objects.
|
|
1004
|
+
* For plain text message signing, use signMessage() instead.
|
|
1005
|
+
*/
|
|
1006
|
+
async signTransaction(transaction) {
|
|
1007
|
+
this.ensureConnected();
|
|
1008
|
+
try {
|
|
1009
|
+
const tronWeb = this.getTronWeb();
|
|
1010
|
+
const signature = await tronWeb.trx.sign(transaction);
|
|
1011
|
+
return signature;
|
|
1012
|
+
} catch (error) {
|
|
1013
|
+
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
1014
|
+
throw new SignatureRejectedError("Transaction signature was rejected by user");
|
|
1015
|
+
}
|
|
1016
|
+
if (error.message?.includes("Invalid transaction")) {
|
|
1017
|
+
throw new Error("Invalid transaction format. Please provide a properly formatted Tron transaction object.");
|
|
1018
|
+
}
|
|
910
1019
|
throw error;
|
|
911
1020
|
}
|
|
912
1021
|
}
|
|
1022
|
+
/**
|
|
1023
|
+
* 读取合约
|
|
1024
|
+
*/
|
|
1025
|
+
async readContract(params) {
|
|
1026
|
+
this.ensureConnected();
|
|
1027
|
+
try {
|
|
1028
|
+
const tronWeb = this.getTronWeb();
|
|
1029
|
+
const contract = await tronWeb.contract(params.abi, params.address);
|
|
1030
|
+
const result = await contract[params.functionName](...params.args || []).call();
|
|
1031
|
+
return result;
|
|
1032
|
+
} catch (error) {
|
|
1033
|
+
console.error("Read contract error:", error);
|
|
1034
|
+
throw new Error(`Failed to read contract: ${error.message}`);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* 写入合约
|
|
1039
|
+
*/
|
|
1040
|
+
async writeContract(params) {
|
|
1041
|
+
this.ensureConnected();
|
|
1042
|
+
try {
|
|
1043
|
+
const tronWeb = this.getTronWeb();
|
|
1044
|
+
console.log("[TronLink] writeContract params:", {
|
|
1045
|
+
address: params.address,
|
|
1046
|
+
functionName: params.functionName,
|
|
1047
|
+
args: params.args,
|
|
1048
|
+
value: params.value,
|
|
1049
|
+
gas: params.gas
|
|
1050
|
+
});
|
|
1051
|
+
if (!params.args || params.args.length === 0) {
|
|
1052
|
+
throw new Error("Contract function arguments are required");
|
|
1053
|
+
}
|
|
1054
|
+
const hasUndefined = params.args.some((arg) => arg === void 0 || arg === null);
|
|
1055
|
+
if (hasUndefined) {
|
|
1056
|
+
console.error("[TronLink] Invalid args detected:", params.args);
|
|
1057
|
+
throw new Error(`Invalid contract arguments: some arguments are undefined or null`);
|
|
1058
|
+
}
|
|
1059
|
+
const functionAbi = params.abi.find(
|
|
1060
|
+
(item) => item.name === params.functionName && item.type === "function"
|
|
1061
|
+
);
|
|
1062
|
+
if (!functionAbi) {
|
|
1063
|
+
throw new Error(`Function ${params.functionName} not found in ABI`);
|
|
1064
|
+
}
|
|
1065
|
+
console.log("[TronLink] Function ABI:", functionAbi);
|
|
1066
|
+
console.log("[TronLink] Calling with args:", params.args);
|
|
1067
|
+
const options = {
|
|
1068
|
+
feeLimit: params.gas || 1e8,
|
|
1069
|
+
// 默认 100 TRX 的能量限制
|
|
1070
|
+
callValue: params.value || 0
|
|
1071
|
+
// 发送的 TRX 数量(单位:SUN)
|
|
1072
|
+
};
|
|
1073
|
+
const parameter = functionAbi.inputs.map((input, index) => ({
|
|
1074
|
+
type: input.type,
|
|
1075
|
+
value: params.args[index]
|
|
1076
|
+
}));
|
|
1077
|
+
console.log("[TronLink] Transaction options:", options);
|
|
1078
|
+
console.log("[TronLink] Parameters:", parameter);
|
|
1079
|
+
const transaction = await tronWeb.transactionBuilder.triggerSmartContract(
|
|
1080
|
+
params.address,
|
|
1081
|
+
params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")",
|
|
1082
|
+
options,
|
|
1083
|
+
parameter,
|
|
1084
|
+
this.currentAccount.nativeAddress
|
|
1085
|
+
);
|
|
1086
|
+
console.log("[TronLink] Transaction built:", transaction);
|
|
1087
|
+
if (!transaction || !transaction.transaction) {
|
|
1088
|
+
throw new Error("Failed to build transaction");
|
|
1089
|
+
}
|
|
1090
|
+
const signedTx = await tronWeb.trx.sign(transaction.transaction);
|
|
1091
|
+
const broadcast = await tronWeb.trx.sendRawTransaction(signedTx);
|
|
1092
|
+
console.log("[TronLink] Broadcast result:", broadcast);
|
|
1093
|
+
if (!broadcast.result) {
|
|
1094
|
+
throw new Error(broadcast.message || "Transaction broadcast failed");
|
|
1095
|
+
}
|
|
1096
|
+
const txHash = broadcast.txid || broadcast.transaction?.txID;
|
|
1097
|
+
console.log("[TronLink] Transaction hash:", txHash);
|
|
1098
|
+
return txHash || "";
|
|
1099
|
+
} catch (error) {
|
|
1100
|
+
console.error("Write contract error:", error);
|
|
1101
|
+
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
1102
|
+
throw new SignatureRejectedError("Transaction was rejected by user");
|
|
1103
|
+
}
|
|
1104
|
+
throw new Error(`Failed to write contract: ${error.message}`);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* 等待交易确认
|
|
1109
|
+
*/
|
|
1110
|
+
async waitForTransaction(txHash, _confirmations = 1) {
|
|
1111
|
+
try {
|
|
1112
|
+
const tronWeb = this.getTronWeb();
|
|
1113
|
+
let attempts = 0;
|
|
1114
|
+
const maxAttempts = 60;
|
|
1115
|
+
while (attempts < maxAttempts) {
|
|
1116
|
+
try {
|
|
1117
|
+
const txInfo = await tronWeb.trx.getTransactionInfo(txHash);
|
|
1118
|
+
if (txInfo && txInfo.id) {
|
|
1119
|
+
const receipt = {
|
|
1120
|
+
transactionHash: txHash,
|
|
1121
|
+
blockNumber: txInfo.blockNumber || 0,
|
|
1122
|
+
blockHash: txInfo.blockHash || "",
|
|
1123
|
+
from: this.currentAccount.nativeAddress,
|
|
1124
|
+
to: txInfo.contract_address || "",
|
|
1125
|
+
status: txInfo.receipt?.result === "SUCCESS" ? "success" : "failed",
|
|
1126
|
+
gasUsed: (txInfo.receipt?.energy_usage_total || 0).toString(),
|
|
1127
|
+
logs: txInfo.log || []
|
|
1128
|
+
};
|
|
1129
|
+
if (receipt.status === "failed") {
|
|
1130
|
+
throw new TransactionFailedError(txHash, "Transaction failed on Tron network");
|
|
1131
|
+
}
|
|
1132
|
+
return receipt;
|
|
1133
|
+
}
|
|
1134
|
+
} catch (error) {
|
|
1135
|
+
}
|
|
1136
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1137
|
+
attempts++;
|
|
1138
|
+
}
|
|
1139
|
+
throw new Error("Transaction confirmation timeout");
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
throw new Error(`Failed to wait for transaction: ${error.message}`);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
913
1144
|
/**
|
|
914
1145
|
* 获取 Provider
|
|
915
1146
|
*/
|
|
@@ -948,9 +1179,16 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
948
1179
|
setupEventListeners() {
|
|
949
1180
|
if (typeof window === "undefined") return;
|
|
950
1181
|
const w = window;
|
|
951
|
-
|
|
952
|
-
w.tronLink.on
|
|
953
|
-
|
|
1182
|
+
try {
|
|
1183
|
+
if (w.tronLink && typeof w.tronLink.on === "function") {
|
|
1184
|
+
w.tronLink.on("accountsChanged", this.handleAccountsChanged);
|
|
1185
|
+
w.tronLink.on("disconnect", this.handleDisconnect);
|
|
1186
|
+
} else if (w.tronWeb && w.tronWeb.eventServer) {
|
|
1187
|
+
this.startPolling();
|
|
1188
|
+
}
|
|
1189
|
+
} catch (error) {
|
|
1190
|
+
console.warn("TronLink event listener setup failed:", error);
|
|
1191
|
+
this.startPolling();
|
|
954
1192
|
}
|
|
955
1193
|
}
|
|
956
1194
|
/**
|
|
@@ -959,9 +1197,38 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
959
1197
|
removeEventListeners() {
|
|
960
1198
|
if (typeof window === "undefined") return;
|
|
961
1199
|
const w = window;
|
|
962
|
-
|
|
963
|
-
w.tronLink.off
|
|
964
|
-
|
|
1200
|
+
try {
|
|
1201
|
+
if (w.tronLink && typeof w.tronLink.off === "function") {
|
|
1202
|
+
w.tronLink.off("accountsChanged", this.handleAccountsChanged);
|
|
1203
|
+
w.tronLink.off("disconnect", this.handleDisconnect);
|
|
1204
|
+
}
|
|
1205
|
+
} catch (error) {
|
|
1206
|
+
console.warn("TronLink event listener removal failed:", error);
|
|
1207
|
+
}
|
|
1208
|
+
this.stopPolling();
|
|
1209
|
+
}
|
|
1210
|
+
startPolling() {
|
|
1211
|
+
if (this.pollingInterval) return;
|
|
1212
|
+
this.lastKnownAddress = this.currentAccount?.nativeAddress || null;
|
|
1213
|
+
this.pollingInterval = setInterval(async () => {
|
|
1214
|
+
try {
|
|
1215
|
+
const tronWeb = this.getTronWeb();
|
|
1216
|
+
const currentAddress = tronWeb.defaultAddress?.base58;
|
|
1217
|
+
if (currentAddress && currentAddress !== this.lastKnownAddress) {
|
|
1218
|
+
this.lastKnownAddress = currentAddress;
|
|
1219
|
+
this.handleAccountsChanged({ address: { base58: currentAddress } });
|
|
1220
|
+
} else if (!currentAddress && this.lastKnownAddress) {
|
|
1221
|
+
this.lastKnownAddress = null;
|
|
1222
|
+
this.handleAccountsChanged(null);
|
|
1223
|
+
}
|
|
1224
|
+
} catch (error) {
|
|
1225
|
+
}
|
|
1226
|
+
}, 2e3);
|
|
1227
|
+
}
|
|
1228
|
+
stopPolling() {
|
|
1229
|
+
if (this.pollingInterval) {
|
|
1230
|
+
clearInterval(this.pollingInterval);
|
|
1231
|
+
this.pollingInterval = null;
|
|
965
1232
|
}
|
|
966
1233
|
}
|
|
967
1234
|
};
|
|
@@ -972,7 +1239,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
972
1239
|
constructor() {
|
|
973
1240
|
super(...arguments);
|
|
974
1241
|
this.type = "private-key" /* PRIVATE_KEY */;
|
|
975
|
-
this.chainType =
|
|
1242
|
+
this.chainType = ChainType.EVM;
|
|
976
1243
|
this.name = "Private Key (EVM)";
|
|
977
1244
|
this.privateKey = null;
|
|
978
1245
|
this.walletClient = null;
|
|
@@ -1002,7 +1269,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
1002
1269
|
universalAddress: createUniversalAddress(chainId, address),
|
|
1003
1270
|
nativeAddress: address,
|
|
1004
1271
|
chainId,
|
|
1005
|
-
chainType:
|
|
1272
|
+
chainType: ChainType.EVM,
|
|
1006
1273
|
isActive: true
|
|
1007
1274
|
};
|
|
1008
1275
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -1352,9 +1619,10 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1352
1619
|
if (!this.primaryWallet) {
|
|
1353
1620
|
return;
|
|
1354
1621
|
}
|
|
1622
|
+
const chainType = this.primaryWallet.chainType;
|
|
1355
1623
|
await this.primaryWallet.disconnect();
|
|
1356
1624
|
this.removeAdapterListeners(this.primaryWallet);
|
|
1357
|
-
this.connectedWallets.delete(
|
|
1625
|
+
this.connectedWallets.delete(chainType);
|
|
1358
1626
|
this.primaryWallet = null;
|
|
1359
1627
|
if (this.config.enableStorage) {
|
|
1360
1628
|
this.saveToStorage();
|
|
@@ -1459,6 +1727,34 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1459
1727
|
}
|
|
1460
1728
|
return adapter.signTypedData(typedData);
|
|
1461
1729
|
}
|
|
1730
|
+
/**
|
|
1731
|
+
* 签名交易(使用主钱包)
|
|
1732
|
+
*/
|
|
1733
|
+
async signTransaction(transaction) {
|
|
1734
|
+
if (!this.primaryWallet) {
|
|
1735
|
+
throw new WalletNotConnectedError();
|
|
1736
|
+
}
|
|
1737
|
+
if (!this.primaryWallet.signTransaction) {
|
|
1738
|
+
throw new Error(`signTransaction not supported by ${this.primaryWallet.type}`);
|
|
1739
|
+
}
|
|
1740
|
+
return this.primaryWallet.signTransaction(transaction);
|
|
1741
|
+
}
|
|
1742
|
+
/**
|
|
1743
|
+
* 使用指定链类型的钱包签名交易
|
|
1744
|
+
*/
|
|
1745
|
+
async signTransactionWithChainType(transaction, chainType) {
|
|
1746
|
+
if (!chainType) {
|
|
1747
|
+
return this.signTransaction(transaction);
|
|
1748
|
+
}
|
|
1749
|
+
const adapter = this.connectedWallets.get(chainType);
|
|
1750
|
+
if (!adapter) {
|
|
1751
|
+
throw new WalletNotConnectedError(`Wallet for chain type ${chainType}`);
|
|
1752
|
+
}
|
|
1753
|
+
if (!adapter.signTransaction) {
|
|
1754
|
+
throw new Error(`signTransaction not supported by ${adapter.type}`);
|
|
1755
|
+
}
|
|
1756
|
+
return adapter.signTransaction(transaction);
|
|
1757
|
+
}
|
|
1462
1758
|
// ===== 链切换 =====
|
|
1463
1759
|
/**
|
|
1464
1760
|
* 请求切换链(仅 EVM)
|
|
@@ -1619,6 +1915,7 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1619
1915
|
* 移除适配器事件监听
|
|
1620
1916
|
*/
|
|
1621
1917
|
removeAdapterListeners(adapter) {
|
|
1918
|
+
if (!adapter) return;
|
|
1622
1919
|
adapter.removeAllListeners();
|
|
1623
1920
|
}
|
|
1624
1921
|
// ===== 存储 =====
|
|
@@ -1692,7 +1989,7 @@ var AuthMessageGenerator = class {
|
|
|
1692
1989
|
*/
|
|
1693
1990
|
generateAuthMessage(chainType, nonce, chainId, timestamp = Date.now(), statement) {
|
|
1694
1991
|
switch (chainType) {
|
|
1695
|
-
case
|
|
1992
|
+
case ChainType.EVM:
|
|
1696
1993
|
return this.generateEIP191Message({
|
|
1697
1994
|
domain: this.domain,
|
|
1698
1995
|
nonce,
|
|
@@ -1700,7 +1997,7 @@ var AuthMessageGenerator = class {
|
|
|
1700
1997
|
timestamp,
|
|
1701
1998
|
statement
|
|
1702
1999
|
});
|
|
1703
|
-
case
|
|
2000
|
+
case ChainType.TRON:
|
|
1704
2001
|
return this.generateTIP191Message({
|
|
1705
2002
|
domain: this.domain,
|
|
1706
2003
|
nonce,
|
|
@@ -1763,9 +2060,9 @@ var SignatureVerifier = class {
|
|
|
1763
2060
|
*/
|
|
1764
2061
|
async verifySignature(message, signature, expectedAddress, chainType) {
|
|
1765
2062
|
switch (chainType) {
|
|
1766
|
-
case
|
|
2063
|
+
case ChainType.EVM:
|
|
1767
2064
|
return this.verifyEIP191Signature(message, signature, expectedAddress);
|
|
1768
|
-
case
|
|
2065
|
+
case ChainType.TRON:
|
|
1769
2066
|
return this.verifyTIP191Signature(message, signature, expectedAddress);
|
|
1770
2067
|
default:
|
|
1771
2068
|
throw new Error(`Unsupported chain type: ${chainType}`);
|
|
@@ -1803,7 +2100,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1803
2100
|
["metamask" /* METAMASK */]: {
|
|
1804
2101
|
type: "metamask" /* METAMASK */,
|
|
1805
2102
|
name: "MetaMask",
|
|
1806
|
-
chainType:
|
|
2103
|
+
chainType: ChainType.EVM,
|
|
1807
2104
|
icon: "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg",
|
|
1808
2105
|
downloadUrl: "https://metamask.io/download/",
|
|
1809
2106
|
description: "The most popular Ethereum wallet"
|
|
@@ -1811,7 +2108,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1811
2108
|
["walletconnect" /* WALLETCONNECT */]: {
|
|
1812
2109
|
type: "walletconnect" /* WALLETCONNECT */,
|
|
1813
2110
|
name: "WalletConnect",
|
|
1814
|
-
chainType:
|
|
2111
|
+
chainType: ChainType.EVM,
|
|
1815
2112
|
icon: "https://avatars.githubusercontent.com/u/37784886",
|
|
1816
2113
|
downloadUrl: "https://walletconnect.com/",
|
|
1817
2114
|
description: "Connect to 170+ wallets"
|
|
@@ -1819,7 +2116,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1819
2116
|
["coinbase-wallet" /* COINBASE_WALLET */]: {
|
|
1820
2117
|
type: "coinbase-wallet" /* COINBASE_WALLET */,
|
|
1821
2118
|
name: "Coinbase Wallet",
|
|
1822
|
-
chainType:
|
|
2119
|
+
chainType: ChainType.EVM,
|
|
1823
2120
|
icon: "https://www.coinbase.com/img/favicon/favicon-96x96.png",
|
|
1824
2121
|
downloadUrl: "https://www.coinbase.com/wallet",
|
|
1825
2122
|
description: "Coinbase self-custody wallet"
|
|
@@ -1827,7 +2124,7 @@ var SUPPORTED_WALLETS = {
|
|
|
1827
2124
|
["tronlink" /* TRONLINK */]: {
|
|
1828
2125
|
type: "tronlink" /* TRONLINK */,
|
|
1829
2126
|
name: "TronLink",
|
|
1830
|
-
chainType:
|
|
2127
|
+
chainType: ChainType.TRON,
|
|
1831
2128
|
icon: "https://www.tronlink.org/static/logoIcon.svg",
|
|
1832
2129
|
downloadUrl: "https://www.tronlink.org/",
|
|
1833
2130
|
description: "The official Tron wallet"
|
|
@@ -1835,14 +2132,14 @@ var SUPPORTED_WALLETS = {
|
|
|
1835
2132
|
["walletconnect-tron" /* WALLETCONNECT_TRON */]: {
|
|
1836
2133
|
type: "walletconnect-tron" /* WALLETCONNECT_TRON */,
|
|
1837
2134
|
name: "WalletConnect (Tron)",
|
|
1838
|
-
chainType:
|
|
2135
|
+
chainType: ChainType.TRON,
|
|
1839
2136
|
downloadUrl: "https://walletconnect.com/",
|
|
1840
2137
|
description: "WalletConnect for Tron"
|
|
1841
2138
|
},
|
|
1842
2139
|
["private-key" /* PRIVATE_KEY */]: {
|
|
1843
2140
|
type: "private-key" /* PRIVATE_KEY */,
|
|
1844
2141
|
name: "Private Key",
|
|
1845
|
-
chainType:
|
|
2142
|
+
chainType: ChainType.EVM,
|
|
1846
2143
|
// 可以用于任何链
|
|
1847
2144
|
description: "Import wallet using private key (for development)"
|
|
1848
2145
|
}
|
|
@@ -1852,12 +2149,12 @@ function getWalletMetadata(type) {
|
|
|
1852
2149
|
}
|
|
1853
2150
|
function getEVMWallets() {
|
|
1854
2151
|
return Object.values(SUPPORTED_WALLETS).filter(
|
|
1855
|
-
(wallet) => wallet.chainType ===
|
|
2152
|
+
(wallet) => wallet.chainType === ChainType.EVM
|
|
1856
2153
|
);
|
|
1857
2154
|
}
|
|
1858
2155
|
function getTronWallets() {
|
|
1859
2156
|
return Object.values(SUPPORTED_WALLETS).filter(
|
|
1860
|
-
(wallet) => wallet.chainType ===
|
|
2157
|
+
(wallet) => wallet.chainType === ChainType.TRON
|
|
1861
2158
|
);
|
|
1862
2159
|
}
|
|
1863
2160
|
|
|
@@ -1884,7 +2181,7 @@ var WalletDetector = class {
|
|
|
1884
2181
|
if (!metadata) {
|
|
1885
2182
|
return {
|
|
1886
2183
|
walletType,
|
|
1887
|
-
chainType:
|
|
2184
|
+
chainType: ChainType.EVM,
|
|
1888
2185
|
// 默认
|
|
1889
2186
|
isAvailable: false,
|
|
1890
2187
|
detected: false
|
|
@@ -1923,11 +2220,11 @@ var WalletDetector = class {
|
|
|
1923
2220
|
}
|
|
1924
2221
|
}
|
|
1925
2222
|
/**
|
|
1926
|
-
* 检测 MetaMask
|
|
2223
|
+
* 检测 MetaMask(现在支持所有 window.ethereum 钱包)
|
|
1927
2224
|
*/
|
|
1928
2225
|
isMetaMaskAvailable() {
|
|
1929
2226
|
const w = window;
|
|
1930
|
-
return !!
|
|
2227
|
+
return !!w.ethereum;
|
|
1931
2228
|
}
|
|
1932
2229
|
/**
|
|
1933
2230
|
* 检测 TronLink
|
|
@@ -1992,9 +2289,9 @@ function shortenTronAddress(address, chars = 4) {
|
|
|
1992
2289
|
// src/utils/validation.ts
|
|
1993
2290
|
function validateAddress(address, chainType) {
|
|
1994
2291
|
switch (chainType) {
|
|
1995
|
-
case
|
|
2292
|
+
case ChainType.EVM:
|
|
1996
2293
|
return isValidEVMAddress(address);
|
|
1997
|
-
case
|
|
2294
|
+
case ChainType.TRON:
|
|
1998
2295
|
return isValidTronAddress(address);
|
|
1999
2296
|
default:
|
|
2000
2297
|
return false;
|
|
@@ -2015,9 +2312,9 @@ function isValidSignature(signature) {
|
|
|
2015
2312
|
}
|
|
2016
2313
|
function isValidTransactionHash(txHash, chainType) {
|
|
2017
2314
|
switch (chainType) {
|
|
2018
|
-
case
|
|
2315
|
+
case ChainType.EVM:
|
|
2019
2316
|
return /^0x[0-9a-fA-F]{64}$/.test(txHash);
|
|
2020
|
-
case
|
|
2317
|
+
case ChainType.TRON:
|
|
2021
2318
|
return /^[0-9a-fA-F]{64}$/.test(txHash);
|
|
2022
2319
|
default:
|
|
2023
2320
|
return false;
|