@xchainjs/xchain-tron 2.0.0
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/LICENSE +21 -0
- package/README.md +35 -0
- package/lib/client.d.ts +153 -0
- package/lib/clientKeystore.d.ts +22 -0
- package/lib/const.d.ts +22 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.esm.js +1024 -0
- package/lib/index.esm.js.map +1 -0
- package/lib/index.js +1045 -0
- package/lib/index.js.map +1 -0
- package/lib/types.d.ts +38 -0
- package/lib/utils/index.d.ts +3 -0
- package/lib/utils/trongrid/index.d.ts +2 -0
- package/lib/utils/trongrid/trongrid.d.ts +57 -0
- package/lib/utils/trongrid/types.d.ts +137 -0
- package/package.json +47 -0
package/lib/index.esm.js
ADDED
|
@@ -0,0 +1,1024 @@
|
|
|
1
|
+
import { HDKey } from '@scure/bip32';
|
|
2
|
+
import { mnemonicToSeedSync } from '@scure/bip39';
|
|
3
|
+
import TW, { TronWeb } from 'tronweb';
|
|
4
|
+
import { ExplorerProvider, Network, TxType, BaseXChainClient, FeeType } from '@xchainjs/xchain-client';
|
|
5
|
+
import { AssetType, baseAmount } from '@xchainjs/xchain-util';
|
|
6
|
+
|
|
7
|
+
/******************************************************************************
|
|
8
|
+
Copyright (c) Microsoft Corporation.
|
|
9
|
+
|
|
10
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
11
|
+
purpose with or without fee is hereby granted.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
14
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
15
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
16
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
17
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
18
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
19
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
20
|
+
***************************************************************************** */
|
|
21
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
25
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
26
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
27
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
28
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
29
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
30
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
35
|
+
var e = new Error(message);
|
|
36
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const TRX_DECIMAL = 6;
|
|
40
|
+
const TRON_DERIVATION_PATH = "m/44'/195'/0'/0/";
|
|
41
|
+
/**
|
|
42
|
+
* Chain identifier for Tron mainnet
|
|
43
|
+
*/
|
|
44
|
+
const TRONChain = 'TRON';
|
|
45
|
+
const AssetTRX = {
|
|
46
|
+
chain: TRONChain,
|
|
47
|
+
symbol: 'TRX',
|
|
48
|
+
ticker: 'TRX',
|
|
49
|
+
type: AssetType.NATIVE,
|
|
50
|
+
};
|
|
51
|
+
const AssetTRONUSDT = {
|
|
52
|
+
chain: TRONChain,
|
|
53
|
+
symbol: 'USDT-TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
|
|
54
|
+
ticker: 'USDT',
|
|
55
|
+
type: AssetType.TOKEN,
|
|
56
|
+
};
|
|
57
|
+
// Explorer providers for Tron
|
|
58
|
+
const TRON_MAINNET_EXPLORER = new ExplorerProvider('https://tronscan.org/', 'https://tronscan.org/#/address/%%ADDRESS%%', 'https://tronscan.org/#/transaction/%%TX_ID%%');
|
|
59
|
+
const TRON_TESTNET_EXPLORER = new ExplorerProvider('https://nile.tronscan.org/', 'https://nile.tronscan.org/accounts/%%ADDRESS%%', 'https://nile.tronscan.org/transactions/%%TX_ID%%');
|
|
60
|
+
const TRON_DEFAULT_RPC = 'https://tron-rpc.publicnode.com';
|
|
61
|
+
const tronExplorerProviders = {
|
|
62
|
+
[Network.Mainnet]: TRON_MAINNET_EXPLORER,
|
|
63
|
+
[Network.Stagenet]: TRON_MAINNET_EXPLORER,
|
|
64
|
+
[Network.Testnet]: TRON_TESTNET_EXPLORER,
|
|
65
|
+
};
|
|
66
|
+
const TRX_TRANSFER_BANDWIDTH = 268; // Bandwidth consumed by a TRX transfer
|
|
67
|
+
const TRC20_TRANSFER_ENERGY = 13000; // Average energy consumed by TRC20 transfer
|
|
68
|
+
const TRC20_TRANSFER_BANDWIDTH = 345; // Bandwidth consumed by TRC20 transfer
|
|
69
|
+
const TRON_USDT_CONTRACT = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';
|
|
70
|
+
const MAX_APPROVAL = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
|
|
71
|
+
const TRX_FEE_LIMIT = 100000000;
|
|
72
|
+
|
|
73
|
+
const validateAddress = (address) => {
|
|
74
|
+
return TronWeb.isAddress(address);
|
|
75
|
+
};
|
|
76
|
+
const getTRC20AssetContractAddress = (asset) => {
|
|
77
|
+
try {
|
|
78
|
+
return asset.symbol.slice(asset.ticker.length + 1);
|
|
79
|
+
}
|
|
80
|
+
catch (_err) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
var trc20ABI = [
|
|
86
|
+
{
|
|
87
|
+
constant: true,
|
|
88
|
+
inputs: [
|
|
89
|
+
{
|
|
90
|
+
name: "_owner",
|
|
91
|
+
type: "address"
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
name: "balanceOf",
|
|
95
|
+
outputs: [
|
|
96
|
+
{
|
|
97
|
+
name: "balance",
|
|
98
|
+
type: "uint256"
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
stateMutability: "view",
|
|
102
|
+
type: "function"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
constant: false,
|
|
106
|
+
inputs: [
|
|
107
|
+
{
|
|
108
|
+
name: "_to",
|
|
109
|
+
type: "address"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: "_value",
|
|
113
|
+
type: "uint256"
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
name: "transfer",
|
|
117
|
+
outputs: [
|
|
118
|
+
{
|
|
119
|
+
name: "success",
|
|
120
|
+
type: "bool"
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
stateMutability: "nonpayable",
|
|
124
|
+
type: "function"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
constant: true,
|
|
128
|
+
inputs: [
|
|
129
|
+
],
|
|
130
|
+
name: "decimals",
|
|
131
|
+
outputs: [
|
|
132
|
+
{
|
|
133
|
+
name: "",
|
|
134
|
+
type: "uint8"
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
stateMutability: "view",
|
|
138
|
+
type: "function"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
constant: true,
|
|
142
|
+
inputs: [
|
|
143
|
+
],
|
|
144
|
+
name: "symbol",
|
|
145
|
+
outputs: [
|
|
146
|
+
{
|
|
147
|
+
name: "",
|
|
148
|
+
type: "string"
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
stateMutability: "view",
|
|
152
|
+
type: "function"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
constant: true,
|
|
156
|
+
inputs: [
|
|
157
|
+
],
|
|
158
|
+
name: "name",
|
|
159
|
+
outputs: [
|
|
160
|
+
{
|
|
161
|
+
name: "",
|
|
162
|
+
type: "string"
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
stateMutability: "view",
|
|
166
|
+
type: "function"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
constant: true,
|
|
170
|
+
inputs: [
|
|
171
|
+
{
|
|
172
|
+
name: "_owner",
|
|
173
|
+
type: "address"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "_spender",
|
|
177
|
+
type: "address"
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
name: "allowance",
|
|
181
|
+
outputs: [
|
|
182
|
+
{
|
|
183
|
+
name: "remaining",
|
|
184
|
+
type: "uint256"
|
|
185
|
+
}
|
|
186
|
+
],
|
|
187
|
+
stateMutability: "view",
|
|
188
|
+
type: "function"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
constant: false,
|
|
192
|
+
inputs: [
|
|
193
|
+
{
|
|
194
|
+
name: "_spender",
|
|
195
|
+
type: "address"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: "_value",
|
|
199
|
+
type: "uint256"
|
|
200
|
+
}
|
|
201
|
+
],
|
|
202
|
+
name: "approve",
|
|
203
|
+
outputs: [
|
|
204
|
+
{
|
|
205
|
+
name: "success",
|
|
206
|
+
type: "bool"
|
|
207
|
+
}
|
|
208
|
+
],
|
|
209
|
+
stateMutability: "nonpayable",
|
|
210
|
+
type: "function"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
constant: true,
|
|
214
|
+
inputs: [
|
|
215
|
+
],
|
|
216
|
+
name: "totalSupply",
|
|
217
|
+
outputs: [
|
|
218
|
+
{
|
|
219
|
+
name: "",
|
|
220
|
+
type: "uint256"
|
|
221
|
+
}
|
|
222
|
+
],
|
|
223
|
+
stateMutability: "view",
|
|
224
|
+
type: "function"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
constant: false,
|
|
228
|
+
inputs: [
|
|
229
|
+
{
|
|
230
|
+
name: "_from",
|
|
231
|
+
type: "address"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
name: "_to",
|
|
235
|
+
type: "address"
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: "_value",
|
|
239
|
+
type: "uint256"
|
|
240
|
+
}
|
|
241
|
+
],
|
|
242
|
+
name: "transferFrom",
|
|
243
|
+
outputs: [
|
|
244
|
+
{
|
|
245
|
+
name: "success",
|
|
246
|
+
type: "bool"
|
|
247
|
+
}
|
|
248
|
+
],
|
|
249
|
+
stateMutability: "nonpayable",
|
|
250
|
+
type: "function"
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
anonymous: false,
|
|
254
|
+
inputs: [
|
|
255
|
+
{
|
|
256
|
+
indexed: true,
|
|
257
|
+
name: "_from",
|
|
258
|
+
type: "address"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
indexed: true,
|
|
262
|
+
name: "_to",
|
|
263
|
+
type: "address"
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
indexed: false,
|
|
267
|
+
name: "_value",
|
|
268
|
+
type: "uint256"
|
|
269
|
+
}
|
|
270
|
+
],
|
|
271
|
+
name: "Transfer",
|
|
272
|
+
type: "event"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
anonymous: false,
|
|
276
|
+
inputs: [
|
|
277
|
+
{
|
|
278
|
+
indexed: true,
|
|
279
|
+
name: "_owner",
|
|
280
|
+
type: "address"
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
indexed: true,
|
|
284
|
+
name: "_spender",
|
|
285
|
+
type: "address"
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
indexed: false,
|
|
289
|
+
name: "_value",
|
|
290
|
+
type: "uint256"
|
|
291
|
+
}
|
|
292
|
+
],
|
|
293
|
+
name: "Approval",
|
|
294
|
+
type: "event"
|
|
295
|
+
}
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
const TRONGRID_API_BASE_URL = 'https://api.trongrid.io';
|
|
299
|
+
class TronGrid {
|
|
300
|
+
constructor() {
|
|
301
|
+
this.tronWeb = new TronWeb({ fullHost: TRON_DEFAULT_RPC });
|
|
302
|
+
}
|
|
303
|
+
getAccount(address) {
|
|
304
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
305
|
+
try {
|
|
306
|
+
const response = yield fetch(`${TRONGRID_API_BASE_URL}/v1/accounts/${address}`);
|
|
307
|
+
if (!response.ok) {
|
|
308
|
+
throw new Error(`TronGrid API error: ${response.status} ${response.statusText}`);
|
|
309
|
+
}
|
|
310
|
+
const data = (yield response.json());
|
|
311
|
+
if (!(data.success && data.data) || data.data.length === 0) {
|
|
312
|
+
throw new Error('Invalid response from TronGrid API');
|
|
313
|
+
}
|
|
314
|
+
// Convert search address to hex format for comparison
|
|
315
|
+
let searchAddressHex;
|
|
316
|
+
try {
|
|
317
|
+
// If address is base58, convert to hex
|
|
318
|
+
searchAddressHex = TronWeb.address.toHex(address).toLowerCase();
|
|
319
|
+
}
|
|
320
|
+
catch (_a) {
|
|
321
|
+
// If conversion fails, assume it's already hex
|
|
322
|
+
searchAddressHex = address.toLowerCase();
|
|
323
|
+
}
|
|
324
|
+
// Find the account that matches the requested address
|
|
325
|
+
const account = data.data.find((acc) => {
|
|
326
|
+
return acc.address.toLowerCase() === searchAddressHex;
|
|
327
|
+
});
|
|
328
|
+
if (!account) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
return account;
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
throw error;
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
getTransactions(params) {
|
|
339
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
340
|
+
const { address, offset, limit } = params;
|
|
341
|
+
const url = `https://api.trongrid.io/v1/accounts/${address}/transactions?limit=${limit}&start=${offset}`;
|
|
342
|
+
const res = yield fetch(url);
|
|
343
|
+
const { data } = yield res.json();
|
|
344
|
+
const txs = [];
|
|
345
|
+
for (const tx of data) {
|
|
346
|
+
const contract = tx.raw_data.contract[0];
|
|
347
|
+
// Case 1: Native TRX transfer
|
|
348
|
+
if (contract.type === 'TransferContract') {
|
|
349
|
+
const amount = baseAmount(contract.parameter.value.amount, TRX_DECIMAL);
|
|
350
|
+
const from = [{ from: TronWeb.address.fromHex(contract.parameter.value.owner_address), amount }];
|
|
351
|
+
const to = [{ to: TronWeb.address.fromHex(contract.parameter.value.to_address), amount }];
|
|
352
|
+
txs.push({
|
|
353
|
+
asset: AssetTRX,
|
|
354
|
+
type: TxType.Transfer,
|
|
355
|
+
from,
|
|
356
|
+
to,
|
|
357
|
+
date: new Date(tx.block_timestamp),
|
|
358
|
+
hash: tx.txID,
|
|
359
|
+
});
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
// Case 2: TRC20 transfer (TriggerSmartContract)
|
|
363
|
+
if (contract.type === 'TriggerSmartContract') {
|
|
364
|
+
const { contract_address, data: inputData, owner_address } = contract.parameter.value;
|
|
365
|
+
// `inputData` starts with 4-byte method selector (transfer(address,uint256))
|
|
366
|
+
// and then encoded params
|
|
367
|
+
try {
|
|
368
|
+
const decoded = TW.utils.abi.decodeParams(['_to', '_value'], // parameter names
|
|
369
|
+
['address', 'uint256'], // parameter types
|
|
370
|
+
inputData, // full input data (with selector)
|
|
371
|
+
true);
|
|
372
|
+
const toAddress = decoded._to;
|
|
373
|
+
const fromAddress = TronWeb.address.fromHex(owner_address);
|
|
374
|
+
const rawValue = decoded._value.toString();
|
|
375
|
+
// Get token contract instance
|
|
376
|
+
const contractHex = TronWeb.address.fromHex(contract_address);
|
|
377
|
+
const tokenContract = yield this.tronWeb.contract().at(contractHex);
|
|
378
|
+
// Call symbol() and decimals()
|
|
379
|
+
const symbol = yield tokenContract.symbol().call();
|
|
380
|
+
const decimals = yield tokenContract.decimals().call();
|
|
381
|
+
const amount = baseAmount(rawValue, decimals);
|
|
382
|
+
const from = [{ from: fromAddress, amount }];
|
|
383
|
+
const to = [{ to: toAddress, amount }];
|
|
384
|
+
const asset = {
|
|
385
|
+
chain: 'TRON',
|
|
386
|
+
symbol: `${symbol}-${contract_address}`,
|
|
387
|
+
ticker: symbol,
|
|
388
|
+
type: AssetType.TOKEN,
|
|
389
|
+
};
|
|
390
|
+
txs.push({
|
|
391
|
+
asset,
|
|
392
|
+
type: TxType.Transfer,
|
|
393
|
+
from,
|
|
394
|
+
to,
|
|
395
|
+
date: new Date(tx.block_timestamp),
|
|
396
|
+
hash: tx.txID,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
catch (_e) {
|
|
400
|
+
// Not an ERC20 transfer (could be another contract call)
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return {
|
|
406
|
+
total: txs.length,
|
|
407
|
+
txs,
|
|
408
|
+
};
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
getTransactionData(txId) {
|
|
412
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
413
|
+
var _a, _b, _c;
|
|
414
|
+
const url = `${TRONGRID_API_BASE_URL}/walletsolidity/gettransactionbyid`;
|
|
415
|
+
const res = yield fetch(url, {
|
|
416
|
+
method: 'POST',
|
|
417
|
+
headers: { 'Content-Type': 'application/json' },
|
|
418
|
+
body: JSON.stringify({ value: txId }),
|
|
419
|
+
});
|
|
420
|
+
const tx = yield res.json();
|
|
421
|
+
if (!tx || !((_b = (_a = tx.raw_data) === null || _a === void 0 ? void 0 : _a.contract) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
422
|
+
throw new Error('Transaction not found');
|
|
423
|
+
}
|
|
424
|
+
const contract = tx.raw_data.contract[0];
|
|
425
|
+
// Case 1: Native TRX transfer
|
|
426
|
+
if (contract.type === 'TransferContract') {
|
|
427
|
+
const amount = baseAmount(contract.parameter.value.amount, TRX_DECIMAL);
|
|
428
|
+
const from = [{ from: TronWeb.address.fromHex(contract.parameter.value.owner_address), amount }];
|
|
429
|
+
const to = [{ to: TronWeb.address.fromHex(contract.parameter.value.to_address), amount }];
|
|
430
|
+
return {
|
|
431
|
+
asset: AssetTRX,
|
|
432
|
+
type: TxType.Transfer,
|
|
433
|
+
from,
|
|
434
|
+
to,
|
|
435
|
+
date: new Date((_c = tx.raw_data.timestamp) !== null && _c !== void 0 ? _c : Date.now()),
|
|
436
|
+
hash: tx.txID,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
// Case 2: TRC20 transfer (must decode ABI input manually)
|
|
440
|
+
if (contract.type === 'TriggerSmartContract') {
|
|
441
|
+
const { owner_address, contract_address, data: inputData } = contract.parameter.value;
|
|
442
|
+
// ERC20 transfer selector = a9059cbb
|
|
443
|
+
if (inputData.startsWith('a9059cbb')) {
|
|
444
|
+
const decoded = TW.utils.abi.decodeParams(['_to', '_value'], // parameter names
|
|
445
|
+
['address', 'uint256'], // parameter types
|
|
446
|
+
inputData, // full input data (with selector)
|
|
447
|
+
true);
|
|
448
|
+
const toAddress = TronWeb.address.fromHex(decoded._to);
|
|
449
|
+
const fromAddress = TronWeb.address.fromHex(owner_address);
|
|
450
|
+
const rawValue = decoded._value.toString();
|
|
451
|
+
// should set owner_address
|
|
452
|
+
this.tronWeb.setAddress(fromAddress);
|
|
453
|
+
// Get token contract instance
|
|
454
|
+
const contract = TronWeb.address.fromHex(contract_address);
|
|
455
|
+
const tokenContract = yield this.tronWeb.contract().at(contract);
|
|
456
|
+
// Call symbol() and decimals()
|
|
457
|
+
const symbol = yield tokenContract.symbol().call();
|
|
458
|
+
const decimals = yield tokenContract.decimals().call();
|
|
459
|
+
const amount = baseAmount(rawValue, decimals);
|
|
460
|
+
const from = [{ from: fromAddress, amount }];
|
|
461
|
+
const to = [{ to: toAddress, amount }];
|
|
462
|
+
const asset = {
|
|
463
|
+
chain: 'TRON',
|
|
464
|
+
symbol: `${symbol}-${contract_address}`,
|
|
465
|
+
ticker: symbol,
|
|
466
|
+
type: AssetType.TOKEN,
|
|
467
|
+
};
|
|
468
|
+
return {
|
|
469
|
+
asset,
|
|
470
|
+
type: TxType.Transfer,
|
|
471
|
+
from,
|
|
472
|
+
to,
|
|
473
|
+
date: new Date(tx.raw_data.timestamp),
|
|
474
|
+
hash: tx.txID,
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
throw new Error(`Unsupported or non-transfer transaction: ${contract.type}`);
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Default parameters for the Tron client
|
|
484
|
+
const defaultTRONParams = {
|
|
485
|
+
network: Network.Mainnet,
|
|
486
|
+
phrase: '',
|
|
487
|
+
explorerProviders: tronExplorerProviders,
|
|
488
|
+
rootDerivationPaths: {
|
|
489
|
+
[Network.Mainnet]: TRON_DERIVATION_PATH,
|
|
490
|
+
[Network.Testnet]: TRON_DERIVATION_PATH,
|
|
491
|
+
[Network.Stagenet]: TRON_DERIVATION_PATH,
|
|
492
|
+
},
|
|
493
|
+
};
|
|
494
|
+
class Client extends BaseXChainClient {
|
|
495
|
+
constructor(params = defaultTRONParams) {
|
|
496
|
+
const clientParams = Object.assign(Object.assign({}, defaultTRONParams), params);
|
|
497
|
+
super(TRONChain, clientParams);
|
|
498
|
+
/**
|
|
499
|
+
* Get token balance and info directly from contract
|
|
500
|
+
*/
|
|
501
|
+
this.fetchTokenMetadata = (_a) => __awaiter(this, [_a], void 0, function* ({ contractAddress }) {
|
|
502
|
+
const contract = this.tronWeb.contract(trc20ABI, contractAddress);
|
|
503
|
+
const [symbolRaw, decimalsRaw] = yield Promise.all([
|
|
504
|
+
contract
|
|
505
|
+
.symbol()
|
|
506
|
+
.call()
|
|
507
|
+
.catch(() => 'UNKNOWN'),
|
|
508
|
+
contract
|
|
509
|
+
.decimals()
|
|
510
|
+
.call()
|
|
511
|
+
.catch(() => '18'),
|
|
512
|
+
]);
|
|
513
|
+
return { decimals: Number(decimalsRaw !== null && decimalsRaw !== void 0 ? decimalsRaw : 18), symbol: symbolRaw !== null && symbolRaw !== void 0 ? symbolRaw : 'UNKNOWN' };
|
|
514
|
+
});
|
|
515
|
+
/**
|
|
516
|
+
* Get token balance and info directly from contract
|
|
517
|
+
*/
|
|
518
|
+
this.fetchTokenBalance = (_a) => __awaiter(this, [_a], void 0, function* ({ contractAddress, address }) {
|
|
519
|
+
var _b;
|
|
520
|
+
try {
|
|
521
|
+
const contract = this.tronWeb.contract(trc20ABI, contractAddress);
|
|
522
|
+
if (!((_b = contract.methods) === null || _b === void 0 ? void 0 : _b.balanceOf)) {
|
|
523
|
+
return BigInt(0);
|
|
524
|
+
}
|
|
525
|
+
const [balance] = yield contract.methods.balanceOf(address).call();
|
|
526
|
+
return balance ? (typeof balance === 'bigint' ? balance : BigInt(balance)) : BigInt(0);
|
|
527
|
+
}
|
|
528
|
+
catch (err) {
|
|
529
|
+
console.warn(`balanceOf() failed for ${contractAddress}:`, err);
|
|
530
|
+
return BigInt(0);
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
/**
|
|
534
|
+
* Get current chain parameters including resource prices
|
|
535
|
+
*/
|
|
536
|
+
this.getChainParameters = () => __awaiter(this, void 0, void 0, function* () {
|
|
537
|
+
try {
|
|
538
|
+
const parameters = yield this.tronWeb.trx.getChainParameters();
|
|
539
|
+
const paramMap = {};
|
|
540
|
+
for (const param of parameters) {
|
|
541
|
+
paramMap[param.key] = param.value;
|
|
542
|
+
}
|
|
543
|
+
return {
|
|
544
|
+
bandwidthFee: paramMap.getTransactionFee || 1000, // SUN per bandwidth unit
|
|
545
|
+
createAccountFee: paramMap.getCreateAccountFee || 100000, // 0.1 TRX in SUN
|
|
546
|
+
energyFee: paramMap.getEnergyFee || 420, // SUN per energy unit
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
catch (_a) {
|
|
550
|
+
// Return default values if unable to fetch
|
|
551
|
+
return { bandwidthFee: 1000, createAccountFee: 100000, energyFee: 420 };
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
/**
|
|
555
|
+
* Check if an address exists on the blockchain
|
|
556
|
+
*/
|
|
557
|
+
this.accountExists = (address) => __awaiter(this, void 0, void 0, function* () {
|
|
558
|
+
try {
|
|
559
|
+
const account = yield this.tronWeb.trx.getAccount(address);
|
|
560
|
+
return account && Object.keys(account).length > 0;
|
|
561
|
+
}
|
|
562
|
+
catch (_a) {
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
/**
|
|
567
|
+
* Get account resources (bandwidth and energy)
|
|
568
|
+
*/
|
|
569
|
+
this.getAccountResources = (address) => __awaiter(this, void 0, void 0, function* () {
|
|
570
|
+
var _a, _b;
|
|
571
|
+
try {
|
|
572
|
+
const resources = yield this.tronWeb.trx.getAccountResources(address);
|
|
573
|
+
return {
|
|
574
|
+
bandwidth: {
|
|
575
|
+
free: ((_a = resources === null || resources === void 0 ? void 0 : resources.freeNetLimit) !== null && _a !== void 0 ? _a : 0) - ((_b = resources === null || resources === void 0 ? void 0 : resources.freeNetUsed) !== null && _b !== void 0 ? _b : 0),
|
|
576
|
+
total: resources.NetLimit || 0,
|
|
577
|
+
used: resources.NetUsed || 0,
|
|
578
|
+
},
|
|
579
|
+
energy: { total: resources.EnergyLimit || 0, used: resources.EnergyUsed || 0 },
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
catch (_c) {
|
|
583
|
+
// Return default structure if unable to fetch
|
|
584
|
+
return {
|
|
585
|
+
bandwidth: { free: 600, total: 0, used: 0 }, // 600 free bandwidth daily
|
|
586
|
+
energy: { total: 0, used: 0 },
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
this.createTransaction = (params) => __awaiter(this, void 0, void 0, function* () {
|
|
591
|
+
var _a, _b;
|
|
592
|
+
const { asset, amount: baseValue, recipient, memo, walletIndex } = params;
|
|
593
|
+
if (!asset)
|
|
594
|
+
throw Error('Asset not provided');
|
|
595
|
+
const sender = this.getAddress(walletIndex);
|
|
596
|
+
const amount = baseValue.amount().toString();
|
|
597
|
+
if (asset.type === AssetType.NATIVE) {
|
|
598
|
+
const transaction = yield this.tronWeb.transactionBuilder.sendTrx(recipient, Number(amount), sender);
|
|
599
|
+
if (memo) {
|
|
600
|
+
return this.tronWeb.transactionBuilder.addUpdateData(transaction, memo, 'utf8');
|
|
601
|
+
}
|
|
602
|
+
return transaction;
|
|
603
|
+
}
|
|
604
|
+
const contractAddress = getTRC20AssetContractAddress(asset);
|
|
605
|
+
if (!contractAddress) {
|
|
606
|
+
throw new Error('TRC20 Asset Contract Address is not valid');
|
|
607
|
+
}
|
|
608
|
+
// Build TRC20 transfer transaction
|
|
609
|
+
const functionSelector = 'transfer(address,uint256)';
|
|
610
|
+
const parameter = [
|
|
611
|
+
{ type: 'address', value: recipient },
|
|
612
|
+
{ type: 'uint256', value: amount },
|
|
613
|
+
];
|
|
614
|
+
const options = { callValue: 0, feeLimit: TRX_FEE_LIMIT };
|
|
615
|
+
const res = yield this.tronWeb.transactionBuilder.triggerSmartContract(contractAddress, functionSelector, options, parameter, sender);
|
|
616
|
+
// Some nodes don’t throw; they return result=false + message
|
|
617
|
+
if (!(((_a = res === null || res === void 0 ? void 0 : res.result) === null || _a === void 0 ? void 0 : _a.result) && (res === null || res === void 0 ? void 0 : res.transaction))) {
|
|
618
|
+
throw new Error((_b = res === null || res === void 0 ? void 0 : res.result) === null || _b === void 0 ? void 0 : _b.message);
|
|
619
|
+
}
|
|
620
|
+
// Attach memo if requested
|
|
621
|
+
const tx = memo
|
|
622
|
+
? yield this.tronWeb.transactionBuilder.addUpdateData(res.transaction, memo, 'utf8')
|
|
623
|
+
: res.transaction;
|
|
624
|
+
return tx;
|
|
625
|
+
});
|
|
626
|
+
/**
|
|
627
|
+
* Check the current allowance for a spender on a token
|
|
628
|
+
*/
|
|
629
|
+
this.getApprovedAmount = (_a) => __awaiter(this, [_a], void 0, function* ({ contractAddress, spenderAddress, from }) {
|
|
630
|
+
var _b;
|
|
631
|
+
this.tronWeb.setAddress(from);
|
|
632
|
+
const contract = this.tronWeb.contract(trc20ABI, contractAddress);
|
|
633
|
+
if (!((_b = contract.methods) === null || _b === void 0 ? void 0 : _b.allowance)) {
|
|
634
|
+
throw new Error('invalid contract');
|
|
635
|
+
}
|
|
636
|
+
const [allowance] = yield contract.methods.allowance(from, spenderAddress).call();
|
|
637
|
+
return allowance ? (typeof allowance === 'bigint' ? allowance : BigInt(allowance)) : BigInt(0);
|
|
638
|
+
});
|
|
639
|
+
this.explorerProviders = clientParams.explorerProviders;
|
|
640
|
+
this.tronWeb = new TronWeb({ fullHost: TRON_DEFAULT_RPC });
|
|
641
|
+
this.tronGrid = new TronGrid();
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Get TRX asset info.
|
|
645
|
+
* @returns {AssetInfo} TRX asset information.
|
|
646
|
+
*/
|
|
647
|
+
getAssetInfo() {
|
|
648
|
+
const assetInfo = {
|
|
649
|
+
asset: AssetTRX,
|
|
650
|
+
decimal: TRX_DECIMAL,
|
|
651
|
+
};
|
|
652
|
+
return assetInfo;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Get the explorer URL.
|
|
656
|
+
*
|
|
657
|
+
* @returns {string} The explorer URL.
|
|
658
|
+
*/
|
|
659
|
+
getExplorerUrl() {
|
|
660
|
+
return this.explorerProviders[this.getNetwork()].getExplorerUrl();
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Get the explorer url for the given address.
|
|
664
|
+
*
|
|
665
|
+
* @param {Address} address
|
|
666
|
+
* @returns {string} The explorer url for the given address.
|
|
667
|
+
*/
|
|
668
|
+
getExplorerAddressUrl(address) {
|
|
669
|
+
return this.explorerProviders[this.getNetwork()].getExplorerAddressUrl(address);
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Get the explorer url for the given transaction id.
|
|
673
|
+
*
|
|
674
|
+
* @param {string} txID
|
|
675
|
+
* @returns {string} The explorer url for the given transaction id.
|
|
676
|
+
*/
|
|
677
|
+
getExplorerTxUrl(txID) {
|
|
678
|
+
return this.explorerProviders[this.getNetwork()].getExplorerTxUrl(txID);
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Validate the given Tron address.
|
|
682
|
+
* @param {string} address Tron address to validate.
|
|
683
|
+
* @returns {boolean} `true` if the address is valid, `false` otherwise.
|
|
684
|
+
*/
|
|
685
|
+
validateAddress(address) {
|
|
686
|
+
return validateAddress(address);
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Retrieves the balance of a given address.
|
|
690
|
+
* @param {Address} address - The address to retrieve the balance for.
|
|
691
|
+
* @param {TokenAsset[]} assets - Assets to retrieve the balance for (optional).
|
|
692
|
+
* @returns {Promise<Balance[]>} An array containing the balance of the address.
|
|
693
|
+
*/
|
|
694
|
+
getBalance(address) {
|
|
695
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
696
|
+
const ZeroBalance = [
|
|
697
|
+
{
|
|
698
|
+
asset: AssetTRX,
|
|
699
|
+
amount: baseAmount(0, TRX_DECIMAL),
|
|
700
|
+
},
|
|
701
|
+
];
|
|
702
|
+
// Try get balance from TronGrid
|
|
703
|
+
try {
|
|
704
|
+
const accountData = yield this.tronGrid.getAccount(address);
|
|
705
|
+
if (!accountData)
|
|
706
|
+
return ZeroBalance;
|
|
707
|
+
const balances = [];
|
|
708
|
+
// Add TRX balance
|
|
709
|
+
balances.push({
|
|
710
|
+
asset: AssetTRX,
|
|
711
|
+
amount: baseAmount(accountData.balance, TRX_DECIMAL),
|
|
712
|
+
});
|
|
713
|
+
// Add TRC20 balances
|
|
714
|
+
for (const token of accountData.trc20) {
|
|
715
|
+
const entries = Object.entries(token);
|
|
716
|
+
if (entries.length !== 1)
|
|
717
|
+
continue;
|
|
718
|
+
const [contractAddress, balance] = entries[0];
|
|
719
|
+
if (!(contractAddress && balance))
|
|
720
|
+
continue;
|
|
721
|
+
const tokenMetaData = yield this.fetchTokenMetadata({ contractAddress });
|
|
722
|
+
if (!tokenMetaData)
|
|
723
|
+
continue;
|
|
724
|
+
balances.push({
|
|
725
|
+
asset: {
|
|
726
|
+
chain: TRONChain,
|
|
727
|
+
symbol: `${tokenMetaData.symbol}-${contractAddress}`,
|
|
728
|
+
ticker: tokenMetaData.symbol,
|
|
729
|
+
type: AssetType.TOKEN,
|
|
730
|
+
},
|
|
731
|
+
amount: baseAmount(balance || 0, tokenMetaData.decimals),
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
return balances;
|
|
735
|
+
}
|
|
736
|
+
catch (_error) {
|
|
737
|
+
// Fallback: get TRX and USDT Balance from TronWeb
|
|
738
|
+
const balances = [];
|
|
739
|
+
const trxBalanceInSun = yield this.tronWeb.trx.getBalance(address);
|
|
740
|
+
if (trxBalanceInSun && Number(trxBalanceInSun) > 0) {
|
|
741
|
+
balances.push({
|
|
742
|
+
asset: AssetTRX,
|
|
743
|
+
amount: baseAmount(trxBalanceInSun, TRX_DECIMAL),
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
const usdtBalance = yield this.fetchTokenBalance({ address, contractAddress: TRON_USDT_CONTRACT });
|
|
747
|
+
if (usdtBalance) {
|
|
748
|
+
balances.push({
|
|
749
|
+
asset: {
|
|
750
|
+
chain: TRONChain,
|
|
751
|
+
symbol: `USDT-${TRON_USDT_CONTRACT}`,
|
|
752
|
+
ticker: 'USDT',
|
|
753
|
+
type: AssetType.TOKEN,
|
|
754
|
+
},
|
|
755
|
+
amount: baseAmount(usdtBalance.toString(), 6),
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
return balances;
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Get transaction fees.
|
|
764
|
+
* @param {TxParams} params - Tx param
|
|
765
|
+
* @returns {Fees} The average, fast, and fastest fees.
|
|
766
|
+
*/
|
|
767
|
+
getFees(params) {
|
|
768
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
769
|
+
if (!params)
|
|
770
|
+
throw new Error('Params need to be passed');
|
|
771
|
+
const { asset, recipient, walletIndex } = params;
|
|
772
|
+
const isNative = (asset === null || asset === void 0 ? void 0 : asset.type) === AssetType.NATIVE;
|
|
773
|
+
let feeAmount;
|
|
774
|
+
// Get sender address
|
|
775
|
+
const senderAddress = this.getAddress(walletIndex);
|
|
776
|
+
if (!senderAddress) {
|
|
777
|
+
// If no signer, return default fee
|
|
778
|
+
feeAmount = isNative ? baseAmount(0.1 * Math.pow(10, 6), TRX_DECIMAL) : baseAmount(15 * Math.pow(10, 6), TRX_DECIMAL);
|
|
779
|
+
}
|
|
780
|
+
else {
|
|
781
|
+
// Get chain parameters for current resource prices
|
|
782
|
+
const chainParams = yield this.getChainParameters();
|
|
783
|
+
// Check if recipient account exists (new accounts require activation fee)
|
|
784
|
+
const recipientExists = yield this.accountExists(recipient);
|
|
785
|
+
const activationFee = recipientExists ? 0 : chainParams.createAccountFee;
|
|
786
|
+
// Get account resources
|
|
787
|
+
const resources = yield this.getAccountResources(senderAddress);
|
|
788
|
+
if (isNative) {
|
|
789
|
+
// Calculate bandwidth needed for TRX transfer
|
|
790
|
+
const bandwidthNeeded = TRX_TRANSFER_BANDWIDTH;
|
|
791
|
+
const availableBandwidth = resources.bandwidth.free + (resources.bandwidth.total - resources.bandwidth.used);
|
|
792
|
+
let bandwidthFee = 0;
|
|
793
|
+
if (bandwidthNeeded > availableBandwidth) {
|
|
794
|
+
// Need to burn TRX for bandwidth
|
|
795
|
+
const bandwidthToBuy = bandwidthNeeded - availableBandwidth;
|
|
796
|
+
bandwidthFee = bandwidthToBuy * chainParams.bandwidthFee;
|
|
797
|
+
}
|
|
798
|
+
// Total fee in SUN
|
|
799
|
+
const totalFeeSun = activationFee + bandwidthFee;
|
|
800
|
+
feeAmount = baseAmount(totalFeeSun, TRX_DECIMAL);
|
|
801
|
+
}
|
|
802
|
+
else {
|
|
803
|
+
// TRC20 Transfer - needs both bandwidth and energy
|
|
804
|
+
const bandwidthNeeded = TRC20_TRANSFER_BANDWIDTH;
|
|
805
|
+
const energyNeeded = TRC20_TRANSFER_ENERGY;
|
|
806
|
+
const availableBandwidth = resources.bandwidth.free + (resources.bandwidth.total - resources.bandwidth.used);
|
|
807
|
+
const availableEnergy = resources.energy.total - resources.energy.used;
|
|
808
|
+
let bandwidthFee = 0;
|
|
809
|
+
if (bandwidthNeeded > availableBandwidth) {
|
|
810
|
+
const bandwidthToBuy = bandwidthNeeded - availableBandwidth;
|
|
811
|
+
bandwidthFee = bandwidthToBuy * chainParams.bandwidthFee;
|
|
812
|
+
}
|
|
813
|
+
let energyFee = 0;
|
|
814
|
+
if (energyNeeded > availableEnergy) {
|
|
815
|
+
const energyToBuy = energyNeeded - availableEnergy;
|
|
816
|
+
energyFee = energyToBuy * chainParams.energyFee;
|
|
817
|
+
}
|
|
818
|
+
// Total fee in SUN
|
|
819
|
+
const totalFeeSun = activationFee + bandwidthFee + energyFee;
|
|
820
|
+
feeAmount = baseAmount(totalFeeSun, TRX_DECIMAL);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
// Tron has Fixed Fee model, unlike ETH or BTC
|
|
824
|
+
return {
|
|
825
|
+
average: feeAmount,
|
|
826
|
+
fast: feeAmount,
|
|
827
|
+
fastest: feeAmount,
|
|
828
|
+
type: FeeType.FlatFee,
|
|
829
|
+
};
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Transfer TRON Asset
|
|
834
|
+
* @param {TxParams} params The transfer options.
|
|
835
|
+
* @returns {TxHash} The transaction hash.
|
|
836
|
+
*/
|
|
837
|
+
transfer(params) {
|
|
838
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
839
|
+
const { asset, amount: baseValue, recipient, memo, walletIndex } = params;
|
|
840
|
+
if (!asset)
|
|
841
|
+
throw Error('Asset not provided');
|
|
842
|
+
const amount = baseValue.amount().toString();
|
|
843
|
+
const sender = this.getAddress(walletIndex);
|
|
844
|
+
const isNative = asset.type === AssetType.NATIVE;
|
|
845
|
+
if (isNative) {
|
|
846
|
+
const transaction = yield this.tronWeb.transactionBuilder.sendTrx(recipient, Number(amount), sender);
|
|
847
|
+
if (memo) {
|
|
848
|
+
const transactionWithMemo = yield this.tronWeb.transactionBuilder.addUpdateData(transaction, memo, 'utf8');
|
|
849
|
+
const signedTx = yield this.signTransaction(transactionWithMemo, walletIndex);
|
|
850
|
+
const { txid } = yield this.tronWeb.trx.sendRawTransaction(signedTx);
|
|
851
|
+
return txid;
|
|
852
|
+
}
|
|
853
|
+
const signedTx = yield this.signTransaction(transaction, walletIndex);
|
|
854
|
+
const { txid } = yield this.tronWeb.trx.sendRawTransaction(signedTx);
|
|
855
|
+
return txid;
|
|
856
|
+
}
|
|
857
|
+
// TRC20 Token Transfer - always use createTransaction + sign pattern
|
|
858
|
+
const transaction = yield this.createTransaction(params);
|
|
859
|
+
const signedTx = yield this.signTransaction(transaction, walletIndex);
|
|
860
|
+
const { txid } = yield this.tronWeb.trx.sendRawTransaction(signedTx);
|
|
861
|
+
if (!txid) {
|
|
862
|
+
throw new Error('TRON Transfer falied');
|
|
863
|
+
}
|
|
864
|
+
return txid;
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Check TRC20 allowance.
|
|
869
|
+
* @param {Address} contractAddress The contract address.
|
|
870
|
+
* @param {Address} spenderAddress The spender address.
|
|
871
|
+
* @param {BaseAmount} amount The amount to check if it's allowed to spend or not (optional).
|
|
872
|
+
* @param {number} walletIndex (optional) HD wallet index
|
|
873
|
+
* @param {IsApprovedParams} params - Parameters for checking allowance.
|
|
874
|
+
* @returns {boolean} `true` if the allowance is approved, `false` otherwise.
|
|
875
|
+
*/
|
|
876
|
+
isApproved(_a) {
|
|
877
|
+
return __awaiter(this, arguments, void 0, function* ({ contractAddress, spenderAddress, amount, walletIndex }) {
|
|
878
|
+
const from = this.getAddress(walletIndex);
|
|
879
|
+
const allowance = yield this.getApprovedAmount({ contractAddress, from, spenderAddress });
|
|
880
|
+
if (!amount) {
|
|
881
|
+
// If no amount specified, check if there's any approval
|
|
882
|
+
return allowance > BigInt(0);
|
|
883
|
+
}
|
|
884
|
+
return allowance >= BigInt(amount.amount().toString());
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Approves an allowance for spending tokens.
|
|
889
|
+
*
|
|
890
|
+
* @param {ApproveParams} params - Parameters for approving an allowance.
|
|
891
|
+
* @param {Address} contractAddress The contract address.
|
|
892
|
+
* @param {Address} spenderAddress The spender address.
|
|
893
|
+
* @param {BaseAmount} amount The amount of token. By default, it will be unlimited token allowance. (optional)
|
|
894
|
+
* @param {number} walletIndex (optional) HD wallet index
|
|
895
|
+
* @returns {TransactionResponse} The result of the approval transaction.
|
|
896
|
+
* @throws Error If gas estimation fails.
|
|
897
|
+
*/
|
|
898
|
+
approve(_a) {
|
|
899
|
+
return __awaiter(this, arguments, void 0, function* ({ contractAddress, spenderAddress, amount, walletIndex = 0 }) {
|
|
900
|
+
const fromAddress = this.getAddress(walletIndex);
|
|
901
|
+
const approvalAmount = amount !== undefined ? amount.amount().toString() : MAX_APPROVAL;
|
|
902
|
+
// Build approve transaction using triggerSmartContract
|
|
903
|
+
const functionSelector = 'approve(address,uint256)';
|
|
904
|
+
const parameter = [
|
|
905
|
+
{ type: 'address', value: spenderAddress },
|
|
906
|
+
{ type: 'uint256', value: approvalAmount },
|
|
907
|
+
];
|
|
908
|
+
const feeLimit = TRX_FEE_LIMIT;
|
|
909
|
+
const options = { callValue: 0, feeLimit };
|
|
910
|
+
const { transaction } = yield this.tronWeb.transactionBuilder.triggerSmartContract(contractAddress, functionSelector, options, parameter, fromAddress);
|
|
911
|
+
if (!transaction) {
|
|
912
|
+
throw new Error('Failed to build approve transaction');
|
|
913
|
+
}
|
|
914
|
+
const signedTx = yield this.signTransaction(transaction, walletIndex);
|
|
915
|
+
const { txid } = yield this.tronWeb.trx.sendRawTransaction(signedTx);
|
|
916
|
+
if (!txid) {
|
|
917
|
+
throw new Error('TRC20 Approve Failed');
|
|
918
|
+
}
|
|
919
|
+
return txid;
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
broadcastTransaction(signedTx) {
|
|
923
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
924
|
+
const { txid } = yield this.tronWeb.trx.sendRawTransaction(signedTx);
|
|
925
|
+
return txid;
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
getTransactions(params) {
|
|
929
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
930
|
+
const address = (params === null || params === void 0 ? void 0 : params.address) || this.getAddress();
|
|
931
|
+
const offset = (params === null || params === void 0 ? void 0 : params.offset) || 0;
|
|
932
|
+
const limit = (params === null || params === void 0 ? void 0 : params.limit) || 10;
|
|
933
|
+
return this.tronGrid.getTransactions({ address, limit, offset });
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Get the transaction details of a given transaction ID.
|
|
938
|
+
*
|
|
939
|
+
* @param {string} txId The transaction ID.
|
|
940
|
+
* @returns {Tx} The transaction details.
|
|
941
|
+
*/
|
|
942
|
+
getTransactionData(txId) {
|
|
943
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
944
|
+
return this.tronGrid.getTransactionData(txId);
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
broadcastTx(_signedTx) {
|
|
948
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
949
|
+
throw Error('Error: not supported');
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
prepareTx(_) {
|
|
953
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
954
|
+
throw new Error('Error: raw tx string not supported');
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
getFeesWithRates() {
|
|
958
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
959
|
+
throw Error('Error: not supported');
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
getFeeRates() {
|
|
963
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
964
|
+
throw Error('Error: not supported');
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
class ClientKeystore extends Client {
|
|
970
|
+
constructor(params = defaultTRONParams) {
|
|
971
|
+
const clientParams = Object.assign(Object.assign({}, defaultTRONParams), params);
|
|
972
|
+
super(clientParams);
|
|
973
|
+
}
|
|
974
|
+
getSigner(walletIndex = 0) {
|
|
975
|
+
if (!this.phrase)
|
|
976
|
+
throw new Error('Phrase must be provided');
|
|
977
|
+
const seed = mnemonicToSeedSync(this.phrase);
|
|
978
|
+
const hdKey = HDKey.fromMasterSeed(seed);
|
|
979
|
+
const derived = hdKey.derive(this.getFullDerivationPath(walletIndex));
|
|
980
|
+
if (!derived.privateKey) {
|
|
981
|
+
throw new Error('No Tron Signer');
|
|
982
|
+
}
|
|
983
|
+
const privateKeyHex = Buffer.from(derived.privateKey).toString('hex');
|
|
984
|
+
const isolatedTronWeb = new TronWeb({
|
|
985
|
+
fullHost: TRON_DEFAULT_RPC,
|
|
986
|
+
privateKey: privateKeyHex,
|
|
987
|
+
});
|
|
988
|
+
const address = isolatedTronWeb.address.fromPrivateKey(privateKeyHex);
|
|
989
|
+
return {
|
|
990
|
+
getAddress: () => (typeof address === 'string' ? address : ''),
|
|
991
|
+
signTransaction: (transaction) => __awaiter(this, void 0, void 0, function* () {
|
|
992
|
+
// Use isolated instance - no shared state
|
|
993
|
+
const signedTx = yield isolatedTronWeb.trx.sign(transaction);
|
|
994
|
+
return signedTx;
|
|
995
|
+
}),
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Get the current address synchronously.
|
|
1000
|
+
*/
|
|
1001
|
+
getAddress(walletIndex = 0) {
|
|
1002
|
+
return this.getSigner(walletIndex).getAddress();
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Get the current address asynchronously.
|
|
1006
|
+
*
|
|
1007
|
+
* @param {number} index The index of the address. Default 0
|
|
1008
|
+
* @returns {Address} The TRON address related to the index provided.
|
|
1009
|
+
* @throws {"Phrase must be provided"} Thrown if the phrase has not been set before.
|
|
1010
|
+
*/
|
|
1011
|
+
getAddressAsync() {
|
|
1012
|
+
return __awaiter(this, arguments, void 0, function* (walletIndex = 0) {
|
|
1013
|
+
return this.getAddress(walletIndex);
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
signTransaction(transaction_1) {
|
|
1017
|
+
return __awaiter(this, arguments, void 0, function* (transaction, walletIndex = 0) {
|
|
1018
|
+
return this.getSigner(walletIndex).signTransaction(transaction);
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
export { AssetTRONUSDT, AssetTRX, ClientKeystore as Client, MAX_APPROVAL, TRC20_TRANSFER_BANDWIDTH, TRC20_TRANSFER_ENERGY, TRONChain, TRON_DEFAULT_RPC, TRON_DERIVATION_PATH, TRON_USDT_CONTRACT, TRX_DECIMAL, TRX_FEE_LIMIT, TRX_TRANSFER_BANDWIDTH, defaultTRONParams, tronExplorerProviders, validateAddress };
|
|
1024
|
+
//# sourceMappingURL=index.esm.js.map
|