@stableflow/wallet-tron 3.0.0-beta-02a59f37a0-20260515

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.js ADDED
@@ -0,0 +1,884 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var core = require('@stableflow/core');
6
+ var bridges = require('@stableflow/bridges');
7
+ var utilsEvm = require('@stableflow/utils-evm');
8
+ var utilsSolana = require('@stableflow/utils-solana');
9
+ var ethers = require('ethers');
10
+ var Big = require('big.js');
11
+ var tronweb = require('tronweb');
12
+
13
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
+
15
+ var Big__default = /*#__PURE__*/_interopDefault(Big);
16
+
17
+ // src/tron.ts
18
+ var DefaultTronWalletAddress = core.DefaultAddresses["tron"];
19
+ var getCustomTronWeb = () => {
20
+ return new tronweb.TronWeb({
21
+ fullHost: core.getChainRpcUrl("tron").rpcUrl,
22
+ headers: {},
23
+ privateKey: ""
24
+ });
25
+ };
26
+ var TronWallet = class {
27
+ constructor(options) {
28
+ this.signAndSendTransaction = options.signAndSendTransaction;
29
+ this.address = options.address;
30
+ const customTronWeb = getCustomTronWeb();
31
+ customTronWeb.setAddress(this.address || DefaultTronWalletAddress);
32
+ this.tronWeb = customTronWeb;
33
+ const cs = new core.Csl(core.OpenAPI.DEBUG);
34
+ this.csl = cs.log;
35
+ }
36
+ async waitForTronWeb() {
37
+ return new Promise((resolve) => {
38
+ if (this.tronWeb) {
39
+ const address = this.tronWeb.defaultAddress.base58 || DefaultTronWalletAddress;
40
+ const customTronWeb = getCustomTronWeb();
41
+ customTronWeb.setAddress(address);
42
+ this.tronWeb = customTronWeb;
43
+ resolve(this.tronWeb);
44
+ return;
45
+ }
46
+ const checkTronWeb = () => {
47
+ if (window.tronWeb) {
48
+ this.tronWeb = window.tronWeb;
49
+ const address = this.tronWeb.defaultAddress.base58 || DefaultTronWalletAddress;
50
+ const customTronWeb = getCustomTronWeb();
51
+ customTronWeb.setAddress(address);
52
+ this.tronWeb = customTronWeb;
53
+ resolve(this.tronWeb);
54
+ } else {
55
+ setTimeout(checkTronWeb, 100);
56
+ }
57
+ };
58
+ checkTronWeb();
59
+ setTimeout(() => {
60
+ const customTronWeb = getCustomTronWeb();
61
+ customTronWeb.setAddress(DefaultTronWalletAddress);
62
+ this.tronWeb = customTronWeb;
63
+ resolve(this.tronWeb);
64
+ this.csl("TronWallet waitForTronWeb", "red-500", "TronWeb initialization timeout");
65
+ }, 1e4);
66
+ });
67
+ }
68
+ async transfer(data) {
69
+ const { originAsset, depositAddress, amount } = data;
70
+ await this.waitForTronWeb();
71
+ if (originAsset === "TRX" || originAsset === "trx") {
72
+ return await this.transferTRX(depositAddress, amount);
73
+ }
74
+ return await this.transferToken(originAsset, depositAddress, amount);
75
+ }
76
+ async transferTRX(to, amount) {
77
+ await this.waitForTronWeb();
78
+ const transaction = await this.tronWeb.transactionBuilder.sendTrx(
79
+ to,
80
+ this.tronWeb.toSun(amount)
81
+ );
82
+ return this.sendTransaction({ tx: { transaction } });
83
+ }
84
+ async transferToken(contractAddress, to, amount) {
85
+ await this.waitForTronWeb();
86
+ const functionSelector = "transfer(address,uint256)";
87
+ const parameter = [{ type: "address", value: to }, { type: "uint256", value: amount }];
88
+ const tx = await this.tronWeb.transactionBuilder.triggerSmartContract(contractAddress, functionSelector, {}, parameter);
89
+ return this.sendTransaction({ tx });
90
+ }
91
+ async getBalance(token, account, options) {
92
+ await this.waitForTronWeb();
93
+ if (token.symbol === "TRX" || token.symbol === "trx" || token.symbol === "native") {
94
+ return await this.getTRXBalance(account, options);
95
+ }
96
+ return await this.getTokenBalance(token.contractAddress, account, options);
97
+ }
98
+ async getTRXBalance(account, options) {
99
+ const { isCatchError = false } = options || {};
100
+ await this.waitForTronWeb();
101
+ try {
102
+ const balance = await this.tronWeb.trx.getBalance(account);
103
+ return balance.toString();
104
+ } catch (error) {
105
+ this.csl("Tron getTRXBalance", "red-500", "Get TRX balance failed: %o", error);
106
+ if (isCatchError) {
107
+ throw error;
108
+ }
109
+ return "0";
110
+ }
111
+ }
112
+ async getTokenBalance(contractAddress, account, options) {
113
+ const { isCatchError = false } = options || {};
114
+ await this.waitForTronWeb();
115
+ try {
116
+ const contract = await this.tronWeb.contract().at(contractAddress);
117
+ const balance = await contract.balanceOf(account).call();
118
+ return balance.toString();
119
+ } catch (error) {
120
+ this.csl("Tron getTokenBalance", "red-500", "Get token balance failed: %o", error);
121
+ if (isCatchError) {
122
+ throw error;
123
+ }
124
+ return "0";
125
+ }
126
+ }
127
+ async balanceOf(token, account, options) {
128
+ return await this.getBalance(token, account, options);
129
+ }
130
+ /**
131
+ * Estimate gas limit for transfer transaction
132
+ * @param data Transfer data
133
+ * @returns Gas limit estimate (bandwidth or energy), gas price, and estimated gas cost
134
+ */
135
+ async estimateTransferGas(data) {
136
+ const { fromToken } = data;
137
+ const originAsset = fromToken.contractAddress;
138
+ let gasLimit;
139
+ if (originAsset === "TRX" || originAsset === "trx") {
140
+ gasLimit = 268n;
141
+ } else {
142
+ gasLimit = 30000n;
143
+ }
144
+ gasLimit = gasLimit * 120n / 100n;
145
+ let gasPrice = 100n;
146
+ const estimateGas = gasLimit * gasPrice;
147
+ return {
148
+ gasLimit,
149
+ gasPrice,
150
+ estimateGas
151
+ };
152
+ }
153
+ async getEstimateGas(params) {
154
+ const { gasLimit, price, nativeToken } = params;
155
+ const energyPrice = BigInt(100);
156
+ const estimateGas = Big__default.default(gasLimit.toString()).times(energyPrice.toString());
157
+ const estimateGasAmount = Big__default.default(estimateGas).div(10 ** nativeToken.decimals);
158
+ const estimateGasUsd = Big__default.default(estimateGasAmount).times(price || 1);
159
+ return {
160
+ gasPrice: energyPrice,
161
+ usd: core.numberRemoveEndZero(Big__default.default(estimateGasUsd).toFixed(20)),
162
+ wei: BigInt(estimateGas.toFixed(0)),
163
+ amount: core.numberRemoveEndZero(Big__default.default(estimateGasAmount).toFixed(nativeToken.decimals))
164
+ };
165
+ }
166
+ async estimateTransaction(params) {
167
+ const {
168
+ dry,
169
+ transactionParams,
170
+ fromToken,
171
+ prices,
172
+ defaultEnergyUsed,
173
+ defaultRawDataHexLength,
174
+ buffer
175
+ } = params;
176
+ const nativeTokenPrice = core.getPrice(prices, fromToken.nativeToken.symbol);
177
+ let energyUsed = defaultEnergyUsed || 2e5;
178
+ let rawDataHexLength = defaultRawDataHexLength || 1e3;
179
+ try {
180
+ const transaction = await this.tronWeb.transactionBuilder.triggerConstantContract(...transactionParams);
181
+ energyUsed = transaction.energy_used || 2e5;
182
+ rawDataHexLength = transaction.transaction.raw_data_hex.length || 1e3;
183
+ } catch (error) {
184
+ this.csl("Usdt0 Tron", "red-500", "estimateTransaction triggerConstantContract error: %o, action: %o", error, transactionParams?.[1]);
185
+ }
186
+ const bandwidthAmount = Big__default.default(Big__default.default(rawDataHexLength).div(2).plus(bridges.DATA_HEX_PROTOBUF_EXTRA).plus(bridges.SIGNATURE_SIZE)).times(1e-3);
187
+ const bandwidthUsed = Big__default.default(bandwidthAmount).div(100).times(10 ** fromToken.nativeToken.decimals);
188
+ let totalUsed = Big__default.default(energyUsed).plus(bandwidthUsed);
189
+ if (buffer) {
190
+ totalUsed = Big__default.default(totalUsed).times(Big__default.default(1).plus(buffer));
191
+ }
192
+ const { usd, wei } = await this.getEstimateGas({
193
+ gasLimit: totalUsed.toFixed(0),
194
+ price: nativeTokenPrice,
195
+ nativeToken: fromToken.nativeToken
196
+ });
197
+ const result = {
198
+ estimateSourceGasLimit: energyUsed,
199
+ estimateSourceGas: wei,
200
+ estimateSourceGasUsd: usd
201
+ };
202
+ return result;
203
+ }
204
+ async estimateApprove(params) {
205
+ const {
206
+ dry,
207
+ spender,
208
+ amountWei,
209
+ fromToken,
210
+ prices
211
+ } = params;
212
+ const approveParams = [
213
+ fromToken.contractAddress,
214
+ "approve(address,uint256)",
215
+ {},
216
+ [
217
+ { type: "address", value: spender },
218
+ { type: "uint256", value: amountWei }
219
+ ]
220
+ ];
221
+ return this.estimateTransaction({
222
+ dry,
223
+ transactionParams: approveParams,
224
+ fromToken,
225
+ prices,
226
+ defaultEnergyUsed: 1e5,
227
+ defaultRawDataHexLength: 500,
228
+ // +10%
229
+ buffer: 0.1
230
+ });
231
+ }
232
+ async pollingTransactionStatus(txHash, options) {
233
+ await this.waitForTronWeb();
234
+ const { maxPolls = 60, pollInterval = 2e3, isTRX } = options || {};
235
+ let pollCount = 0;
236
+ return new Promise((resolve) => {
237
+ const poll = async () => {
238
+ pollCount++;
239
+ this.csl("TronWallet pollingTransactionStatus", "teal-400", "polling transaction status (%s), %d times", txHash, pollCount);
240
+ try {
241
+ const txInfo = await this.tronWeb.trx.getTransactionInfo(txHash);
242
+ this.csl("TronWallet pollingTransactionStatus", "teal-400", "transaction info (%s): %o", txHash, txInfo);
243
+ if (txInfo && txInfo.receipt) {
244
+ if (isTRX) {
245
+ resolve(true);
246
+ return;
247
+ }
248
+ const result = txInfo.receipt.result;
249
+ if (result === "SUCCESS") {
250
+ this.csl("TronWallet pollingTransactionStatus", "teal-400", "transaction success (%s)", txHash);
251
+ resolve(true);
252
+ return;
253
+ } else if (result === "FAILED" || result === "REVERT") {
254
+ this.csl("TronWallet pollingTransactionStatus", "red-500", "transaction failed (%s), result: %s", txHash, result);
255
+ resolve(false);
256
+ return;
257
+ } else {
258
+ this.csl("TronWallet pollingTransactionStatus", "teal-400", "unknown transaction status (%s), result: %s, continue polling...", txHash, result);
259
+ }
260
+ } else {
261
+ this.csl("TronWallet pollingTransactionStatus", "teal-400", "transaction not confirmed (%s), continue polling...", txHash);
262
+ }
263
+ } catch (error) {
264
+ const errorMessage = error?.message || String(error);
265
+ if (errorMessage.includes("not found") || errorMessage.includes("does not exist") || errorMessage.includes("not exist")) {
266
+ this.csl("TronWallet pollingTransactionStatus", "teal-400", "transaction not on-chain (%s), continue polling...", txHash);
267
+ } else {
268
+ console.warn(`query transaction status error (${txHash}): %o`, errorMessage);
269
+ }
270
+ }
271
+ if (pollCount >= maxPolls) {
272
+ console.error(`polling timeout (${txHash}), maximum polling times reached: ${maxPolls}`);
273
+ resolve(false);
274
+ return;
275
+ }
276
+ setTimeout(poll, pollInterval);
277
+ };
278
+ poll();
279
+ });
280
+ }
281
+ async checkTransactionStatus(txHash) {
282
+ await this.waitForTronWeb();
283
+ try {
284
+ const txInfo = await this.tronWeb.trx.getTransactionInfo(txHash);
285
+ if (txInfo && txInfo.receipt) {
286
+ return txInfo.receipt.result === "SUCCESS";
287
+ }
288
+ return false;
289
+ } catch (error) {
290
+ return false;
291
+ }
292
+ }
293
+ async getTransactionResult(txHash) {
294
+ await this.waitForTronWeb();
295
+ try {
296
+ const txInfo = await this.tronWeb.trx.getTransactionInfo(txHash);
297
+ return txInfo;
298
+ } catch (error) {
299
+ return {};
300
+ }
301
+ }
302
+ async allowance(params) {
303
+ const {
304
+ dry,
305
+ contractAddress,
306
+ spender,
307
+ address,
308
+ amountWei,
309
+ strict = false
310
+ } = params;
311
+ const contract = await this.tronWeb.contract().at(contractAddress);
312
+ if (dry) {
313
+ return {
314
+ contract,
315
+ allowance: "0",
316
+ needApprove: false
317
+ };
318
+ }
319
+ await this.waitForTronWeb();
320
+ try {
321
+ let allowance = "0";
322
+ try {
323
+ const allowanceResult = await contract.allowance(address, spender).call();
324
+ allowance = allowanceResult.toString();
325
+ } catch (error) {
326
+ this.csl("TronWallet allowance", "red-500", "Error getting allowance: %o", error);
327
+ if (strict) {
328
+ throw error;
329
+ }
330
+ }
331
+ return {
332
+ contract,
333
+ allowance,
334
+ needApprove: Big__default.default(amountWei || 0).gt(allowance || 0)
335
+ };
336
+ } catch (error) {
337
+ this.csl("TronWallet allowance", "red-500", "Error in allowance: %o", error);
338
+ if (strict) {
339
+ throw error;
340
+ }
341
+ return {
342
+ contract: null,
343
+ allowance: "0",
344
+ needApprove: true
345
+ };
346
+ }
347
+ }
348
+ async approve(params) {
349
+ const {
350
+ contractAddress,
351
+ spender,
352
+ amountWei,
353
+ isApproveMax = false,
354
+ isDetails = false,
355
+ isWaitTxReceipt = true
356
+ } = params;
357
+ await this.waitForTronWeb();
358
+ const detailResult = {
359
+ success: false,
360
+ data: {},
361
+ message: null
362
+ };
363
+ try {
364
+ let _amountWei = amountWei;
365
+ if (isApproveMax) {
366
+ _amountWei = "115792089237316195423570985008687907853269984665640564039457584007913129639935";
367
+ }
368
+ const functionSelector = "approve(address,uint256)";
369
+ const parameter = [
370
+ { type: "address", value: spender },
371
+ { type: "uint256", value: _amountWei }
372
+ ];
373
+ const tx = await this.tronWeb.transactionBuilder.triggerSmartContract(
374
+ contractAddress,
375
+ functionSelector,
376
+ {},
377
+ parameter
378
+ );
379
+ const txHash = await this.sendTransaction({ tx });
380
+ let txInfo = null;
381
+ if (isWaitTxReceipt) {
382
+ const pollingResult = await this.pollingTransactionStatus(txHash, {
383
+ maxPolls: 120,
384
+ pollInterval: 2e3
385
+ });
386
+ if (!pollingResult) {
387
+ this.csl("TronWallet approve", "red-500", "Failed polling approve transaction status");
388
+ if (isDetails) {
389
+ detailResult.message = "Failed to get approve result";
390
+ return detailResult;
391
+ }
392
+ return false;
393
+ }
394
+ txInfo = await this.getTransactionResult(txHash);
395
+ }
396
+ if (isDetails) {
397
+ const txReceipt = txInfo?.receipt;
398
+ detailResult.success = true;
399
+ detailResult.data = {
400
+ txHash,
401
+ txInfo,
402
+ receiptResult: txReceipt?.result,
403
+ blockNumber: txInfo?.blockNumber,
404
+ blockTimeStamp: txInfo?.blockTimeStamp
405
+ };
406
+ return detailResult;
407
+ }
408
+ return txHash;
409
+ } catch (error) {
410
+ this.csl("TronWallet approve", "red-500", "Error approve: %o", error);
411
+ if (isDetails) {
412
+ detailResult.message = error.message;
413
+ return detailResult;
414
+ }
415
+ return false;
416
+ }
417
+ }
418
+ toBytes32(addr) {
419
+ const hex = this.tronWeb.address.toHex(addr).slice(2);
420
+ return "0x" + hex.padStart(64, "0");
421
+ }
422
+ async quoteOFT(params) {
423
+ const {
424
+ dry,
425
+ abi,
426
+ dstEid,
427
+ recipient,
428
+ amountWei,
429
+ slippageTolerance,
430
+ payInLzToken,
431
+ fromToken,
432
+ toToken,
433
+ prices,
434
+ originLayerzeroAddress,
435
+ destinationLayerzeroAddress,
436
+ excludeFees,
437
+ refundTo,
438
+ multiHopComposer,
439
+ isMultiHopComposer,
440
+ isOriginLegacy,
441
+ isDestinationLegacy,
442
+ originLayerzero,
443
+ destinationLayerzero
444
+ } = params;
445
+ const { Options } = await import('@layerzerolabs/lz-v2-utilities');
446
+ const result = {
447
+ needApprove: false,
448
+ approveSpender: originLayerzeroAddress,
449
+ sendParam: void 0,
450
+ quoteParam: {
451
+ ...params,
452
+ originLayerzeroAddress,
453
+ destinationLayerzeroAddress
454
+ },
455
+ fees: {},
456
+ totalFeesUsd: void 0,
457
+ estimateSourceGas: void 0,
458
+ totalEstimateSourceGas: 0n,
459
+ estimateSourceGasUsd: void 0,
460
+ estimateTime: 0,
461
+ // seconds - dynamically calculated using LayerZero formula
462
+ outputAmount: core.numberRemoveEndZero(Big__default.default(amountWei || 0).div(10 ** params.fromToken.decimals).toFixed(params.fromToken.decimals, 0))
463
+ };
464
+ const execTime = new core.ExecTime({ type: "USDT0 Tron", logStyle: "indigo-300", isDebug: core.OpenAPI.DEBUG });
465
+ await this.waitForTronWeb();
466
+ execTime.log("waitForTronWeb");
467
+ execTime.breakpoint();
468
+ const oftContract = await this.tronWeb.contract(abi, originLayerzeroAddress);
469
+ execTime.log("tronWeb.contract originLayerzeroAddress");
470
+ execTime.breakpoint();
471
+ const userAddress = refundTo || this.tronWeb.defaultAddress.base58;
472
+ const approvalRequired = isOriginLegacy ? originLayerzero.oftLegacyApprovalRequired : originLayerzero.oftApprovalRequired;
473
+ execTime.log("approvalRequired");
474
+ const lzReceiveOptionGas = isDestinationLegacy ? destinationLayerzero.lzReceiveOptionGasLegacy : destinationLayerzero.lzReceiveOptionGas;
475
+ let lzReceiveOptionValue = 0;
476
+ execTime.breakpoint();
477
+ const destATA = await utilsSolana.getDestinationAssociatedTokenAddress({
478
+ recipient,
479
+ toToken
480
+ });
481
+ execTime.log("getDestinationAssociatedTokenAddress");
482
+ if (destATA.needCreateTokenAccount) {
483
+ lzReceiveOptionValue = bridges.LZ_RECEIVE_VALUE[toToken.chainName] || 0;
484
+ }
485
+ let unMultiHopExtraOptions = Options.newOptions().toHex();
486
+ if (!isMultiHopComposer && lzReceiveOptionValue) {
487
+ unMultiHopExtraOptions = Options.newOptions().addExecutorLzReceiveOption(lzReceiveOptionGas, lzReceiveOptionValue).toHex();
488
+ }
489
+ const sendParam = [
490
+ // dstEid
491
+ dstEid,
492
+ // to
493
+ // "0x0000000000000000000000000000000000000000000000000000000000000000",
494
+ core.addressToBytes32(toToken.chainType, recipient),
495
+ // amountLD
496
+ amountWei,
497
+ // minAmountLD
498
+ "0",
499
+ // extraOptions
500
+ unMultiHopExtraOptions,
501
+ // composeMsg
502
+ "0x",
503
+ // oftCmd
504
+ "0x"
505
+ ];
506
+ if (isMultiHopComposer) {
507
+ sendParam[0] = multiHopComposer.eid;
508
+ sendParam[1] = core.addressToBytes32("evm", multiHopComposer.oftMultiHopComposer);
509
+ }
510
+ if (!dry) {
511
+ execTime.breakpoint();
512
+ const oftData = await oftContract.quoteOFT(sendParam).call();
513
+ execTime.log("quoteOFT");
514
+ const [, , oftReceipt] = oftData;
515
+ sendParam[3] = Big__default.default(oftReceipt[1].toString()).times(Big__default.default(1).minus(Big__default.default(slippageTolerance || 0).div(100))).toFixed(0);
516
+ }
517
+ if (isMultiHopComposer) {
518
+ let multiHopExtraOptions = Options.newOptions().toHex();
519
+ if (lzReceiveOptionValue) {
520
+ multiHopExtraOptions = Options.newOptions().addExecutorLzReceiveOption(lzReceiveOptionGas, lzReceiveOptionValue).toHex();
521
+ }
522
+ const composeMsgSendParam = {
523
+ dstEid,
524
+ to: core.addressToBytes32(toToken.chainType, recipient),
525
+ amountLD: sendParam[2],
526
+ minAmountLD: sendParam[3],
527
+ extraOptions: multiHopExtraOptions,
528
+ composeMsg: "0x",
529
+ oftCmd: "0x"
530
+ };
531
+ execTime.breakpoint();
532
+ const hopMsgFee = await bridges.getHopMsgFee({
533
+ sendParam: composeMsgSendParam,
534
+ toToken
535
+ });
536
+ execTime.log("getHopMsgFee");
537
+ sendParam[4] = Options.newOptions().addExecutorComposeOption(0, originLayerzero.composeOptionGas || 8e5, hopMsgFee).toHex();
538
+ const abiCoder = ethers.ethers.AbiCoder.defaultAbiCoder();
539
+ sendParam[5] = abiCoder.encode(
540
+ ["tuple(uint32 dstEid, bytes32 to, uint256 amountLD, uint256 minAmountLD, bytes extraOptions, bytes composeMsg, bytes oftCmd)"],
541
+ [Object.values(composeMsgSendParam)]
542
+ );
543
+ }
544
+ execTime.breakpoint();
545
+ const mergedCalls = [
546
+ oftContract.quoteSend(sendParam, payInLzToken).call()
547
+ ];
548
+ if (approvalRequired) {
549
+ mergedCalls.push(
550
+ this.allowance({
551
+ dry,
552
+ contractAddress: fromToken.contractAddress,
553
+ spender: originLayerzeroAddress,
554
+ address: userAddress,
555
+ amountWei
556
+ })
557
+ );
558
+ }
559
+ const [msgFee, allowanceResult] = await Promise.all(mergedCalls);
560
+ if (approvalRequired) {
561
+ result.needApprove = allowanceResult.needApprove;
562
+ }
563
+ execTime.log("quoteSend & allowance", "allowanceResult: %o", allowanceResult);
564
+ let nativeMsgFee = msgFee[0]["nativeFee"];
565
+ this.csl("Tron quoteOFT", "red-600", "nativeFee: %o", nativeMsgFee);
566
+ if (nativeMsgFee) {
567
+ nativeMsgFee = BigInt(Big__default.default(nativeMsgFee.toString()).times(Number(utilsEvm.NATIVE_MSG_FEE_BUFFER) / 100).toFixed(0));
568
+ }
569
+ this.csl("Tron quoteOFT", "red-600", "nativeFee after buffer: %o", nativeMsgFee);
570
+ result.totalEstimateSourceGas = nativeMsgFee;
571
+ this.csl("TronWallet quoteOFT", "teal-400", "MsgFee: %o", msgFee);
572
+ result.sendParam = {
573
+ param: [
574
+ // sendParam
575
+ sendParam,
576
+ // feeParam
577
+ [
578
+ // nativeFee
579
+ nativeMsgFee.toString(),
580
+ // lzTokenFee
581
+ msgFee[0]["lzTokenFee"].toString()
582
+ ],
583
+ // refundAddress
584
+ refundTo
585
+ ],
586
+ options: { callValue: nativeMsgFee.toString() }
587
+ };
588
+ const nativeFeeUsd = Big__default.default(nativeMsgFee?.toString() || 0).div(10 ** fromToken.nativeToken.decimals).times(core.getPrice(prices, fromToken.nativeToken.symbol));
589
+ result.fees.nativeFee = core.numberRemoveEndZero(Big__default.default(nativeMsgFee?.toString() || 0).div(10 ** fromToken.nativeToken.decimals).toFixed(fromToken.nativeToken.decimals));
590
+ result.fees.nativeFeeUsd = core.numberRemoveEndZero(Big__default.default(nativeFeeUsd).toFixed(20));
591
+ result.fees.lzTokenFeeUsd = core.numberRemoveEndZero(Big__default.default(msgFee[0]["lzTokenFee"]?.toString() || 0).div(10 ** fromToken.decimals).toFixed(20));
592
+ if (isOriginLegacy || isDestinationLegacy) {
593
+ result.fees.legacyMeshFeeUsd = core.numberRemoveEndZero(Big__default.default(amountWei || 0).div(10 ** fromToken.decimals).times(bridges.USDT0_LEGACY_MESH_TRANSFTER_FEE).toFixed(fromToken.decimals));
594
+ result.outputAmount = core.numberRemoveEndZero(Big__default.default(Big__default.default(amountWei || 0).div(10 ** params.fromToken.decimals)).minus(result.fees.legacyMeshFeeUsd || 0).toFixed(params.fromToken.decimals, 0));
595
+ }
596
+ const transactionParams = [
597
+ originLayerzeroAddress,
598
+ "send((uint32,bytes32,uint256,uint256,bytes,bytes,bytes),(uint256,uint256),address)",
599
+ result.sendParam.options,
600
+ [
601
+ {
602
+ type: "tuple(uint32,bytes32,uint256,uint256,bytes,bytes,bytes)",
603
+ value: result.sendParam.param[0]
604
+ },
605
+ {
606
+ type: "tuple(uint256,uint256)",
607
+ value: result.sendParam.param[1]
608
+ },
609
+ {
610
+ type: "address",
611
+ value: result.sendParam.param[2]
612
+ }
613
+ ],
614
+ this.tronWeb.defaultAddress.base58 || refundTo
615
+ ];
616
+ if (!dry) {
617
+ execTime.breakpoint();
618
+ const tx = await this.tronWeb.transactionBuilder.triggerSmartContract(...transactionParams);
619
+ execTime.log("transactionBuilder.triggerSmartContract");
620
+ result.sendParam.tx = tx;
621
+ }
622
+ execTime.breakpoint();
623
+ const ett = await this.estimateTransaction({
624
+ dry,
625
+ transactionParams,
626
+ fromToken,
627
+ prices,
628
+ defaultEnergyUsed: 3e5,
629
+ defaultRawDataHexLength: 1e3
630
+ });
631
+ execTime.log("estimateTransaction");
632
+ result.fees.estimateGasUsd = ett.estimateSourceGasUsd;
633
+ result.estimateSourceGas = ett.estimateSourceGas;
634
+ result.totalEstimateSourceGas += ett.estimateSourceGas;
635
+ result.estimateSourceGasUsd = ett.estimateSourceGasUsd;
636
+ if (result.needApprove) {
637
+ execTime.breakpoint();
638
+ const estApproveGas = await this.estimateApprove({
639
+ dry,
640
+ amountWei,
641
+ spender: result.approveSpender,
642
+ fromToken,
643
+ prices
644
+ });
645
+ result.estimateApproveGas = estApproveGas.estimateSourceGas;
646
+ execTime.log("estimateApprove");
647
+ }
648
+ for (const feeKey in result.fees) {
649
+ if (excludeFees.includes(feeKey) || !/Usd$/.test(feeKey)) {
650
+ continue;
651
+ }
652
+ result.totalFeesUsd = Big__default.default(result.totalFeesUsd || 0).plus(result.fees[feeKey] || 0);
653
+ }
654
+ result.totalFeesUsd = core.numberRemoveEndZero(Big__default.default(result.totalFeesUsd).toFixed(20));
655
+ result.sendParam.transactionParams = transactionParams;
656
+ execTime.log("quoteOFT");
657
+ return result;
658
+ }
659
+ async sendTransaction(params) {
660
+ const {
661
+ tx
662
+ } = params;
663
+ const transaction = tx?.transaction;
664
+ if (!transaction?.raw_data) {
665
+ throw new Error("Invalid transaction");
666
+ }
667
+ this.csl("Tron sendTransaction", "red-400", "transaction: %o", transaction);
668
+ const startTimestamp = Date.now();
669
+ const expirationDuration = 5 * 60 * 1e3;
670
+ const expiration = startTimestamp + expirationDuration;
671
+ let transactionWithExpiration = {
672
+ ...transaction,
673
+ raw_data: {
674
+ ...transaction.raw_data,
675
+ expiration
676
+ }
677
+ };
678
+ try {
679
+ await this.waitForTronWeb();
680
+ transactionWithExpiration = await this.tronWeb.transactionBuilder.newTxID(transactionWithExpiration, { txLocal: true });
681
+ } catch (error) {
682
+ console.warn("Failed to refresh transaction ID after extending expiration:", error);
683
+ }
684
+ this.csl("Tron sendTransaction", "red-400", "override transaction: %o", transactionWithExpiration);
685
+ const result = await this.signAndSendTransaction(transactionWithExpiration);
686
+ this.csl("Tron sendTransaction", "red-400", "Transaction sent with result: %o", result);
687
+ if (typeof result === "object") {
688
+ const code = result.code ? String(result.code) : "";
689
+ const message = result.message ? String(result.message) : "";
690
+ const combined = `${code} ${message}`.toUpperCase();
691
+ if (combined.includes("TRANSACTION_EXPIRATION_ERROR") || combined.includes("TRANSACTION_EXPIRED") || combined.includes("EXPIRED")) {
692
+ throw new Error("Transaction expired. Try again.");
693
+ }
694
+ }
695
+ this.csl("Tron sendTransaction", "red-400", "success: %o", result);
696
+ if (typeof result === "string") {
697
+ return result;
698
+ }
699
+ return result?.txid || result?.txID || transactionWithExpiration.txID;
700
+ }
701
+ /**
702
+ * Unified quote method that routes to specific quote methods based on type
703
+ * @param type Service type from Service
704
+ * @param params Parameters for the quote
705
+ */
706
+ async quote(type, params) {
707
+ switch (type) {
708
+ case core.Service.Usdt0:
709
+ return await this.quoteOFT(params);
710
+ case core.Service.OneClick:
711
+ return await this.quoteOneClickProxy(params);
712
+ default:
713
+ throw new Error(`Unsupported quote type: ${type}`);
714
+ }
715
+ }
716
+ /**
717
+ * Unified send method that routes to specific send methods based on type
718
+ * @param type Send type from SendType enum
719
+ * @param params Parameters for the send transaction
720
+ */
721
+ async send(type, params) {
722
+ switch (type) {
723
+ case core.SendType.SEND:
724
+ return await this.sendTransaction(params);
725
+ case core.SendType.TRANSFER:
726
+ return await this.transfer(params);
727
+ default:
728
+ throw new Error(`Unsupported send type: ${type}`);
729
+ }
730
+ }
731
+ async quoteOneClickProxy(params) {
732
+ const {
733
+ dry,
734
+ proxyAddress,
735
+ abi,
736
+ fromToken,
737
+ refundTo,
738
+ depositAddress,
739
+ amountWei,
740
+ prices
741
+ } = params;
742
+ const result = { fees: {} };
743
+ const execTime = new core.ExecTime({ type: "Oneclick Tron", logStyle: "indigo-400", isDebug: core.OpenAPI.DEBUG });
744
+ await this.waitForTronWeb();
745
+ execTime.log("waitForTronWeb");
746
+ const userAddress = refundTo || this.tronWeb.defaultAddress.base58;
747
+ execTime.breakpoint();
748
+ const allowance = await this.allowance({
749
+ dry,
750
+ contractAddress: fromToken.contractAddress,
751
+ address: userAddress,
752
+ spender: proxyAddress,
753
+ amountWei
754
+ });
755
+ result.needApprove = allowance.needApprove;
756
+ result.approveSpender = proxyAddress;
757
+ execTime.log("allowance");
758
+ const proxyParam = [
759
+ // tokenAddress
760
+ fromToken.contractAddress,
761
+ // recipient
762
+ depositAddress,
763
+ // amount
764
+ amountWei
765
+ ];
766
+ result.sendParam = {
767
+ param: proxyParam
768
+ };
769
+ const transactionParams = [
770
+ proxyAddress,
771
+ "proxyTransfer(address,address,uint256)",
772
+ {},
773
+ [
774
+ {
775
+ type: "address",
776
+ value: result.sendParam.param[0]
777
+ // tokenAddress
778
+ },
779
+ {
780
+ type: "address",
781
+ value: result.sendParam.param[1]
782
+ // recipient
783
+ },
784
+ {
785
+ type: "uint256",
786
+ value: result.sendParam.param[2]
787
+ // amount
788
+ }
789
+ ],
790
+ this.tronWeb.defaultAddress.base58 || refundTo
791
+ ];
792
+ execTime.breakpoint();
793
+ const tx = await this.tronWeb.transactionBuilder.triggerSmartContract(...transactionParams);
794
+ execTime.log("transactionBuilder.triggerSmartContract");
795
+ result.sendParam.tx = tx;
796
+ execTime.breakpoint();
797
+ const ett = await this.estimateTransaction({
798
+ dry,
799
+ transactionParams,
800
+ fromToken,
801
+ prices,
802
+ defaultEnergyUsed: 2e5,
803
+ defaultRawDataHexLength: 500
804
+ });
805
+ execTime.log("estimateTransaction");
806
+ result.fees.estimateGasUsd = ett.estimateSourceGasUsd;
807
+ result.estimateSourceGas = ett.estimateSourceGas;
808
+ result.totalEstimateSourceGas = ett.estimateSourceGas;
809
+ result.estimateSourceGasUsd = ett.estimateSourceGasUsd;
810
+ if (result.needApprove) {
811
+ execTime.breakpoint();
812
+ const estApproveGas = await this.estimateApprove({
813
+ dry,
814
+ amountWei,
815
+ spender: result.approveSpender,
816
+ fromToken,
817
+ prices
818
+ });
819
+ result.estimateApproveGas = estApproveGas.estimateSourceGas;
820
+ execTime.log("estimateApprove");
821
+ }
822
+ result.sendParam.transactionParams = transactionParams;
823
+ execTime.logTotal("quoteOneClickPorxy");
824
+ return result;
825
+ }
826
+ async getAccountResources(params) {
827
+ const { account } = params;
828
+ const result = {
829
+ energy: 0,
830
+ bandwidth: 0,
831
+ success: false,
832
+ error: "TronWeb is not initialized or the wallet is not connected"
833
+ };
834
+ await this.waitForTronWeb();
835
+ if (!this.tronWeb || !account) {
836
+ return result;
837
+ }
838
+ try {
839
+ let availableEnergy;
840
+ let availableBandwidth;
841
+ try {
842
+ if (this.tronWeb.trx.getAccountResources) {
843
+ const resources = await this.tronWeb.trx.getAccountResources(account);
844
+ this.csl("TronWallet getAccountResources", "teal-400", "resources: %o", resources);
845
+ if (resources) {
846
+ availableEnergy = (resources.EnergyLimit || 0) - (resources.EnergyUsed || 0);
847
+ availableBandwidth = (resources.freeNetLimit || 0) - (resources.freeNetUsed || 0);
848
+ }
849
+ }
850
+ } catch (resourcesErr) {
851
+ console.warn("getAccountResources API is not available, try other way:", resourcesErr);
852
+ }
853
+ if (availableEnergy === void 0 && availableBandwidth === void 0) {
854
+ const accountInfo = await this.tronWeb.trx.getAccount(account);
855
+ if (accountInfo.account_resource) {
856
+ const accountResource = accountInfo.account_resource;
857
+ availableEnergy = (accountResource.EnergyLimit || 0) - (accountResource.EnergyUsed || 0);
858
+ availableBandwidth = (accountResource.NetLimit || 0) - (accountResource.NetUsed || 0);
859
+ } else if (accountInfo.energy !== void 0) {
860
+ availableEnergy = accountInfo.energy || 0;
861
+ }
862
+ if (accountInfo.bandwidth !== void 0) {
863
+ if (typeof accountInfo.bandwidth === "number") {
864
+ availableBandwidth = accountInfo.bandwidth;
865
+ } else if (accountInfo.bandwidth) {
866
+ availableBandwidth = accountInfo.bandwidth.available || accountInfo.bandwidth.freeNetUsage || 0;
867
+ }
868
+ }
869
+ }
870
+ result.energy = Math.max(0, availableEnergy);
871
+ result.bandwidth = Math.max(0, availableBandwidth);
872
+ result.success = true;
873
+ result.error = null;
874
+ } catch (error) {
875
+ console.error("Failed to get account resources:", error);
876
+ }
877
+ return result;
878
+ }
879
+ };
880
+
881
+ exports.TronWallet = TronWallet;
882
+ exports.default = TronWallet;
883
+ //# sourceMappingURL=index.js.map
884
+ //# sourceMappingURL=index.js.map