@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/react/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var React = require('react');
|
|
4
4
|
var EventEmitter = require('eventemitter3');
|
|
5
|
+
var chainUtils = require('@enclave-hq/chain-utils');
|
|
5
6
|
var viem = require('viem');
|
|
6
7
|
var accounts = require('viem/accounts');
|
|
7
8
|
|
|
@@ -39,6 +40,7 @@ var TypedEventEmitter = class {
|
|
|
39
40
|
return this;
|
|
40
41
|
}
|
|
41
42
|
};
|
|
43
|
+
var ChainType = chainUtils.ChainType;
|
|
42
44
|
|
|
43
45
|
// src/core/errors.ts
|
|
44
46
|
var WalletSDKError = class _WalletSDKError extends Error {
|
|
@@ -219,14 +221,15 @@ function formatEVMAddress(address) {
|
|
|
219
221
|
}
|
|
220
222
|
return viem.getAddress(address);
|
|
221
223
|
}
|
|
222
|
-
|
|
223
|
-
// src/utils/chain-info.ts
|
|
224
224
|
var CHAIN_INFO = {
|
|
225
225
|
// EVM Mainnet
|
|
226
226
|
1: {
|
|
227
227
|
id: 1,
|
|
228
|
+
slip44: 60,
|
|
229
|
+
// Ethereum SLIP-44
|
|
228
230
|
name: "Ethereum Mainnet",
|
|
229
|
-
chainType:
|
|
231
|
+
chainType: chainUtils.ChainType.EVM,
|
|
232
|
+
symbol: "ETH",
|
|
230
233
|
nativeCurrency: {
|
|
231
234
|
name: "Ether",
|
|
232
235
|
symbol: "ETH",
|
|
@@ -239,7 +242,8 @@ var CHAIN_INFO = {
|
|
|
239
242
|
11155111: {
|
|
240
243
|
id: 11155111,
|
|
241
244
|
name: "Sepolia Testnet",
|
|
242
|
-
chainType:
|
|
245
|
+
chainType: chainUtils.ChainType.EVM,
|
|
246
|
+
symbol: "ETH",
|
|
243
247
|
nativeCurrency: {
|
|
244
248
|
name: "Sepolia Ether",
|
|
245
249
|
symbol: "ETH",
|
|
@@ -251,8 +255,11 @@ var CHAIN_INFO = {
|
|
|
251
255
|
// Binance Smart Chain
|
|
252
256
|
56: {
|
|
253
257
|
id: 56,
|
|
258
|
+
slip44: 714,
|
|
259
|
+
// BSC SLIP-44
|
|
254
260
|
name: "BNB Smart Chain",
|
|
255
|
-
chainType:
|
|
261
|
+
chainType: chainUtils.ChainType.EVM,
|
|
262
|
+
symbol: "BNB",
|
|
256
263
|
nativeCurrency: {
|
|
257
264
|
name: "BNB",
|
|
258
265
|
symbol: "BNB",
|
|
@@ -264,7 +271,8 @@ var CHAIN_INFO = {
|
|
|
264
271
|
97: {
|
|
265
272
|
id: 97,
|
|
266
273
|
name: "BNB Smart Chain Testnet",
|
|
267
|
-
chainType:
|
|
274
|
+
chainType: chainUtils.ChainType.EVM,
|
|
275
|
+
symbol: "BNB",
|
|
268
276
|
nativeCurrency: {
|
|
269
277
|
name: "BNB",
|
|
270
278
|
symbol: "BNB",
|
|
@@ -276,8 +284,11 @@ var CHAIN_INFO = {
|
|
|
276
284
|
// Polygon
|
|
277
285
|
137: {
|
|
278
286
|
id: 137,
|
|
287
|
+
slip44: 966,
|
|
288
|
+
// Polygon SLIP-44
|
|
279
289
|
name: "Polygon Mainnet",
|
|
280
|
-
chainType:
|
|
290
|
+
chainType: chainUtils.ChainType.EVM,
|
|
291
|
+
symbol: "MATIC",
|
|
281
292
|
nativeCurrency: {
|
|
282
293
|
name: "MATIC",
|
|
283
294
|
symbol: "MATIC",
|
|
@@ -289,7 +300,8 @@ var CHAIN_INFO = {
|
|
|
289
300
|
80002: {
|
|
290
301
|
id: 80002,
|
|
291
302
|
name: "Polygon Amoy Testnet",
|
|
292
|
-
chainType:
|
|
303
|
+
chainType: chainUtils.ChainType.EVM,
|
|
304
|
+
symbol: "MATIC",
|
|
293
305
|
nativeCurrency: {
|
|
294
306
|
name: "MATIC",
|
|
295
307
|
symbol: "MATIC",
|
|
@@ -301,8 +313,11 @@ var CHAIN_INFO = {
|
|
|
301
313
|
// Tron
|
|
302
314
|
195: {
|
|
303
315
|
id: 195,
|
|
316
|
+
slip44: 195,
|
|
317
|
+
// Tron SLIP-44
|
|
304
318
|
name: "Tron Mainnet",
|
|
305
|
-
chainType:
|
|
319
|
+
chainType: chainUtils.ChainType.TRON,
|
|
320
|
+
symbol: "TRX",
|
|
306
321
|
nativeCurrency: {
|
|
307
322
|
name: "TRX",
|
|
308
323
|
symbol: "TRX",
|
|
@@ -314,8 +329,11 @@ var CHAIN_INFO = {
|
|
|
314
329
|
// Arbitrum
|
|
315
330
|
42161: {
|
|
316
331
|
id: 42161,
|
|
332
|
+
slip44: 1042161,
|
|
333
|
+
// Custom SLIP-44 (1000000 + 42161)
|
|
317
334
|
name: "Arbitrum One",
|
|
318
|
-
chainType:
|
|
335
|
+
chainType: chainUtils.ChainType.EVM,
|
|
336
|
+
symbol: "ETH",
|
|
319
337
|
nativeCurrency: {
|
|
320
338
|
name: "Ether",
|
|
321
339
|
symbol: "ETH",
|
|
@@ -327,8 +345,11 @@ var CHAIN_INFO = {
|
|
|
327
345
|
// Optimism
|
|
328
346
|
10: {
|
|
329
347
|
id: 10,
|
|
348
|
+
slip44: 1000010,
|
|
349
|
+
// Custom SLIP-44 (1000000 + 10)
|
|
330
350
|
name: "Optimism",
|
|
331
|
-
chainType:
|
|
351
|
+
chainType: chainUtils.ChainType.EVM,
|
|
352
|
+
symbol: "ETH",
|
|
332
353
|
nativeCurrency: {
|
|
333
354
|
name: "Ether",
|
|
334
355
|
symbol: "ETH",
|
|
@@ -340,8 +361,11 @@ var CHAIN_INFO = {
|
|
|
340
361
|
// Avalanche
|
|
341
362
|
43114: {
|
|
342
363
|
id: 43114,
|
|
364
|
+
slip44: 9e3,
|
|
365
|
+
// Avalanche SLIP-44
|
|
343
366
|
name: "Avalanche C-Chain",
|
|
344
|
-
chainType:
|
|
367
|
+
chainType: chainUtils.ChainType.EVM,
|
|
368
|
+
symbol: "AVAX",
|
|
345
369
|
nativeCurrency: {
|
|
346
370
|
name: "AVAX",
|
|
347
371
|
symbol: "AVAX",
|
|
@@ -360,26 +384,34 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
360
384
|
constructor() {
|
|
361
385
|
super(...arguments);
|
|
362
386
|
this.type = "metamask" /* METAMASK */;
|
|
363
|
-
this.chainType =
|
|
387
|
+
this.chainType = ChainType.EVM;
|
|
364
388
|
this.name = "MetaMask";
|
|
365
389
|
this.icon = "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg";
|
|
366
390
|
this.walletClient = null;
|
|
367
391
|
this.publicClient = null;
|
|
368
392
|
/**
|
|
369
393
|
* 处理账户变化
|
|
394
|
+
*
|
|
395
|
+
* 注意:MetaMask 的行为
|
|
396
|
+
* - 切换到已连接的账户:触发事件,返回新账户 ['0xNewAddress']
|
|
397
|
+
* - 切换到未连接的账户:不触发事件(用户需要手动断开和重新连接)
|
|
398
|
+
* - 锁定钱包:触发事件,返回空数组 []
|
|
370
399
|
*/
|
|
371
400
|
this.handleAccountsChanged = (accounts) => {
|
|
401
|
+
console.log("[MetaMask] accountsChanged event triggered:", accounts);
|
|
372
402
|
if (accounts.length === 0) {
|
|
403
|
+
console.log("[MetaMask] Disconnecting: wallet locked or manually disconnected");
|
|
373
404
|
this.setState("disconnected" /* DISCONNECTED */);
|
|
374
405
|
this.setAccount(null);
|
|
375
406
|
this.emitAccountChanged(null);
|
|
376
407
|
} else {
|
|
377
408
|
const address = formatEVMAddress(accounts[0]);
|
|
409
|
+
console.log("[MetaMask] Account changed to:", address);
|
|
378
410
|
const account = {
|
|
379
411
|
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
380
412
|
nativeAddress: address,
|
|
381
413
|
chainId: this.currentAccount.chainId,
|
|
382
|
-
chainType:
|
|
414
|
+
chainType: ChainType.EVM,
|
|
383
415
|
isActive: true
|
|
384
416
|
};
|
|
385
417
|
this.setAccount(account);
|
|
@@ -431,21 +463,23 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
431
463
|
if (chainId && chainId !== parsedChainId) {
|
|
432
464
|
await this.switchChain(chainId);
|
|
433
465
|
}
|
|
466
|
+
const finalChainId = chainId || parsedChainId;
|
|
467
|
+
const viemChain = this.getViemChain(finalChainId);
|
|
434
468
|
this.walletClient = viem.createWalletClient({
|
|
435
469
|
account: accounts[0],
|
|
470
|
+
chain: viemChain,
|
|
436
471
|
transport: viem.custom(provider)
|
|
437
472
|
});
|
|
438
|
-
const finalChainId = chainId || parsedChainId;
|
|
439
473
|
this.publicClient = viem.createPublicClient({
|
|
440
|
-
chain:
|
|
441
|
-
transport: viem.
|
|
474
|
+
chain: viemChain,
|
|
475
|
+
transport: viem.custom(provider)
|
|
442
476
|
});
|
|
443
477
|
const address = formatEVMAddress(accounts[0]);
|
|
444
478
|
const account = {
|
|
445
479
|
universalAddress: createUniversalAddress(finalChainId, address),
|
|
446
480
|
nativeAddress: address,
|
|
447
481
|
chainId: finalChainId,
|
|
448
|
-
chainType:
|
|
482
|
+
chainType: ChainType.EVM,
|
|
449
483
|
isActive: true
|
|
450
484
|
};
|
|
451
485
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -499,6 +533,40 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
499
533
|
throw error;
|
|
500
534
|
}
|
|
501
535
|
}
|
|
536
|
+
/**
|
|
537
|
+
* 签名交易
|
|
538
|
+
*
|
|
539
|
+
* Note: This signs a raw transaction without sending it.
|
|
540
|
+
* The transaction can be broadcast later using the returned signature.
|
|
541
|
+
*/
|
|
542
|
+
async signTransaction(transaction) {
|
|
543
|
+
this.ensureConnected();
|
|
544
|
+
try {
|
|
545
|
+
const provider = this.getBrowserProvider();
|
|
546
|
+
const tx = {
|
|
547
|
+
from: this.currentAccount.nativeAddress,
|
|
548
|
+
to: transaction.to,
|
|
549
|
+
value: transaction.value ? `0x${BigInt(transaction.value).toString(16)}` : void 0,
|
|
550
|
+
data: transaction.data || "0x",
|
|
551
|
+
gas: transaction.gas ? `0x${BigInt(transaction.gas).toString(16)}` : void 0,
|
|
552
|
+
gasPrice: transaction.gasPrice && transaction.gasPrice !== "auto" ? `0x${BigInt(transaction.gasPrice).toString(16)}` : void 0,
|
|
553
|
+
maxFeePerGas: transaction.maxFeePerGas ? `0x${BigInt(transaction.maxFeePerGas).toString(16)}` : void 0,
|
|
554
|
+
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ? `0x${BigInt(transaction.maxPriorityFeePerGas).toString(16)}` : void 0,
|
|
555
|
+
nonce: transaction.nonce !== void 0 ? `0x${transaction.nonce.toString(16)}` : void 0,
|
|
556
|
+
chainId: transaction.chainId || this.currentAccount.chainId
|
|
557
|
+
};
|
|
558
|
+
const signature = await provider.request({
|
|
559
|
+
method: "eth_signTransaction",
|
|
560
|
+
params: [tx]
|
|
561
|
+
});
|
|
562
|
+
return signature;
|
|
563
|
+
} catch (error) {
|
|
564
|
+
if (error.code === 4001) {
|
|
565
|
+
throw new SignatureRejectedError("Transaction signature was rejected by user");
|
|
566
|
+
}
|
|
567
|
+
throw error;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
502
570
|
/**
|
|
503
571
|
* 切换链
|
|
504
572
|
*/
|
|
@@ -579,6 +647,16 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
579
647
|
throw new Error("Wallet client not initialized");
|
|
580
648
|
}
|
|
581
649
|
try {
|
|
650
|
+
console.log("\u{1F50D} [MetaMask writeContract] params.gasPrice:", params.gasPrice, "type:", typeof params.gasPrice);
|
|
651
|
+
let processedGasPrice;
|
|
652
|
+
if (!params.gasPrice) {
|
|
653
|
+
processedGasPrice = void 0;
|
|
654
|
+
} else if (params.gasPrice === "auto") {
|
|
655
|
+
processedGasPrice = void 0;
|
|
656
|
+
} else {
|
|
657
|
+
processedGasPrice = BigInt(params.gasPrice);
|
|
658
|
+
}
|
|
659
|
+
console.log("\u{1F50D} [MetaMask writeContract] processedGasPrice:", processedGasPrice);
|
|
582
660
|
const txHash = await this.walletClient.writeContract({
|
|
583
661
|
address: params.address,
|
|
584
662
|
abi: params.abi,
|
|
@@ -586,7 +664,7 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
586
664
|
...params.args ? { args: params.args } : {},
|
|
587
665
|
value: params.value ? BigInt(params.value) : void 0,
|
|
588
666
|
gas: params.gas ? BigInt(params.gas) : void 0,
|
|
589
|
-
gasPrice:
|
|
667
|
+
gasPrice: processedGasPrice
|
|
590
668
|
});
|
|
591
669
|
return txHash;
|
|
592
670
|
} catch (error) {
|
|
@@ -729,9 +807,14 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
729
807
|
constructor() {
|
|
730
808
|
super(...arguments);
|
|
731
809
|
this.type = "tronlink" /* TRONLINK */;
|
|
732
|
-
this.chainType =
|
|
810
|
+
this.chainType = ChainType.TRON;
|
|
733
811
|
this.name = "TronLink";
|
|
734
812
|
this.icon = "https://www.tronlink.org/static/logoIcon.svg";
|
|
813
|
+
/**
|
|
814
|
+
* 轮询检测账户变化(备用方案)
|
|
815
|
+
*/
|
|
816
|
+
this.pollingInterval = null;
|
|
817
|
+
this.lastKnownAddress = null;
|
|
735
818
|
/**
|
|
736
819
|
* 处理账户变化
|
|
737
820
|
*/
|
|
@@ -746,7 +829,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
746
829
|
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
747
830
|
nativeAddress: address,
|
|
748
831
|
chainId: this.currentAccount.chainId,
|
|
749
|
-
chainType:
|
|
832
|
+
chainType: ChainType.TRON,
|
|
750
833
|
isActive: true
|
|
751
834
|
};
|
|
752
835
|
this.setAccount(account);
|
|
@@ -785,7 +868,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
785
868
|
universalAddress: createUniversalAddress(tronChainId, address),
|
|
786
869
|
nativeAddress: address,
|
|
787
870
|
chainId: tronChainId,
|
|
788
|
-
chainType:
|
|
871
|
+
chainType: ChainType.TRON,
|
|
789
872
|
isActive: true
|
|
790
873
|
};
|
|
791
874
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -803,20 +886,177 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
803
886
|
}
|
|
804
887
|
/**
|
|
805
888
|
* 签名消息
|
|
889
|
+
*
|
|
890
|
+
* Note: TronLink supports two signing methods:
|
|
891
|
+
* - trx.sign(): Signs a transaction object
|
|
892
|
+
* - trx.signMessageV2(): Signs a plain text message (what we use here)
|
|
806
893
|
*/
|
|
807
894
|
async signMessage(message) {
|
|
808
895
|
this.ensureConnected();
|
|
809
896
|
try {
|
|
810
897
|
const tronWeb = this.getTronWeb();
|
|
811
|
-
|
|
812
|
-
|
|
898
|
+
if (typeof tronWeb.trx.signMessageV2 === "function") {
|
|
899
|
+
const signature = await tronWeb.trx.signMessageV2(message);
|
|
900
|
+
return signature;
|
|
901
|
+
} else {
|
|
902
|
+
console.warn("[TronLink] signMessageV2 not available, falling back to sign()");
|
|
903
|
+
const signature = await tronWeb.trx.sign(message);
|
|
904
|
+
return signature;
|
|
905
|
+
}
|
|
813
906
|
} catch (error) {
|
|
814
907
|
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
815
908
|
throw new SignatureRejectedError();
|
|
816
909
|
}
|
|
910
|
+
if (error.message?.includes("Invalid transaction")) {
|
|
911
|
+
throw new Error("Invalid message format. For transaction signing, use signTransaction() instead.");
|
|
912
|
+
}
|
|
913
|
+
throw error;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* 签名交易
|
|
918
|
+
*
|
|
919
|
+
* Note: This uses trx.sign() which is specifically for signing transaction objects.
|
|
920
|
+
* For plain text message signing, use signMessage() instead.
|
|
921
|
+
*/
|
|
922
|
+
async signTransaction(transaction) {
|
|
923
|
+
this.ensureConnected();
|
|
924
|
+
try {
|
|
925
|
+
const tronWeb = this.getTronWeb();
|
|
926
|
+
const signature = await tronWeb.trx.sign(transaction);
|
|
927
|
+
return signature;
|
|
928
|
+
} catch (error) {
|
|
929
|
+
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
930
|
+
throw new SignatureRejectedError("Transaction signature was rejected by user");
|
|
931
|
+
}
|
|
932
|
+
if (error.message?.includes("Invalid transaction")) {
|
|
933
|
+
throw new Error("Invalid transaction format. Please provide a properly formatted Tron transaction object.");
|
|
934
|
+
}
|
|
817
935
|
throw error;
|
|
818
936
|
}
|
|
819
937
|
}
|
|
938
|
+
/**
|
|
939
|
+
* 读取合约
|
|
940
|
+
*/
|
|
941
|
+
async readContract(params) {
|
|
942
|
+
this.ensureConnected();
|
|
943
|
+
try {
|
|
944
|
+
const tronWeb = this.getTronWeb();
|
|
945
|
+
const contract = await tronWeb.contract(params.abi, params.address);
|
|
946
|
+
const result = await contract[params.functionName](...params.args || []).call();
|
|
947
|
+
return result;
|
|
948
|
+
} catch (error) {
|
|
949
|
+
console.error("Read contract error:", error);
|
|
950
|
+
throw new Error(`Failed to read contract: ${error.message}`);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* 写入合约
|
|
955
|
+
*/
|
|
956
|
+
async writeContract(params) {
|
|
957
|
+
this.ensureConnected();
|
|
958
|
+
try {
|
|
959
|
+
const tronWeb = this.getTronWeb();
|
|
960
|
+
console.log("[TronLink] writeContract params:", {
|
|
961
|
+
address: params.address,
|
|
962
|
+
functionName: params.functionName,
|
|
963
|
+
args: params.args,
|
|
964
|
+
value: params.value,
|
|
965
|
+
gas: params.gas
|
|
966
|
+
});
|
|
967
|
+
if (!params.args || params.args.length === 0) {
|
|
968
|
+
throw new Error("Contract function arguments are required");
|
|
969
|
+
}
|
|
970
|
+
const hasUndefined = params.args.some((arg) => arg === void 0 || arg === null);
|
|
971
|
+
if (hasUndefined) {
|
|
972
|
+
console.error("[TronLink] Invalid args detected:", params.args);
|
|
973
|
+
throw new Error(`Invalid contract arguments: some arguments are undefined or null`);
|
|
974
|
+
}
|
|
975
|
+
const functionAbi = params.abi.find(
|
|
976
|
+
(item) => item.name === params.functionName && item.type === "function"
|
|
977
|
+
);
|
|
978
|
+
if (!functionAbi) {
|
|
979
|
+
throw new Error(`Function ${params.functionName} not found in ABI`);
|
|
980
|
+
}
|
|
981
|
+
console.log("[TronLink] Function ABI:", functionAbi);
|
|
982
|
+
console.log("[TronLink] Calling with args:", params.args);
|
|
983
|
+
const options = {
|
|
984
|
+
feeLimit: params.gas || 1e8,
|
|
985
|
+
// 默认 100 TRX 的能量限制
|
|
986
|
+
callValue: params.value || 0
|
|
987
|
+
// 发送的 TRX 数量(单位:SUN)
|
|
988
|
+
};
|
|
989
|
+
const parameter = functionAbi.inputs.map((input, index) => ({
|
|
990
|
+
type: input.type,
|
|
991
|
+
value: params.args[index]
|
|
992
|
+
}));
|
|
993
|
+
console.log("[TronLink] Transaction options:", options);
|
|
994
|
+
console.log("[TronLink] Parameters:", parameter);
|
|
995
|
+
const transaction = await tronWeb.transactionBuilder.triggerSmartContract(
|
|
996
|
+
params.address,
|
|
997
|
+
params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")",
|
|
998
|
+
options,
|
|
999
|
+
parameter,
|
|
1000
|
+
this.currentAccount.nativeAddress
|
|
1001
|
+
);
|
|
1002
|
+
console.log("[TronLink] Transaction built:", transaction);
|
|
1003
|
+
if (!transaction || !transaction.transaction) {
|
|
1004
|
+
throw new Error("Failed to build transaction");
|
|
1005
|
+
}
|
|
1006
|
+
const signedTx = await tronWeb.trx.sign(transaction.transaction);
|
|
1007
|
+
const broadcast = await tronWeb.trx.sendRawTransaction(signedTx);
|
|
1008
|
+
console.log("[TronLink] Broadcast result:", broadcast);
|
|
1009
|
+
if (!broadcast.result) {
|
|
1010
|
+
throw new Error(broadcast.message || "Transaction broadcast failed");
|
|
1011
|
+
}
|
|
1012
|
+
const txHash = broadcast.txid || broadcast.transaction?.txID;
|
|
1013
|
+
console.log("[TronLink] Transaction hash:", txHash);
|
|
1014
|
+
return txHash || "";
|
|
1015
|
+
} catch (error) {
|
|
1016
|
+
console.error("Write contract error:", error);
|
|
1017
|
+
if (error.message?.includes("User rejected") || error.message?.includes("Confirmation declined")) {
|
|
1018
|
+
throw new SignatureRejectedError("Transaction was rejected by user");
|
|
1019
|
+
}
|
|
1020
|
+
throw new Error(`Failed to write contract: ${error.message}`);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* 等待交易确认
|
|
1025
|
+
*/
|
|
1026
|
+
async waitForTransaction(txHash, _confirmations = 1) {
|
|
1027
|
+
try {
|
|
1028
|
+
const tronWeb = this.getTronWeb();
|
|
1029
|
+
let attempts = 0;
|
|
1030
|
+
const maxAttempts = 60;
|
|
1031
|
+
while (attempts < maxAttempts) {
|
|
1032
|
+
try {
|
|
1033
|
+
const txInfo = await tronWeb.trx.getTransactionInfo(txHash);
|
|
1034
|
+
if (txInfo && txInfo.id) {
|
|
1035
|
+
const receipt = {
|
|
1036
|
+
transactionHash: txHash,
|
|
1037
|
+
blockNumber: txInfo.blockNumber || 0,
|
|
1038
|
+
blockHash: txInfo.blockHash || "",
|
|
1039
|
+
from: this.currentAccount.nativeAddress,
|
|
1040
|
+
to: txInfo.contract_address || "",
|
|
1041
|
+
status: txInfo.receipt?.result === "SUCCESS" ? "success" : "failed",
|
|
1042
|
+
gasUsed: (txInfo.receipt?.energy_usage_total || 0).toString(),
|
|
1043
|
+
logs: txInfo.log || []
|
|
1044
|
+
};
|
|
1045
|
+
if (receipt.status === "failed") {
|
|
1046
|
+
throw new TransactionFailedError(txHash, "Transaction failed on Tron network");
|
|
1047
|
+
}
|
|
1048
|
+
return receipt;
|
|
1049
|
+
}
|
|
1050
|
+
} catch (error) {
|
|
1051
|
+
}
|
|
1052
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1053
|
+
attempts++;
|
|
1054
|
+
}
|
|
1055
|
+
throw new Error("Transaction confirmation timeout");
|
|
1056
|
+
} catch (error) {
|
|
1057
|
+
throw new Error(`Failed to wait for transaction: ${error.message}`);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
820
1060
|
/**
|
|
821
1061
|
* 获取 Provider
|
|
822
1062
|
*/
|
|
@@ -855,9 +1095,16 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
855
1095
|
setupEventListeners() {
|
|
856
1096
|
if (typeof window === "undefined") return;
|
|
857
1097
|
const w = window;
|
|
858
|
-
|
|
859
|
-
w.tronLink.on
|
|
860
|
-
|
|
1098
|
+
try {
|
|
1099
|
+
if (w.tronLink && typeof w.tronLink.on === "function") {
|
|
1100
|
+
w.tronLink.on("accountsChanged", this.handleAccountsChanged);
|
|
1101
|
+
w.tronLink.on("disconnect", this.handleDisconnect);
|
|
1102
|
+
} else if (w.tronWeb && w.tronWeb.eventServer) {
|
|
1103
|
+
this.startPolling();
|
|
1104
|
+
}
|
|
1105
|
+
} catch (error) {
|
|
1106
|
+
console.warn("TronLink event listener setup failed:", error);
|
|
1107
|
+
this.startPolling();
|
|
861
1108
|
}
|
|
862
1109
|
}
|
|
863
1110
|
/**
|
|
@@ -866,9 +1113,38 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
866
1113
|
removeEventListeners() {
|
|
867
1114
|
if (typeof window === "undefined") return;
|
|
868
1115
|
const w = window;
|
|
869
|
-
|
|
870
|
-
w.tronLink.off
|
|
871
|
-
|
|
1116
|
+
try {
|
|
1117
|
+
if (w.tronLink && typeof w.tronLink.off === "function") {
|
|
1118
|
+
w.tronLink.off("accountsChanged", this.handleAccountsChanged);
|
|
1119
|
+
w.tronLink.off("disconnect", this.handleDisconnect);
|
|
1120
|
+
}
|
|
1121
|
+
} catch (error) {
|
|
1122
|
+
console.warn("TronLink event listener removal failed:", error);
|
|
1123
|
+
}
|
|
1124
|
+
this.stopPolling();
|
|
1125
|
+
}
|
|
1126
|
+
startPolling() {
|
|
1127
|
+
if (this.pollingInterval) return;
|
|
1128
|
+
this.lastKnownAddress = this.currentAccount?.nativeAddress || null;
|
|
1129
|
+
this.pollingInterval = setInterval(async () => {
|
|
1130
|
+
try {
|
|
1131
|
+
const tronWeb = this.getTronWeb();
|
|
1132
|
+
const currentAddress = tronWeb.defaultAddress?.base58;
|
|
1133
|
+
if (currentAddress && currentAddress !== this.lastKnownAddress) {
|
|
1134
|
+
this.lastKnownAddress = currentAddress;
|
|
1135
|
+
this.handleAccountsChanged({ address: { base58: currentAddress } });
|
|
1136
|
+
} else if (!currentAddress && this.lastKnownAddress) {
|
|
1137
|
+
this.lastKnownAddress = null;
|
|
1138
|
+
this.handleAccountsChanged(null);
|
|
1139
|
+
}
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
}
|
|
1142
|
+
}, 2e3);
|
|
1143
|
+
}
|
|
1144
|
+
stopPolling() {
|
|
1145
|
+
if (this.pollingInterval) {
|
|
1146
|
+
clearInterval(this.pollingInterval);
|
|
1147
|
+
this.pollingInterval = null;
|
|
872
1148
|
}
|
|
873
1149
|
}
|
|
874
1150
|
};
|
|
@@ -879,7 +1155,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
879
1155
|
constructor() {
|
|
880
1156
|
super(...arguments);
|
|
881
1157
|
this.type = "private-key" /* PRIVATE_KEY */;
|
|
882
|
-
this.chainType =
|
|
1158
|
+
this.chainType = ChainType.EVM;
|
|
883
1159
|
this.name = "Private Key (EVM)";
|
|
884
1160
|
this.privateKey = null;
|
|
885
1161
|
this.walletClient = null;
|
|
@@ -909,7 +1185,7 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
909
1185
|
universalAddress: createUniversalAddress(chainId, address),
|
|
910
1186
|
nativeAddress: address,
|
|
911
1187
|
chainId,
|
|
912
|
-
chainType:
|
|
1188
|
+
chainType: ChainType.EVM,
|
|
913
1189
|
isActive: true
|
|
914
1190
|
};
|
|
915
1191
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -1259,9 +1535,10 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1259
1535
|
if (!this.primaryWallet) {
|
|
1260
1536
|
return;
|
|
1261
1537
|
}
|
|
1538
|
+
const chainType = this.primaryWallet.chainType;
|
|
1262
1539
|
await this.primaryWallet.disconnect();
|
|
1263
1540
|
this.removeAdapterListeners(this.primaryWallet);
|
|
1264
|
-
this.connectedWallets.delete(
|
|
1541
|
+
this.connectedWallets.delete(chainType);
|
|
1265
1542
|
this.primaryWallet = null;
|
|
1266
1543
|
if (this.config.enableStorage) {
|
|
1267
1544
|
this.saveToStorage();
|
|
@@ -1366,6 +1643,34 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1366
1643
|
}
|
|
1367
1644
|
return adapter.signTypedData(typedData);
|
|
1368
1645
|
}
|
|
1646
|
+
/**
|
|
1647
|
+
* 签名交易(使用主钱包)
|
|
1648
|
+
*/
|
|
1649
|
+
async signTransaction(transaction) {
|
|
1650
|
+
if (!this.primaryWallet) {
|
|
1651
|
+
throw new WalletNotConnectedError();
|
|
1652
|
+
}
|
|
1653
|
+
if (!this.primaryWallet.signTransaction) {
|
|
1654
|
+
throw new Error(`signTransaction not supported by ${this.primaryWallet.type}`);
|
|
1655
|
+
}
|
|
1656
|
+
return this.primaryWallet.signTransaction(transaction);
|
|
1657
|
+
}
|
|
1658
|
+
/**
|
|
1659
|
+
* 使用指定链类型的钱包签名交易
|
|
1660
|
+
*/
|
|
1661
|
+
async signTransactionWithChainType(transaction, chainType) {
|
|
1662
|
+
if (!chainType) {
|
|
1663
|
+
return this.signTransaction(transaction);
|
|
1664
|
+
}
|
|
1665
|
+
const adapter = this.connectedWallets.get(chainType);
|
|
1666
|
+
if (!adapter) {
|
|
1667
|
+
throw new WalletNotConnectedError(`Wallet for chain type ${chainType}`);
|
|
1668
|
+
}
|
|
1669
|
+
if (!adapter.signTransaction) {
|
|
1670
|
+
throw new Error(`signTransaction not supported by ${adapter.type}`);
|
|
1671
|
+
}
|
|
1672
|
+
return adapter.signTransaction(transaction);
|
|
1673
|
+
}
|
|
1369
1674
|
// ===== 链切换 =====
|
|
1370
1675
|
/**
|
|
1371
1676
|
* 请求切换链(仅 EVM)
|
|
@@ -1526,6 +1831,7 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1526
1831
|
* 移除适配器事件监听
|
|
1527
1832
|
*/
|
|
1528
1833
|
removeAdapterListeners(adapter) {
|
|
1834
|
+
if (!adapter) return;
|
|
1529
1835
|
adapter.removeAllListeners();
|
|
1530
1836
|
}
|
|
1531
1837
|
// ===== 存储 =====
|
|
@@ -1623,6 +1929,9 @@ function WalletProvider({ children, walletManager: externalWalletManager }) {
|
|
|
1623
1929
|
const signMessage = React.useCallback(async (message) => {
|
|
1624
1930
|
return walletManager.signMessage(message);
|
|
1625
1931
|
}, [walletManager]);
|
|
1932
|
+
const signTransaction = React.useCallback(async (transaction) => {
|
|
1933
|
+
return walletManager.signTransaction(transaction);
|
|
1934
|
+
}, [walletManager]);
|
|
1626
1935
|
React.useEffect(() => {
|
|
1627
1936
|
const handleAccountChanged = (newAccount) => {
|
|
1628
1937
|
setAccount(newAccount);
|
|
@@ -1662,7 +1971,8 @@ function WalletProvider({ children, walletManager: externalWalletManager }) {
|
|
|
1662
1971
|
connectAdditional,
|
|
1663
1972
|
disconnect,
|
|
1664
1973
|
switchPrimaryWallet,
|
|
1665
|
-
signMessage
|
|
1974
|
+
signMessage,
|
|
1975
|
+
signTransaction
|
|
1666
1976
|
};
|
|
1667
1977
|
return /* @__PURE__ */ React__default.default.createElement(WalletContext.Provider, { value }, children);
|
|
1668
1978
|
}
|
|
@@ -1771,12 +2081,37 @@ function useSignMessage() {
|
|
|
1771
2081
|
error
|
|
1772
2082
|
};
|
|
1773
2083
|
}
|
|
2084
|
+
function useSignTransaction() {
|
|
2085
|
+
const { signTransaction: contextSignTransaction } = useWallet();
|
|
2086
|
+
const [isSigning, setIsSigning] = React.useState(false);
|
|
2087
|
+
const [error, setError] = React.useState(null);
|
|
2088
|
+
const signTransaction = async (transaction) => {
|
|
2089
|
+
setIsSigning(true);
|
|
2090
|
+
setError(null);
|
|
2091
|
+
try {
|
|
2092
|
+
const signature = await contextSignTransaction(transaction);
|
|
2093
|
+
return signature;
|
|
2094
|
+
} catch (err) {
|
|
2095
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
2096
|
+
setError(error2);
|
|
2097
|
+
throw error2;
|
|
2098
|
+
} finally {
|
|
2099
|
+
setIsSigning(false);
|
|
2100
|
+
}
|
|
2101
|
+
};
|
|
2102
|
+
return {
|
|
2103
|
+
signTransaction,
|
|
2104
|
+
isSigning,
|
|
2105
|
+
error
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
1774
2108
|
|
|
1775
2109
|
exports.WalletProvider = WalletProvider;
|
|
1776
2110
|
exports.useAccount = useAccount;
|
|
1777
2111
|
exports.useConnect = useConnect;
|
|
1778
2112
|
exports.useDisconnect = useDisconnect;
|
|
1779
2113
|
exports.useSignMessage = useSignMessage;
|
|
2114
|
+
exports.useSignTransaction = useSignTransaction;
|
|
1780
2115
|
exports.useWallet = useWallet;
|
|
1781
2116
|
//# sourceMappingURL=index.js.map
|
|
1782
2117
|
//# sourceMappingURL=index.js.map
|