@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
package/src/api/index.ts
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
|
+
import { rejectBalanceOptions } from "@ledgerhq/coin-module-framework/api/getBalance/rejectBalanceOptions";
|
|
1
2
|
import {
|
|
2
3
|
AlpacaApi,
|
|
4
|
+
Balance,
|
|
5
|
+
CraftedTransaction,
|
|
3
6
|
Cursor,
|
|
4
|
-
ListOperationsOptions,
|
|
5
|
-
Page,
|
|
6
|
-
Validator,
|
|
7
7
|
FeeEstimation,
|
|
8
|
+
ListOperationsOptions,
|
|
8
9
|
Operation,
|
|
10
|
+
Page,
|
|
9
11
|
Reward,
|
|
10
12
|
Stake,
|
|
11
13
|
TransactionIntent,
|
|
12
|
-
CraftedTransaction,
|
|
13
14
|
TransactionValidation,
|
|
14
|
-
|
|
15
|
+
Validator,
|
|
16
|
+
BalanceOptions,
|
|
15
17
|
} from "@ledgerhq/coin-module-framework/api/index";
|
|
18
|
+
import { craftTransactionData } from "@ledgerhq/coin-module-framework/logic/craftTransactionData";
|
|
16
19
|
import coinConfig, { type TronConfig } from "../config";
|
|
17
20
|
import {
|
|
18
21
|
broadcast,
|
|
@@ -22,13 +25,15 @@ import {
|
|
|
22
25
|
getBalance,
|
|
23
26
|
getBlock,
|
|
24
27
|
getBlockInfo,
|
|
25
|
-
listOperations as listOperationsLogic,
|
|
26
28
|
lastBlock,
|
|
29
|
+
listOperations as listOperationsLogic,
|
|
27
30
|
validateAddress,
|
|
28
31
|
} from "../logic";
|
|
29
32
|
import { defaultFetchParams, getBlock as getBlockNetwork } from "../network";
|
|
30
33
|
import type { TronMemo } from "../types";
|
|
31
34
|
|
|
35
|
+
const MAX_TRONGRID_LIMIT = 200;
|
|
36
|
+
|
|
32
37
|
export function createApi(config: TronConfig): AlpacaApi<TronMemo> {
|
|
33
38
|
coinConfig.setCoinConfig(() => ({ ...config, status: { type: "active" } }));
|
|
34
39
|
|
|
@@ -45,7 +50,8 @@ export function createApi(config: TronConfig): AlpacaApi<TronMemo> {
|
|
|
45
50
|
throw new Error("craftRawTransaction is not supported");
|
|
46
51
|
},
|
|
47
52
|
estimateFees: estimate,
|
|
48
|
-
getBalance,
|
|
53
|
+
getBalance: (address: string, options?: BalanceOptions) =>
|
|
54
|
+
rejectBalanceOptions(() => getBalance(address), options),
|
|
49
55
|
lastBlock,
|
|
50
56
|
listOperations,
|
|
51
57
|
getBlock,
|
|
@@ -70,6 +76,7 @@ export function createApi(config: TronConfig): AlpacaApi<TronMemo> {
|
|
|
70
76
|
throw new Error("getNextSequence is not supported");
|
|
71
77
|
},
|
|
72
78
|
validateAddress,
|
|
79
|
+
craftTransactionData,
|
|
73
80
|
};
|
|
74
81
|
}
|
|
75
82
|
|
|
@@ -82,7 +89,10 @@ async function listOperations(
|
|
|
82
89
|
address: string,
|
|
83
90
|
{ minHeight, order, cursor, limit }: ListOperationsOptions,
|
|
84
91
|
): Promise<Page<Operation>> {
|
|
85
|
-
|
|
92
|
+
if (limit !== undefined && limit > MAX_TRONGRID_LIMIT) {
|
|
93
|
+
throw new Error(`limit must be <= ${MAX_TRONGRID_LIMIT} for Tron (TronGrid API restriction)`);
|
|
94
|
+
}
|
|
95
|
+
const effectiveLimit = limit ?? MAX_TRONGRID_LIMIT;
|
|
86
96
|
const effectiveOrder = order ?? "asc";
|
|
87
97
|
|
|
88
98
|
let minTimestamp = defaultFetchParams.minTimestamp;
|
package/src/bridge/index.ts
CHANGED
|
@@ -16,7 +16,6 @@ import broadcast from "./broadcast";
|
|
|
16
16
|
import createTransaction from "./createTransaction";
|
|
17
17
|
import estimateMaxSpendable from "./estimateMaxSpendable";
|
|
18
18
|
import getTransactionStatus from "./getTransactionStatus";
|
|
19
|
-
import { hydrate, preload } from "./preload";
|
|
20
19
|
import { prepareTransaction } from "./prepareTransaction";
|
|
21
20
|
import {
|
|
22
21
|
assignFromAccountRaw,
|
|
@@ -37,8 +36,8 @@ function buildCurrencyBridge(signerContext: SignerContext<TronSigner>): Currency
|
|
|
37
36
|
});
|
|
38
37
|
|
|
39
38
|
return {
|
|
40
|
-
preload,
|
|
41
|
-
hydrate,
|
|
39
|
+
preload: () => Promise.resolve({}),
|
|
40
|
+
hydrate: () => undefined,
|
|
42
41
|
scanAccounts,
|
|
43
42
|
};
|
|
44
43
|
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js";
|
|
2
|
+
import { accountNamesCache, getTronAccountNetwork } from "../network";
|
|
3
|
+
import { NetworkInfo, Transaction, TronAccount } from "../types";
|
|
4
|
+
import { prepareTransaction } from "./prepareTransaction";
|
|
5
|
+
|
|
6
|
+
jest.mock("../network", () => ({
|
|
7
|
+
getTronAccountNetwork: jest.fn(),
|
|
8
|
+
accountNamesCache: jest.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const mockGetTronAccountNetwork = jest.mocked(getTronAccountNetwork);
|
|
12
|
+
const mockAccountNamesCache = jest.mocked(accountNamesCache);
|
|
13
|
+
|
|
14
|
+
const baseNetworkInfo: NetworkInfo = {
|
|
15
|
+
family: "tron",
|
|
16
|
+
freeNetUsed: new BigNumber(1),
|
|
17
|
+
freeNetLimit: new BigNumber(2),
|
|
18
|
+
netUsed: new BigNumber(3),
|
|
19
|
+
netLimit: new BigNumber(4),
|
|
20
|
+
energyUsed: new BigNumber(5),
|
|
21
|
+
energyLimit: new BigNumber(6),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const createTransaction = (overrides: Partial<Transaction> = {}): Transaction => ({
|
|
25
|
+
family: "tron",
|
|
26
|
+
mode: "send",
|
|
27
|
+
resource: "BANDWIDTH",
|
|
28
|
+
networkInfo: undefined,
|
|
29
|
+
duration: null,
|
|
30
|
+
votes: [],
|
|
31
|
+
amount: new BigNumber(0),
|
|
32
|
+
recipient: "mock-recipient",
|
|
33
|
+
...overrides,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const createAccount = (overrides: Partial<TronAccount> = {}): TronAccount =>
|
|
37
|
+
({
|
|
38
|
+
freshAddress: "TMockFreshAddress",
|
|
39
|
+
...overrides,
|
|
40
|
+
}) as TronAccount;
|
|
41
|
+
|
|
42
|
+
describe("prepareTransaction", () => {
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
jest.clearAllMocks();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should return the same transaction when networkInfo is already set", async () => {
|
|
48
|
+
const account = createAccount();
|
|
49
|
+
const transaction = createTransaction({ networkInfo: baseNetworkInfo });
|
|
50
|
+
|
|
51
|
+
const result = await prepareTransaction(account, transaction);
|
|
52
|
+
|
|
53
|
+
expect(result).toBe(transaction);
|
|
54
|
+
expect(mockGetTronAccountNetwork).not.toHaveBeenCalled();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should fetch network info when networkInfo is missing", async () => {
|
|
58
|
+
const account = createAccount({ freshAddress: "TAddr123" });
|
|
59
|
+
const transaction = createTransaction({ networkInfo: undefined });
|
|
60
|
+
mockGetTronAccountNetwork.mockResolvedValue(baseNetworkInfo);
|
|
61
|
+
|
|
62
|
+
const result = await prepareTransaction(account, transaction);
|
|
63
|
+
|
|
64
|
+
expect(mockGetTronAccountNetwork).toHaveBeenCalledTimes(1);
|
|
65
|
+
expect(mockGetTronAccountNetwork).toHaveBeenCalledWith("TAddr123");
|
|
66
|
+
expect(result).not.toBe(transaction);
|
|
67
|
+
expect(result.networkInfo).toEqual(baseNetworkInfo);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should enrich vote names using accountNamesCache when votes are present", async () => {
|
|
71
|
+
const account = createAccount();
|
|
72
|
+
const voteAddress = "TVoteAddr";
|
|
73
|
+
const transaction = createTransaction({
|
|
74
|
+
networkInfo: baseNetworkInfo,
|
|
75
|
+
votes: [{ address: voteAddress, voteCount: 100, name: undefined }],
|
|
76
|
+
});
|
|
77
|
+
mockAccountNamesCache.mockResolvedValue("SR name");
|
|
78
|
+
|
|
79
|
+
const result = await prepareTransaction(account, transaction);
|
|
80
|
+
|
|
81
|
+
expect(mockAccountNamesCache).toHaveBeenCalledWith(voteAddress);
|
|
82
|
+
expect(result.votes).toEqual([
|
|
83
|
+
{ address: voteAddress, voteCount: 100, name: "SR name" },
|
|
84
|
+
]);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should enrich multiple votes in parallel", async () => {
|
|
88
|
+
const account = createAccount();
|
|
89
|
+
const transaction = createTransaction({
|
|
90
|
+
networkInfo: baseNetworkInfo,
|
|
91
|
+
votes: [
|
|
92
|
+
{ address: "TA", voteCount: 1, name: undefined },
|
|
93
|
+
{ address: "TB", voteCount: 2, name: undefined },
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
mockAccountNamesCache.mockImplementation(async addr =>
|
|
97
|
+
addr === "TA" ? "Name A" : "Name B",
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
await prepareTransaction(account, transaction);
|
|
101
|
+
|
|
102
|
+
expect(mockAccountNamesCache).toHaveBeenCalledTimes(2);
|
|
103
|
+
expect(mockAccountNamesCache).toHaveBeenCalledWith("TA");
|
|
104
|
+
expect(mockAccountNamesCache).toHaveBeenCalledWith("TB");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should not call accountNamesCache when there are no votes", async () => {
|
|
108
|
+
const account = createAccount();
|
|
109
|
+
const transaction = createTransaction({
|
|
110
|
+
networkInfo: baseNetworkInfo,
|
|
111
|
+
votes: [],
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
await prepareTransaction(account, transaction);
|
|
115
|
+
|
|
116
|
+
expect(mockAccountNamesCache).not.toHaveBeenCalled();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AccountBridge } from "@ledgerhq/types-live";
|
|
2
|
-
import { getTronAccountNetwork } from "../network";
|
|
2
|
+
import { accountNamesCache, getTronAccountNetwork } from "../network";
|
|
3
3
|
import { Transaction, TronAccount } from "../types";
|
|
4
4
|
|
|
5
5
|
export const prepareTransaction: AccountBridge<
|
|
@@ -8,5 +8,15 @@ export const prepareTransaction: AccountBridge<
|
|
|
8
8
|
>["prepareTransaction"] = async (account, transaction) => {
|
|
9
9
|
const networkInfo =
|
|
10
10
|
transaction.networkInfo || (await getTronAccountNetwork(account.freshAddress));
|
|
11
|
+
|
|
12
|
+
if (transaction.votes.length) {
|
|
13
|
+
transaction.votes = await Promise.all(
|
|
14
|
+
transaction.votes.map(async vote => ({
|
|
15
|
+
...vote,
|
|
16
|
+
name: await accountNamesCache(vote.address),
|
|
17
|
+
})),
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
11
21
|
return transaction.networkInfo === networkInfo ? transaction : { ...transaction, networkInfo };
|
|
12
22
|
};
|
package/src/bridge/utils.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { encodeOperationId } from "@ledgerhq/ledger-wallet-framework/operation";
|
|
2
|
+
import get from "lodash/get";
|
|
2
3
|
import type { Account, OperationType } from "@ledgerhq/types-live";
|
|
3
4
|
import { BigNumber } from "bignumber.js";
|
|
4
5
|
import { type AccountInfo, getTronResources as getTronResourcesLogic } from "../logic/utils";
|
|
5
|
-
import { getTronAccountNetwork, getUnwithdrawnReward } from "../network";
|
|
6
|
+
import { accountNamesCache, getTronAccountNetwork, getUnwithdrawnReward } from "../network";
|
|
6
7
|
import { encode58Check } from "../network/format";
|
|
7
8
|
import type {
|
|
8
9
|
BandwidthInfo,
|
|
@@ -251,8 +252,18 @@ export async function getTronResources(
|
|
|
251
252
|
};
|
|
252
253
|
const lastVotedDate = txs ? getLastVotedDate(txs) : undefined;
|
|
253
254
|
|
|
255
|
+
const rawVotes = get(acc, "votes", []).sort((a, b) => b.vote_count - a.vote_count);
|
|
256
|
+
const votes = await Promise.all(
|
|
257
|
+
rawVotes.map(async v => ({
|
|
258
|
+
name: await accountNamesCache(v.vote_address),
|
|
259
|
+
address: v.vote_address,
|
|
260
|
+
voteCount: v.vote_count,
|
|
261
|
+
})),
|
|
262
|
+
);
|
|
263
|
+
|
|
254
264
|
return {
|
|
255
265
|
...getTronResourcesLogic(acc),
|
|
266
|
+
votes,
|
|
256
267
|
energy,
|
|
257
268
|
bandwidth,
|
|
258
269
|
unwithdrawnReward,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
dropTxsBeforeCursor,
|
|
11
11
|
parseCursor,
|
|
12
12
|
} from "./cursor";
|
|
13
|
+
import { TronEmptyPage } from "../types/errors";
|
|
13
14
|
|
|
14
15
|
// Pagination uses a SUI-style cursor approach to handle two separate endpoints
|
|
15
16
|
// (native transactions and TRC20 transactions) while maintaining chronological order.
|
|
@@ -64,6 +65,15 @@ export async function listOperations(
|
|
|
64
65
|
},
|
|
65
66
|
);
|
|
66
67
|
|
|
68
|
+
// TronGrid occasionally returns an empty page for a valid cursor (transient API failure).
|
|
69
|
+
// A cursor is only issued when TronGrid indicated hasNextPage=true, so 0 results here
|
|
70
|
+
// is never a legitimate end-of-stream — throw so the client can retry with the same cursor.
|
|
71
|
+
if (parsedCursor && nativeTxs.txs.length === 0 && trc20Txs.txs.length === 0) {
|
|
72
|
+
throw new TronEmptyPage(
|
|
73
|
+
`TronGrid returned empty page for cursor ${cursor} — transient failure, retry required`,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
67
77
|
// Merge and dedupe: some transactions appear in both native and TRC20 results
|
|
68
78
|
const mergedTxs = uniqBy([...nativeTxs.txs, ...trc20Txs.txs], tx => tx.txID);
|
|
69
79
|
const sortedTxs = [...mergedTxs].sort(compareTxsByTimestamp(order));
|
|
@@ -3,6 +3,7 @@ import { fetchTronAccountTxsPage, getBlock } from "../network";
|
|
|
3
3
|
import { fromTrongridTxInfoToOperation } from "../network/trongrid/trongrid-adapters";
|
|
4
4
|
import { TrongridTxInfo } from "../types";
|
|
5
5
|
import { listOperations, ListOperationsOptions } from "./listOperations";
|
|
6
|
+
import { TronEmptyPage } from "../types/errors";
|
|
6
7
|
|
|
7
8
|
jest.mock("../network", () => ({
|
|
8
9
|
fetchTronAccountTxsPage: jest.fn(),
|
|
@@ -67,7 +68,7 @@ describe("listOperations", () => {
|
|
|
67
68
|
expect(result.next).toBeUndefined();
|
|
68
69
|
});
|
|
69
70
|
|
|
70
|
-
it("should handle empty transactions", async () => {
|
|
71
|
+
it("should handle empty transactions on first page (no cursor)", async () => {
|
|
71
72
|
(fetchTronAccountTxsPage as jest.Mock).mockResolvedValue({
|
|
72
73
|
nativeTxs: { txs: [], hasNextPage: false },
|
|
73
74
|
trc20Txs: { txs: [], hasNextPage: false },
|
|
@@ -79,6 +80,21 @@ describe("listOperations", () => {
|
|
|
79
80
|
expect(result.next).toBeUndefined();
|
|
80
81
|
});
|
|
81
82
|
|
|
83
|
+
it("should throw TronEmptyPage when cursor is provided but TronGrid returns empty page", async () => {
|
|
84
|
+
// TronGrid occasionally returns 0 results for a valid cursor (transient failure).
|
|
85
|
+
// A cursor is only issued when hasNextPage=true, so this is never a legitimate end-of-stream.
|
|
86
|
+
(fetchTronAccountTxsPage as jest.Mock).mockResolvedValue({
|
|
87
|
+
nativeTxs: { txs: [], hasNextPage: false },
|
|
88
|
+
trc20Txs: { txs: [], hasNextPage: false },
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const cursor = `${new Date("2023-01-01T01:00:00Z").getTime()}:tx1`;
|
|
92
|
+
|
|
93
|
+
await expect(listOperations(mockAddress, { ...defaultOptions, cursor })).rejects.toThrow(
|
|
94
|
+
TronEmptyPage,
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
82
98
|
it("should return cursor when hasNextPage is true", async () => {
|
|
83
99
|
const mockTxs: Partial<TrongridTxInfo>[] = [
|
|
84
100
|
{
|
|
@@ -434,13 +450,26 @@ describe("listOperations", () => {
|
|
|
434
450
|
});
|
|
435
451
|
|
|
436
452
|
it("should pass cursor timestamp as minTimestamp for asc order pagination", async () => {
|
|
453
|
+
const cursorTimestamp = new Date("2023-01-01T02:00:00Z").getTime();
|
|
454
|
+
const cursor = `${cursorTimestamp}:tx2`;
|
|
437
455
|
(fetchTronAccountTxsPage as jest.Mock).mockResolvedValue({
|
|
438
|
-
nativeTxs: {
|
|
456
|
+
nativeTxs: {
|
|
457
|
+
txs: [
|
|
458
|
+
{
|
|
459
|
+
txID: "tx3",
|
|
460
|
+
value: new BigNumber(30),
|
|
461
|
+
date: new Date("2023-01-01T03:00:00Z"),
|
|
462
|
+
blockHeight: 300,
|
|
463
|
+
},
|
|
464
|
+
],
|
|
465
|
+
hasNextPage: false,
|
|
466
|
+
},
|
|
439
467
|
trc20Txs: { txs: [], hasNextPage: false },
|
|
440
468
|
});
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
469
|
+
(fromTrongridTxInfoToOperation as jest.Mock).mockImplementation(tx => ({
|
|
470
|
+
tx: { hash: tx.txID },
|
|
471
|
+
value: BigInt(tx.value.toString()),
|
|
472
|
+
}));
|
|
444
473
|
const minTimestamp = 1000;
|
|
445
474
|
|
|
446
475
|
await listOperations(mockAddress, {
|
package/src/logic/utils.test.ts
CHANGED
|
@@ -127,7 +127,6 @@ describe("getTronResources", () => {
|
|
|
127
127
|
legacyFrozen: { bandwidth: undefined, energy: undefined },
|
|
128
128
|
tronPower: 0,
|
|
129
129
|
unFrozen: { bandwidth: [], energy: [] },
|
|
130
|
-
votes: [],
|
|
131
130
|
},
|
|
132
131
|
},
|
|
133
132
|
{
|
|
@@ -142,7 +141,6 @@ describe("getTronResources", () => {
|
|
|
142
141
|
legacyFrozen: { bandwidth: undefined, energy: undefined },
|
|
143
142
|
tronPower: 10,
|
|
144
143
|
unFrozen: { bandwidth: [], energy: [] },
|
|
145
|
-
votes: [],
|
|
146
144
|
},
|
|
147
145
|
},
|
|
148
146
|
{
|
|
@@ -159,7 +157,6 @@ describe("getTronResources", () => {
|
|
|
159
157
|
legacyFrozen: { bandwidth: undefined, energy: undefined },
|
|
160
158
|
tronPower: 11,
|
|
161
159
|
unFrozen: { bandwidth: [], energy: [] },
|
|
162
|
-
votes: [],
|
|
163
160
|
},
|
|
164
161
|
},
|
|
165
162
|
{
|
|
@@ -178,7 +175,6 @@ describe("getTronResources", () => {
|
|
|
178
175
|
legacyFrozen: { bandwidth: undefined, energy: undefined },
|
|
179
176
|
tronPower: 0,
|
|
180
177
|
unFrozen: { bandwidth: [], energy: [] },
|
|
181
|
-
votes: [],
|
|
182
178
|
},
|
|
183
179
|
},
|
|
184
180
|
{
|
|
@@ -198,7 +194,6 @@ describe("getTronResources", () => {
|
|
|
198
194
|
legacyFrozen: { bandwidth: undefined, energy: undefined },
|
|
199
195
|
tronPower: 12,
|
|
200
196
|
unFrozen: { bandwidth: [], energy: [] },
|
|
201
|
-
votes: [],
|
|
202
197
|
},
|
|
203
198
|
},
|
|
204
199
|
{
|
|
@@ -218,7 +213,6 @@ describe("getTronResources", () => {
|
|
|
218
213
|
legacyFrozen: { bandwidth: undefined, energy: undefined },
|
|
219
214
|
tronPower: 0,
|
|
220
215
|
unFrozen: { bandwidth: [], energy: [] },
|
|
221
|
-
votes: [],
|
|
222
216
|
},
|
|
223
217
|
},
|
|
224
218
|
{
|
|
@@ -237,7 +231,6 @@ describe("getTronResources", () => {
|
|
|
237
231
|
legacyFrozen: { bandwidth: undefined, energy: undefined },
|
|
238
232
|
tronPower: 14,
|
|
239
233
|
unFrozen: { bandwidth: [], energy: [] },
|
|
240
|
-
votes: [],
|
|
241
234
|
},
|
|
242
235
|
},
|
|
243
236
|
{
|
|
@@ -252,7 +245,6 @@ describe("getTronResources", () => {
|
|
|
252
245
|
legacyFrozen: { bandwidth: undefined, energy: undefined },
|
|
253
246
|
tronPower: 0,
|
|
254
247
|
unFrozen: { bandwidth: [], energy: [] },
|
|
255
|
-
votes: [],
|
|
256
248
|
},
|
|
257
249
|
},
|
|
258
250
|
{
|
|
@@ -278,7 +270,6 @@ describe("getTronResources", () => {
|
|
|
278
270
|
},
|
|
279
271
|
tronPower: 15,
|
|
280
272
|
unFrozen: { bandwidth: [], energy: [] },
|
|
281
|
-
votes: [],
|
|
282
273
|
},
|
|
283
274
|
},
|
|
284
275
|
{
|
|
@@ -304,7 +295,6 @@ describe("getTronResources", () => {
|
|
|
304
295
|
},
|
|
305
296
|
tronPower: 16,
|
|
306
297
|
unFrozen: { bandwidth: [], energy: [] },
|
|
307
|
-
votes: [],
|
|
308
298
|
},
|
|
309
299
|
},
|
|
310
300
|
{
|
|
@@ -342,32 +332,6 @@ describe("getTronResources", () => {
|
|
|
342
332
|
},
|
|
343
333
|
],
|
|
344
334
|
},
|
|
345
|
-
votes: [],
|
|
346
|
-
},
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
name: "Votes",
|
|
350
|
-
account: {
|
|
351
|
-
votes: [
|
|
352
|
-
{
|
|
353
|
-
vote_address: "VOTE ADDRESS",
|
|
354
|
-
vote_count: 23,
|
|
355
|
-
},
|
|
356
|
-
],
|
|
357
|
-
},
|
|
358
|
-
expected: {
|
|
359
|
-
delegatedFrozen: { bandwidth: undefined, energy: undefined },
|
|
360
|
-
frozen: { bandwidth: undefined, energy: undefined },
|
|
361
|
-
lastWithdrawnRewardDate: undefined,
|
|
362
|
-
legacyFrozen: { bandwidth: undefined, energy: undefined },
|
|
363
|
-
tronPower: 0,
|
|
364
|
-
unFrozen: { bandwidth: [], energy: [] },
|
|
365
|
-
votes: [
|
|
366
|
-
{
|
|
367
|
-
address: "VOTE ADDRESS",
|
|
368
|
-
voteCount: 23,
|
|
369
|
-
},
|
|
370
|
-
],
|
|
371
335
|
},
|
|
372
336
|
},
|
|
373
337
|
{
|
|
@@ -382,7 +346,6 @@ describe("getTronResources", () => {
|
|
|
382
346
|
legacyFrozen: { bandwidth: undefined, energy: undefined },
|
|
383
347
|
tronPower: 0,
|
|
384
348
|
unFrozen: { bandwidth: [], energy: [] },
|
|
385
|
-
votes: [],
|
|
386
349
|
},
|
|
387
350
|
},
|
|
388
351
|
];
|
package/src/logic/utils.ts
CHANGED
|
@@ -256,7 +256,12 @@ export function getTronResources(
|
|
|
256
256
|
acc: AccountInfo,
|
|
257
257
|
): Omit<
|
|
258
258
|
TronResources,
|
|
259
|
-
|
|
259
|
+
| "energy"
|
|
260
|
+
| "bandwidth"
|
|
261
|
+
| "unwithdrawnReward"
|
|
262
|
+
| "lastVotedDate"
|
|
263
|
+
| "cacheTransactionInfoById"
|
|
264
|
+
| "votes"
|
|
260
265
|
> {
|
|
261
266
|
const delegatedFrozenBandwidth = get(acc, "delegated_frozenV2_balance_for_bandwidth", undefined);
|
|
262
267
|
const delegatedFrozenEnergy = get(
|
|
@@ -361,11 +366,6 @@ export function getTronResources(
|
|
|
361
366
|
.integerValue(BigNumber.ROUND_FLOOR)
|
|
362
367
|
.toNumber();
|
|
363
368
|
|
|
364
|
-
const votes = get(acc, "votes", []).map((v: any) => ({
|
|
365
|
-
address: v.vote_address,
|
|
366
|
-
voteCount: v.vote_count,
|
|
367
|
-
}));
|
|
368
|
-
|
|
369
369
|
const lastWithdrawnRewardDate = acc.latest_withdraw_time
|
|
370
370
|
? new Date(acc.latest_withdraw_time)
|
|
371
371
|
: undefined;
|
|
@@ -375,7 +375,6 @@ export function getTronResources(
|
|
|
375
375
|
unFrozen,
|
|
376
376
|
delegatedFrozen,
|
|
377
377
|
legacyFrozen,
|
|
378
|
-
votes,
|
|
379
378
|
tronPower,
|
|
380
379
|
lastWithdrawnRewardDate,
|
|
381
380
|
};
|