@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.
- package/CHANGELOG.md +74 -0
- package/lib/api/index.d.ts.map +1 -1
- package/lib/api/index.js +9 -2
- package/lib/api/index.js.map +1 -1
- package/lib/bridge/index.d.ts.map +1 -1
- package/lib/bridge/index.js +2 -3
- package/lib/bridge/index.js.map +1 -1
- package/lib/bridge/prepareTransaction.d.ts.map +1 -1
- package/lib/bridge/prepareTransaction.js +6 -0
- package/lib/bridge/prepareTransaction.js.map +1 -1
- package/lib/bridge/utils.d.ts.map +1 -1
- package/lib/bridge/utils.js +11 -0
- package/lib/bridge/utils.js.map +1 -1
- package/lib/logic/listOperations.d.ts.map +1 -1
- package/lib/logic/listOperations.js +7 -0
- package/lib/logic/listOperations.js.map +1 -1
- package/lib/logic/utils.d.ts +1 -1
- package/lib/logic/utils.d.ts.map +1 -1
- package/lib/logic/utils.js +0 -5
- package/lib/logic/utils.js.map +1 -1
- package/lib/network/format.d.ts +1 -1
- package/lib/network/format.d.ts.map +1 -1
- package/lib/network/format.js +19 -9
- package/lib/network/format.js.map +1 -1
- package/lib/network/index.d.ts +1 -1
- package/lib/network/index.d.ts.map +1 -1
- package/lib/network/index.js +13 -28
- package/lib/network/index.js.map +1 -1
- package/lib/network/trongrid/trongrid-adapters.js +1 -1
- package/lib/network/trongrid/trongrid-adapters.js.map +1 -1
- package/lib/test/bridgeDatasetTest.d.ts.map +1 -1
- package/lib/test/bridgeDatasetTest.js +21 -3
- package/lib/test/bridgeDatasetTest.js.map +1 -1
- package/lib/test/cli.d.ts.map +1 -1
- package/lib/test/cli.js +11 -3
- package/lib/test/cli.js.map +1 -1
- package/lib/types/bridge.d.ts +2 -2
- package/lib/types/bridge.d.ts.map +1 -1
- package/lib/types/bridge.js.map +1 -1
- package/lib/types/errors.d.ts +3 -0
- package/lib/types/errors.d.ts.map +1 -1
- package/lib/types/errors.js +2 -1
- package/lib/types/errors.js.map +1 -1
- package/lib-es/api/index.d.ts.map +1 -1
- package/lib-es/api/index.js +10 -3
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/bridge/index.d.ts.map +1 -1
- package/lib-es/bridge/index.js +2 -3
- package/lib-es/bridge/index.js.map +1 -1
- package/lib-es/bridge/prepareTransaction.d.ts.map +1 -1
- package/lib-es/bridge/prepareTransaction.js +7 -1
- package/lib-es/bridge/prepareTransaction.js.map +1 -1
- package/lib-es/bridge/utils.d.ts.map +1 -1
- package/lib-es/bridge/utils.js +9 -1
- package/lib-es/bridge/utils.js.map +1 -1
- package/lib-es/logic/listOperations.d.ts.map +1 -1
- package/lib-es/logic/listOperations.js +7 -0
- package/lib-es/logic/listOperations.js.map +1 -1
- package/lib-es/logic/utils.d.ts +1 -1
- package/lib-es/logic/utils.d.ts.map +1 -1
- package/lib-es/logic/utils.js +0 -5
- package/lib-es/logic/utils.js.map +1 -1
- package/lib-es/network/format.d.ts +1 -1
- package/lib-es/network/format.d.ts.map +1 -1
- package/lib-es/network/format.js +19 -9
- package/lib-es/network/format.js.map +1 -1
- package/lib-es/network/index.d.ts +1 -1
- package/lib-es/network/index.d.ts.map +1 -1
- package/lib-es/network/index.js +11 -25
- package/lib-es/network/index.js.map +1 -1
- package/lib-es/network/trongrid/trongrid-adapters.js +1 -1
- package/lib-es/network/trongrid/trongrid-adapters.js.map +1 -1
- package/lib-es/test/bridgeDatasetTest.d.ts.map +1 -1
- package/lib-es/test/bridgeDatasetTest.js +21 -3
- package/lib-es/test/bridgeDatasetTest.js.map +1 -1
- package/lib-es/test/cli.d.ts.map +1 -1
- package/lib-es/test/cli.js +11 -3
- package/lib-es/test/cli.js.map +1 -1
- package/lib-es/types/bridge.d.ts +2 -2
- package/lib-es/types/bridge.d.ts.map +1 -1
- package/lib-es/types/bridge.js.map +1 -1
- package/lib-es/types/errors.d.ts +3 -0
- package/lib-es/types/errors.d.ts.map +1 -1
- package/lib-es/types/errors.js +1 -0
- package/lib-es/types/errors.js.map +1 -1
- package/package.json +8 -8
- package/src/api/index.test.ts +42 -5
- package/src/api/index.ts +18 -8
- package/src/bridge/index.ts +2 -3
- package/src/bridge/prepareTransaction.test.ts +118 -0
- package/src/bridge/prepareTransaction.ts +11 -1
- package/src/bridge/utils.ts +12 -1
- package/src/logic/listOperations.ts +10 -0
- package/src/logic/listOperations.unit.test.ts +34 -5
- package/src/logic/utils.test.ts +0 -37
- package/src/logic/utils.ts +6 -7
- package/src/network/format.test.ts +301 -2
- package/src/network/format.ts +25 -10
- package/src/network/index.ts +28 -45
- package/src/network/trongrid/trongrid-adapters.test.ts +13 -0
- package/src/network/trongrid/trongrid-adapters.ts +1 -1
- package/src/test/bridgeDatasetTest.ts +21 -3
- package/src/test/cli.ts +11 -6
- package/src/types/bridge.ts +2 -2
- package/src/types/errors.ts +1 -0
- package/.turbo/turbo-build.log +0 -4
- package/lib/bridge/preload.d.ts +0 -8
- package/lib/bridge/preload.d.ts.map +0 -1
- package/lib/bridge/preload.js +0 -23
- package/lib/bridge/preload.js.map +0 -1
- package/lib-es/bridge/preload.d.ts +0 -8
- package/lib-es/bridge/preload.d.ts.map +0 -1
- package/lib-es/bridge/preload.js +0 -18
- package/lib-es/bridge/preload.js.map +0 -1
- package/src/bridge/preload.ts +0 -24
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
import BigNumber from "bignumber.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
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", () => {
|
package/src/network/format.ts
CHANGED
|
@@ -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 =
|
|
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
|
|
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
|
-
|
|
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:
|
|
128
|
-
|
|
129
|
-
|
|
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;
|
package/src/network/index.ts
CHANGED
|
@@ -589,10 +589,12 @@ export async function fetchTronAccountTxsPage(
|
|
|
589
589
|
),
|
|
590
590
|
]);
|
|
591
591
|
|
|
592
|
-
const nativeTxsFormatted =
|
|
593
|
-
.
|
|
594
|
-
|
|
595
|
-
|
|
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
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
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
|
-
|
|
629
|
-
|
|
630
|
-
|
|
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
|
|
832
|
-
const superRepresentatives =
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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
|
-
{
|
|
868
|
-
|
|
869
|
-
|
|
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 =
|
|
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}`,
|