@ledgerhq/live-common 22.0.3 → 22.1.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 (95) hide show
  1. package/lib/__tests__/families/bitcoin/wallet-btc/xpub.txs.dogecoin.test.d.ts +2 -0
  2. package/lib/__tests__/families/bitcoin/wallet-btc/xpub.txs.dogecoin.test.d.ts.map +1 -0
  3. package/lib/__tests__/families/bitcoin/wallet-btc/xpub.txs.dogecoin.test.js +147 -0
  4. package/lib/__tests__/families/bitcoin/wallet-btc/xpub.txs.dogecoin.test.js.map +1 -0
  5. package/lib/api/Ripple.d.ts +17 -21
  6. package/lib/api/Ripple.d.ts.map +1 -1
  7. package/lib/api/Ripple.js +117 -176
  8. package/lib/api/Ripple.js.map +1 -1
  9. package/lib/api/index.d.ts.map +1 -1
  10. package/lib/api/index.js +1 -5
  11. package/lib/api/index.js.map +1 -1
  12. package/lib/env.d.ts +6 -6
  13. package/lib/env.d.ts.map +1 -1
  14. package/lib/env.js +3 -3
  15. package/lib/env.js.map +1 -1
  16. package/lib/env.react.d.ts +1 -1
  17. package/lib/env.react.d.ts.map +1 -1
  18. package/lib/errors.d.ts +3 -0
  19. package/lib/errors.d.ts.map +1 -1
  20. package/lib/errors.js +2 -1
  21. package/lib/errors.js.map +1 -1
  22. package/lib/families/bitcoin/getAccountNetworkInfo.d.ts.map +1 -1
  23. package/lib/families/bitcoin/getAccountNetworkInfo.js +4 -2
  24. package/lib/families/bitcoin/getAccountNetworkInfo.js.map +1 -1
  25. package/lib/families/bitcoin/specs.d.ts.map +1 -1
  26. package/lib/families/bitcoin/specs.js +5 -2
  27. package/lib/families/bitcoin/specs.js.map +1 -1
  28. package/lib/families/bitcoin/wallet-btc/utils.d.ts +2 -0
  29. package/lib/families/bitcoin/wallet-btc/utils.d.ts.map +1 -1
  30. package/lib/families/bitcoin/wallet-btc/utils.js +9 -1
  31. package/lib/families/bitcoin/wallet-btc/utils.js.map +1 -1
  32. package/lib/families/bitcoin/wallet-btc/wallet.d.ts.map +1 -1
  33. package/lib/families/bitcoin/wallet-btc/wallet.js +11 -11
  34. package/lib/families/bitcoin/wallet-btc/wallet.js.map +1 -1
  35. package/lib/families/cosmos/js-prepareTransaction.d.ts.map +1 -1
  36. package/lib/families/cosmos/js-prepareTransaction.js +29 -5
  37. package/lib/families/cosmos/js-prepareTransaction.js.map +1 -1
  38. package/lib/families/cosmos/js-signOperation.d.ts.map +1 -1
  39. package/lib/families/cosmos/js-signOperation.js +76 -39
  40. package/lib/families/cosmos/js-signOperation.js.map +1 -1
  41. package/lib/families/cosmos/validators.js +1 -1
  42. package/lib/families/ripple/bridge/js.d.ts +2 -1
  43. package/lib/families/ripple/bridge/js.d.ts.map +1 -1
  44. package/lib/families/ripple/bridge/js.js +96 -466
  45. package/lib/families/ripple/bridge/js.js.map +1 -1
  46. package/lib/families/ripple/bridge.test.js +0 -48
  47. package/lib/families/ripple/bridge.test.js.map +1 -1
  48. package/lib/families/ripple/js-synchronization.d.ts +10 -0
  49. package/lib/families/ripple/js-synchronization.d.ts.map +1 -0
  50. package/lib/families/ripple/js-synchronization.js +156 -0
  51. package/lib/families/ripple/js-synchronization.js.map +1 -0
  52. package/lib/families/ripple/test-dataset.d.ts.map +1 -1
  53. package/lib/families/ripple/test-dataset.js +1 -1
  54. package/lib/families/ripple/test-dataset.js.map +1 -1
  55. package/lib/families/ripple/types.api.d.ts +24 -0
  56. package/lib/families/ripple/types.api.d.ts.map +1 -0
  57. package/lib/families/ripple/types.api.js +3 -0
  58. package/lib/families/ripple/types.api.js.map +1 -0
  59. package/lib/families/solana/api/chain/instruction/token/types.d.ts +3 -3
  60. package/lib/featureFlags/defaultFeatures.d.ts.map +1 -1
  61. package/lib/featureFlags/defaultFeatures.js +46 -0
  62. package/lib/featureFlags/defaultFeatures.js.map +1 -1
  63. package/lib/featureFlags/types.d.ts +2 -1
  64. package/lib/featureFlags/types.d.ts.map +1 -1
  65. package/lib/platform/providers/GlobalCatalogProvider/api/mock.json +0 -26
  66. package/lib/platform/providers/RemoteLiveAppProvider/api/mock.json +0 -63
  67. package/lib/types/nft.d.ts +1 -1
  68. package/lib/types/nft.d.ts.map +1 -1
  69. package/package.json +7 -7
  70. package/src/__tests__/families/bitcoin/wallet-btc/xpub.txs.dogecoin.test.ts +96 -0
  71. package/src/api/Ripple.ts +95 -160
  72. package/src/api/index.ts +0 -2
  73. package/src/currencies/__snapshots__/sortByMarketcap.test.ts.snap +47 -3
  74. package/src/env.ts +3 -3
  75. package/src/errors.ts +4 -0
  76. package/src/families/bitcoin/getAccountNetworkInfo.ts +4 -2
  77. package/src/families/bitcoin/specs.ts +4 -5
  78. package/src/families/bitcoin/wallet-btc/utils.ts +8 -0
  79. package/src/families/bitcoin/wallet-btc/wallet.ts +24 -12
  80. package/src/families/cosmos/__snapshots__/bridge.test.ts.snap +128 -7
  81. package/src/families/cosmos/js-prepareTransaction.ts +7 -5
  82. package/src/families/cosmos/js-signOperation.ts +54 -36
  83. package/src/families/cosmos/validators.ts +1 -1
  84. package/src/families/ripple/bridge/js.ts +89 -494
  85. package/src/families/ripple/bridge.test.ts +0 -6
  86. package/src/families/ripple/js-synchronization.ts +153 -0
  87. package/src/families/ripple/test-dataset.ts +2 -0
  88. package/src/families/ripple/types.api.ts +23 -0
  89. package/src/featureFlags/defaultFeatures.ts +47 -0
  90. package/src/featureFlags/types.ts +7 -1
  91. package/src/platform/providers/GlobalCatalogProvider/api/mock.json +0 -26
  92. package/src/platform/providers/RemoteLiveAppProvider/api/mock.json +0 -63
  93. package/src/types/nft.ts +1 -1
  94. package/src/.DS_Store +0 -0
  95. package/src/__tests__/.DS_Store +0 -0
@@ -1,77 +1,42 @@
1
1
  /* eslint-disable no-param-reassign */
2
- import invariant from "invariant";
3
- import { BigNumber } from "bignumber.js";
4
- import { Observable } from "rxjs";
5
- import bs58check from "ripple-bs58check";
6
2
  import {
7
3
  AmountRequired,
8
- NotEnoughBalanceBecauseDestinationNotCreated,
9
- NotEnoughSpendableBalance,
10
- InvalidAddress,
11
4
  FeeNotLoaded,
5
+ FeeRequired,
12
6
  FeeTooHigh,
13
- NetworkDown,
7
+ InvalidAddress,
14
8
  InvalidAddressBecauseDestinationIsAlsoSource,
15
- FeeRequired,
9
+ NetworkDown,
10
+ NotEnoughBalanceBecauseDestinationNotCreated,
11
+ NotEnoughSpendableBalance,
16
12
  RecipientRequired,
17
13
  } from "@ledgerhq/errors";
18
- import type { Account, Operation, SignOperationEvent } from "../../../types";
19
- import {
20
- getDerivationModesForCurrency,
21
- getDerivationScheme,
22
- runDerivationScheme,
23
- isIterableDerivationMode,
24
- derivationModeSupportsIndex,
25
- } from "../../../derivation";
26
- import { formatCurrencyUnit } from "../../../currencies";
27
- import { patchOperationWithHash } from "../../../operation";
14
+ import { BigNumber } from "bignumber.js";
15
+ import invariant from "invariant";
16
+ import bs58check from "ripple-bs58check";
17
+ import { Observable } from "rxjs";
28
18
  import { getMainAccount } from "../../../account";
29
- import {
30
- getAccountPlaceholderName,
31
- getNewAccountPlaceholderName,
32
- emptyHistoryCache,
33
- } from "../../../account";
34
- import getAddress from "../../../hw/getAddress";
35
- import { withDevice } from "../../../hw/deviceAccess";
36
- import {
37
- parseAPIValue,
38
- parseAPICurrencyObject,
39
- formatAPICurrencyXRP,
40
- } from "../../../api/Ripple";
41
- import type { CurrencyBridge, AccountBridge } from "../../../types/bridge";
42
- import signTransaction from "../../../hw/signTransaction";
43
- import type { Transaction, NetworkInfo } from "../types";
44
- import { makeAccountBridgeReceive, mergeOps } from "../../../bridge/jsHelpers";
45
- import {
46
- preparePayment,
47
- submit,
19
+ import getLedgerIndex, {
48
20
  getAccountInfo,
49
21
  getServerInfo,
50
- getTransactions,
22
+ parseAPIValue,
23
+ submit,
51
24
  } from "../../../api/Ripple";
25
+ import { makeAccountBridgeReceive } from "../../../bridge/jsHelpers";
26
+ import { formatCurrencyUnit } from "../../../currencies";
27
+ import signTransaction from "../../../hw/signTransaction";
28
+ import { withDevice } from "../../../hw/deviceAccess";
29
+ import { patchOperationWithHash } from "../../../operation";
30
+ import type { Account, Operation, SignOperationEvent } from "../../../types";
31
+ import type { AccountBridge, CurrencyBridge } from "../../../types/bridge";
32
+ import { scanAccounts, sync } from "../js-synchronization";
33
+ import type { NetworkInfo, Transaction } from "../types";
52
34
 
53
- // true if the error should be forwarded and is not a "not found" case
54
- const checkAccountNotFound = (e) => {
55
- return (
56
- !e.data || (e.message !== "actNotFound" && e.data.error !== "actNotFound")
57
- );
58
- };
35
+ export const NEW_ACCOUNT_ERROR_MESSAGE = "actNotFound";
36
+ const LEDGER_OFFSET = 20;
59
37
 
60
38
  const receive = makeAccountBridgeReceive();
61
39
 
62
- const getSequenceNumber = async (account) => {
63
- const lastOp = account.operations.find((op) => op.type === "OUT");
64
-
65
- if (lastOp && lastOp.transactionSequenceNumber) {
66
- return (
67
- lastOp.transactionSequenceNumber + account.pendingOperations.length + 1
68
- );
69
- }
70
-
71
- const info = await getAccountInfo(account.freshAddress);
72
- return info.sequence + account.pendingOperations.length;
73
- };
74
-
75
40
  const uint32maxPlus1 = new BigNumber(2).pow(32);
76
41
 
77
42
  const validateTag = (tag) => {
@@ -84,6 +49,11 @@ const validateTag = (tag) => {
84
49
  );
85
50
  };
86
51
 
52
+ const getNextValidSequence = async (account: Account) => {
53
+ const accInfo = await getAccountInfo(account.freshAddress, true);
54
+ return accInfo.account_data.Sequence;
55
+ };
56
+
87
57
  const signOperation = ({
88
58
  account,
89
59
  transaction,
@@ -97,46 +67,36 @@ const signOperation = ({
97
67
  if (!fee) throw new FeeNotLoaded();
98
68
 
99
69
  async function main() {
100
- const amount = formatAPICurrencyXRP(transaction.amount);
101
- const tag = transaction.tag ? transaction.tag : undefined;
102
- const payment = {
103
- source: {
104
- address: account.freshAddress,
105
- amount,
106
- },
107
- destination: {
108
- address: transaction.recipient,
109
- minAmount: amount,
110
- tag,
111
- },
112
- };
113
- const instruction = {
114
- fee: formatAPICurrencyXRP(fee).value,
115
- maxLedgerVersionOffset: 12,
116
- };
117
- if (tag)
118
- invariant(
119
- validateTag(new BigNumber(tag)),
120
- `tag is set but is not in a valid format, should be between [0 - ${uint32maxPlus1
121
- .minus(1)
122
- .toString()}]`
123
- );
124
- const prepared = await preparePayment(
125
- account.freshAddress,
126
- payment,
127
- instruction
128
- );
129
- let signature;
130
-
131
70
  try {
71
+ const tag = transaction.tag ? transaction.tag : undefined;
72
+ const nextSequenceNumber = await getNextValidSequence(account);
73
+ const payment = {
74
+ TransactionType: "Payment",
75
+ Account: account.freshAddress,
76
+ Amount: transaction.amount.toString(),
77
+ Destination: transaction.recipient,
78
+ DestinationTag: tag,
79
+ Fee: fee.toString(),
80
+ Flags: 2147483648,
81
+ Sequence: nextSequenceNumber,
82
+ LastLedgerSequence: (await getLedgerIndex()) + LEDGER_OFFSET,
83
+ };
84
+ if (tag)
85
+ invariant(
86
+ validateTag(new BigNumber(tag)),
87
+ `tag is set but is not in a valid format, should be between [0 - ${uint32maxPlus1
88
+ .minus(1)
89
+ .toString()}]`
90
+ );
91
+
132
92
  o.next({
133
93
  type: "device-signature-requested",
134
94
  });
135
- signature = await signTransaction(
95
+ const signature = await signTransaction(
136
96
  account.currency,
137
97
  transport,
138
98
  account.freshAddressPath,
139
- JSON.parse(prepared.txJSON)
99
+ payment
140
100
  );
141
101
  o.next({
142
102
  type: "device-signature-granted",
@@ -155,15 +115,10 @@ const signOperation = ({
155
115
  senders: [account.freshAddress],
156
116
  recipients: [transaction.recipient],
157
117
  date: new Date(),
158
- // we probably can't get it so it's a predictive value
159
- transactionSequenceNumber: await getSequenceNumber(account),
118
+ transactionSequenceNumber: nextSequenceNumber,
160
119
  extra: {} as any,
161
120
  };
162
121
 
163
- if (transaction.tag) {
164
- operation.extra.tag = transaction.tag;
165
- }
166
-
167
122
  o.next({
168
123
  type: "signed",
169
124
  signedOperation: {
@@ -188,7 +143,9 @@ const signOperation = ({
188
143
  })
189
144
  );
190
145
 
191
- const broadcast = async ({ signedOperation: { signature, operation } }) => {
146
+ const broadcast = async ({
147
+ signedOperation: { signature, operation },
148
+ }): Promise<Operation> => {
192
149
  const submittedPayment = await submit(signature);
193
150
 
194
151
  if (
@@ -202,7 +159,7 @@ const broadcast = async ({ signedOperation: { signature, operation } }) => {
202
159
  return patchOperationWithHash(operation, hash);
203
160
  };
204
161
 
205
- function isRecipientValid(recipient) {
162
+ function isRecipientValid(recipient: string): boolean {
206
163
  try {
207
164
  bs58check.decode(recipient);
208
165
  return true;
@@ -211,125 +168,14 @@ function isRecipientValid(recipient) {
211
168
  }
212
169
  }
213
170
 
214
- type Tx = {
215
- type: string;
216
- address: string;
217
- sequence: number;
218
- id: string;
219
- specification: {
220
- source: {
221
- address: string;
222
- maxAmount: {
223
- currency: string;
224
- value: string;
225
- };
226
- };
227
- destination: {
228
- address: string;
229
- amount: {
230
- currency: string;
231
- value: string;
232
- };
233
- tag?: string;
234
- };
235
- paths: string;
236
- };
237
- outcome: {
238
- result: string;
239
- fee: string;
240
- timestamp: string;
241
- deliveredAmount?: {
242
- currency: string;
243
- value: string;
244
- counterparty: string;
245
- };
246
- balanceChanges: Record<
247
- string,
248
- Array<{
249
- counterparty: string;
250
- currency: string;
251
- value: string;
252
- }>
253
- >;
254
- orderbookChanges: Record<
255
- string,
256
- Array<{
257
- direction: string;
258
- quantity: {
259
- currency: string;
260
- value: string;
261
- };
262
- totalPrice: {
263
- currency: string;
264
- counterparty: string;
265
- value: string;
266
- };
267
- makeExchangeRate: string;
268
- sequence: number;
269
- status: string;
270
- }>
271
- >;
272
- ledgerVersion: number;
273
- indexInLedger: number;
274
- };
275
- };
276
-
277
- const txToOperation =
278
- (account: Account) =>
279
- ({
280
- id,
281
- sequence,
282
- outcome: { fee, deliveredAmount, ledgerVersion, timestamp },
283
- specification: { source, destination },
284
- }: Tx): Operation | null | undefined => {
285
- const type = source.address === account.freshAddress ? "OUT" : "IN";
286
- let value = deliveredAmount
287
- ? parseAPICurrencyObject(deliveredAmount)
288
- : new BigNumber(0);
289
- const feeValue = parseAPIValue(fee);
290
-
291
- if (type === "OUT") {
292
- if (!Number.isNaN(feeValue)) {
293
- value = value.plus(feeValue);
294
- }
295
- }
296
-
297
- const op: Operation = {
298
- id: `${account.id}-${id}-${type}`,
299
- hash: id,
300
- accountId: account.id,
301
- type,
302
- value,
303
- fee: feeValue,
304
- blockHash: null,
305
- blockHeight: ledgerVersion,
306
- senders: [source.address],
307
- recipients: [destination.address],
308
- date: new Date(timestamp),
309
- transactionSequenceNumber: sequence,
310
- extra: {},
311
- };
312
-
313
- if (destination.tag) {
314
- op.extra.tag = destination.tag;
315
- }
316
-
317
- return op;
318
- };
319
-
320
- const recipientIsNew = async (endpointConfig, recipient) => {
171
+ const recipientIsNew = async (recipient: string): Promise<boolean> => {
321
172
  if (!isRecipientValid(recipient)) return false;
322
173
 
323
- try {
324
- await getAccountInfo(recipient, endpointConfig);
325
- return false;
326
- } catch (e) {
327
- if (checkAccountNotFound(e)) {
328
- throw e;
329
- }
330
-
174
+ const info = await getAccountInfo(recipient);
175
+ if (info.error === NEW_ACCOUNT_ERROR_MESSAGE) {
331
176
  return true;
332
177
  }
178
+ return false;
333
179
  };
334
180
 
335
181
  // FIXME this could be cleaner
@@ -348,284 +194,18 @@ const remapError = (error) => {
348
194
 
349
195
  const cacheRecipientsNew = {};
350
196
 
351
- const cachedRecipientIsNew = (endpointConfig, recipient) => {
197
+ const cachedRecipientIsNew = (recipient: string) => {
352
198
  if (recipient in cacheRecipientsNew) return cacheRecipientsNew[recipient];
353
- cacheRecipientsNew[recipient] = recipientIsNew(endpointConfig, recipient);
199
+ cacheRecipientsNew[recipient] = recipientIsNew(recipient);
354
200
  return cacheRecipientsNew[recipient];
355
201
  };
356
202
 
357
203
  const currencyBridge: CurrencyBridge = {
358
204
  preload: () => Promise.resolve({}),
359
205
  hydrate: () => {},
360
- scanAccounts: ({ currency, deviceId }) =>
361
- withDevice(deviceId)(
362
- (transport) =>
363
- new Observable((o) => {
364
- let finished = false;
365
-
366
- const unsubscribe = () => {
367
- finished = true;
368
- };
369
-
370
- async function main() {
371
- try {
372
- const serverInfo = await getServerInfo();
373
- const ledgers = serverInfo.completeLedgers.split("-");
374
- const minLedgerVersion = Number(ledgers[0]);
375
- const maxLedgerVersion = Number(ledgers[1]);
376
- const derivationModes = getDerivationModesForCurrency(currency);
377
-
378
- for (const derivationMode of derivationModes) {
379
- const derivationScheme = getDerivationScheme({
380
- derivationMode,
381
- currency,
382
- });
383
- const stopAt = isIterableDerivationMode(derivationMode)
384
- ? 255
385
- : 1;
386
-
387
- for (let index = 0; index < stopAt; index++) {
388
- if (!derivationModeSupportsIndex(derivationMode, index))
389
- continue;
390
- const freshAddressPath = runDerivationScheme(
391
- derivationScheme,
392
- currency,
393
- {
394
- account: index,
395
- }
396
- );
397
- const { address } = await getAddress(transport, {
398
- currency,
399
- path: freshAddressPath,
400
- derivationMode,
401
- });
402
- if (finished) return;
403
- const accountId = `ripplejs:2:${currency.id}:${address}:${derivationMode}`;
404
- let info;
405
-
406
- try {
407
- info = await getAccountInfo(address);
408
- } catch (e) {
409
- if (checkAccountNotFound(e)) {
410
- throw e;
411
- }
412
- }
413
-
414
- // fresh address is address. ripple never changes.
415
- const freshAddress = address;
416
-
417
- if (!info) {
418
- // account does not exist in Ripple server
419
- // we are generating a new account locally
420
- if (derivationMode === "") {
421
- o.next({
422
- type: "discovered",
423
- account: {
424
- type: "Account",
425
- id: accountId,
426
- seedIdentifier: freshAddress,
427
- derivationMode,
428
- name: getNewAccountPlaceholderName({
429
- currency,
430
- index,
431
- derivationMode,
432
- }),
433
- starred: false,
434
- used: false,
435
- freshAddress,
436
- freshAddressPath,
437
- freshAddresses: [
438
- {
439
- address: freshAddress,
440
- derivationPath: freshAddressPath,
441
- },
442
- ],
443
- balance: new BigNumber(0),
444
- spendableBalance: new BigNumber(0),
445
- blockHeight: maxLedgerVersion,
446
- index,
447
- currency,
448
- operationsCount: 0,
449
- operations: [],
450
- pendingOperations: [],
451
- unit: currency.units[0],
452
- // @ts-expect-error archived does not exists on type Account
453
- archived: false,
454
- lastSyncDate: new Date(),
455
- creationDate: new Date(),
456
- swapHistory: [],
457
- balanceHistoryCache: emptyHistoryCache, // calculated in the jsHelpers
458
- },
459
- });
460
- }
461
-
462
- break;
463
- }
464
-
465
- if (finished) return;
466
- const balance = parseAPIValue(info.xrpBalance);
467
- invariant(
468
- !balance.isNaN() && balance.isFinite(),
469
- `Ripple: invalid balance=${balance.toString()} for address ${address}`
470
- );
471
- const transactions = await getTransactions(address, {
472
- minLedgerVersion,
473
- maxLedgerVersion,
474
- types: ["payment"],
475
- });
476
- if (finished) return;
477
- const account: Account = {
478
- type: "Account",
479
- id: accountId,
480
- seedIdentifier: freshAddress,
481
- derivationMode,
482
- name: getAccountPlaceholderName({
483
- currency,
484
- index,
485
- derivationMode,
486
- }),
487
- starred: false,
488
- used: true,
489
- freshAddress,
490
- freshAddressPath,
491
- freshAddresses: [
492
- {
493
- address: freshAddress,
494
- derivationPath: freshAddressPath,
495
- },
496
- ],
497
- balance,
498
- spendableBalance: balance,
499
- // TODO calc with base reserve
500
- blockHeight: maxLedgerVersion,
501
- index,
502
- currency,
503
- operationsCount: 0,
504
- operations: [],
505
- pendingOperations: [],
506
- unit: currency.units[0],
507
- lastSyncDate: new Date(),
508
- creationDate: new Date(),
509
- swapHistory: [],
510
- balanceHistoryCache: emptyHistoryCache, // calculated in the jsHelpers
511
- };
512
- account.operations = transactions
513
- .map(txToOperation(account))
514
- .filter(Boolean);
515
- account.operationsCount = account.operations.length;
516
-
517
- if (account.operations.length > 0) {
518
- account.creationDate =
519
- account.operations[account.operations.length - 1].date;
520
- }
521
-
522
- o.next({
523
- type: "discovered",
524
- account,
525
- });
526
- }
527
- }
528
-
529
- o.complete();
530
- } catch (e) {
531
- o.error(e);
532
- }
533
- }
534
-
535
- main();
536
- return unsubscribe;
537
- })
538
- ),
206
+ scanAccounts,
539
207
  };
540
208
 
541
- const sync = ({
542
- endpointConfig,
543
- freshAddress,
544
- blockHeight,
545
- operations,
546
- }: any): Observable<(arg0: Account) => Account> =>
547
- new Observable((o) => {
548
- let finished = false;
549
- const currentOpsLength = operations ? operations.length : 0;
550
-
551
- const unsubscribe = () => {
552
- finished = true;
553
- };
554
-
555
- async function main() {
556
- try {
557
- if (finished) return;
558
- const serverInfo = await getServerInfo(endpointConfig);
559
- if (finished) return;
560
- const ledgers = serverInfo.completeLedgers.split("-");
561
- const minLedgerVersion = Number(ledgers[0]);
562
- const maxLedgerVersion = Number(ledgers[1]);
563
- let info;
564
-
565
- try {
566
- info = await getAccountInfo(freshAddress);
567
- } catch (e) {
568
- if (checkAccountNotFound(e)) {
569
- throw e;
570
- }
571
- }
572
-
573
- if (finished) return;
574
-
575
- if (!info) {
576
- // account does not exist, we have nothing to sync but to update the last sync date
577
- o.next((a) => ({ ...a, lastSyncDate: new Date() }));
578
- o.complete();
579
- return;
580
- }
581
-
582
- const balance = parseAPIValue(info.xrpBalance);
583
- invariant(
584
- !balance.isNaN() && balance.isFinite(),
585
- `Ripple: invalid balance=${balance.toString()} for address ${freshAddress}`
586
- );
587
- const transactions = await getTransactions(freshAddress, {
588
- minLedgerVersion: Math.max(
589
- currentOpsLength === 0 ? 0 : blockHeight, // if there is no ops, it might be after a clear and we prefer to pull from the oldest possible history
590
- minLedgerVersion
591
- ),
592
- maxLedgerVersion,
593
- types: ["payment"],
594
- });
595
- if (finished) return;
596
- o.next((a) => {
597
- const newOps = transactions.map(txToOperation(a));
598
- const operations = mergeOps(a.operations, newOps);
599
- const [last] = operations;
600
- const pendingOperations = a.pendingOperations.filter(
601
- (oo) =>
602
- !operations.some((op) => oo.hash === op.hash) &&
603
- last &&
604
- last.transactionSequenceNumber &&
605
- oo.transactionSequenceNumber &&
606
- oo.transactionSequenceNumber > last.transactionSequenceNumber
607
- );
608
- return {
609
- ...a,
610
- balance,
611
- spendableBalance: balance,
612
- // TODO use reserve
613
- operations,
614
- pendingOperations,
615
- blockHeight: maxLedgerVersion,
616
- lastSyncDate: new Date(),
617
- };
618
- });
619
- o.complete();
620
- } catch (e) {
621
- o.error(remapError(e));
622
- }
623
- }
624
-
625
- main();
626
- return unsubscribe;
627
- });
628
-
629
209
  const createTransaction = (): Transaction => ({
630
210
  family: "ripple",
631
211
  amount: new BigNumber(0),
@@ -636,15 +216,23 @@ const createTransaction = (): Transaction => ({
636
216
  feeCustomUnit: null,
637
217
  });
638
218
 
639
- const updateTransaction = (t, patch) => ({ ...t, ...patch });
219
+ const updateTransaction = (
220
+ t: Transaction,
221
+ patch: Transaction
222
+ ): Transaction => ({ ...t, ...patch });
640
223
 
641
- const prepareTransaction = async (a: Account, t: Transaction) => {
224
+ const prepareTransaction = async (
225
+ a: Account,
226
+ t: Transaction
227
+ ): Promise<Transaction> => {
642
228
  let networkInfo: NetworkInfo | null | undefined = t.networkInfo;
643
229
 
644
230
  if (!networkInfo) {
645
231
  try {
646
232
  const info = await getServerInfo(a.endpointConfig);
647
- const serverFee = parseAPIValue(info.validatedLedger.baseFeeXRP);
233
+ const serverFee = parseAPIValue(
234
+ info.info.validated_ledger.base_fee_xrp.toString()
235
+ );
648
236
  networkInfo = {
649
237
  family: "ripple",
650
238
  serverFee,
@@ -664,7 +252,7 @@ const prepareTransaction = async (a: Account, t: Transaction) => {
664
252
  return t;
665
253
  };
666
254
 
667
- const getTransactionStatus = async (a, t) => {
255
+ const getTransactionStatus = async (a: Account, t: Transaction) => {
668
256
  const errors: {
669
257
  fee?: Error;
670
258
  amount?: Error;
@@ -674,7 +262,9 @@ const getTransactionStatus = async (a, t) => {
674
262
  feeTooHigh?: Error;
675
263
  } = {};
676
264
  const r = await getServerInfo(a.endpointConfig);
677
- const reserveBaseXRP = parseAPIValue(r.validatedLedger.reserveBaseXRP);
265
+ const reserveBaseXRP = parseAPIValue(
266
+ r.info.validated_ledger.reserve_base_xrp.toString()
267
+ );
678
268
  const estimatedFees = new BigNumber(t.fee || 0);
679
269
  const totalSpent = new BigNumber(t.amount).plus(estimatedFees);
680
270
  const amount = new BigNumber(t.amount);
@@ -697,12 +287,15 @@ const getTransactionStatus = async (a, t) => {
697
287
  });
698
288
  } else if (
699
289
  t.recipient &&
700
- (await cachedRecipientIsNew(a.endpointConfig, t.recipient)) &&
290
+ (await cachedRecipientIsNew(t.recipient)) &&
701
291
  t.amount.lt(reserveBaseXRP)
702
292
  ) {
703
- const f = formatAPICurrencyXRP(reserveBaseXRP);
704
293
  errors.amount = new NotEnoughBalanceBecauseDestinationNotCreated("", {
705
- minimalAmount: `${f.currency} ${new BigNumber(f.value).toFixed()}`,
294
+ minimalAmount: formatCurrencyUnit(a.currency.units[0], reserveBaseXRP, {
295
+ disableRounding: true,
296
+ useGrouping: false,
297
+ showCode: true,
298
+ }),
706
299
  });
707
300
  }
708
301
 
@@ -737,10 +330,12 @@ const estimateMaxSpendable = async ({
737
330
  account,
738
331
  parentAccount,
739
332
  transaction,
740
- }) => {
333
+ }): Promise<BigNumber> => {
741
334
  const mainAccount = getMainAccount(account, parentAccount);
742
335
  const r = await getServerInfo(mainAccount.endpointConfig);
743
- const reserveBaseXRP = parseAPIValue(r.validatedLedger.reserveBaseXRP);
336
+ const reserveBaseXRP = parseAPIValue(
337
+ r.info.validated_ledger.reserve_base_xrp.toString()
338
+ );
744
339
  const t = await prepareTransaction(mainAccount, {
745
340
  ...createTransaction(),
746
341
  ...transaction,
@@ -761,7 +356,7 @@ const accountBridge: AccountBridge<Transaction> = {
761
356
  prepareTransaction,
762
357
  getTransactionStatus,
763
358
  estimateMaxSpendable,
764
- sync,
359
+ sync: sync,
765
360
  receive,
766
361
  signOperation,
767
362
  broadcast,