@ledgerhq/live-common 21.23.0 → 21.24.0-beta.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 (65) hide show
  1. package/lib/data/icons/react/index.d.ts +1 -0
  2. package/lib/data/icons/react/index.d.ts.map +1 -1
  3. package/lib/data/icons/react/index.js +4 -2
  4. package/lib/data/icons/react/index.js.map +1 -1
  5. package/lib/data/icons/react/ssv.d.ts +8 -0
  6. package/lib/data/icons/react/ssv.d.ts.map +1 -0
  7. package/lib/data/icons/react/ssv.js +31 -0
  8. package/lib/data/icons/react/ssv.js.map +1 -0
  9. package/lib/data/icons/reactNative/index.d.ts +1 -0
  10. package/lib/data/icons/reactNative/index.d.ts.map +1 -1
  11. package/lib/data/icons/reactNative/index.js +4 -2
  12. package/lib/data/icons/reactNative/index.js.map +1 -1
  13. package/lib/data/icons/reactNative/ssv.d.ts +8 -0
  14. package/lib/data/icons/reactNative/ssv.d.ts.map +1 -0
  15. package/lib/data/icons/reactNative/ssv.js +32 -0
  16. package/lib/data/icons/reactNative/ssv.js.map +1 -0
  17. package/lib/env.d.ts +10 -5
  18. package/lib/env.d.ts.map +1 -1
  19. package/lib/env.js +5 -0
  20. package/lib/env.js.map +1 -1
  21. package/lib/env.react.d.ts +1 -1
  22. package/lib/env.react.d.ts.map +1 -1
  23. package/lib/families/bitcoin/js-synchronisation.d.ts.map +1 -1
  24. package/lib/families/bitcoin/js-synchronisation.js +10 -12
  25. package/lib/families/bitcoin/js-synchronisation.js.map +1 -1
  26. package/lib/families/bitcoin/wallet-btc/crypto/base.d.ts.map +1 -1
  27. package/lib/families/bitcoin/wallet-btc/crypto/base.js +30 -22
  28. package/lib/families/bitcoin/wallet-btc/crypto/base.js.map +1 -1
  29. package/lib/families/bitcoin/wallet-btc/crypto/bip32.d.ts +11 -0
  30. package/lib/families/bitcoin/wallet-btc/crypto/bip32.d.ts.map +1 -0
  31. package/lib/families/bitcoin/wallet-btc/crypto/bip32.js +32 -0
  32. package/lib/families/bitcoin/wallet-btc/crypto/bip32.js.map +1 -0
  33. package/lib/families/bitcoin/wallet-btc/crypto/decred.d.ts.map +1 -1
  34. package/lib/families/bitcoin/wallet-btc/crypto/decred.js +3 -114
  35. package/lib/families/bitcoin/wallet-btc/crypto/decred.js.map +1 -1
  36. package/lib/families/bitcoin/wallet-btc/storage/index.d.ts +24 -8
  37. package/lib/families/bitcoin/wallet-btc/storage/index.d.ts.map +1 -1
  38. package/lib/families/bitcoin/wallet-btc/storage/index.js +114 -128
  39. package/lib/families/bitcoin/wallet-btc/storage/index.js.map +1 -1
  40. package/lib/families/bitcoin/wallet-btc/storage/types.d.ts +8 -7
  41. package/lib/families/bitcoin/wallet-btc/storage/types.d.ts.map +1 -1
  42. package/lib/families/bitcoin/wallet-btc/xpub.d.ts.map +1 -1
  43. package/lib/families/bitcoin/wallet-btc/xpub.js +42 -63
  44. package/lib/families/bitcoin/wallet-btc/xpub.js.map +1 -1
  45. package/lib/families/tezos/signOperation.d.ts.map +1 -1
  46. package/lib/families/tezos/signOperation.js +9 -0
  47. package/lib/families/tezos/signOperation.js.map +1 -1
  48. package/lib/families/tezos/synchronisation.js +1 -1
  49. package/lib/families/tezos/synchronisation.js.map +1 -1
  50. package/package.json +3 -3
  51. package/src/data/icons/react/index.tsx +1 -0
  52. package/src/data/icons/react/ssv.tsx +12 -0
  53. package/src/data/icons/reactNative/index.tsx +1 -0
  54. package/src/data/icons/reactNative/ssv.tsx +13 -0
  55. package/src/data/icons/svg/SSV.svg +4 -0
  56. package/src/env.ts +5 -0
  57. package/src/families/bitcoin/js-synchronisation.ts +14 -13
  58. package/src/families/bitcoin/wallet-btc/crypto/base.ts +33 -21
  59. package/src/families/bitcoin/wallet-btc/crypto/bip32.ts +36 -0
  60. package/src/families/bitcoin/wallet-btc/crypto/decred.ts +3 -154
  61. package/src/families/bitcoin/wallet-btc/storage/index.ts +23 -11
  62. package/src/families/bitcoin/wallet-btc/storage/types.ts +8 -10
  63. package/src/families/bitcoin/wallet-btc/xpub.ts +14 -10
  64. package/src/families/tezos/signOperation.ts +12 -0
  65. package/src/families/tezos/synchronisation.ts +1 -1
@@ -0,0 +1,36 @@
1
+ import ecc from "tiny-secp256k1";
2
+ import createHmac from "create-hmac";
3
+
4
+ // the BIP32 class is inspired from https://github.com/bitcoinjs/bip32/blob/master/src/bip32.js
5
+ class BIP32 {
6
+ publicKey: any;
7
+ chainCode: any;
8
+ network: any;
9
+ depth: number;
10
+ index: number;
11
+ constructor(
12
+ publicKey: any,
13
+ chainCode: any,
14
+ network: any,
15
+ depth = 0,
16
+ index = 0
17
+ ) {
18
+ this.publicKey = publicKey;
19
+ this.chainCode = chainCode;
20
+ this.network = network;
21
+ this.depth = depth;
22
+ this.index = index;
23
+ }
24
+ derive(index: number) {
25
+ const data = Buffer.allocUnsafe(37);
26
+ this.publicKey.copy(data, 0);
27
+ data.writeUInt32BE(index, 33);
28
+ const I = createHmac("sha512", this.chainCode).update(data).digest();
29
+ const IL = I.slice(0, 32);
30
+ const IR = I.slice(32);
31
+ const Ki = ecc.pointAddScalar(this.publicKey, IL, true);
32
+ return new BIP32(Ki, IR, this.network, this.depth + 1, index);
33
+ }
34
+ }
35
+
36
+ export default BIP32;
@@ -6,149 +6,7 @@ import bs58check from "bs58check";
6
6
  import createBlakeHash from "blake-hash";
7
7
  import RIPEMD160 from "ripemd160";
8
8
  import bs58 from "bs58";
9
- import ecc from "tiny-secp256k1";
10
- import createHash from "create-hash";
11
- import createHmac from "create-hmac";
12
-
13
- // the BIP32 class is inspired from https://github.com/bitcoinjs/bip32/blob/master/src/bip32.js
14
- class BIP32 {
15
- privateKey: any;
16
- publicKey: any;
17
- chainCode: any;
18
- network: any;
19
- depth: number;
20
- index: number;
21
- ParentFingerprint: number;
22
- lowR: boolean;
23
- constructor(
24
- privateKey,
25
- publicKey,
26
- chainCode,
27
- network,
28
- depth = 0,
29
- index = 0,
30
- ParentFingerprint = 0x00000000
31
- ) {
32
- this.privateKey = privateKey;
33
- this.publicKey = publicKey;
34
- this.chainCode = chainCode;
35
- this.network = network;
36
- this.depth = depth;
37
- this.index = index;
38
- this.ParentFingerprint = ParentFingerprint;
39
- this.lowR = false;
40
- }
41
- pk() {
42
- if (this.publicKey === undefined)
43
- this.publicKey = ecc.pointFromScalar(this.privateKey, true);
44
- return this.publicKey;
45
- }
46
- isNeutered() {
47
- return this.privateKey === undefined;
48
- }
49
- neutered() {
50
- return new BIP32(
51
- undefined,
52
- this.pk(),
53
- this.chainCode,
54
- this.network,
55
- this.depth,
56
- this.index,
57
- this.ParentFingerprint
58
- );
59
- }
60
- hmacSHA512(key, data) {
61
- return createHmac("sha512", key).update(data).digest();
62
- }
63
- hashSHA256(buffer) {
64
- return createHash("sha256").update(buffer).digest();
65
- }
66
- fingerprint() {
67
- return this.hashSHA256(this.pk()).slice(0, 4);
68
- }
69
-
70
- toBase58() {
71
- const network = this.network;
72
- const version = !this.isNeutered()
73
- ? network.bip32.private
74
- : network.bip32.public;
75
- const buffer = Buffer.allocUnsafe(78);
76
- // 4 bytes: version bytes
77
- buffer.writeUInt32BE(version, 0);
78
- // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ....
79
- buffer.writeUInt8(this.depth, 4);
80
- // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
81
- buffer.writeUInt32BE(this.ParentFingerprint, 5);
82
- // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized.
83
- // This is encoded in big endian. (0x00000000 if master key)
84
- buffer.writeUInt32BE(this.index, 9);
85
- // 32 bytes: the chain code
86
- this.chainCode.copy(buffer, 13);
87
- // 33 bytes: the public key or private key data
88
- if (!this.isNeutered()) {
89
- // 0x00 + k for private keys
90
- buffer.writeUInt8(0, 45);
91
- this.privateKey.copy(buffer, 46);
92
- // 33 bytes: the public key
93
- } else {
94
- // X9.62 encoding for public keys
95
- this.pk().copy(buffer, 45);
96
- }
97
- return bs58check.encode(buffer);
98
- }
99
- // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#child-key-derivation-ckd-functions
100
- derive(index) {
101
- const isHardened = index >= 0x80000000;
102
- const data = Buffer.allocUnsafe(37);
103
- // Hardened child
104
- if (isHardened) {
105
- data[0] = 0x00;
106
- this.privateKey.copy(data, 1);
107
- data.writeUInt32BE(index, 33);
108
- } else {
109
- this.pk().copy(data, 0);
110
- data.writeUInt32BE(index, 33);
111
- }
112
- const I = this.hmacSHA512(this.chainCode, data);
113
- const IL = I.slice(0, 32);
114
- const IR = I.slice(32);
115
- // if parse256(IL) >= n, proceed with the next value for i
116
- if (!ecc.isPrivate(IL)) return this.derive(index + 1);
117
- // Private parent key -> private child key
118
- let hd;
119
- if (!this.isNeutered()) {
120
- // ki = parse256(IL) + kpar (mod n)
121
- const ki = ecc.privateAdd(this.privateKey, IL);
122
- // In case ki == 0, proceed with the next value for i
123
- if (ki == null) return this.derive(index + 1);
124
- hd = new BIP32(
125
- ki,
126
- undefined,
127
- IR,
128
- this.network,
129
- this.depth + 1,
130
- index,
131
- this.fingerprint().readUInt32BE(0)
132
- );
133
- } else {
134
- // Ki = point(parse256(IL)) + Kpar
135
- // = G*IL + Kpar
136
- const Ki = ecc.pointAddScalar(this.pk(), IL, true);
137
- // In case Ki is the point at infinity, proceed with the next value for i
138
- if (Ki === null) return this.derive(index + 1);
139
- hd = new BIP32(
140
- undefined,
141
- Ki,
142
- IR,
143
- this.network,
144
- this.depth + 1,
145
- index,
146
- this.fingerprint().readUInt32BE(0)
147
- );
148
- }
149
- return hd;
150
- }
151
- }
9
+ import BIP32 from "./bip32";
152
10
 
153
11
  class Decred extends Base {
154
12
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -226,20 +84,11 @@ class Decred extends Base {
226
84
  buffer = bs58check.decode(xpub);
227
85
  }
228
86
  const depth = buffer[4];
229
- const parentFingerprint = buffer.readUInt32BE(5);
230
87
  const i = buffer.readUInt32BE(9);
231
88
  const chainCode = buffer.slice(13, 45);
232
89
  const X = buffer.slice(45, 78);
233
- const hd = new BIP32(
234
- undefined,
235
- X,
236
- chainCode,
237
- this.network,
238
- depth,
239
- i,
240
- parentFingerprint
241
- );
242
- const publicKey = hd.derive(account).derive(index).pk();
90
+ const hd = new BIP32(X, chainCode, this.network, depth, i);
91
+ const publicKey = hd.derive(account).derive(index).publicKey;
243
92
  const address = Decred.getAddressFromPk(publicKey);
244
93
  Base.addressCache[`${derivationMode}-${xpub}-${account}-${index}`] =
245
94
  address;
@@ -1,4 +1,5 @@
1
1
  import { findLast, filter, uniqBy, findIndex, has } from "lodash";
2
+ import Base from "../crypto/base";
2
3
  import { Input, IStorage, Output, TX, Address } from "./types";
3
4
 
4
5
  // a mock storage class that just use js objects
@@ -12,12 +13,14 @@ class BitcoinLikeStorage implements IStorage {
12
13
  // accounting
13
14
  unspentUtxos: { [key: string]: Output[] } = {};
14
15
 
16
+ addressCache: { [key: string]: string } = {};
17
+
15
18
  // only needed to handle the case when the input
16
19
  // is seen before the output (typically explorer
17
20
  // returning unordered tx within the same block)
18
21
  spentUtxos: { [key: string]: Input[] } = {};
19
22
 
20
- async getLastTx(txFilter: {
23
+ getLastTx(txFilter: {
21
24
  account?: number;
22
25
  index?: number;
23
26
  address?: string;
@@ -38,18 +41,18 @@ class BitcoinLikeStorage implements IStorage {
38
41
  return tx;
39
42
  }
40
43
 
41
- async getTx(address: string, hash: string) {
44
+ getTx(address: string, hash: string) {
42
45
  const index = `${address}-${hash}`;
43
46
  return this.txs[this.primaryIndex[index]];
44
47
  }
45
48
 
46
49
  // TODO: only expose unspentUtxos
47
- async getAddressUnspentUtxos(address: Address) {
50
+ getAddressUnspentUtxos(address: Address) {
48
51
  const indexAddress = address.address;
49
52
  return this.unspentUtxos[indexAddress];
50
53
  }
51
54
 
52
- async appendTxs(txs: TX[]) {
55
+ appendTxs(txs: TX[]) {
53
56
  const lastLength = this.txs.length;
54
57
 
55
58
  txs.forEach((tx) => {
@@ -97,10 +100,7 @@ class BitcoinLikeStorage implements IStorage {
97
100
  return this.txs.length - lastLength;
98
101
  }
99
102
 
100
- async getUniquesAddresses(addressesFilter: {
101
- account?: number;
102
- index?: number;
103
- }) {
103
+ getUniquesAddresses(addressesFilter: { account?: number; index?: number }) {
104
104
  // TODO: to speed up, create more useful indexes in appendTxs
105
105
  return uniqBy(
106
106
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -114,7 +114,7 @@ class BitcoinLikeStorage implements IStorage {
114
114
  );
115
115
  }
116
116
 
117
- async removeTxs(txsFilter: { account: number; index: number }) {
117
+ removeTxs(txsFilter: { account: number; index: number }) {
118
118
  const newTxs: TX[] = [];
119
119
  this.primaryIndex = {};
120
120
 
@@ -137,7 +137,7 @@ class BitcoinLikeStorage implements IStorage {
137
137
 
138
138
  // We are a bit ugly because we can't rely undo unspentUTXO
139
139
  // So we clean the address and rebuild without the pendings
140
- async removePendingTxs(txsFilter: { account: number; index: number }) {
140
+ removePendingTxs(txsFilter: { account: number; index: number }) {
141
141
  const newTxs: TX[] = [];
142
142
  const txsToReAdd: TX[] = [];
143
143
  this.primaryIndex = {};
@@ -161,7 +161,14 @@ class BitcoinLikeStorage implements IStorage {
161
161
  });
162
162
 
163
163
  this.txs = newTxs;
164
- await this.appendTxs(txsToReAdd);
164
+ this.appendTxs(txsToReAdd);
165
+ }
166
+
167
+ addAddress(key: string, address: string): void {
168
+ if (!this.addressCache) {
169
+ this.addressCache = {};
170
+ }
171
+ this.addressCache[key] = address;
165
172
  }
166
173
 
167
174
  exportSync() {
@@ -169,6 +176,7 @@ class BitcoinLikeStorage implements IStorage {
169
176
  txs: this.txs,
170
177
  primaryIndex: this.primaryIndex,
171
178
  unspentUtxos: this.unspentUtxos,
179
+ addressCache: this.addressCache,
172
180
  };
173
181
  }
174
182
 
@@ -176,10 +184,13 @@ class BitcoinLikeStorage implements IStorage {
176
184
  txs: TX[];
177
185
  primaryIndex: { [key: string]: number };
178
186
  unspentUtxos: { [key: string]: Output[] };
187
+ addressCache: { [key: string]: string };
179
188
  }) {
180
189
  this.txs = data.txs;
181
190
  this.primaryIndex = data.primaryIndex;
182
191
  this.unspentUtxos = data.unspentUtxos;
192
+ this.addressCache = data.addressCache;
193
+ Base.addressCache = { ...Base.addressCache, ...this.addressCache };
183
194
  }
184
195
 
185
196
  async export() {
@@ -190,6 +201,7 @@ class BitcoinLikeStorage implements IStorage {
190
201
  txs: TX[];
191
202
  primaryIndex: { [key: string]: number };
192
203
  unspentUtxos: { [key: string]: Output[] };
204
+ addressCache: { [key: string]: string };
193
205
  }) {
194
206
  return this.loadSync(data);
195
207
  }
@@ -43,24 +43,22 @@ export interface Address {
43
43
  }
44
44
 
45
45
  export interface IStorage {
46
- appendTxs(txs: TX[]): Promise<number>;
47
- getAddressUnspentUtxos(address: Address): Promise<Output[]>;
46
+ appendTxs(txs: TX[]): number;
47
+ getAddressUnspentUtxos(address: Address): Output[];
48
48
  getLastTx(txFilter: {
49
49
  account?: number;
50
50
  index?: number;
51
51
  address?: string;
52
52
  confirmed?: boolean;
53
- }): Promise<TX | undefined>;
54
- getTx(address: string, hash: string): Promise<TX | undefined>;
53
+ }): TX | undefined;
54
+ getTx(address: string, hash: string): TX | undefined;
55
55
  getUniquesAddresses(addressesFilter: {
56
56
  account?: number;
57
57
  index?: number;
58
- }): Promise<Address[]>;
59
- removeTxs(txsFilter: { account: number; index: number }): Promise<void>;
60
- removePendingTxs(txsFilter: {
61
- account: number;
62
- index: number;
63
- }): Promise<void>;
58
+ }): Address[];
59
+ removeTxs(txsFilter: { account: number; index: number }): void;
60
+ removePendingTxs(txsFilter: { account: number; index: number }): void;
61
+ addAddress(key: string, address: string): void;
64
62
  export(): Promise<unknown>;
65
63
  load(data: unknown): Promise<void>;
66
64
  exportSync(): unknown;
@@ -66,6 +66,10 @@ class Xpub extends EventEmitter {
66
66
  index
67
67
  );
68
68
 
69
+ this.storage.addAddress(
70
+ `${this.derivationMode}-${this.xpub}-${account}-${index}`,
71
+ address
72
+ );
69
73
  await this.whenSynced("address", address);
70
74
 
71
75
  const data = {
@@ -87,13 +91,13 @@ class Xpub extends EventEmitter {
87
91
 
88
92
  // in case pendings have changed we clean them out
89
93
  // TODO perf : bad : looping in the tx array
90
- const hasPendings = !!(await this.storage.getLastTx({
94
+ const hasPendings = !!this.storage.getLastTx({
91
95
  confirmed: false,
92
96
  account,
93
97
  index,
94
- }));
98
+ });
95
99
  if (hasPendings) {
96
- await this.storage.removePendingTxs({ account, index });
100
+ this.storage.removePendingTxs({ account, index });
97
101
  }
98
102
  total = await this.fetchHydrateAndStoreNewTxs(address, account, index);
99
103
  } catch (e) {
@@ -103,7 +107,7 @@ class Xpub extends EventEmitter {
103
107
 
104
108
  this.emitSynced({ ...data, total });
105
109
 
106
- const lastTx = await this.storage.getLastTx({
110
+ const lastTx = this.storage.getLastTx({
107
111
  account,
108
112
  index,
109
113
  });
@@ -200,7 +204,7 @@ class Xpub extends EventEmitter {
200
204
  async getAddressBalance(address: Address) {
201
205
  await this.whenSynced("address", address.address);
202
206
 
203
- const unspentUtxos = await this.storage.getAddressUnspentUtxos(address);
207
+ const unspentUtxos = this.storage.getAddressUnspentUtxos(address);
204
208
 
205
209
  return unspentUtxos.reduce(
206
210
  (total, { value }) => total.plus(value),
@@ -419,7 +423,7 @@ class Xpub extends EventEmitter {
419
423
  let txs: TX[] = [];
420
424
  let inserted = 0;
421
425
  do {
422
- const lastTx = await this.storage.getLastTx({
426
+ const lastTx = this.storage.getLastTx({
423
427
  account,
424
428
  index,
425
429
  confirmed: true,
@@ -433,14 +437,14 @@ class Xpub extends EventEmitter {
433
437
  if (pendingTxs.length === 0) {
434
438
  pendingTxs = txs.filter((tx) => !tx.block);
435
439
  }
436
- inserted += await this.storage.appendTxs(txs.filter((tx) => tx.block)); // only insert not pending tx
440
+ inserted += this.storage.appendTxs(txs.filter((tx) => tx.block)); // only insert not pending tx
437
441
  } while (txs.length - pendingTxs.length >= this.txsSyncArraySize); // check whether page is full, if not, it is the last page
438
- inserted += await this.storage.appendTxs(pendingTxs);
442
+ inserted += this.storage.appendTxs(pendingTxs);
439
443
  return inserted;
440
444
  }
441
445
 
442
446
  async checkAddressReorg(account: number, index: number) {
443
- const lastTx = await this.storage.getLastTx({
447
+ const lastTx = this.storage.getLastTx({
444
448
  account,
445
449
  index,
446
450
  confirmed: true,
@@ -462,7 +466,7 @@ class Xpub extends EventEmitter {
462
466
  // TODO: delete only everything for this (address, block)
463
467
  // but need to think if its possible with current storage implem
464
468
 
465
- await this.storage.removeTxs({
469
+ this.storage.removeTxs({
466
470
  account,
467
471
  index,
468
472
  });
@@ -8,6 +8,8 @@ import type { Account, SignOperationEvent } from "../../types";
8
8
  import { withDevice } from "../../hw/deviceAccess";
9
9
  import { getEnv } from "../../env";
10
10
  import { FeeNotLoaded } from "@ledgerhq/errors";
11
+ import { upperModulo } from "../../modulo";
12
+ import BigNumber from "bignumber.js";
11
13
 
12
14
  export const signOperation = ({
13
15
  account,
@@ -53,6 +55,16 @@ export const signOperation = ({
53
55
  storageLimit: transaction.storageLimit?.toNumber() || 0,
54
56
  gasLimit: transaction.gasLimit?.toNumber() || 0,
55
57
  };
58
+
59
+ if (["delegate", "undelegate"].includes(transaction.mode)) {
60
+ // https://ledgerhq.atlassian.net/browse/LL-8821
61
+ params.gasLimit = upperModulo(
62
+ transaction.gasLimit || new BigNumber(0),
63
+ new BigNumber(136),
64
+ new BigNumber(1000)
65
+ ).toNumber();
66
+ }
67
+
56
68
  switch (transaction.mode) {
57
69
  case "send":
58
70
  res = await tezos.contract.transfer({
@@ -226,7 +226,7 @@ const txToOp =
226
226
  }
227
227
 
228
228
  return {
229
- id: encodeOperationId(accountId, hash, type),
229
+ id: encodeOperationId(accountId, hash + String(tx.id), type),
230
230
  hash,
231
231
  type,
232
232
  value,