@ledgerhq/coin-xrp 7.3.0 → 7.3.1-nightly.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 +7 -0
- package/lib/api/index.integ.test.js +162 -5
- package/lib/api/index.integ.test.js.map +1 -1
- package/lib/api/index.js +13 -52
- package/lib/api/index.js.map +1 -1
- package/lib/api/index.test.js +16 -20
- package/lib/api/index.test.js.map +1 -1
- package/lib/logic/listOperations.js +1 -6
- package/lib/logic/listOperations.js.map +1 -1
- package/lib/logic/listOperations.test.js +2 -3
- package/lib/logic/listOperations.test.js.map +1 -1
- package/lib/types/model.d.ts +1 -2
- package/lib/types/model.d.ts.map +1 -1
- package/lib-es/api/index.integ.test.js +162 -5
- package/lib-es/api/index.integ.test.js.map +1 -1
- package/lib-es/api/index.js +13 -52
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/api/index.test.js +16 -20
- package/lib-es/api/index.test.js.map +1 -1
- package/lib-es/logic/listOperations.js +1 -6
- package/lib-es/logic/listOperations.js.map +1 -1
- package/lib-es/logic/listOperations.test.js +2 -3
- package/lib-es/logic/listOperations.test.js.map +1 -1
- package/lib-es/types/model.d.ts +1 -2
- package/lib-es/types/model.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/api/index.integ.test.ts +187 -5
- package/src/api/index.test.ts +16 -20
- package/src/api/index.ts +13 -68
- package/src/logic/listOperations.test.ts +2 -4
- package/src/logic/listOperations.ts +1 -6
- package/src/types/model.ts +1 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { decode } from "ripple-binary-codec";
|
|
2
2
|
import { createApi } from ".";
|
|
3
|
+
import { Operation } from "@ledgerhq/coin-framework/api/types";
|
|
3
4
|
//import { decode, encodeForSigning } from "ripple-binary-codec";
|
|
4
5
|
//import { sign } from "ripple-keypairs";
|
|
5
6
|
|
|
6
|
-
describe("Xrp Api", () => {
|
|
7
|
+
describe("Xrp Api (testnet)", () => {
|
|
7
8
|
const SENDER = "rh1HPuRVsYYvThxG2Bs1MfjmrVC73S16Fb";
|
|
8
9
|
const api = createApi({ node: "https://s.altnet.rippletest.net:51234" });
|
|
9
10
|
|
|
@@ -33,7 +34,7 @@ describe("Xrp Api", () => {
|
|
|
33
34
|
describe("listOperations", () => {
|
|
34
35
|
it.skip("returns a list regarding address parameter", async () => {
|
|
35
36
|
// When
|
|
36
|
-
const [tx, _] = await api.listOperations(SENDER, { minHeight: 200 });
|
|
37
|
+
const [tx, _] = await api.listOperations(SENDER, { minHeight: 200, order: "asc" });
|
|
37
38
|
|
|
38
39
|
// https://blockexplorer.one/xrp/testnet/address/rh1HPuRVsYYvThxG2Bs1MfjmrVC73S16Fb
|
|
39
40
|
// as of 2025-03-18, the address has 287 transactions
|
|
@@ -51,7 +52,10 @@ describe("Xrp Api", () => {
|
|
|
51
52
|
const SENDER_WITH_TRANSACTIONS = "rUxSkt6hQpWxXQwTNRUCYYRQ7BC2yRA3F8";
|
|
52
53
|
|
|
53
54
|
// When
|
|
54
|
-
const [ops, _] = await api.listOperations(SENDER_WITH_TRANSACTIONS, {
|
|
55
|
+
const [ops, _] = await api.listOperations(SENDER_WITH_TRANSACTIONS, {
|
|
56
|
+
minHeight: 0,
|
|
57
|
+
order: "asc",
|
|
58
|
+
});
|
|
55
59
|
// Then
|
|
56
60
|
const checkSet = new Set(ops.map(elt => elt.tx.hash));
|
|
57
61
|
expect(checkSet.size).toEqual(ops.length);
|
|
@@ -64,6 +68,21 @@ describe("Xrp Api", () => {
|
|
|
64
68
|
// so here we are checking that this limit is bypassed
|
|
65
69
|
expect(ops.length).toBeGreaterThan(200);
|
|
66
70
|
});
|
|
71
|
+
|
|
72
|
+
it("returns operations from latest, but in asc order", async () => {
|
|
73
|
+
// When
|
|
74
|
+
const SENDER_WITH_TRANSACTIONS = "rUxSkt6hQpWxXQwTNRUCYYRQ7BC2yRA3F8";
|
|
75
|
+
const [txDesc] = await api.listOperations(SENDER_WITH_TRANSACTIONS, {
|
|
76
|
+
minHeight: 200,
|
|
77
|
+
order: "desc",
|
|
78
|
+
});
|
|
79
|
+
expect(txDesc.length).toBeGreaterThanOrEqual(200);
|
|
80
|
+
// Then
|
|
81
|
+
// Check if the result is sorted in ascending order
|
|
82
|
+
expect(txDesc[0].tx.block.height).toBeGreaterThanOrEqual(
|
|
83
|
+
txDesc[txDesc.length - 1].tx.block.height,
|
|
84
|
+
);
|
|
85
|
+
});
|
|
67
86
|
});
|
|
68
87
|
|
|
69
88
|
describe("lastBlock", () => {
|
|
@@ -82,13 +101,13 @@ describe("Xrp Api", () => {
|
|
|
82
101
|
// Account with no transaction (at the time of this writing)
|
|
83
102
|
const SENDER_WITH_NO_TRANSACTION = "rKtXXTVno77jhu6tto1MAXjepyuaKaLcqB";
|
|
84
103
|
|
|
85
|
-
it("returns
|
|
104
|
+
it("returns a balance", async () => {
|
|
86
105
|
// When
|
|
87
106
|
const result = await api.getBalance(SENDER);
|
|
88
107
|
|
|
89
108
|
// Then
|
|
90
109
|
expect(result[0].asset).toEqual({ type: "native" });
|
|
91
|
-
expect(result[0].value).
|
|
110
|
+
expect(result[0].value).toBeGreaterThanOrEqual(BigInt(0));
|
|
92
111
|
});
|
|
93
112
|
|
|
94
113
|
it("returns 0 when address has no transaction", async () => {
|
|
@@ -162,6 +181,169 @@ describe("Xrp Api", () => {
|
|
|
162
181
|
});
|
|
163
182
|
});
|
|
164
183
|
|
|
184
|
+
describe("Xrp Api (mainnet)", () => {
|
|
185
|
+
const SENDER = "rn5BQvhksnPfbo277LtFks4iyYStPKGrnJ";
|
|
186
|
+
const api = createApi({ node: "https://xrp.coin.ledger.com" });
|
|
187
|
+
|
|
188
|
+
describe("estimateFees", () => {
|
|
189
|
+
it("returns a default value", async () => {
|
|
190
|
+
// Given
|
|
191
|
+
const amount = BigInt(100);
|
|
192
|
+
|
|
193
|
+
// When
|
|
194
|
+
const result = await api.estimateFees({
|
|
195
|
+
asset: { type: "native" },
|
|
196
|
+
type: "send",
|
|
197
|
+
sender: SENDER,
|
|
198
|
+
amount,
|
|
199
|
+
recipient: "r9m6MwViR4GnUNqoGXGa8eroBrZ9FAPHFS",
|
|
200
|
+
memo: {
|
|
201
|
+
type: "map",
|
|
202
|
+
memos: new Map(),
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Then
|
|
207
|
+
expect(result.value).toEqual(BigInt(10));
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
describe("listOperations", () => {
|
|
212
|
+
let ops: Operation[];
|
|
213
|
+
|
|
214
|
+
beforeAll(async () => {
|
|
215
|
+
const resp = await api.listOperations(SENDER, { minHeight: 0 });
|
|
216
|
+
ops = resp[0];
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("returns operations", async () => {
|
|
220
|
+
// https://xrpscan.com/account/rn5BQvhksnPfbo277LtFks4iyYStPKGrnJ
|
|
221
|
+
expect(ops.length).toBeGreaterThanOrEqual(200);
|
|
222
|
+
const checkSet = new Set(ops.map(elt => elt.tx.hash));
|
|
223
|
+
expect(checkSet.size).toEqual(ops.length);
|
|
224
|
+
ops.forEach(operation => {
|
|
225
|
+
const isSenderOrReceipt =
|
|
226
|
+
operation.senders.includes(SENDER) || operation.recipients.includes(SENDER);
|
|
227
|
+
expect(isSenderOrReceipt).toBeTruthy();
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("returns IN operation", async () => {
|
|
232
|
+
// https://xrpscan.com/tx/805E371FDA0223E8910F831802EE93DBA1A4CA40AC8C1337F26F566CD67788F5
|
|
233
|
+
const inTx = {
|
|
234
|
+
hash: "9E5141DCAE8158E51ED612333FF3EC2D60A3D2DCD2F6DD5E4F92E4A6704C3CE9",
|
|
235
|
+
amount: 7.5,
|
|
236
|
+
recipient: SENDER,
|
|
237
|
+
sender: "rnXQmrXk9HSKdNwkut1k9dpAMVYuBsJV49",
|
|
238
|
+
type: "IN",
|
|
239
|
+
fees: 0.00001,
|
|
240
|
+
};
|
|
241
|
+
const op = ops.find(o => o.tx.hash === inTx.hash) as Operation;
|
|
242
|
+
expect(op.tx.hash).toEqual(inTx.hash);
|
|
243
|
+
expect(op.value).toEqual(BigInt(inTx.amount * 1e6));
|
|
244
|
+
expect(op.recipients).toContain(inTx.recipient);
|
|
245
|
+
expect(op.senders).toContain(inTx.sender);
|
|
246
|
+
expect(op.type).toEqual(inTx.type);
|
|
247
|
+
expect(op.tx.fees).toEqual(BigInt(inTx.fees * 1e6));
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("returns OUT operation", async () => {
|
|
251
|
+
// https://xrpscan.com/tx/8D13FD7EE0D28B615905903D033A3DC3839FBAA2F545417E3DE51A1A745C1688
|
|
252
|
+
const outTx = {
|
|
253
|
+
hash: "8D13FD7EE0D28B615905903D033A3DC3839FBAA2F545417E3DE51A1A745C1688",
|
|
254
|
+
amount: 0.1,
|
|
255
|
+
recipient: "r3XzsqzQCC6r4ZzifWnwa32sFR2H9exkew",
|
|
256
|
+
sender: SENDER,
|
|
257
|
+
type: "OUT",
|
|
258
|
+
fees: 0.00001,
|
|
259
|
+
};
|
|
260
|
+
const op = ops.find(o => o.tx.hash === outTx.hash) as Operation;
|
|
261
|
+
expect(op.tx.hash).toEqual(outTx.hash);
|
|
262
|
+
expect(op.value).toEqual(BigInt(outTx.amount * 1e6));
|
|
263
|
+
expect(op.recipients).toContain(outTx.recipient);
|
|
264
|
+
expect(op.senders).toContain(outTx.sender);
|
|
265
|
+
expect(op.type).toEqual(outTx.type);
|
|
266
|
+
expect(op.tx.fees).toEqual(BigInt(outTx.fees * 1e6));
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
describe("lastBlock", () => {
|
|
271
|
+
it("returns last block info", async () => {
|
|
272
|
+
const result = await api.lastBlock();
|
|
273
|
+
expect(result.hash).toBeDefined();
|
|
274
|
+
expect(result.height).toBeDefined();
|
|
275
|
+
expect(result.time).toBeInstanceOf(Date);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe("getBalance", () => {
|
|
280
|
+
it("returns an amount", async () => {
|
|
281
|
+
const result = await api.getBalance(SENDER);
|
|
282
|
+
expect(result[0].asset).toEqual({ type: "native" });
|
|
283
|
+
expect(result[0].value).toBeGreaterThanOrEqual(BigInt(0));
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe("craftTransaction", () => {
|
|
288
|
+
const RECIPIENT = "r9m6MwViR4GnUNqoGXGa8eroBrZ9FAPHFS";
|
|
289
|
+
|
|
290
|
+
it("returns a raw transaction", async () => {
|
|
291
|
+
const result = await api.craftTransaction({
|
|
292
|
+
asset: { type: "native" },
|
|
293
|
+
type: "send",
|
|
294
|
+
sender: SENDER,
|
|
295
|
+
recipient: RECIPIENT,
|
|
296
|
+
amount: BigInt(10),
|
|
297
|
+
memo: {
|
|
298
|
+
type: "map",
|
|
299
|
+
memos: new Map([["memos", ["testdata"]]]),
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
expect(result.length).toEqual(178);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("should use default fees when user does not provide them for crafting a transaction", async () => {
|
|
306
|
+
const result = await api.craftTransaction({
|
|
307
|
+
asset: { type: "native" },
|
|
308
|
+
type: "send",
|
|
309
|
+
sender: SENDER,
|
|
310
|
+
recipient: RECIPIENT,
|
|
311
|
+
amount: BigInt(10),
|
|
312
|
+
memo: {
|
|
313
|
+
type: "map",
|
|
314
|
+
memos: new Map(),
|
|
315
|
+
},
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
expect(decode(result)).toMatchObject({
|
|
319
|
+
Fee: "10",
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it("should use custom user fees when user provides it for crafting a transaction", async () => {
|
|
324
|
+
const customFees = 99n;
|
|
325
|
+
const result = await api.craftTransaction(
|
|
326
|
+
{
|
|
327
|
+
asset: { type: "native" },
|
|
328
|
+
type: "send",
|
|
329
|
+
sender: SENDER,
|
|
330
|
+
recipient: RECIPIENT,
|
|
331
|
+
amount: BigInt(10),
|
|
332
|
+
memo: {
|
|
333
|
+
type: "map",
|
|
334
|
+
memos: new Map(),
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
{ value: customFees },
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
expect(decode(result)).toMatchObject({
|
|
341
|
+
Fee: customFees.toString(),
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
|
|
165
347
|
// To enable this test, you need to fill an `.env` file at the root of this package. Example can be found in `.env.integ.test.example`.
|
|
166
348
|
// The value hardcoded here depends on the value filled in the `.env` file.
|
|
167
349
|
/*describe.skip("combine", () => {
|
package/src/api/index.test.ts
CHANGED
|
@@ -106,14 +106,13 @@ describe("listOperations", () => {
|
|
|
106
106
|
const txs = givenTxs(BigInt(10), BigInt(10), "src", "dest");
|
|
107
107
|
// each time it's called it returns a marker, so in theory it would loop forever
|
|
108
108
|
mockGetTransactions.mockResolvedValue(mockNetworkTxs(txs, defaultMarker));
|
|
109
|
-
const [results, _] = await api.listOperations("src", { minHeight: 0 });
|
|
109
|
+
const [results, _] = await api.listOperations("src", { minHeight: 0, order: "asc" });
|
|
110
110
|
|
|
111
|
-
// called
|
|
112
|
-
|
|
113
|
-
expect(
|
|
114
|
-
expect(mockGetTransactions).toHaveBeenCalledTimes(10);
|
|
111
|
+
// called 1 times because the client is expected to do the pagination itself
|
|
112
|
+
expect(mockGetServerInfos).toHaveBeenCalledTimes(1);
|
|
113
|
+
expect(mockGetTransactions).toHaveBeenCalledTimes(1);
|
|
115
114
|
|
|
116
|
-
expect(results.length).toBe(txs.length
|
|
115
|
+
expect(results.length).toBe(txs.length);
|
|
117
116
|
});
|
|
118
117
|
|
|
119
118
|
it("should pass the token returned by previous calls", async () => {
|
|
@@ -122,11 +121,10 @@ describe("listOperations", () => {
|
|
|
122
121
|
.mockReturnValueOnce(mockNetworkTxs(txs, defaultMarker))
|
|
123
122
|
.mockReturnValueOnce(mockNetworkTxs(txs, undefined));
|
|
124
123
|
|
|
125
|
-
const [results,
|
|
124
|
+
const [results, token] = await api.listOperations("src", { minHeight: 0, order: "asc" });
|
|
126
125
|
|
|
127
|
-
|
|
128
|
-
expect(
|
|
129
|
-
expect(mockGetTransactions).toHaveBeenCalledTimes(2);
|
|
126
|
+
expect(mockGetServerInfos).toHaveBeenCalledTimes(1);
|
|
127
|
+
expect(mockGetTransactions).toHaveBeenCalledTimes(1);
|
|
130
128
|
|
|
131
129
|
// check tokens are passed
|
|
132
130
|
const baseOptions = {
|
|
@@ -135,13 +133,14 @@ describe("listOperations", () => {
|
|
|
135
133
|
forward: true,
|
|
136
134
|
};
|
|
137
135
|
expect(mockGetTransactions).toHaveBeenNthCalledWith(1, "src", baseOptions);
|
|
136
|
+
await api.listOperations("src", { minHeight: 0, order: "asc", lastPagingToken: token });
|
|
138
137
|
const optionsWithToken = {
|
|
139
138
|
...baseOptions,
|
|
140
139
|
marker: defaultMarker,
|
|
141
140
|
};
|
|
142
141
|
expect(mockGetTransactions).toHaveBeenNthCalledWith(2, "src", optionsWithToken);
|
|
143
142
|
|
|
144
|
-
expect(results.length).toBe(txs.length
|
|
143
|
+
expect(results.length).toBe(txs.length);
|
|
145
144
|
});
|
|
146
145
|
|
|
147
146
|
it.each([
|
|
@@ -171,15 +170,12 @@ describe("listOperations", () => {
|
|
|
171
170
|
mockGetTransactions.mockResolvedValue(mockNetworkTxs([], undefined));
|
|
172
171
|
|
|
173
172
|
// When
|
|
174
|
-
const [results, _] = await api.listOperations(address, { minHeight: 0 });
|
|
173
|
+
const [results, _] = await api.listOperations(address, { minHeight: 0, order: "asc" });
|
|
175
174
|
|
|
176
175
|
// Then
|
|
177
|
-
|
|
178
|
-
expect(
|
|
179
|
-
expect(mockGetTransactions).toHaveBeenCalledTimes(2);
|
|
176
|
+
expect(mockGetServerInfos).toHaveBeenCalledTimes(1);
|
|
177
|
+
expect(mockGetTransactions).toHaveBeenCalledTimes(1);
|
|
180
178
|
|
|
181
|
-
// if expectedType is "OUT", compute value with fees (i.e. delivered_amount + Fee)
|
|
182
|
-
const expectedValue = expectedType === "IN" ? deliveredAmount : deliveredAmount + fee;
|
|
183
179
|
// the order is reversed so that the result is always sorted by newest tx first element of the list
|
|
184
180
|
expect(results).toEqual([
|
|
185
181
|
{
|
|
@@ -196,7 +192,7 @@ describe("listOperations", () => {
|
|
|
196
192
|
},
|
|
197
193
|
},
|
|
198
194
|
type: expectedType,
|
|
199
|
-
value:
|
|
195
|
+
value: deliveredAmount,
|
|
200
196
|
senders: [opSender],
|
|
201
197
|
recipients: [opDestination],
|
|
202
198
|
details: {
|
|
@@ -224,7 +220,7 @@ describe("listOperations", () => {
|
|
|
224
220
|
},
|
|
225
221
|
},
|
|
226
222
|
type: expectedType,
|
|
227
|
-
value:
|
|
223
|
+
value: deliveredAmount,
|
|
228
224
|
senders: [opSender],
|
|
229
225
|
recipients: [opDestination],
|
|
230
226
|
details: {
|
|
@@ -247,7 +243,7 @@ describe("listOperations", () => {
|
|
|
247
243
|
},
|
|
248
244
|
},
|
|
249
245
|
type: expectedType,
|
|
250
|
-
value:
|
|
246
|
+
value: deliveredAmount,
|
|
251
247
|
senders: [opSender],
|
|
252
248
|
recipients: [opDestination],
|
|
253
249
|
details: {
|
package/src/api/index.ts
CHANGED
|
@@ -102,75 +102,20 @@ async function estimate(): Promise<FeeEstimation> {
|
|
|
102
102
|
return { value: estimation.fees };
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
type PaginationState = {
|
|
106
|
-
readonly pageSize: number; // must be large enough to avoid unnecessary calls to the underlying explorer
|
|
107
|
-
readonly maxIterations: number; // a security to avoid infinite loop
|
|
108
|
-
currentIteration: number;
|
|
109
|
-
readonly minHeight: number;
|
|
110
|
-
continueIterations: boolean;
|
|
111
|
-
apiNextCursor?: string;
|
|
112
|
-
accumulator: Operation[];
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
async function operationsFromHeight(
|
|
116
|
-
address: string,
|
|
117
|
-
minHeight: number,
|
|
118
|
-
): Promise<[Operation[], string]> {
|
|
119
|
-
async function fetchNextPage(state: PaginationState): Promise<PaginationState> {
|
|
120
|
-
const options: ListOperationsOptions = {
|
|
121
|
-
limit: state.pageSize,
|
|
122
|
-
minHeight: state.minHeight,
|
|
123
|
-
order: "asc",
|
|
124
|
-
};
|
|
125
|
-
if (state.apiNextCursor) {
|
|
126
|
-
options.token = state.apiNextCursor;
|
|
127
|
-
}
|
|
128
|
-
const [operations, apiNextCursor] = await listOperations(address, options);
|
|
129
|
-
const newCurrentIteration = state.currentIteration + 1;
|
|
130
|
-
let continueIteration = true;
|
|
131
|
-
if (apiNextCursor === "") {
|
|
132
|
-
continueIteration = false;
|
|
133
|
-
} else if (newCurrentIteration >= state.maxIterations) {
|
|
134
|
-
log("coin:xrp", "(api/operations): max iterations reached", state.maxIterations);
|
|
135
|
-
continueIteration = false;
|
|
136
|
-
}
|
|
137
|
-
const accumulated = state.accumulator.concat(operations);
|
|
138
|
-
return {
|
|
139
|
-
...state,
|
|
140
|
-
currentIteration: newCurrentIteration,
|
|
141
|
-
continueIterations: continueIteration,
|
|
142
|
-
apiNextCursor: apiNextCursor,
|
|
143
|
-
accumulator: accumulated,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const firstState: PaginationState = {
|
|
148
|
-
pageSize: 200,
|
|
149
|
-
maxIterations: 10,
|
|
150
|
-
currentIteration: 0,
|
|
151
|
-
minHeight: minHeight,
|
|
152
|
-
continueIterations: true,
|
|
153
|
-
accumulator: [],
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
let state = await fetchNextPage(firstState);
|
|
157
|
-
while (state.continueIterations) {
|
|
158
|
-
state = await fetchNextPage(state);
|
|
159
|
-
}
|
|
160
|
-
return [state.accumulator, state.apiNextCursor ?? ""];
|
|
161
|
-
}
|
|
162
|
-
|
|
163
105
|
// NOTE: double check
|
|
164
106
|
async function operations(address: string, pagination: Pagination): Promise<[Operation[], string]> {
|
|
165
|
-
const { minHeight, lastPagingToken } = pagination;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const newPagination = {
|
|
172
|
-
minHeight: isInitSync ? 0 : parseInt(lastPagingToken || "0", 10),
|
|
107
|
+
const { minHeight, lastPagingToken, order } = pagination;
|
|
108
|
+
const options: ListOperationsOptions = {
|
|
109
|
+
limit: 200,
|
|
110
|
+
minHeight: minHeight,
|
|
111
|
+
order: order ?? "asc",
|
|
173
112
|
};
|
|
174
|
-
|
|
175
|
-
|
|
113
|
+
if (lastPagingToken) {
|
|
114
|
+
const token = lastPagingToken.split("-");
|
|
115
|
+
options.token = JSON.stringify({ ledger: Number(token[0]), seq: Number(token[1]) });
|
|
116
|
+
log(options.token);
|
|
117
|
+
}
|
|
118
|
+
const [operations, apiNextCursor] = await listOperations(address, options);
|
|
119
|
+
const next = apiNextCursor ? JSON.parse(apiNextCursor) : null;
|
|
120
|
+
return [operations, next ? next.ledger + "-" + next.seq : ""];
|
|
176
121
|
}
|
|
@@ -41,7 +41,7 @@ describe("listOperations", () => {
|
|
|
41
41
|
// Given
|
|
42
42
|
mockNetworkGetTransactions.mockResolvedValue(mockNetworkTxs([]));
|
|
43
43
|
// When
|
|
44
|
-
const [results, token] = await listOperations("any address", { minHeight: 0 });
|
|
44
|
+
const [results, token] = await listOperations("any address", { minHeight: 0, order: "asc" });
|
|
45
45
|
// Then
|
|
46
46
|
expect(mockGetServerInfos).toHaveBeenCalledTimes(1);
|
|
47
47
|
expect(mockNetworkGetTransactions).toHaveBeenCalledTimes(1);
|
|
@@ -215,9 +215,7 @@ describe("listOperations", () => {
|
|
|
215
215
|
// Then
|
|
216
216
|
expect(mockGetServerInfos).toHaveBeenCalledTimes(1);
|
|
217
217
|
expect(mockNetworkGetTransactions).toHaveBeenCalledTimes(1);
|
|
218
|
-
|
|
219
|
-
const expectedValue =
|
|
220
|
-
expectedType === "IN" ? BigInt(deliveredAmount) : BigInt(deliveredAmount + fees);
|
|
218
|
+
const expectedValue = BigInt(deliveredAmount);
|
|
221
219
|
expect(results).toEqual([
|
|
222
220
|
{
|
|
223
221
|
id: "HASH_VALUE",
|
|
@@ -120,17 +120,12 @@ const convertToCoreOperation =
|
|
|
120
120
|
} = operation;
|
|
121
121
|
|
|
122
122
|
const type = Account === address ? "OUT" : "IN";
|
|
123
|
-
|
|
123
|
+
const value =
|
|
124
124
|
delivered_amount && typeof delivered_amount === "string"
|
|
125
125
|
? BigInt(delivered_amount)
|
|
126
126
|
: BigInt(0);
|
|
127
127
|
|
|
128
128
|
const fees = BigInt(Fee);
|
|
129
|
-
if (type === "OUT") {
|
|
130
|
-
if (!Number.isNaN(fees)) {
|
|
131
|
-
value = value + fees;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
129
|
|
|
135
130
|
const toEpochDate = (RIPPLE_EPOCH + date) * 1000;
|
|
136
131
|
|
package/src/types/model.ts
CHANGED