@ledgerhq/coin-framework 0.3.5 → 0.3.6-next.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 (41) hide show
  1. package/.eslintrc.js +8 -46
  2. package/CHANGELOG.md +13 -0
  3. package/package.json +9 -18
  4. package/src/account/accountId.ts +20 -30
  5. package/src/account/accountName.ts +1 -4
  6. package/src/account/balanceHistoryCache.ts +18 -37
  7. package/src/account/groupOperations.ts +4 -6
  8. package/src/account/helpers.test.ts +6 -26
  9. package/src/account/helpers.ts +33 -66
  10. package/src/account/ordering.ts +10 -18
  11. package/src/account/pending.ts +6 -15
  12. package/src/account/serialization.ts +8 -19
  13. package/src/account/support.ts +8 -18
  14. package/src/account.test.ts +25 -40
  15. package/src/bot/specs.ts +24 -43
  16. package/src/bot/types.ts +1 -1
  17. package/src/bridge/getAddressWrapper.ts +5 -13
  18. package/src/bridge/jsHelpers.ts +215 -259
  19. package/src/cache.ts +4 -4
  20. package/src/currencies/BigNumberToLocaleString.test.ts +25 -33
  21. package/src/currencies/BigNumberToLocaleString.ts +3 -8
  22. package/src/currencies/CurrencyURIScheme.ts +1 -3
  23. package/src/currencies/chopCurrencyUnitDecimals.ts +1 -4
  24. package/src/currencies/formatCurrencyUnit.ts +11 -21
  25. package/src/currencies/index.ts +1 -4
  26. package/src/currencies/localeUtility.ts +2 -4
  27. package/src/currencies/parseCurrencyUnit.ts +1 -4
  28. package/src/currencies/sanitizeValueString.ts +1 -1
  29. package/src/currencies/support.ts +3 -9
  30. package/src/derivation.test.ts +1 -4
  31. package/src/derivation.ts +45 -95
  32. package/src/errors.test.ts +1 -1
  33. package/src/errors.ts +2 -6
  34. package/src/mocks/account.ts +27 -80
  35. package/src/mocks/fixtures/nfts.test.ts +2 -6
  36. package/src/mocks/fixtures/nfts.ts +12 -38
  37. package/src/mocks/helpers.ts +2 -8
  38. package/src/nft/nftId.ts +2 -2
  39. package/src/operation.test.ts +6 -31
  40. package/src/operation.ts +12 -26
  41. package/src/transaction/common.ts +9 -22
@@ -2,10 +2,7 @@ import { BigNumber } from "bignumber.js";
2
2
  import { flattenAccounts, getAccountCurrency } from "./helpers";
3
3
  import type { FlattenAccountsOptions } from "./helpers";
4
4
  import type { Account, AccountLike } from "@ledgerhq/types-live";
5
- import type {
6
- CryptoCurrency,
7
- TokenCurrency,
8
- } from "@ledgerhq/types-cryptoassets";
5
+ import type { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets";
9
6
 
10
7
  export type AccountComparator = (a: AccountLike, b: AccountLike) => number;
11
8
 
@@ -29,8 +26,8 @@ export const sortAccountsComparatorFromOrder = (
29
26
  orderAccounts: string,
30
27
  calculateCountervalue: (
31
28
  currency: TokenCurrency | CryptoCurrency,
32
- value: BigNumber
33
- ) => BigNumber | null | undefined
29
+ value: BigNumber,
30
+ ) => BigNumber | null | undefined,
34
31
  ): AccountComparator => {
35
32
  const [order, sort] = orderAccounts.split("|");
36
33
  const ascValue = sort === "desc" ? -1 : 1;
@@ -47,9 +44,7 @@ export const sortAccountsComparatorFromOrder = (
47
44
 
48
45
  const lazyCalcCV = (a: AccountLike) => {
49
46
  if (a.id in cvCaches) return cvCaches[a.id];
50
- const v =
51
- calculateCountervalue(getAccountCurrency(a), a.balance) ||
52
- new BigNumber(-1);
47
+ const v = calculateCountervalue(getAccountCurrency(a), a.balance) || new BigNumber(-1);
53
48
  cvCaches[a.id] = v;
54
49
  return v;
55
50
  };
@@ -62,7 +57,7 @@ export const sortAccountsComparatorFromOrder = (
62
57
  };
63
58
  export const comparatorSortAccounts = <TA extends AccountLike>(
64
59
  accounts: TA[],
65
- comparator: AccountComparator
60
+ comparator: AccountComparator,
66
61
  ): TA[] => {
67
62
  const meta = accounts
68
63
  .map((ta, index) => ({
@@ -77,24 +72,24 @@ export const comparatorSortAccounts = <TA extends AccountLike>(
77
72
  }
78
73
 
79
74
  // otherwise, need to reorder
80
- return meta.map((m) => accounts[m.index]);
75
+ return meta.map(m => accounts[m.index]);
81
76
  };
82
77
  // flatten accounts and sort between them (used for grid mode)
83
78
  export const flattenSortAccounts = (
84
79
  accounts: Account[],
85
80
  comparator: AccountComparator,
86
- o?: FlattenAccountsOptions
81
+ o?: FlattenAccountsOptions,
87
82
  ): AccountLike[] => {
88
83
  return comparatorSortAccounts(flattenAccounts(accounts, o), comparator);
89
84
  };
90
85
  // sort top level accounts and the inner sub accounts if necessary (used for lists)
91
86
  export const nestedSortAccounts = (
92
87
  topAccounts: Account[],
93
- comparator: AccountComparator
88
+ comparator: AccountComparator,
94
89
  ): Account[] => {
95
90
  let oneAccountHaveChanged = false;
96
91
  // first of all we sort the inner token accounts
97
- const accounts = topAccounts.map((a) => {
92
+ const accounts = topAccounts.map(a => {
98
93
  if (!a.subAccounts) return a;
99
94
  const subAccounts = comparatorSortAccounts(a.subAccounts, comparator);
100
95
  if (subAccounts === a.subAccounts) return a;
@@ -102,8 +97,5 @@ export const nestedSortAccounts = (
102
97
  return { ...a, subAccounts };
103
98
  });
104
99
  // then we sort again between them
105
- return comparatorSortAccounts(
106
- oneAccountHaveChanged ? accounts : topAccounts,
107
- comparator
108
- );
100
+ return comparatorSortAccounts(oneAccountHaveChanged ? accounts : topAccounts, comparator);
109
101
  };
@@ -1,9 +1,6 @@
1
1
  import type { Account, Operation, SubAccount } from "@ledgerhq/types-live";
2
2
  import { getEnv } from "@ledgerhq/live-env";
3
- export function shouldRetainPendingOperation(
4
- account: Account,
5
- op: Operation
6
- ): boolean {
3
+ export function shouldRetainPendingOperation(account: Account, op: Operation): boolean {
7
4
  // FIXME: valueOf to compare dates in typescript
8
5
  const delay = new Date().valueOf() - op.date.valueOf();
9
6
  const last = account.operations[0];
@@ -22,22 +19,19 @@ export function shouldRetainPendingOperation(
22
19
 
23
20
  const appendPendingOp = (ops: Operation[], op: Operation) => {
24
21
  const filtered: Operation[] = ops.filter(
25
- (o) => o.transactionSequenceNumber !== op.transactionSequenceNumber
22
+ o => o.transactionSequenceNumber !== op.transactionSequenceNumber,
26
23
  );
27
24
  filtered.unshift(op);
28
25
  return filtered;
29
26
  };
30
27
 
31
- export const addPendingOperation = (
32
- account: Account,
33
- operation: Operation
34
- ): Account => {
28
+ export const addPendingOperation = (account: Account, operation: Operation): Account => {
35
29
  const accountCopy = { ...account };
36
30
  const { subOperations } = operation;
37
31
  const { subAccounts } = account;
38
32
 
39
33
  function addInSubAccount(subaccounts: SubAccount[], op: Operation) {
40
- const acc = subaccounts.find((sub) => sub.id === op.accountId);
34
+ const acc = subaccounts.find(sub => sub.id === op.accountId);
41
35
 
42
36
  if (acc) {
43
37
  const copy: SubAccount = { ...acc };
@@ -48,17 +42,14 @@ export const addPendingOperation = (
48
42
 
49
43
  if (subOperations && subAccounts) {
50
44
  const taCopy: SubAccount[] = subAccounts.slice(0);
51
- subOperations.forEach((op) => {
45
+ subOperations.forEach(op => {
52
46
  addInSubAccount(taCopy, op);
53
47
  });
54
48
  accountCopy.subAccounts = taCopy;
55
49
  }
56
50
 
57
51
  if (accountCopy.id === operation.accountId) {
58
- accountCopy.pendingOperations = appendPendingOp(
59
- accountCopy.pendingOperations,
60
- operation
61
- );
52
+ accountCopy.pendingOperations = appendPendingOp(accountCopy.pendingOperations, operation);
62
53
  } else if (subAccounts) {
63
54
  const taCopy: SubAccount[] = subAccounts.slice(0);
64
55
  addInSubAccount(taCopy, operation);
@@ -1,9 +1,7 @@
1
1
  import { BigNumber } from "bignumber.js";
2
2
  import type { Operation, OperationRaw, SubAccount } from "@ledgerhq/types-live";
3
3
 
4
- export type ExtractExtraFn = (
5
- extra: Record<string, any>
6
- ) => Record<string, any>;
4
+ export type ExtractExtraFn = (extra: Record<string, any>) => Record<string, any>;
7
5
 
8
6
  export const toOperationRaw = (
9
7
  {
@@ -30,7 +28,7 @@ export const toOperationRaw = (
30
28
  tokenId,
31
29
  transactionRaw,
32
30
  }: Operation,
33
- preserveSubOperation?: boolean
31
+ preserveSubOperation?: boolean,
34
32
  ): OperationRaw => {
35
33
  const copy: OperationRaw = {
36
34
  id,
@@ -64,9 +62,7 @@ export const toOperationRaw = (
64
62
  }
65
63
 
66
64
  if (internalOperations) {
67
- copy.internalOperations = internalOperations.map((o: Operation) =>
68
- toOperationRaw(o)
69
- );
65
+ copy.internalOperations = internalOperations.map((o: Operation) => toOperationRaw(o));
70
66
  }
71
67
 
72
68
  if (nftOperations) {
@@ -79,10 +75,7 @@ export const toOperationRaw = (
79
75
 
80
76
  return copy;
81
77
  };
82
- export const inferSubOperations = (
83
- txHash: string,
84
- subAccounts: SubAccount[]
85
- ): Operation[] => {
78
+ export const inferSubOperations = (txHash: string, subAccounts: SubAccount[]): Operation[] => {
86
79
  const all: Operation[] = [];
87
80
 
88
81
  for (let i = 0; i < subAccounts.length; i++) {
@@ -132,7 +125,7 @@ export const fromOperationRaw = (
132
125
  transactionRaw,
133
126
  }: OperationRaw,
134
127
  accountId: string,
135
- subAccounts?: SubAccount[] | null | undefined
128
+ subAccounts?: SubAccount[] | null | undefined,
136
129
  ): Operation => {
137
130
  const res: Operation = {
138
131
  id,
@@ -164,21 +157,17 @@ export const fromOperationRaw = (
164
157
  if (subAccounts) {
165
158
  res.subOperations = inferSubOperations(hash, subAccounts);
166
159
  } else if (subOperations) {
167
- res.subOperations = subOperations.map((o: OperationRaw) =>
168
- fromOperationRaw(o, o.accountId)
169
- );
160
+ res.subOperations = subOperations.map((o: OperationRaw) => fromOperationRaw(o, o.accountId));
170
161
  }
171
162
 
172
163
  if (internalOperations) {
173
164
  res.internalOperations = internalOperations.map((o: OperationRaw) =>
174
- fromOperationRaw(o, o.accountId)
165
+ fromOperationRaw(o, o.accountId),
175
166
  );
176
167
  }
177
168
 
178
169
  if (nftOperations) {
179
- res.nftOperations = nftOperations.map((o: OperationRaw) =>
180
- fromOperationRaw(o, o.accountId)
181
- );
170
+ res.nftOperations = nftOperations.map((o: OperationRaw) => fromOperationRaw(o, o.accountId));
182
171
  }
183
172
 
184
173
  if (transactionRaw !== undefined) {
@@ -4,10 +4,7 @@ import {
4
4
  UnavailableTezosOriginatedAccountReceive,
5
5
  } from "@ledgerhq/errors";
6
6
  import { getEnv } from "@ledgerhq/live-env";
7
- import {
8
- getAllDerivationModes,
9
- getDerivationModesForCurrency,
10
- } from "../derivation";
7
+ import { getAllDerivationModes, getDerivationModesForCurrency } from "../derivation";
11
8
  import { isCurrencySupported } from "../currencies";
12
9
  import type { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
13
10
  import type { Account, AccountLike } from "@ledgerhq/types-live";
@@ -15,7 +12,7 @@ import type { DerivationMode } from "../derivation";
15
12
 
16
13
  export const shouldShowNewAccount = (
17
14
  currency: CryptoCurrency,
18
- derivationMode: DerivationMode
15
+ derivationMode: DerivationMode,
19
16
  ): boolean => {
20
17
  const modes = getDerivationModesForCurrency(currency);
21
18
  // last mode is always creatable by convention
@@ -37,25 +34,18 @@ export const shouldShowNewAccount = (
37
34
  };
38
35
  export const getReceiveFlowError = (
39
36
  account: AccountLike,
40
- parentAccount: Account | null | undefined
37
+ parentAccount: Account | null | undefined,
41
38
  ): Error | null | undefined => {
42
39
  if (parentAccount && parentAccount.currency.id === "tezos") {
43
40
  return new UnavailableTezosOriginatedAccountReceive("");
44
41
  }
45
42
  };
46
43
 
47
- export function checkAccountSupported(
48
- account: Account
49
- ): Error | null | undefined {
50
- if (
51
- !getAllDerivationModes().includes(account.derivationMode as DerivationMode)
52
- ) {
53
- return new AccountNotSupported(
54
- "derivation not supported " + account.derivationMode,
55
- {
56
- reason: account.derivationMode,
57
- }
58
- );
44
+ export function checkAccountSupported(account: Account): Error | null | undefined {
45
+ if (!getAllDerivationModes().includes(account.derivationMode as DerivationMode)) {
46
+ return new AccountNotSupported("derivation not supported " + account.derivationMode, {
47
+ reason: account.derivationMode,
48
+ });
59
49
  }
60
50
 
61
51
  if (!isCurrencySupported(account.currency)) {
@@ -1,11 +1,7 @@
1
1
  import "./test-helpers/staticTime";
2
2
  import { BigNumber } from "bignumber.js";
3
3
  import flatMap from "lodash/flatMap";
4
- import {
5
- getCryptoCurrencyById,
6
- getTokenById,
7
- setSupportedCurrencies,
8
- } from "./currencies";
4
+ import { getCryptoCurrencyById, getTokenById, setSupportedCurrencies } from "./currencies";
9
5
  import {
10
6
  groupAccountOperationsByDay,
11
7
  groupAccountsOperationsByDay,
@@ -35,10 +31,10 @@ describe("groupAccountOperationsByDay", () => {
35
31
  expect(res2.completed).toBe(true);
36
32
  expect(
37
33
  // $FlowFixMe
38
- flatMap(res2.sections, (s) => s.data).slice(0, 10)
34
+ flatMap(res2.sections, s => s.data).slice(0, 10),
39
35
  ).toMatchObject(
40
36
  // $FlowFixMe
41
- flatMap(res1.sections, (s) => s.data)
37
+ flatMap(res1.sections, s => s.data),
42
38
  );
43
39
  });
44
40
  test("basic 2", () => {
@@ -56,10 +52,10 @@ describe("groupAccountOperationsByDay", () => {
56
52
  expect(res2.completed).toBe(true);
57
53
  expect(
58
54
  // $FlowFixMe
59
- flatMap(res2.sections, (s) => s.data).slice(0, 100)
55
+ flatMap(res2.sections, s => s.data).slice(0, 100),
60
56
  ).toMatchObject(
61
57
  // $FlowFixMe
62
- flatMap(res1.sections, (s) => s.data)
58
+ flatMap(res1.sections, s => s.data),
63
59
  );
64
60
  });
65
61
  test("filterOperation", () => {
@@ -78,7 +74,7 @@ describe("groupAccountOperationsByDay", () => {
78
74
  expect(res2).toEqual(
79
75
  groupAccountOperationsByDay(account, {
80
76
  count: 10,
81
- })
77
+ }),
82
78
  );
83
79
  const res3 = groupAccountOperationsByDay(account, {
84
80
  count: 10,
@@ -91,15 +87,13 @@ describe("groupAccountOperationsByDay", () => {
91
87
  groupAccountOperationsByDay(
92
88
  {
93
89
  ...account,
94
- operations: account.operations.filter((op) => op.type === "OUT"),
95
- pendingOperations: account.pendingOperations.filter(
96
- (op) => op.type === "OUT"
97
- ),
90
+ operations: account.operations.filter(op => op.type === "OUT"),
91
+ pendingOperations: account.pendingOperations.filter(op => op.type === "OUT"),
98
92
  },
99
93
  {
100
94
  count: 10,
101
- }
102
- )
95
+ },
96
+ ),
103
97
  );
104
98
  });
105
99
  test("provide at least the requested count even if some op yield nothing", () => {
@@ -119,8 +113,7 @@ describe("groupAccountOperationsByDay", () => {
119
113
  });
120
114
  expect(res1.completed).toBe(false);
121
115
  expect(
122
- res1.sections.reduce((acc, s) => acc.concat(s.data), <Operation[]>[])
123
- .length
116
+ res1.sections.reduce((acc, s) => acc.concat(s.data), <Operation[]>[]).length,
124
117
  ).toBeGreaterThanOrEqual(100);
125
118
  });
126
119
  test("to dedup", () => {
@@ -137,12 +130,12 @@ describe("groupAccountOperationsByDay", () => {
137
130
  });
138
131
  });
139
132
  test("shortAddressPreview", () => {
140
- expect(
141
- shortAddressPreview("0x112233445566778899001234567890aAbBcCdDeEfF")
142
- ).toBe("0x112233...cCdDeEfF");
143
- expect(
144
- shortAddressPreview("0x112233445566778899001234567890aAbBcCdDeEfF", 30)
145
- ).toBe("0x11223344556...0aAbBcCdDeEfF");
133
+ expect(shortAddressPreview("0x112233445566778899001234567890aAbBcCdDeEfF")).toBe(
134
+ "0x112233...cCdDeEfF",
135
+ );
136
+ expect(shortAddressPreview("0x112233445566778899001234567890aAbBcCdDeEfF", 30)).toBe(
137
+ "0x11223344556...0aAbBcCdDeEfF",
138
+ );
146
139
  });
147
140
  test("accountWithMandatoryTokens ethereum", () => {
148
141
  const currency = getCryptoCurrencyById("ethereum");
@@ -150,9 +143,7 @@ test("accountWithMandatoryTokens ethereum", () => {
150
143
  currency,
151
144
  subAccountsCount: 5,
152
145
  });
153
- const enhance = accountWithMandatoryTokens(account, [
154
- getTokenById("ethereum/erc20/0x_project"),
155
- ]);
146
+ const enhance = accountWithMandatoryTokens(account, [getTokenById("ethereum/erc20/0x_project")]);
156
147
  const doubleEnhance = accountWithMandatoryTokens(enhance, [
157
148
  getTokenById("ethereum/erc20/0x_project"),
158
149
  ]);
@@ -161,7 +152,7 @@ test("accountWithMandatoryTokens ethereum", () => {
161
152
  ...account,
162
153
  subAccounts: [],
163
154
  });
164
- expect((enhance.subAccounts || []).map((a) => a.id)).toMatchSnapshot();
155
+ expect((enhance.subAccounts || []).map(a => a.id)).toMatchSnapshot();
165
156
  });
166
157
  test("withoutToken ethereum", () => {
167
158
  const isTokenAccount = (account: SubAccount, tokenId: string) =>
@@ -179,10 +170,7 @@ test("withoutToken ethereum", () => {
179
170
  subAccountsCount: 0,
180
171
  });
181
172
  //Enhance the account with some tokens
182
- const enhance = accountWithMandatoryTokens(
183
- account,
184
- tokenIds.map(getTokenById)
185
- );
173
+ const enhance = accountWithMandatoryTokens(account, tokenIds.map(getTokenById));
186
174
  //Get a version of that account without all the tokens
187
175
  let demote = enhance;
188
176
 
@@ -195,8 +183,8 @@ test("withoutToken ethereum", () => {
195
183
 
196
184
  //See if we have added/removed them correctly
197
185
  for (const tokenId of tokenIds) {
198
- expect(saTokens.find((a) => isTokenAccount(a, tokenId))).toBeTruthy();
199
- expect(saNoTokens.find((a) => isTokenAccount(a, tokenId))).toBeFalsy();
186
+ expect(saTokens.find(a => isTokenAccount(a, tokenId))).toBeTruthy();
187
+ expect(saNoTokens.find(a => isTokenAccount(a, tokenId))).toBeFalsy();
200
188
  }
201
189
  });
202
190
  test("withoutToken tron", () => {
@@ -215,10 +203,7 @@ test("withoutToken tron", () => {
215
203
  subAccountsCount: 0,
216
204
  });
217
205
  //Enhance the account with some tokens
218
- const enhance = accountWithMandatoryTokens(
219
- account,
220
- tokenIds.map(getTokenById)
221
- );
206
+ const enhance = accountWithMandatoryTokens(account, tokenIds.map(getTokenById));
222
207
  //Get a version of that account without all the tokens
223
208
  let demote = enhance;
224
209
 
@@ -231,7 +216,7 @@ test("withoutToken tron", () => {
231
216
 
232
217
  //See if we have added/removed them correctly
233
218
  for (const tokenId of tokenIds) {
234
- expect(saTokens.find((a) => isTokenAccount(a, tokenId))).toBeTruthy();
235
- expect(saNoTokens.find((a) => isTokenAccount(a, tokenId))).toBeFalsy();
219
+ expect(saTokens.find(a => isTokenAccount(a, tokenId))).toBeTruthy();
220
+ expect(saNoTokens.find(a => isTokenAccount(a, tokenId))).toBeFalsy();
236
221
  }
237
222
  });
package/src/bot/specs.ts CHANGED
@@ -4,11 +4,7 @@ import { log } from "@ledgerhq/logs";
4
4
  import expect from "expect";
5
5
  import sample from "lodash/sample";
6
6
  import { isAccountEmpty } from "../account";
7
- import type {
8
- DeviceAction,
9
- DeviceActionArg,
10
- TransactionDestinationTestInput,
11
- } from "./types";
7
+ import type { DeviceAction, DeviceActionArg, TransactionDestinationTestInput } from "./types";
12
8
  import { Account, TransactionCommon } from "@ledgerhq/types-live";
13
9
  import { botTest } from "./bot-test-context";
14
10
  import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets";
@@ -21,16 +17,13 @@ const stepValueTransformDefault = (s: string) => s.trim();
21
17
 
22
18
  // TODO should weight the choice to favorize accounts with small amounts
23
19
  export function pickSiblings(siblings: Account[], maxAccount = 5): Account {
24
- const withoutEmpties = siblings.filter((a) => a.used);
20
+ const withoutEmpties = siblings.filter(a => a.used);
25
21
 
26
22
  if (withoutEmpties.length >= maxAccount) {
27
23
  // we are no longer creating accounts
28
24
  const maybeAccount = sample(withoutEmpties);
29
25
  if (!maybeAccount) {
30
- throw new Error(
31
- "at least one non-empty sibling account exists. maxAccount=" +
32
- maxAccount
33
- );
26
+ throw new Error("at least one non-empty sibling account exists. maxAccount=" + maxAccount);
34
27
  }
35
28
  return maybeAccount;
36
29
  }
@@ -40,14 +33,12 @@ export function pickSiblings(siblings: Account[], maxAccount = 5): Account {
40
33
  empties.sort((a, b) => a.index - b.index);
41
34
 
42
35
  if (empties.length > 0) {
43
- empties = empties.filter((e) => e.index === empties[0].index);
36
+ empties = empties.filter(e => e.index === empties[0].index);
44
37
  }
45
38
 
46
39
  const maybeAccount = sample(withoutEmpties.concat(empties));
47
40
  if (!maybeAccount) {
48
- throw new Error(
49
- "at least one sibling account exists. maxAccount=" + maxAccount
50
- );
41
+ throw new Error("at least one sibling account exists. maxAccount=" + maxAccount);
51
42
  }
52
43
  return maybeAccount;
53
44
  }
@@ -77,7 +68,7 @@ type Step<T extends TransactionCommon> = {
77
68
  acc: Array<{
78
69
  title: string;
79
70
  value: string;
80
- }>
71
+ }>,
81
72
  ) => string;
82
73
  ignoreAssertionFailure?: boolean;
83
74
  trimValue?: boolean;
@@ -92,7 +83,7 @@ type FlowDesc<T extends TransactionCommon> = {
92
83
  };
93
84
  // generalized logic of device actions
94
85
  export function deviceActionFlow<T extends TransactionCommon>(
95
- description: FlowDesc<T>
86
+ description: FlowDesc<T>,
96
87
  ): DeviceAction<T, State<T>> {
97
88
  return (arg: DeviceActionArg<T, State<T>>) => {
98
89
  const { transport, event, state, disableStrictStepValueValidation } = arg;
@@ -111,8 +102,7 @@ export function deviceActionFlow<T extends TransactionCommon>(
111
102
  // there were accumulated text and we are on new step, we need to release it and compare to expected
112
103
  if (currentStep && currentStep.expectedValue) {
113
104
  const { expectedValue, ignoreAssertionFailure } = currentStep;
114
- const stepValueTransform =
115
- currentStep.stepValueTransform || stepValueTransformDefault;
105
+ const stepValueTransform = currentStep.stepValueTransform || stepValueTransformDefault;
116
106
 
117
107
  if (!ignoreAssertionFailure && !disableStrictStepValueValidation) {
118
108
  botTest("deviceAction confirm step '" + stepTitle + "'", () => {
@@ -122,10 +112,7 @@ export function deviceActionFlow<T extends TransactionCommon>(
122
112
  // FIXME: OCR of speculos couldn't retrieve S properly
123
113
  // Issue on speculos repository : https://github.com/LedgerHQ/speculos/issues/204
124
114
  [stepTitle]: expectedValue(arg, acc)
125
- .replace(
126
- /S/g,
127
- arg.appCandidate.model === DeviceModelId.nanoS ? "S" : ""
128
- )
115
+ .replace(/S/g, arg.appCandidate.model === DeviceModelId.nanoS ? "S" : "")
129
116
  .trim(),
130
117
  });
131
118
  });
@@ -155,13 +142,12 @@ export function deviceActionFlow<T extends TransactionCommon>(
155
142
  }
156
143
 
157
144
  if (!finalState) {
158
- let possibleKnownStep: Step<T> | null | undefined =
159
- description.steps.find((s) => {
160
- if (s.maxY) {
161
- return event.text.startsWith(s.title) && event.y < s.maxY;
162
- }
163
- return event.text.startsWith(s.title);
164
- });
145
+ let possibleKnownStep: Step<T> | null | undefined = description.steps.find(s => {
146
+ if (s.maxY) {
147
+ return event.text.startsWith(s.title) && event.y < s.maxY;
148
+ }
149
+ return event.text.startsWith(s.title);
150
+ });
165
151
 
166
152
  // if there is a fallback provided, we will run it to try to detect another possible known step
167
153
  if (!possibleKnownStep && description.fallback) {
@@ -211,7 +197,7 @@ const sep = " ";
211
197
  export function formatDeviceAmount(
212
198
  currency: CryptoCurrency | TokenCurrency,
213
199
  value: BigNumber,
214
- options: Partial<DeviceAmountFormatOptions> = defaultFormatOptions
200
+ options: Partial<DeviceAmountFormatOptions> = defaultFormatOptions,
215
201
  ): string {
216
202
  const [unit] = currency.units;
217
203
  let code = unit.code;
@@ -220,9 +206,7 @@ export function formatDeviceAmount(
220
206
  if (deviceTicker) code = deviceTicker;
221
207
  }
222
208
  const fValue = value.div(new BigNumber(10).pow(unit.magnitude));
223
- let v = options.showAllDigits
224
- ? fValue.toFixed(unit.magnitude)
225
- : fValue.toString(10);
209
+ let v = options.showAllDigits ? fValue.toFixed(unit.magnitude) : fValue.toString(10);
226
210
  if (options.forceFloating) {
227
211
  if (!v.includes(".")) {
228
212
  // if the value is pure integer, in the app it will automatically add an .0
@@ -238,20 +222,17 @@ export function formatDeviceAmount(
238
222
  // Usage: put these in your spec, on the mutation transaction functions that intend to do more "delegations"
239
223
  export function expectSiblingsHaveSpendablePartGreaterThan(
240
224
  siblings: Account[],
241
- threshold: number
225
+ threshold: number,
242
226
  ): void {
243
227
  const spendableTotal = siblings.reduce(
244
228
  (acc, a) => acc.plus(a.spendableBalance),
245
- new BigNumber(0)
246
- );
247
- const total = siblings.reduce(
248
- (acc, a) => acc.plus(a.balance),
249
- new BigNumber(0)
229
+ new BigNumber(0),
250
230
  );
231
+ const total = siblings.reduce((acc, a) => acc.plus(a.balance), new BigNumber(0));
251
232
  invariant(
252
233
  spendableTotal.div(total).gt(threshold),
253
234
  "the spendable part of accounts is sufficient (threshold: %s)",
254
- threshold
235
+ threshold,
255
236
  );
256
237
  }
257
238
 
@@ -264,8 +245,8 @@ export const genericTestDestination = <T>({
264
245
  const amount = sendingOperation.value.minus(sendingOperation.fee);
265
246
  botTest("account balance increased with transaction amount", () =>
266
247
  expect(destination.balance.toString()).toBe(
267
- destinationBeforeTransaction.balance.plus(amount).toString()
268
- )
248
+ destinationBeforeTransaction.balance.plus(amount).toString(),
249
+ ),
269
250
  );
270
251
  botTest("operation amount is consistent with sendingOperation", () =>
271
252
  expect({
@@ -274,6 +255,6 @@ export const genericTestDestination = <T>({
274
255
  }).toMatchObject({
275
256
  type: "IN",
276
257
  amount: amount.toString(),
277
- })
258
+ }),
278
259
  );
279
260
  };
package/src/bot/types.ts CHANGED
@@ -56,7 +56,7 @@ export type DeviceActionArg<T extends TransactionCommon, S> = {
56
56
  disableStrictStepValueValidation?: boolean;
57
57
  };
58
58
  export type DeviceAction<T extends TransactionCommon, S> = (
59
- arg0: DeviceActionArg<T, S>
59
+ arg0: DeviceActionArg<T, S>,
60
60
  ) => S | null | undefined;
61
61
  export type TransactionArg<T extends TransactionCommon> = {
62
62
  appCandidate: AppCandidate;
@@ -1,27 +1,19 @@
1
1
  import Transport from "@ledgerhq/hw-transport";
2
- import {
3
- DeviceAppVerifyNotSupported,
4
- StatusCodes,
5
- UserRefusedAddress,
6
- } from "@ledgerhq/errors";
2
+ import { DeviceAppVerifyNotSupported, StatusCodes, UserRefusedAddress } from "@ledgerhq/errors";
7
3
  import { log } from "@ledgerhq/logs";
8
4
  import type { Result, GetAddressOptions } from "../derivation";
9
5
 
10
- export type Resolver = (
11
- transport: Transport,
12
- addressOpt: GetAddressOptions
13
- ) => Promise<Result>;
6
+ export type Resolver = (transport: Transport, addressOpt: GetAddressOptions) => Promise<Result>;
14
7
 
15
8
  const getAddressWrapper =
16
- (getAddressFn: Resolver) =>
17
- (transport: Transport, opts: GetAddressOptions) => {
9
+ (getAddressFn: Resolver) => (transport: Transport, opts: GetAddressOptions) => {
18
10
  const { currency, path, verify } = opts;
19
11
  return getAddressFn(transport, opts)
20
- .then((result) => {
12
+ .then(result => {
21
13
  log("hw", `getAddress ${currency.id} on ${path}`, result);
22
14
  return result;
23
15
  })
24
- .catch((e) => {
16
+ .catch(e => {
25
17
  log("hw", `getAddress ${currency.id} on ${path} FAILED ${String(e)}`);
26
18
 
27
19
  if (e && e.name === "TransportStatusError") {