@ledgerhq/coin-tron 5.18.0 → 5.19.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/lib/api/index.d.ts.map +1 -1
  3. package/lib/api/index.js +9 -2
  4. package/lib/api/index.js.map +1 -1
  5. package/lib/bridge/index.d.ts.map +1 -1
  6. package/lib/bridge/index.js +2 -3
  7. package/lib/bridge/index.js.map +1 -1
  8. package/lib/bridge/prepareTransaction.d.ts.map +1 -1
  9. package/lib/bridge/prepareTransaction.js +6 -0
  10. package/lib/bridge/prepareTransaction.js.map +1 -1
  11. package/lib/bridge/utils.d.ts.map +1 -1
  12. package/lib/bridge/utils.js +11 -0
  13. package/lib/bridge/utils.js.map +1 -1
  14. package/lib/logic/listOperations.d.ts.map +1 -1
  15. package/lib/logic/listOperations.js +7 -0
  16. package/lib/logic/listOperations.js.map +1 -1
  17. package/lib/logic/utils.d.ts +1 -1
  18. package/lib/logic/utils.d.ts.map +1 -1
  19. package/lib/logic/utils.js +0 -5
  20. package/lib/logic/utils.js.map +1 -1
  21. package/lib/network/format.d.ts +1 -1
  22. package/lib/network/format.d.ts.map +1 -1
  23. package/lib/network/format.js +19 -9
  24. package/lib/network/format.js.map +1 -1
  25. package/lib/network/index.d.ts +1 -1
  26. package/lib/network/index.d.ts.map +1 -1
  27. package/lib/network/index.js +13 -28
  28. package/lib/network/index.js.map +1 -1
  29. package/lib/network/trongrid/trongrid-adapters.js +1 -1
  30. package/lib/network/trongrid/trongrid-adapters.js.map +1 -1
  31. package/lib/test/bridgeDatasetTest.d.ts.map +1 -1
  32. package/lib/test/bridgeDatasetTest.js +21 -3
  33. package/lib/test/bridgeDatasetTest.js.map +1 -1
  34. package/lib/test/cli.d.ts.map +1 -1
  35. package/lib/test/cli.js +11 -3
  36. package/lib/test/cli.js.map +1 -1
  37. package/lib/types/bridge.d.ts +2 -2
  38. package/lib/types/bridge.d.ts.map +1 -1
  39. package/lib/types/bridge.js.map +1 -1
  40. package/lib/types/errors.d.ts +3 -0
  41. package/lib/types/errors.d.ts.map +1 -1
  42. package/lib/types/errors.js +2 -1
  43. package/lib/types/errors.js.map +1 -1
  44. package/lib-es/api/index.d.ts.map +1 -1
  45. package/lib-es/api/index.js +10 -3
  46. package/lib-es/api/index.js.map +1 -1
  47. package/lib-es/bridge/index.d.ts.map +1 -1
  48. package/lib-es/bridge/index.js +2 -3
  49. package/lib-es/bridge/index.js.map +1 -1
  50. package/lib-es/bridge/prepareTransaction.d.ts.map +1 -1
  51. package/lib-es/bridge/prepareTransaction.js +7 -1
  52. package/lib-es/bridge/prepareTransaction.js.map +1 -1
  53. package/lib-es/bridge/utils.d.ts.map +1 -1
  54. package/lib-es/bridge/utils.js +9 -1
  55. package/lib-es/bridge/utils.js.map +1 -1
  56. package/lib-es/logic/listOperations.d.ts.map +1 -1
  57. package/lib-es/logic/listOperations.js +7 -0
  58. package/lib-es/logic/listOperations.js.map +1 -1
  59. package/lib-es/logic/utils.d.ts +1 -1
  60. package/lib-es/logic/utils.d.ts.map +1 -1
  61. package/lib-es/logic/utils.js +0 -5
  62. package/lib-es/logic/utils.js.map +1 -1
  63. package/lib-es/network/format.d.ts +1 -1
  64. package/lib-es/network/format.d.ts.map +1 -1
  65. package/lib-es/network/format.js +19 -9
  66. package/lib-es/network/format.js.map +1 -1
  67. package/lib-es/network/index.d.ts +1 -1
  68. package/lib-es/network/index.d.ts.map +1 -1
  69. package/lib-es/network/index.js +11 -25
  70. package/lib-es/network/index.js.map +1 -1
  71. package/lib-es/network/trongrid/trongrid-adapters.js +1 -1
  72. package/lib-es/network/trongrid/trongrid-adapters.js.map +1 -1
  73. package/lib-es/test/bridgeDatasetTest.d.ts.map +1 -1
  74. package/lib-es/test/bridgeDatasetTest.js +21 -3
  75. package/lib-es/test/bridgeDatasetTest.js.map +1 -1
  76. package/lib-es/test/cli.d.ts.map +1 -1
  77. package/lib-es/test/cli.js +11 -3
  78. package/lib-es/test/cli.js.map +1 -1
  79. package/lib-es/types/bridge.d.ts +2 -2
  80. package/lib-es/types/bridge.d.ts.map +1 -1
  81. package/lib-es/types/bridge.js.map +1 -1
  82. package/lib-es/types/errors.d.ts +3 -0
  83. package/lib-es/types/errors.d.ts.map +1 -1
  84. package/lib-es/types/errors.js +1 -0
  85. package/lib-es/types/errors.js.map +1 -1
  86. package/package.json +8 -8
  87. package/src/api/index.test.ts +42 -5
  88. package/src/api/index.ts +18 -8
  89. package/src/bridge/index.ts +2 -3
  90. package/src/bridge/prepareTransaction.test.ts +118 -0
  91. package/src/bridge/prepareTransaction.ts +11 -1
  92. package/src/bridge/utils.ts +12 -1
  93. package/src/logic/listOperations.ts +10 -0
  94. package/src/logic/listOperations.unit.test.ts +34 -5
  95. package/src/logic/utils.test.ts +0 -37
  96. package/src/logic/utils.ts +6 -7
  97. package/src/network/format.test.ts +301 -2
  98. package/src/network/format.ts +25 -10
  99. package/src/network/index.ts +28 -45
  100. package/src/network/trongrid/trongrid-adapters.test.ts +13 -0
  101. package/src/network/trongrid/trongrid-adapters.ts +1 -1
  102. package/src/test/bridgeDatasetTest.ts +21 -3
  103. package/src/test/cli.ts +11 -6
  104. package/src/types/bridge.ts +2 -2
  105. package/src/types/errors.ts +1 -0
  106. package/.turbo/turbo-build.log +0 -4
  107. package/lib/bridge/preload.d.ts +0 -8
  108. package/lib/bridge/preload.d.ts.map +0 -1
  109. package/lib/bridge/preload.js +0 -23
  110. package/lib/bridge/preload.js.map +0 -1
  111. package/lib-es/bridge/preload.d.ts +0 -8
  112. package/lib-es/bridge/preload.d.ts.map +0 -1
  113. package/lib-es/bridge/preload.js +0 -18
  114. package/lib-es/bridge/preload.js.map +0 -1
  115. package/src/bridge/preload.ts +0 -24
@@ -1,6 +1,43 @@
1
1
  import BigNumber from "bignumber.js";
2
- import { decode58Check, encode58Check, formatTrongridTrc20TxResponse } from "./format";
3
- import { Trc20API } from "./types";
2
+ import {
3
+ decode58Check,
4
+ encode58Check,
5
+ formatTrongridTrc20TxResponse,
6
+ formatTrongridTxResponse,
7
+ } from "./format";
8
+ import { Trc20API, TransactionTronAPI } from "./types";
9
+ import type { TronTransactionInfo } from "../types";
10
+
11
+ const ownerHex = "41fd49eda0f23ff7ec1d03b52c3a45991c24cd440e";
12
+ const toHex = "4198927ffb9f554dc4a453c64b2e553a02d6df514b";
13
+ const trc20ContractHex = "4142a1e39aefa49290f2b3f9ed688d7cecf86cd6e0";
14
+
15
+ function baseTransactionTronApi(
16
+ contract: TransactionTronAPI["raw_data"]["contract"][0],
17
+ overrides: Partial<TransactionTronAPI & { detail?: TronTransactionInfo }> = {},
18
+ ): TransactionTronAPI & { detail?: TronTransactionInfo } {
19
+ return {
20
+ ret: [{ contractRet: "SUCCESS", fee: 1000 }],
21
+ signature: [],
22
+ txID: "txId",
23
+ net_usage: 0,
24
+ raw_data_hex: "",
25
+ net_fee: 0,
26
+ energy_usage: 0,
27
+ block_timestamp: 1,
28
+ blockNumber: 42,
29
+ energy_fee: 0,
30
+ energy_usage_total: 0,
31
+ raw_data: {
32
+ contract: [contract],
33
+ ref_block_bytes: "",
34
+ ref_block_hash: "",
35
+ expiration: 0,
36
+ },
37
+ internal_transactions: [],
38
+ ...overrides,
39
+ };
40
+ }
4
41
 
5
42
  describe("formatTrongridTrc20TxResponse", () => {
6
43
  it("should return correct TrongridTxInfo for Approval tx type", () => {
@@ -30,6 +67,7 @@ describe("formatTrongridTrc20TxResponse", () => {
30
67
  hasFailed: false,
31
68
  tokenType: "trc20",
32
69
  tokenAddress: "addr",
70
+ feesPayer: "from",
33
71
  });
34
72
  });
35
73
 
@@ -60,8 +98,269 @@ describe("formatTrongridTrc20TxResponse", () => {
60
98
  hasFailed: false,
61
99
  tokenType: "trc20",
62
100
  tokenAddress: "tokenId",
101
+ feesPayer: "from",
63
102
  });
64
103
  });
104
+
105
+ it("should fall back to contract_address when token_info.address is missing (unindexed LP contract)", () => {
106
+ const tx = {
107
+ from: "from",
108
+ to: "to",
109
+ block_timestamp: 1,
110
+ detail: {
111
+ ret: [{ fee: 0 }],
112
+ raw_data: {
113
+ contract: [
114
+ {
115
+ parameter: {
116
+ value: {
117
+ owner_address: "41f1fe9d73ffb3b6ab532858b266c02f63410fbd70",
118
+ // hex for TU1wcXoAq5EXhZp7ga6E1Vb1Sqw1ciQP4s (unindexed LP contract)
119
+ contract_address: "41c5f6aa996edd0696a0295b07fd7b20b0dd84c557",
120
+ },
121
+ },
122
+ },
123
+ ],
124
+ },
125
+ },
126
+ value: "20000000000",
127
+ transaction_id: "txId",
128
+ token_info: {},
129
+ type: "Transfer",
130
+ };
131
+ const result = formatTrongridTrc20TxResponse(tx as unknown as Trc20API);
132
+ expect(result).toMatchObject({
133
+ type: "TriggerSmartContract",
134
+ tokenId: "TU1wcXoAq5EXhZp7ga6E1Vb1Sqw1ciQP4s",
135
+ tokenAddress: "TU1wcXoAq5EXhZp7ga6E1Vb1Sqw1ciQP4s",
136
+ });
137
+ });
138
+
139
+ it("should set feesPayer from owner_address when it differs from from (transferFrom case)", () => {
140
+ // owner_address is the Tron tx initiator (hex); `from` is the TRC20 token source (base58)
141
+ const tx = {
142
+ from: "TTokenSourceAddress",
143
+ to: "to",
144
+ block_timestamp: 1,
145
+ detail: {
146
+ ret: [{ fee: 1 }],
147
+ raw_data: {
148
+ contract: [
149
+ {
150
+ parameter: {
151
+ value: {
152
+ // hex for TY2ksFgpvb82TgGPwUSa7iseqPW5weYQyh
153
+ owner_address: "41f1fe9d73ffb3b6ab532858b266c02f63410fbd70",
154
+ },
155
+ },
156
+ },
157
+ ],
158
+ },
159
+ },
160
+ value: 100,
161
+ transaction_id: "txId",
162
+ token_info: { address: "tokenAddr" },
163
+ type: "Transfer",
164
+ };
165
+ const result = formatTrongridTrc20TxResponse(tx as unknown as Trc20API);
166
+ expect(result).toEqual({
167
+ txID: "txId",
168
+ date: new Date(1),
169
+ type: "TriggerSmartContract",
170
+ tokenId: "tokenAddr",
171
+ from: "TTokenSourceAddress",
172
+ to: "to",
173
+ blockHeight: undefined,
174
+ value: new BigNumber(100),
175
+ fee: new BigNumber(1),
176
+ hasFailed: false,
177
+ tokenType: "trc20",
178
+ tokenAddress: "tokenAddr",
179
+ feesPayer: "TY2ksFgpvb82TgGPwUSa7iseqPW5weYQyh",
180
+ });
181
+ });
182
+ });
183
+
184
+ describe("formatTrongridTxResponse", () => {
185
+ it("should return correct TrongridTxInfo for TransferContract", async () => {
186
+ const tx = baseTransactionTronApi({
187
+ type: "TransferContract",
188
+ parameter: {
189
+ type_url: "",
190
+ value: {
191
+ owner_address: ownerHex,
192
+ to_address: toHex,
193
+ amount: 1_000_000,
194
+ },
195
+ },
196
+ });
197
+ const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null));
198
+ expect(result).toEqual({
199
+ txID: "txId",
200
+ date: new Date(1),
201
+ type: "TransferContract",
202
+ tokenId: undefined,
203
+ tokenType: undefined,
204
+ tokenAddress: undefined,
205
+ from: encode58Check(ownerHex),
206
+ to: encode58Check(toHex),
207
+ value: new BigNumber(1_000_000),
208
+ fee: new BigNumber(1000),
209
+ blockHeight: 42,
210
+ hasFailed: false,
211
+ feesPayer: encode58Check(ownerHex),
212
+ });
213
+ });
214
+
215
+ it("should set hasFailed when contract execution did not succeed", async () => {
216
+ const tx = baseTransactionTronApi(
217
+ {
218
+ type: "TransferContract",
219
+ parameter: {
220
+ type_url: "",
221
+ value: {
222
+ owner_address: ownerHex,
223
+ to_address: toHex,
224
+ amount: 100,
225
+ },
226
+ },
227
+ },
228
+ { ret: [{ contractRet: "REVERT", fee: 0 }] },
229
+ );
230
+ const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null));
231
+ expect(result?.hasFailed).toBe(true);
232
+ });
233
+
234
+ it("should return correct TrongridTxInfo for TransferAssetContract", async () => {
235
+ const assetName = "10013004";
236
+ const tx = baseTransactionTronApi({
237
+ type: "TransferAssetContract",
238
+ parameter: {
239
+ type_url: "",
240
+ value: {
241
+ owner_address: ownerHex,
242
+ to_address: toHex,
243
+ amount: 100,
244
+ asset_name: assetName,
245
+ },
246
+ },
247
+ });
248
+ const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null));
249
+ expect(result).toEqual({
250
+ txID: "txId",
251
+ date: new Date(1),
252
+ type: "TransferAssetContract",
253
+ tokenId: assetName,
254
+ tokenType: "trc10",
255
+ tokenAddress: undefined,
256
+ from: encode58Check(ownerHex),
257
+ to: encode58Check(toHex),
258
+ value: new BigNumber(100),
259
+ fee: new BigNumber(1000),
260
+ blockHeight: 42,
261
+ hasFailed: false,
262
+ feesPayer: encode58Check(ownerHex),
263
+ });
264
+ });
265
+
266
+ it("should return correct TrongridTxInfo for TriggerSmartContract", async () => {
267
+ const tx = baseTransactionTronApi({
268
+ type: "TriggerSmartContract",
269
+ parameter: {
270
+ type_url: "",
271
+ value: {
272
+ owner_address: ownerHex,
273
+ to_address: toHex,
274
+ contract_address: trc20ContractHex,
275
+ amount: 0,
276
+ },
277
+ },
278
+ });
279
+ const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null));
280
+ expect(result).toEqual({
281
+ txID: "txId",
282
+ date: new Date(1),
283
+ type: "TriggerSmartContract",
284
+ tokenId: encode58Check(trc20ContractHex),
285
+ tokenType: "trc20",
286
+ tokenAddress: encode58Check(trc20ContractHex),
287
+ from: encode58Check(ownerHex),
288
+ to: encode58Check(toHex),
289
+ value: new BigNumber(0),
290
+ fee: new BigNumber(1000),
291
+ blockHeight: 42,
292
+ hasFailed: false,
293
+ feesPayer: encode58Check(ownerHex),
294
+ });
295
+ });
296
+
297
+ it("should map withdraw amount for WithdrawBalanceContract", async () => {
298
+ const tx = baseTransactionTronApi(
299
+ {
300
+ type: "WithdrawBalanceContract",
301
+ parameter: {
302
+ type_url: "",
303
+ value: {
304
+ owner_address: ownerHex,
305
+ },
306
+ },
307
+ },
308
+ { withdraw_amount: 5_000_000 },
309
+ );
310
+ const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null));
311
+ expect(result?.value).toEqual(new BigNumber(5_000_000));
312
+ });
313
+
314
+ it("should map quant for ExchangeTransactionContract", async () => {
315
+ const tx = baseTransactionTronApi({
316
+ type: "ExchangeTransactionContract",
317
+ parameter: {
318
+ type_url: "",
319
+ value: {
320
+ owner_address: ownerHex,
321
+ quant: 777,
322
+ },
323
+ },
324
+ });
325
+ const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null));
326
+ expect(result?.value).toEqual(new BigNumber(777));
327
+ });
328
+
329
+ it("should attach vote extra info using getValidatorName", async () => {
330
+ const voteAddressHex = "41b183301d6301fae224c6ab9b28b19b6d1625bf23";
331
+ const getValidatorName = jest
332
+ .fn()
333
+ .mockImplementation(async (address: string) =>
334
+ address === encode58Check(voteAddressHex) ? "SR-Name" : null,
335
+ );
336
+ const tx = baseTransactionTronApi({
337
+ type: "VoteWitnessContract",
338
+ parameter: {
339
+ type_url: "",
340
+ value: {
341
+ owner_address: ownerHex,
342
+ votes: [{ vote_address: voteAddressHex, vote_count: 3 }],
343
+ },
344
+ },
345
+ });
346
+ const result = await formatTrongridTxResponse(tx, getValidatorName);
347
+ expect(getValidatorName).toHaveBeenCalledWith(encode58Check(voteAddressHex));
348
+ expect(result?.extra).toEqual({
349
+ votes: [
350
+ {
351
+ name: "SR-Name",
352
+ address: encode58Check(voteAddressHex),
353
+ voteCount: 3,
354
+ },
355
+ ],
356
+ });
357
+ });
358
+
359
+ it("should return undefined when the transaction payload cannot be parsed", async () => {
360
+ const tx = { txID: "broken", block_timestamp: 1 } as TransactionTronAPI;
361
+ const result = await formatTrongridTxResponse(tx, () => Promise.resolve(null));
362
+ expect(result).toBeUndefined();
363
+ });
65
364
  });
66
365
 
67
366
  describe("decode58Check", () => {
@@ -20,6 +20,11 @@ export const formatTrongridTrc20TxResponse = (tx: Trc20API): TrongridTxInfo | nu
20
20
  const bnFee = new BigNumber(fee || 0);
21
21
  let formattedValue;
22
22
 
23
+ // token_info.address is missing for unindexed contracts (e.g. LP/DEX pool tokens not in TronGrid registry)
24
+ // fall back to the contract_address from the raw transaction, which is always present
25
+ const contractAddressHex = detail.raw_data?.contract?.[0]?.parameter?.value?.contract_address;
26
+ const tokenAddress = token_info.address ?? (contractAddressHex ? encode58Check(contractAddressHex) : undefined);
27
+
23
28
  switch (type) {
24
29
  case "Approval":
25
30
  txType = "ContractApproval";
@@ -27,7 +32,7 @@ export const formatTrongridTrc20TxResponse = (tx: Trc20API): TrongridTxInfo | nu
27
32
  break;
28
33
  default:
29
34
  txType = "TriggerSmartContract";
30
- tokenId = token_info.address ?? undefined;
35
+ tokenId = tokenAddress;
31
36
  formattedValue = value ? new BigNumber(value) : new BigNumber(0);
32
37
  break;
33
38
  }
@@ -35,12 +40,14 @@ export const formatTrongridTrc20TxResponse = (tx: Trc20API): TrongridTxInfo | nu
35
40
  const date = new Date(block_timestamp);
36
41
 
37
42
  const blockHeight = detail ? detail.blockNumber : undefined;
43
+ const ownerAddressHex = detail.raw_data?.contract?.[0]?.parameter?.value?.owner_address;
44
+ const feesPayer = ownerAddressHex ? encode58Check(ownerAddressHex) : from;
38
45
  return {
39
46
  txID,
40
47
  date,
41
48
  type: txType,
42
49
  tokenId: tokenId,
43
- tokenAddress: token_info.address,
50
+ tokenAddress,
44
51
  tokenType: "trc20",
45
52
  from,
46
53
  to,
@@ -48,6 +55,7 @@ export const formatTrongridTrc20TxResponse = (tx: Trc20API): TrongridTxInfo | nu
48
55
  value: formattedValue,
49
56
  fee: bnFee,
50
57
  hasFailed: false, // trc20 txs are succeeded if returned by trongrid,
58
+ feesPayer,
51
59
  };
52
60
  } catch (e) {
53
61
  log("tron-error", `could not parse transaction ${tx}`);
@@ -55,9 +63,10 @@ export const formatTrongridTrc20TxResponse = (tx: Trc20API): TrongridTxInfo | nu
55
63
  }
56
64
  };
57
65
 
58
- export const formatTrongridTxResponse = (
66
+ export const formatTrongridTxResponse = async (
59
67
  tx: TransactionTronAPI & { detail?: TronTransactionInfo },
60
- ): TrongridTxInfo | null | undefined => {
68
+ getValidatorName: (address: string) => Promise<string | null | undefined>,
69
+ ): Promise<TrongridTxInfo | null | undefined> => {
61
70
  try {
62
71
  const { txID, block_timestamp, detail, blockNumber, unfreeze_amount, withdraw_amount } = tx;
63
72
  const date = new Date(block_timestamp);
@@ -118,16 +127,22 @@ export const formatTrongridTxResponse = (
118
127
  fee: new BigNumber(fee || 0),
119
128
  blockHeight,
120
129
  hasFailed,
130
+ feesPayer: from,
121
131
  };
122
132
 
123
- const getExtra = (): TrongridExtraTxInfo | null | undefined => {
133
+ const getExtra = async (): Promise<TrongridExtraTxInfo | null | undefined> => {
124
134
  switch (type) {
125
135
  case "VoteWitnessContract":
126
136
  return {
127
- votes: votes?.map(v => ({
128
- address: encode58Check(v.vote_address as string),
129
- voteCount: v.vote_count,
130
- })),
137
+ votes:
138
+ votes &&
139
+ (await Promise.all(
140
+ votes.map(async v => ({
141
+ name: await getValidatorName(encode58Check(v.vote_address)),
142
+ address: encode58Check(v.vote_address),
143
+ voteCount: v.vote_count,
144
+ })),
145
+ )),
131
146
  };
132
147
 
133
148
  case "FreezeBalanceContract":
@@ -157,7 +172,7 @@ export const formatTrongridTxResponse = (
157
172
  }
158
173
  };
159
174
 
160
- const extra = getExtra();
175
+ const extra = await getExtra();
161
176
 
162
177
  if (extra) {
163
178
  txInfo.extra = extra;
@@ -589,10 +589,12 @@ export async function fetchTronAccountTxsPage(
589
589
  ),
590
590
  ]);
591
591
 
592
- const nativeTxsFormatted = nativeResult.results
593
- .filter(isTransactionTronAPI)
594
- .filter(isValidNativeTx)
595
- .map(tx => formatTrongridTxResponse(tx));
592
+ const nativeTxsFormatted = await Promise.all(
593
+ nativeResult.results
594
+ .filter(isTransactionTronAPI)
595
+ .filter(isValidNativeTx)
596
+ .map(tx => formatTrongridTxResponse(tx, accountNamesCache)),
597
+ );
596
598
 
597
599
  const trc20TxsFormatted = compact(trc20Result.results.map(formatTrongridTrc20TxResponse));
598
600
  const trc20TxIds = new Set(trc20TxsFormatted.map(t => t.txID));
@@ -616,18 +618,20 @@ export async function fetchTronAccountTxs(
616
618
  ? Math.min(params.limitPerCall, params.hintGlobalLimit)
617
619
  : params.limitPerCall;
618
620
  const queryParams = `limit=${adjustedLimitPerCall}&min_timestamp=${params.minTimestamp}&order_by=block_timestamp,${params.order}`;
619
- const nativeTxs = (
620
- await getAllTransactions<
621
- (TransactionTronAPI & { detail?: TronTransactionInfo }) | MalformedTransactionTronAPI
622
- >(
623
- `${getBaseApiUrl()}/v1/accounts/${addr}/transactions?${queryParams}`,
624
- shouldFetchMoreTxs,
625
- getTransactions(cacheTransactionInfoById),
621
+ const nativeTxs = await Promise.all(
622
+ (
623
+ await getAllTransactions<
624
+ (TransactionTronAPI & { detail?: TronTransactionInfo }) | MalformedTransactionTronAPI
625
+ >(
626
+ `${getBaseApiUrl()}/v1/accounts/${addr}/transactions?${queryParams}`,
627
+ shouldFetchMoreTxs,
628
+ getTransactions(cacheTransactionInfoById),
629
+ )
626
630
  )
627
- )
628
- .filter(isTransactionTronAPI)
629
- .filter(isValidNativeTx)
630
- .map(tx => formatTrongridTxResponse(tx));
631
+ .filter(isTransactionTronAPI)
632
+ .filter(isValidNativeTx)
633
+ .map(tx => formatTrongridTxResponse(tx, accountNamesCache)),
634
+ );
631
635
 
632
636
  // we need to fetch and filter trc20 transactions from another endpoint
633
637
  // doc https://developers.tron.network/reference/get-trc20-transaction-info-by-account-address
@@ -774,19 +778,12 @@ export const validateAddress = async (address: string): Promise<boolean> => {
774
778
  };
775
779
 
776
780
  // cache for account names (name is unchanged over time)
777
- const accountNamesCache = makeLRUCache(
781
+ export const accountNamesCache = makeLRUCache(
778
782
  async (addr: string): Promise<string | null | undefined> => getAccountName(addr),
779
783
  (addr: string) => addr,
780
784
  hours(3, 300),
781
785
  );
782
786
 
783
- // cache for super representative brokerages (brokerage is unchanged over time)
784
- const srBrokeragesCache = makeLRUCache(
785
- async (addr: string): Promise<number> => getBrokerage(addr),
786
- (addr: string) => addr,
787
- hours(3, 300),
788
- );
789
-
790
787
  export const getAccountName = async (addr: string): Promise<string | null | undefined> => {
791
788
  const tronAcc = await fetchTronAccount(addr);
792
789
  const acc = tronAcc[0];
@@ -797,13 +794,6 @@ export const getAccountName = async (addr: string): Promise<string | null | unde
797
794
  return accountName;
798
795
  };
799
796
 
800
- export const getBrokerage = async (addr: string): Promise<number> => {
801
- const { brokerage } = await fetch(`/wallet/getBrokerage?address=${encodeURIComponent(addr)}`);
802
- srBrokeragesCache.hydrate(addr, brokerage); // put it in cache
803
-
804
- return brokerage;
805
- };
806
-
807
797
  const superRepresentativesCache = makeLRUCache(
808
798
  async (): Promise<SuperRepresentative[]> => {
809
799
  const superRepresentatives = await fetchSuperRepresentatives();
@@ -827,21 +817,14 @@ export const hydrateSuperRepresentatives = (list: SuperRepresentative[]) => {
827
817
  };
828
818
 
829
819
  const fetchSuperRepresentatives = async (): Promise<SuperRepresentative[]> => {
830
- const result = await fetch(`/wallet/listwitnesses`);
831
- const sorted = result.witnesses.sort((a: any, b: any) => b.voteCount - a.voteCount);
832
- const superRepresentatives = await promiseAllBatched(3, sorted, async (w: any) => {
833
- const encodedAddress = encode58Check(w.address);
834
- const accountName = await accountNamesCache(encodedAddress);
835
- const brokerage = await srBrokeragesCache(encodedAddress);
836
- return {
837
- ...w,
838
- address: encodedAddress,
839
- name: accountName,
840
- brokerage,
841
- voteCount: w.voteCount || 0,
842
- isJobs: w.isJobs || false,
843
- };
844
- });
820
+ const result = await fetch<{ witnesses: SuperRepresentative[] }>(`/wallet/listwitnesses`);
821
+ const sorted = result.witnesses.sort((a, b) => b.voteCount - a.voteCount);
822
+ const superRepresentatives = sorted.map(w => ({
823
+ ...w,
824
+ address: encode58Check(w.address),
825
+ voteCount: w.voteCount || 0,
826
+ isJobs: w.isJobs || false,
827
+ }));
845
828
  hydrateSuperRepresentatives(superRepresentatives); // put it in cache
846
829
 
847
830
  return superRepresentatives;
@@ -119,6 +119,19 @@ describe("fromTrongridTxInfoToOperation", () => {
119
119
  expect(result.type).toBe("UNKNOWN");
120
120
  });
121
121
 
122
+ it("should use feesPayer over from when set (transferFrom case)", () => {
123
+ const txInfo = {
124
+ ...mockTrongridTxInfo,
125
+ from: mockUserAddress, // TRC20 "from" — our address
126
+ feesPayer: "actualInitiator", // Tron owner_address — someone else called transferFrom
127
+ };
128
+
129
+ const result = fromTrongridTxInfoToOperation(txInfo, mockBlock, mockUserAddress);
130
+
131
+ expect(result.tx.feesPayer).toBe("actualInitiator");
132
+ expect(result.type).toBe("OUT"); // direction still uses `from`
133
+ });
134
+
122
135
  it("should handle missing fee or value gracefully", () => {
123
136
  const txInfo = {
124
137
  ...mockTrongridTxInfo,
@@ -18,7 +18,7 @@ export function fromTrongridTxInfoToOperation(
18
18
  time: block.time || new Date(0),
19
19
  },
20
20
  fees: fromBigNumberToBigInt<bigint>(trongridTxInfo.fee, BigInt(0)),
21
- feesPayer: trongridTxInfo.from,
21
+ feesPayer: trongridTxInfo.feesPayer ?? trongridTxInfo.from,
22
22
  date: trongridTxInfo.date,
23
23
  failed: trongridTxInfo.hasFailed,
24
24
  },
@@ -148,10 +148,12 @@ const tron: CurrenciesData<Transaction> = {
148
148
  resource: undefined,
149
149
  votes: [
150
150
  {
151
+ name: "Node 1",
151
152
  address: "TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH",
152
153
  voteCount: 1,
153
154
  },
154
155
  {
156
+ name: "Node 2",
155
157
  address: "TGj1Ej1qRzL9feLTLhjwgxXF4Ct6GTWg2U",
156
158
  voteCount: 1,
157
159
  },
@@ -643,6 +645,7 @@ const tron: CurrenciesData<Transaction> = {
643
645
  resource: undefined,
644
646
  votes: [
645
647
  {
648
+ name: "Node 1",
646
649
  address: "abcde",
647
650
  voteCount: 1,
648
651
  },
@@ -670,6 +673,7 @@ const tron: CurrenciesData<Transaction> = {
670
673
  resource: undefined,
671
674
  votes: [
672
675
  {
676
+ name: "Node 1",
673
677
  address: "TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH",
674
678
  voteCount: 0,
675
679
  },
@@ -697,10 +701,12 @@ const tron: CurrenciesData<Transaction> = {
697
701
  resource: undefined,
698
702
  votes: [
699
703
  {
704
+ name: "Node 1",
700
705
  address: "TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH",
701
706
  voteCount: 5,
702
707
  },
703
708
  {
709
+ name: "Node 2",
704
710
  address: "TGj1Ej1qRzL9feLTLhjwgxXF4Ct6GTWg2U",
705
711
  voteCount: 5,
706
712
  },
@@ -864,9 +870,21 @@ const tron: CurrenciesData<Transaction> = {
864
870
  energy: { amount: "26000000", expiredAt: "2020-02-01T16:04:51.000Z" },
865
871
  },
866
872
  votes: [
867
- { address: "TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH", voteCount: 15 },
868
- { address: "TGj1Ej1qRzL9feLTLhjwgxXF4Ct6GTWg2U", voteCount: 1 },
869
- { address: "TCZvvbn4SCVyNhCAt1L8Kp1qk5rtMiKdBB", voteCount: 2 },
873
+ {
874
+ name: "Node 1",
875
+ address: "TLyqzVGLV1srkB7dToTAEqgDSfPtXRJZYH",
876
+ voteCount: 15,
877
+ },
878
+ {
879
+ name: "Node 2",
880
+ address: "TGj1Ej1qRzL9feLTLhjwgxXF4Ct6GTWg2U",
881
+ voteCount: 1,
882
+ },
883
+ {
884
+ name: "Node 3",
885
+ address: "TCZvvbn4SCVyNhCAt1L8Kp1qk5rtMiKdBB",
886
+ voteCount: 2,
887
+ },
870
888
  ],
871
889
  tronPower: 26,
872
890
  energy: "326",
package/src/test/cli.ts CHANGED
@@ -36,6 +36,12 @@ const options = [
36
36
  type: String,
37
37
  desc: "reward ENERGY or BANDWIDTH",
38
38
  },
39
+ {
40
+ name: "tronVoteName",
41
+ type: String,
42
+ multiple: true,
43
+ desc: "name of the super representative voting",
44
+ },
39
45
  {
40
46
  name: "tronVoteAddress",
41
47
  type: String,
@@ -111,12 +117,14 @@ function inferTransactions(
111
117
  invariant(["BANDWIDTH", "ENERGY"].includes(resource), `Unexpected resource: ${resource}`);
112
118
  }
113
119
 
120
+ const voteNames: string[] = opts["tronVoteName"] || [];
114
121
  const voteAddresses: string[] = opts["tronVoteAddress"] || [];
115
122
  const voteCounts: number[] = (opts["tronVoteCount"] || []).map((value: string) => {
116
123
  invariant(Number.isInteger(Number(value)), `Invalid integer: ${value}`);
117
124
  return parseInt(value);
118
125
  });
119
- const votes: Vote[] = zipWith(voteAddresses, voteCounts, (a, c) => ({
126
+ const votes: Vote[] = zipWith(voteNames, voteAddresses, voteCounts, (n, a, c) => ({
127
+ name: n,
120
128
  address: a,
121
129
  voteCount: c,
122
130
  }));
@@ -148,12 +156,9 @@ const formatOptStr = (str: string | null | undefined): string => str || "";
148
156
  const superRepresentativesFormatters = {
149
157
  json: (srData: SuperRepresentativeData): string => JSON.stringify(srData),
150
158
  default: (srData: SuperRepresentativeData): string => {
151
- const headerList = 'address "name" url voteCount brokerage isJobs';
159
+ const headerList = "address url voteCount isJobs";
152
160
  const strList = srData.list.map(
153
- sr =>
154
- `${sr.address} "${formatOptStr(sr.name)}" ${formatOptStr(sr.url)} ${sr.voteCount} ${
155
- sr.brokerage
156
- } ${sr.isJobs}`,
161
+ sr => `${sr.address} ${formatOptStr(sr.url)} ${sr.voteCount} ${sr.isJobs}`,
157
162
  );
158
163
  const metaData = [
159
164
  `nextVotingDate: ${srData.nextVotingDate}`,