@ledgerhq/live-common 24.0.0 → 24.1.0-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.
- package/lib/__tests__/range.js +8 -0
- package/lib/__tests__/range.js.map +1 -1
- package/lib/families/bitcoin/js-synchronisation.d.ts.map +1 -1
- package/lib/families/bitcoin/js-synchronisation.js +2 -173
- package/lib/families/bitcoin/js-synchronisation.js.map +1 -1
- package/lib/families/bitcoin/logic.d.ts +6 -1
- package/lib/families/bitcoin/logic.d.ts.map +1 -1
- package/lib/families/bitcoin/logic.js +186 -1
- package/lib/families/bitcoin/logic.js.map +1 -1
- package/lib/families/bitcoin/xpub.txs.txNoOutput.unit.test.d.ts +2 -0
- package/lib/families/bitcoin/xpub.txs.txNoOutput.unit.test.d.ts.map +1 -0
- package/lib/families/bitcoin/xpub.txs.txNoOutput.unit.test.js +72 -0
- package/lib/families/bitcoin/xpub.txs.txNoOutput.unit.test.js.map +1 -0
- package/lib/families/cosmos/api/Cosmos.d.ts.map +1 -1
- package/lib/families/cosmos/api/Cosmos.js +1 -0
- package/lib/families/cosmos/api/Cosmos.js.map +1 -1
- package/lib/families/cosmos/react.test.js +5 -4
- package/lib/families/cosmos/react.test.js.map +1 -1
- package/lib/hw/extractOnboardingState.d.ts +26 -0
- package/lib/hw/extractOnboardingState.d.ts.map +1 -0
- package/lib/hw/extractOnboardingState.js +69 -0
- package/lib/hw/extractOnboardingState.js.map +1 -0
- package/lib/hw/extractOnboardingState.test.d.ts +2 -0
- package/lib/hw/extractOnboardingState.test.d.ts.map +1 -0
- package/lib/hw/extractOnboardingState.test.js +182 -0
- package/lib/hw/extractOnboardingState.test.js.map +1 -0
- package/lib/hw/getOnboardingStatePolling.d.ts +20 -0
- package/lib/hw/getOnboardingStatePolling.d.ts.map +1 -0
- package/lib/hw/getOnboardingStatePolling.js +117 -0
- package/lib/hw/getOnboardingStatePolling.js.map +1 -0
- package/lib/hw/getOnboardingStatePolling.test.d.ts +2 -0
- package/lib/hw/getOnboardingStatePolling.test.d.ts.map +1 -0
- package/lib/hw/getOnboardingStatePolling.test.js +224 -0
- package/lib/hw/getOnboardingStatePolling.test.js.map +1 -0
- package/lib/onboarding/hooks/useOnboardingStatePolling.d.ts +22 -0
- package/lib/onboarding/hooks/useOnboardingStatePolling.d.ts.map +1 -0
- package/lib/onboarding/hooks/useOnboardingStatePolling.js +81 -0
- package/lib/onboarding/hooks/useOnboardingStatePolling.js.map +1 -0
- package/lib/onboarding/hooks/useOnboardingStatePolling.test.d.ts +2 -0
- package/lib/onboarding/hooks/useOnboardingStatePolling.test.d.ts.map +1 -0
- package/lib/onboarding/hooks/useOnboardingStatePolling.test.js +374 -0
- package/lib/onboarding/hooks/useOnboardingStatePolling.test.js.map +1 -0
- package/lib/types/manager.d.ts +5 -0
- package/lib/types/manager.d.ts.map +1 -1
- package/lib/types/manager.js +7 -1
- package/lib/types/manager.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/range.ts +13 -0
- package/src/families/bitcoin/js-synchronisation.ts +3 -172
- package/src/families/bitcoin/logic.ts +169 -0
- package/src/families/bitcoin/xpub.txs.txNoOutput.unit.test.ts +37 -0
- package/src/families/cosmos/api/Cosmos.ts +4 -0
- package/src/families/cosmos/react.test.ts +3 -0
- package/src/hw/extractOnboardingState.test.ts +251 -0
- package/src/hw/extractOnboardingState.ts +97 -0
- package/src/hw/getOnboardingStatePolling.test.ts +247 -0
- package/src/hw/getOnboardingStatePolling.ts +153 -0
- package/src/onboarding/hooks/useOnboardingStatePolling.test.ts +304 -0
- package/src/onboarding/hooks/useOnboardingStatePolling.ts +86 -0
- package/src/types/manager.ts +5 -0
|
@@ -1,26 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
3
|
-
TX,
|
|
4
|
-
Currency,
|
|
5
|
-
Input as WalletInput,
|
|
6
|
-
Output as WalletOutput,
|
|
7
|
-
} from "./wallet-btc";
|
|
1
|
+
import type { Currency, Output as WalletOutput } from "./wallet-btc";
|
|
8
2
|
import { DerivationModes as WalletDerivationModes } from "./wallet-btc";
|
|
9
3
|
import { BigNumber } from "bignumber.js";
|
|
10
4
|
import Btc from "@ledgerhq/hw-app-btc";
|
|
11
5
|
import { log } from "@ledgerhq/logs";
|
|
12
6
|
import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets";
|
|
13
|
-
import type {
|
|
14
|
-
Account,
|
|
15
|
-
Operation,
|
|
16
|
-
OperationType,
|
|
17
|
-
DerivationMode,
|
|
18
|
-
} from "../../types";
|
|
7
|
+
import type { Account, Operation, DerivationMode } from "../../types";
|
|
19
8
|
import type { GetAccountShape } from "../../bridge/jsHelpers";
|
|
20
9
|
import { makeSync, makeScanAccounts, mergeOps } from "../../bridge/jsHelpers";
|
|
21
10
|
import { findCurrencyExplorer } from "../../api/Ledger";
|
|
22
11
|
import { encodeAccountId } from "../../account";
|
|
23
|
-
import { encodeOperationId } from "../../operation";
|
|
24
12
|
import {
|
|
25
13
|
isSegwitDerivationMode,
|
|
26
14
|
isNativeSegwitDerivationMode,
|
|
@@ -30,6 +18,7 @@ import { BitcoinOutput } from "./types";
|
|
|
30
18
|
import { perCoinLogic } from "./logic";
|
|
31
19
|
import wallet from "./wallet-btc";
|
|
32
20
|
import { getAddressWithBtcInstance } from "./hw-getAddress";
|
|
21
|
+
import { mapTxToOperations } from "./logic";
|
|
33
22
|
|
|
34
23
|
// Map LL's DerivationMode to wallet-btc's
|
|
35
24
|
const toWalletDerivationMode = (
|
|
@@ -89,164 +78,6 @@ const deduplicateOperations = (
|
|
|
89
78
|
return out;
|
|
90
79
|
};
|
|
91
80
|
|
|
92
|
-
const mapTxToOperations = (
|
|
93
|
-
tx: TX,
|
|
94
|
-
currencyId: string,
|
|
95
|
-
accountId: string,
|
|
96
|
-
accountAddresses: Set<string>,
|
|
97
|
-
changeAddresses: Set<string>
|
|
98
|
-
): $Shape<Operation[]> => {
|
|
99
|
-
const operations: Operation[] = [];
|
|
100
|
-
const txId = tx.id;
|
|
101
|
-
const fee = new BigNumber(tx.fees);
|
|
102
|
-
const blockHeight = tx.block?.height;
|
|
103
|
-
const blockHash = tx.block?.hash;
|
|
104
|
-
const date = new Date(tx.block?.time || tx.received_at);
|
|
105
|
-
const senders = new Set<string>();
|
|
106
|
-
const recipients: string[] = [];
|
|
107
|
-
let type: OperationType = "OUT";
|
|
108
|
-
let value = new BigNumber(0);
|
|
109
|
-
const hasFailed = false;
|
|
110
|
-
const accountInputs: WalletInput[] = [];
|
|
111
|
-
const accountOutputs: WalletOutput[] = [];
|
|
112
|
-
const syncReplaceAddress = perCoinLogic[currencyId]?.syncReplaceAddress;
|
|
113
|
-
|
|
114
|
-
for (const input of tx.inputs) {
|
|
115
|
-
if (input.address) {
|
|
116
|
-
senders.add(
|
|
117
|
-
syncReplaceAddress ? syncReplaceAddress(input.address) : input.address
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
if (input.value) {
|
|
121
|
-
if (accountAddresses.has(input.address)) {
|
|
122
|
-
// This address is part of the account
|
|
123
|
-
value = value.plus(input.value);
|
|
124
|
-
accountInputs.push(input);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// All inputs of a same transaction have the same sequence
|
|
131
|
-
const transactionSequenceNumber =
|
|
132
|
-
(accountInputs.length > 0 && accountInputs[0].sequence) || undefined;
|
|
133
|
-
|
|
134
|
-
const hasSpentNothing = value.eq(0);
|
|
135
|
-
// Change output is always the last one
|
|
136
|
-
const changeOutputIndex = tx.outputs
|
|
137
|
-
.map((o) => o.output_index)
|
|
138
|
-
.reduce((p, c) => (p > c ? p : c));
|
|
139
|
-
|
|
140
|
-
for (const output of tx.outputs) {
|
|
141
|
-
if (output.address) {
|
|
142
|
-
if (!accountAddresses.has(output.address)) {
|
|
143
|
-
// The output doesn't belong to this account
|
|
144
|
-
if (
|
|
145
|
-
accountInputs.length > 0 && // It's a SEND operation
|
|
146
|
-
(tx.outputs.length === 1 || // The transaction has only 1 output
|
|
147
|
-
output.output_index < changeOutputIndex) // The output isn't the change output
|
|
148
|
-
) {
|
|
149
|
-
recipients.push(
|
|
150
|
-
syncReplaceAddress
|
|
151
|
-
? syncReplaceAddress(output.address)
|
|
152
|
-
: output.address
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
} else {
|
|
156
|
-
// The output belongs to this account
|
|
157
|
-
accountOutputs.push(output);
|
|
158
|
-
|
|
159
|
-
if (!changeAddresses.has(output.address)) {
|
|
160
|
-
// The output isn't a change output of this account
|
|
161
|
-
recipients.push(
|
|
162
|
-
syncReplaceAddress
|
|
163
|
-
? syncReplaceAddress(output.address)
|
|
164
|
-
: output.address
|
|
165
|
-
);
|
|
166
|
-
} else {
|
|
167
|
-
// The output is a change output of this account,
|
|
168
|
-
// we count it as a recipient only in some special cases
|
|
169
|
-
if (
|
|
170
|
-
(recipients.length === 0 &&
|
|
171
|
-
output.output_index >= changeOutputIndex) ||
|
|
172
|
-
hasSpentNothing
|
|
173
|
-
) {
|
|
174
|
-
recipients.push(
|
|
175
|
-
syncReplaceAddress
|
|
176
|
-
? syncReplaceAddress(output.address)
|
|
177
|
-
: output.address
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (accountInputs.length > 0) {
|
|
186
|
-
// It's a SEND operation
|
|
187
|
-
for (const output of accountOutputs) {
|
|
188
|
-
if (changeAddresses.has(output.address)) {
|
|
189
|
-
value = value.minus(output.value);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
type = "OUT";
|
|
194
|
-
operations.push({
|
|
195
|
-
id: encodeOperationId(accountId, txId, type),
|
|
196
|
-
hash: txId,
|
|
197
|
-
type,
|
|
198
|
-
value,
|
|
199
|
-
fee,
|
|
200
|
-
senders: Array.from(senders),
|
|
201
|
-
recipients,
|
|
202
|
-
blockHeight,
|
|
203
|
-
blockHash,
|
|
204
|
-
transactionSequenceNumber,
|
|
205
|
-
accountId,
|
|
206
|
-
date,
|
|
207
|
-
hasFailed,
|
|
208
|
-
extra: {},
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (accountOutputs.length > 0) {
|
|
213
|
-
// It's a RECEIVE operation
|
|
214
|
-
const filterChangeAddresses = !!accountInputs.length;
|
|
215
|
-
let accountOutputCount = 0;
|
|
216
|
-
let finalAmount = new BigNumber(0);
|
|
217
|
-
|
|
218
|
-
for (const output of accountOutputs) {
|
|
219
|
-
if (!filterChangeAddresses || !changeAddresses.has(output.address)) {
|
|
220
|
-
finalAmount = finalAmount.plus(output.value);
|
|
221
|
-
accountOutputCount += 1;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
if (accountOutputCount > 0) {
|
|
226
|
-
value = finalAmount;
|
|
227
|
-
type = "IN";
|
|
228
|
-
operations.push({
|
|
229
|
-
id: encodeOperationId(accountId, txId, type),
|
|
230
|
-
hash: txId,
|
|
231
|
-
type,
|
|
232
|
-
value,
|
|
233
|
-
fee,
|
|
234
|
-
senders: Array.from(senders),
|
|
235
|
-
recipients,
|
|
236
|
-
blockHeight,
|
|
237
|
-
blockHash,
|
|
238
|
-
transactionSequenceNumber,
|
|
239
|
-
accountId,
|
|
240
|
-
date,
|
|
241
|
-
hasFailed,
|
|
242
|
-
extra: {},
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return operations;
|
|
248
|
-
};
|
|
249
|
-
|
|
250
81
|
const getAccountShape: GetAccountShape = async (info) => {
|
|
251
82
|
const {
|
|
252
83
|
transport,
|
|
@@ -9,6 +9,15 @@ import type {
|
|
|
9
9
|
NetworkInfo,
|
|
10
10
|
UtxoStrategy,
|
|
11
11
|
} from "./types";
|
|
12
|
+
import { $Shape } from "utility-types";
|
|
13
|
+
import type {
|
|
14
|
+
TX,
|
|
15
|
+
Input as WalletInput,
|
|
16
|
+
Output as WalletOutput,
|
|
17
|
+
} from "./wallet-btc";
|
|
18
|
+
import { BigNumber } from "bignumber.js";
|
|
19
|
+
import { encodeOperationId } from "../../operation";
|
|
20
|
+
import type { Operation, OperationType } from "../../types";
|
|
12
21
|
|
|
13
22
|
// correspond ~ to min relay fees but determined empirically for a tx to be accepted by network
|
|
14
23
|
const minFees = {
|
|
@@ -176,3 +185,163 @@ export const perCoinLogic: Record<
|
|
|
176
185
|
}),
|
|
177
186
|
},
|
|
178
187
|
};
|
|
188
|
+
|
|
189
|
+
export const mapTxToOperations = (
|
|
190
|
+
tx: TX,
|
|
191
|
+
currencyId: string,
|
|
192
|
+
accountId: string,
|
|
193
|
+
accountAddresses: Set<string>,
|
|
194
|
+
changeAddresses: Set<string>
|
|
195
|
+
): $Shape<Operation[]> => {
|
|
196
|
+
const operations: Operation[] = [];
|
|
197
|
+
const txId = tx.id;
|
|
198
|
+
const fee = new BigNumber(tx.fees);
|
|
199
|
+
const blockHeight = tx.block?.height;
|
|
200
|
+
const blockHash = tx.block?.hash;
|
|
201
|
+
const date = new Date(tx.block?.time || tx.received_at);
|
|
202
|
+
const senders = new Set<string>();
|
|
203
|
+
const recipients: string[] = [];
|
|
204
|
+
let type: OperationType = "OUT";
|
|
205
|
+
let value = new BigNumber(0);
|
|
206
|
+
const hasFailed = false;
|
|
207
|
+
const accountInputs: WalletInput[] = [];
|
|
208
|
+
const accountOutputs: WalletOutput[] = [];
|
|
209
|
+
const syncReplaceAddress = perCoinLogic[currencyId]?.syncReplaceAddress;
|
|
210
|
+
|
|
211
|
+
for (const input of tx.inputs) {
|
|
212
|
+
if (input.address) {
|
|
213
|
+
senders.add(
|
|
214
|
+
syncReplaceAddress ? syncReplaceAddress(input.address) : input.address
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
if (input.value) {
|
|
218
|
+
if (accountAddresses.has(input.address)) {
|
|
219
|
+
// This address is part of the account
|
|
220
|
+
value = value.plus(input.value);
|
|
221
|
+
accountInputs.push(input);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// All inputs of a same transaction have the same sequence
|
|
228
|
+
const transactionSequenceNumber =
|
|
229
|
+
(accountInputs.length > 0 && accountInputs[0].sequence) || undefined;
|
|
230
|
+
|
|
231
|
+
const hasSpentNothing = value.eq(0);
|
|
232
|
+
|
|
233
|
+
// Change output is always the last one
|
|
234
|
+
const changeOutputIndex =
|
|
235
|
+
tx.outputs.length === 0
|
|
236
|
+
? 0
|
|
237
|
+
: tx.outputs.map((o) => o.output_index).reduce((p, c) => (p > c ? p : c));
|
|
238
|
+
|
|
239
|
+
for (const output of tx.outputs) {
|
|
240
|
+
if (output.address) {
|
|
241
|
+
if (!accountAddresses.has(output.address)) {
|
|
242
|
+
// The output doesn't belong to this account
|
|
243
|
+
if (
|
|
244
|
+
accountInputs.length > 0 && // It's a SEND operation
|
|
245
|
+
(tx.outputs.length === 1 || // The transaction has only 1 output
|
|
246
|
+
output.output_index < changeOutputIndex) // The output isn't the change output
|
|
247
|
+
) {
|
|
248
|
+
recipients.push(
|
|
249
|
+
syncReplaceAddress
|
|
250
|
+
? syncReplaceAddress(output.address)
|
|
251
|
+
: output.address
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
} else {
|
|
255
|
+
// The output belongs to this account
|
|
256
|
+
accountOutputs.push(output);
|
|
257
|
+
|
|
258
|
+
if (!changeAddresses.has(output.address)) {
|
|
259
|
+
// The output isn't a change output of this account
|
|
260
|
+
recipients.push(
|
|
261
|
+
syncReplaceAddress
|
|
262
|
+
? syncReplaceAddress(output.address)
|
|
263
|
+
: output.address
|
|
264
|
+
);
|
|
265
|
+
} else {
|
|
266
|
+
// The output is a change output of this account,
|
|
267
|
+
// we count it as a recipient only in some special cases
|
|
268
|
+
if (
|
|
269
|
+
(recipients.length === 0 &&
|
|
270
|
+
output.output_index >= changeOutputIndex) ||
|
|
271
|
+
hasSpentNothing
|
|
272
|
+
) {
|
|
273
|
+
recipients.push(
|
|
274
|
+
syncReplaceAddress
|
|
275
|
+
? syncReplaceAddress(output.address)
|
|
276
|
+
: output.address
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (accountInputs.length > 0) {
|
|
285
|
+
// It's a SEND operation
|
|
286
|
+
for (const output of accountOutputs) {
|
|
287
|
+
if (changeAddresses.has(output.address)) {
|
|
288
|
+
value = value.minus(output.value);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
type = "OUT";
|
|
293
|
+
operations.push({
|
|
294
|
+
id: encodeOperationId(accountId, txId, type),
|
|
295
|
+
hash: txId,
|
|
296
|
+
type,
|
|
297
|
+
value,
|
|
298
|
+
fee,
|
|
299
|
+
senders: Array.from(senders),
|
|
300
|
+
recipients,
|
|
301
|
+
blockHeight,
|
|
302
|
+
blockHash,
|
|
303
|
+
transactionSequenceNumber,
|
|
304
|
+
accountId,
|
|
305
|
+
date,
|
|
306
|
+
hasFailed,
|
|
307
|
+
extra: {},
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (accountOutputs.length > 0) {
|
|
312
|
+
// It's a RECEIVE operation
|
|
313
|
+
const filterChangeAddresses = !!accountInputs.length;
|
|
314
|
+
let accountOutputCount = 0;
|
|
315
|
+
let finalAmount = new BigNumber(0);
|
|
316
|
+
|
|
317
|
+
for (const output of accountOutputs) {
|
|
318
|
+
if (!filterChangeAddresses || !changeAddresses.has(output.address)) {
|
|
319
|
+
finalAmount = finalAmount.plus(output.value);
|
|
320
|
+
accountOutputCount += 1;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (accountOutputCount > 0) {
|
|
325
|
+
value = finalAmount;
|
|
326
|
+
type = "IN";
|
|
327
|
+
operations.push({
|
|
328
|
+
id: encodeOperationId(accountId, txId, type),
|
|
329
|
+
hash: txId,
|
|
330
|
+
type,
|
|
331
|
+
value,
|
|
332
|
+
fee,
|
|
333
|
+
senders: Array.from(senders),
|
|
334
|
+
recipients,
|
|
335
|
+
blockHeight,
|
|
336
|
+
blockHash,
|
|
337
|
+
transactionSequenceNumber,
|
|
338
|
+
accountId,
|
|
339
|
+
date,
|
|
340
|
+
hasFailed,
|
|
341
|
+
extra: {},
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return operations;
|
|
347
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { mapTxToOperations } from "./logic";
|
|
2
|
+
|
|
3
|
+
describe("testing transaction without output", () => {
|
|
4
|
+
it("Parse zcash transaction without output", async () => {
|
|
5
|
+
const tx = {
|
|
6
|
+
id: "0b9f98d07eb418fa20573112d3cba6b871d429a06c724a7888ff0886be5213d1",
|
|
7
|
+
inputs: [
|
|
8
|
+
{
|
|
9
|
+
output_hash:
|
|
10
|
+
"2772f3963856f3eb38cb706ec8c2b62fcdeb2ce10f32cf7160afb3873be6f60d",
|
|
11
|
+
output_index: 0,
|
|
12
|
+
value: "5000000000",
|
|
13
|
+
address: "2NCDBM9DAuMrD1T8XDHMxvbTmLutP7at4AB",
|
|
14
|
+
sequence: 4294967294,
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
outputs: [],
|
|
18
|
+
block: {
|
|
19
|
+
hash: "305d4b8d4a6d6ecca0a3dd0216f8ecd090978ed346d1845883c8aa4529d72fc8",
|
|
20
|
+
height: 120,
|
|
21
|
+
time: "2021-07-28T13:34:38Z",
|
|
22
|
+
},
|
|
23
|
+
account: 0,
|
|
24
|
+
index: 0,
|
|
25
|
+
address: "mwXTtHo8Yy3aNKUUZLkBDrTcKT9qG9TqLb",
|
|
26
|
+
received_at: "2021-07-28T13:34:38Z",
|
|
27
|
+
};
|
|
28
|
+
const out = mapTxToOperations(
|
|
29
|
+
tx,
|
|
30
|
+
"zcash",
|
|
31
|
+
"zcash 1",
|
|
32
|
+
new Set<string>(),
|
|
33
|
+
new Set<string>()
|
|
34
|
+
);
|
|
35
|
+
expect(out.length).toEqual(0);
|
|
36
|
+
}, 30000);
|
|
37
|
+
});
|
|
@@ -128,6 +128,10 @@ const getDelegations = async (
|
|
|
128
128
|
url: `${defaultEndpoint}/cosmos/staking/v1beta1/delegations/${address}`,
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
+
data1.delegation_responses = data1.delegation_responses.filter(
|
|
132
|
+
(d) => d.balance.amount !== "0"
|
|
133
|
+
);
|
|
134
|
+
|
|
131
135
|
let status = "unbonded";
|
|
132
136
|
const statusMap = {
|
|
133
137
|
BOND_STATUS_UNBONDED: "unbonded",
|
|
@@ -49,6 +49,9 @@ describe("cosmos/react", () => {
|
|
|
49
49
|
);
|
|
50
50
|
const delegations = account.cosmosResources?.delegations;
|
|
51
51
|
invariant(delegations, "cosmos: delegations is required");
|
|
52
|
+
expect(
|
|
53
|
+
account.cosmosResources?.delegations?.some((d) => d.amount[0] === 0)
|
|
54
|
+
).toBe(false);
|
|
52
55
|
expect(Array.isArray(result.current)).toBe(true);
|
|
53
56
|
expect(result.current.length).toBe(
|
|
54
57
|
(delegations as CosmosDelegation[]).length
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import {
|
|
2
|
+
extractOnboardingState,
|
|
3
|
+
OnboardingStep,
|
|
4
|
+
} from "./extractOnboardingState";
|
|
5
|
+
|
|
6
|
+
describe("@hw/extractOnboardingState", () => {
|
|
7
|
+
describe("extractOnboardingState", () => {
|
|
8
|
+
describe("When the flag bytes are incorrect", () => {
|
|
9
|
+
it("should throw an error", () => {
|
|
10
|
+
const incompleteFlagsBytes = Buffer.from([0, 0]);
|
|
11
|
+
// DeviceExtractOnboardingStateError is not of type Error,
|
|
12
|
+
// so cannot check in toThrow(DeviceExtractOnboardingStateError)
|
|
13
|
+
expect(() => extractOnboardingState(incompleteFlagsBytes)).toThrow();
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe("When the device is onboarded", () => {
|
|
18
|
+
it("should return a device state that is onboarded", () => {
|
|
19
|
+
const flagsBytes = Buffer.from([1 << 2, 0, 0, 0]);
|
|
20
|
+
|
|
21
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
22
|
+
|
|
23
|
+
expect(onboardingState).not.toBeNull();
|
|
24
|
+
expect(onboardingState?.isOnboarded).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("When the device is in recovery mode", () => {
|
|
29
|
+
it("should return a device state that is in recovery mode", () => {
|
|
30
|
+
const flagsBytes = Buffer.from([1, 0, 0, 0]);
|
|
31
|
+
|
|
32
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
33
|
+
|
|
34
|
+
expect(onboardingState).not.toBeNull();
|
|
35
|
+
expect(onboardingState?.isInRecoveryMode).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe("When the device is not onboarded and in normal mode", () => {
|
|
40
|
+
let flagsBytes: Buffer;
|
|
41
|
+
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
flagsBytes = Buffer.from([0, 0, 0, 0]);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("and the user is on the welcome screen", () => {
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
flagsBytes[3] = 0;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should return an onboarding step that is set at the welcome screen", () => {
|
|
52
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
53
|
+
|
|
54
|
+
expect(onboardingState).not.toBeNull();
|
|
55
|
+
expect(onboardingState?.currentOnboardingStep).toBe(
|
|
56
|
+
OnboardingStep.WelcomeScreen
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe("and the user is choosing what kind of setup they want", () => {
|
|
62
|
+
beforeEach(() => {
|
|
63
|
+
flagsBytes[3] = 1;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should return an onboarding step that is set at the setup choice", () => {
|
|
67
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
68
|
+
|
|
69
|
+
expect(onboardingState).not.toBeNull();
|
|
70
|
+
expect(onboardingState?.currentOnboardingStep).toBe(
|
|
71
|
+
OnboardingStep.SetupChoice
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe("and the user is setting their pin", () => {
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
flagsBytes[3] = 2;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("should return an onboarding step that is set at setting the pin", () => {
|
|
82
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
83
|
+
|
|
84
|
+
expect(onboardingState).not.toBeNull();
|
|
85
|
+
expect(onboardingState?.currentOnboardingStep).toBe(
|
|
86
|
+
OnboardingStep.Pin
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("and the user is generating a new seed", () => {
|
|
92
|
+
describe("and the seed phrase type is set to 24 words", () => {
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
// 24-words seed
|
|
95
|
+
flagsBytes[2] |= 0 << 5;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should return a device state with the correct seed phrase type", () => {
|
|
99
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
100
|
+
|
|
101
|
+
expect(onboardingState).not.toBeNull();
|
|
102
|
+
expect(onboardingState?.seedPhraseType).toBe("24-words");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe("and the user is writing the seed word i", () => {
|
|
106
|
+
beforeEach(() => {
|
|
107
|
+
flagsBytes[3] = 3;
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should return an onboarding step that is set at writting the seed phrase", () => {
|
|
111
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
112
|
+
|
|
113
|
+
expect(onboardingState).not.toBeNull();
|
|
114
|
+
expect(onboardingState?.currentOnboardingStep).toBe(
|
|
115
|
+
OnboardingStep.NewDevice
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("should return a device state with the index of the current seed word being written", () => {
|
|
120
|
+
const byte3 = flagsBytes[2];
|
|
121
|
+
for (let wordIndex = 0; wordIndex < 24; wordIndex++) {
|
|
122
|
+
flagsBytes[2] = byte3 | wordIndex;
|
|
123
|
+
|
|
124
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
125
|
+
|
|
126
|
+
expect(onboardingState).not.toBeNull();
|
|
127
|
+
expect(onboardingState?.currentSeedWordIndex).toBe(wordIndex);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe("and the user is confirming the seed word i", () => {
|
|
133
|
+
beforeEach(() => {
|
|
134
|
+
flagsBytes[3] = 4;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should return an onboarding step that is set at confirming the seed phrase", () => {
|
|
138
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
139
|
+
|
|
140
|
+
expect(onboardingState).not.toBeNull();
|
|
141
|
+
expect(onboardingState?.currentOnboardingStep).toBe(
|
|
142
|
+
OnboardingStep.NewDeviceConfirming
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("should return a device state with the index of the current seed word being confirmed", () => {
|
|
147
|
+
const byte3 = flagsBytes[2];
|
|
148
|
+
for (let wordIndex = 0; wordIndex < 24; wordIndex++) {
|
|
149
|
+
flagsBytes[2] = byte3 | wordIndex;
|
|
150
|
+
|
|
151
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
152
|
+
|
|
153
|
+
expect(onboardingState).not.toBeNull();
|
|
154
|
+
expect(onboardingState?.currentSeedWordIndex).toBe(wordIndex);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe("and the user is recovering a seed", () => {
|
|
162
|
+
describe("and the seed phrase type is set to X words", () => {
|
|
163
|
+
it("should return a device state with the correct seed phrase type", () => {
|
|
164
|
+
const byte3 = flagsBytes[2];
|
|
165
|
+
|
|
166
|
+
// 24-words
|
|
167
|
+
flagsBytes[2] = byte3 | (0 << 5);
|
|
168
|
+
let onboardingState = extractOnboardingState(flagsBytes);
|
|
169
|
+
|
|
170
|
+
expect(onboardingState).not.toBeNull();
|
|
171
|
+
expect(onboardingState?.seedPhraseType).toBe("24-words");
|
|
172
|
+
|
|
173
|
+
// 18-words
|
|
174
|
+
flagsBytes[2] = byte3 | (1 << 5);
|
|
175
|
+
onboardingState = extractOnboardingState(flagsBytes);
|
|
176
|
+
|
|
177
|
+
expect(onboardingState).not.toBeNull();
|
|
178
|
+
expect(onboardingState?.seedPhraseType).toBe("18-words");
|
|
179
|
+
|
|
180
|
+
// 12-words
|
|
181
|
+
flagsBytes[2] = byte3 | (2 << 5);
|
|
182
|
+
onboardingState = extractOnboardingState(flagsBytes);
|
|
183
|
+
|
|
184
|
+
expect(onboardingState).not.toBeNull();
|
|
185
|
+
expect(onboardingState?.seedPhraseType).toBe("12-words");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe("and the user is confirming (seed recovery) the seed word i", () => {
|
|
189
|
+
beforeEach(() => {
|
|
190
|
+
// 24-words seed
|
|
191
|
+
flagsBytes[2] |= 0 << 5;
|
|
192
|
+
|
|
193
|
+
flagsBytes[3] = 5;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("should return an onboarding step that is set at confirming the restored seed phrase", () => {
|
|
197
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
198
|
+
|
|
199
|
+
expect(onboardingState).not.toBeNull();
|
|
200
|
+
expect(onboardingState?.currentOnboardingStep).toBe(
|
|
201
|
+
OnboardingStep.RestoreSeed
|
|
202
|
+
);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("should return a device state with the index of the current seed word being confirmed", () => {
|
|
206
|
+
const byte3 = flagsBytes[2];
|
|
207
|
+
for (let wordIndex = 0; wordIndex < 24; wordIndex++) {
|
|
208
|
+
flagsBytes[2] = byte3 | wordIndex;
|
|
209
|
+
|
|
210
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
211
|
+
|
|
212
|
+
expect(onboardingState).not.toBeNull();
|
|
213
|
+
expect(onboardingState?.currentSeedWordIndex).toBe(wordIndex);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
describe("and the user is on the safety warning screen", () => {
|
|
221
|
+
beforeEach(() => {
|
|
222
|
+
flagsBytes[3] = 6;
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("should return an onboarding step that is set at the safety warning screen", () => {
|
|
226
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
227
|
+
|
|
228
|
+
expect(onboardingState).not.toBeNull();
|
|
229
|
+
expect(onboardingState?.currentOnboardingStep).toBe(
|
|
230
|
+
OnboardingStep.SafetyWarning
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
describe("and the user finished the onboarding process", () => {
|
|
236
|
+
beforeEach(() => {
|
|
237
|
+
flagsBytes[3] = 7;
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it("should return an onboarding step that is set at ready", () => {
|
|
241
|
+
const onboardingState = extractOnboardingState(flagsBytes);
|
|
242
|
+
|
|
243
|
+
expect(onboardingState).not.toBeNull();
|
|
244
|
+
expect(onboardingState?.currentOnboardingStep).toBe(
|
|
245
|
+
OnboardingStep.Ready
|
|
246
|
+
);
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
});
|