@ledgerhq/live-common 21.13.0 → 21.14.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__/currencies.js +2 -0
- package/lib/__tests__/currencies.js.map +1 -1
- package/lib/apps/polyfill.d.ts.map +1 -1
- package/lib/apps/polyfill.js +1 -0
- package/lib/apps/polyfill.js.map +1 -1
- package/lib/derivation.js +1 -1
- package/lib/derivation.js.map +1 -1
- package/lib/env.js +1 -1
- package/lib/env.js.map +1 -1
- package/lib/families/bitcoin/cache.d.ts +1 -0
- package/lib/families/bitcoin/cache.d.ts.map +1 -1
- package/lib/families/bitcoin/cache.js +7 -1
- package/lib/families/bitcoin/cache.js.map +1 -1
- package/lib/families/bitcoin/errors.d.ts +4 -0
- package/lib/families/bitcoin/errors.d.ts.map +1 -0
- package/lib/families/bitcoin/errors.js +6 -0
- package/lib/families/bitcoin/errors.js.map +1 -0
- package/lib/families/bitcoin/js-getTransactionStatus.d.ts.map +1 -1
- package/lib/families/bitcoin/js-getTransactionStatus.js +24 -11
- package/lib/families/bitcoin/js-getTransactionStatus.js.map +1 -1
- package/lib/families/bitcoin/js-synchronisation.js +2 -2
- package/lib/families/bitcoin/js-synchronisation.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/crypto/base.d.ts +4 -0
- package/lib/families/bitcoin/wallet-btc/crypto/base.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/crypto/base.js +35 -5
- package/lib/families/bitcoin/wallet-btc/crypto/base.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/crypto/bitcoin.d.ts +1 -0
- package/lib/families/bitcoin/wallet-btc/crypto/bitcoin.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/crypto/bitcoin.js +19 -1
- package/lib/families/bitcoin/wallet-btc/crypto/bitcoin.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/crypto/bitcoincash.d.ts +1 -0
- package/lib/families/bitcoin/wallet-btc/crypto/bitcoincash.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/crypto/bitcoincash.js +4 -0
- package/lib/families/bitcoin/wallet-btc/crypto/bitcoincash.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/crypto/types.d.ts +1 -0
- package/lib/families/bitcoin/wallet-btc/crypto/types.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/crypto/zec.d.ts +1 -0
- package/lib/families/bitcoin/wallet-btc/crypto/zec.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/crypto/zec.js +4 -0
- package/lib/families/bitcoin/wallet-btc/crypto/zec.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/crypto/zen.d.ts +1 -0
- package/lib/families/bitcoin/wallet-btc/crypto/zen.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/crypto/zen.js +4 -0
- package/lib/families/bitcoin/wallet-btc/crypto/zen.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/explorer/index.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/explorer/index.js +0 -3
- package/lib/families/bitcoin/wallet-btc/explorer/index.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/index.d.ts +2 -2
- package/lib/families/bitcoin/wallet-btc/index.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/index.js +4 -5
- package/lib/families/bitcoin/wallet-btc/index.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/utils.d.ts +1 -0
- package/lib/families/bitcoin/wallet-btc/utils.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/utils.js +13 -1
- package/lib/families/bitcoin/wallet-btc/utils.js.map +1 -1
- package/lib/families/bitcoin/wallet-btc/xpub.d.ts +2 -6
- package/lib/families/bitcoin/wallet-btc/xpub.d.ts.map +1 -1
- package/lib/families/bitcoin/wallet-btc/xpub.js +62 -52
- package/lib/families/bitcoin/wallet-btc/xpub.js.map +1 -1
- package/lib/families/elrond/js-getTransactionStatus.d.ts.map +1 -1
- package/lib/families/elrond/js-getTransactionStatus.js +3 -0
- package/lib/families/elrond/js-getTransactionStatus.js.map +1 -1
- package/lib/families/elrond/js-signOperation.d.ts.map +1 -1
- package/lib/families/elrond/js-signOperation.js +3 -1
- package/lib/families/elrond/js-signOperation.js.map +1 -1
- package/lib/families/ethereum/specs.d.ts +1 -0
- package/lib/families/ethereum/specs.d.ts.map +1 -1
- package/lib/families/ethereum/specs.js +41 -0
- package/lib/families/ethereum/specs.js.map +1 -1
- package/lib/families/polkadot/js-buildTransaction.d.ts +7 -7
- package/lib/generated/specs.d.ts +1 -0
- package/lib/generated/specs.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/__tests__/currencies.ts +2 -0
- package/src/apps/polyfill.ts +1 -0
- package/src/currencies/__snapshots__/sortByMarketcap.test.ts.snap +10 -1
- package/src/derivation.ts +1 -1
- package/src/env.ts +1 -1
- package/src/families/bitcoin/cache.ts +12 -0
- package/src/families/bitcoin/errors.ts +5 -0
- package/src/families/bitcoin/js-getTransactionStatus.ts +15 -1
- package/src/families/bitcoin/js-synchronisation.ts +2 -2
- package/src/families/bitcoin/wallet-btc/crypto/base.ts +39 -5
- package/src/families/bitcoin/wallet-btc/crypto/bitcoin.ts +21 -1
- package/src/families/bitcoin/wallet-btc/crypto/bitcoincash.ts +5 -0
- package/src/families/bitcoin/wallet-btc/crypto/types.ts +1 -0
- package/src/families/bitcoin/wallet-btc/crypto/zec.ts +5 -0
- package/src/families/bitcoin/wallet-btc/crypto/zen.ts +5 -0
- package/src/families/bitcoin/wallet-btc/explorer/index.ts +0 -5
- package/src/families/bitcoin/wallet-btc/index.ts +4 -4
- package/src/families/bitcoin/wallet-btc/utils.ts +10 -0
- package/src/families/bitcoin/wallet-btc/xpub.ts +37 -53
- package/src/families/elrond/js-getTransactionStatus.ts +4 -0
- package/src/families/elrond/js-signOperation.ts +3 -1
- package/src/families/ethereum/specs.ts +47 -0
|
@@ -722,7 +722,6 @@ Array [
|
|
|
722
722
|
"ethereum/erc20/wholeearthcoin",
|
|
723
723
|
"ethereum/erc20/datx",
|
|
724
724
|
"ethereum/erc20/mileverse",
|
|
725
|
-
"ethereum/erc20/cr_coin",
|
|
726
725
|
"ethereum/erc20/biocrypt",
|
|
727
726
|
"ethereum/erc20/bittwatt",
|
|
728
727
|
"ethereum/erc20/ono_token",
|
|
@@ -2186,6 +2185,7 @@ Array [
|
|
|
2186
2185
|
"ethereum/erc20/cpollo",
|
|
2187
2186
|
"ethereum/erc20/cprop",
|
|
2188
2187
|
"ethereum/erc20/cr7coin",
|
|
2188
|
+
"ethereum/erc20/cr_coin",
|
|
2189
2189
|
"ethereum/erc20/crafty_token",
|
|
2190
2190
|
"ethereum/erc20/crb",
|
|
2191
2191
|
"ethereum/erc20/cream",
|
|
@@ -3626,6 +3626,7 @@ Array [
|
|
|
3626
3626
|
"ethereum/erc20/monftertoken",
|
|
3627
3627
|
"ethereum/erc20/monkeycoin",
|
|
3628
3628
|
"ethereum/erc20/monnos_token",
|
|
3629
|
+
"ethereum/erc20/mononoke_inu",
|
|
3629
3630
|
"ethereum/erc20/moon_juice",
|
|
3630
3631
|
"ethereum/erc20/moon_yfi",
|
|
3631
3632
|
"ethereum/erc20/moona239_coins",
|
|
@@ -4271,6 +4272,7 @@ Array [
|
|
|
4271
4272
|
"ethereum/erc20/safeswap",
|
|
4272
4273
|
"ethereum/erc20/saitama_inu",
|
|
4273
4274
|
"ethereum/erc20/saito",
|
|
4275
|
+
"ethereum/erc20/saja",
|
|
4274
4276
|
"ethereum/erc20/sake",
|
|
4275
4277
|
"ethereum/erc20/saketoken",
|
|
4276
4278
|
"ethereum/erc20/sakhalin_husky",
|
|
@@ -4496,6 +4498,7 @@ Array [
|
|
|
4496
4498
|
"ethereum/erc20/spurt_plus",
|
|
4497
4499
|
"ethereum/erc20/squirrel_finance",
|
|
4498
4500
|
"ethereum/erc20/srh",
|
|
4501
|
+
"ethereum/erc20/ssv_token",
|
|
4499
4502
|
"ethereum/erc20/sta",
|
|
4500
4503
|
"ethereum/erc20/stabilize_token",
|
|
4501
4504
|
"ethereum/erc20/stabinol_token",
|
|
@@ -4855,6 +4858,7 @@ Array [
|
|
|
4855
4858
|
"ethereum/erc20/tryfinance",
|
|
4856
4859
|
"ethereum/erc20/tsla.finance",
|
|
4857
4860
|
"ethereum/erc20/tsuki_inu",
|
|
4861
|
+
"ethereum/erc20/tsuzuki_inu",
|
|
4858
4862
|
"ethereum/erc20/ttx_nft",
|
|
4859
4863
|
"ethereum/erc20/tugz",
|
|
4860
4864
|
"ethereum/erc20/tune",
|
|
@@ -5090,6 +5094,7 @@ Array [
|
|
|
5090
5094
|
"ethereum/erc20/wild_credit",
|
|
5091
5095
|
"ethereum/erc20/wilder",
|
|
5092
5096
|
"ethereum/erc20/windbellows",
|
|
5097
|
+
"ethereum/erc20/winry_inu",
|
|
5093
5098
|
"ethereum/erc20/wise_token",
|
|
5094
5099
|
"ethereum/erc20/witch_token",
|
|
5095
5100
|
"ethereum/erc20/wiva",
|
|
@@ -5777,7 +5782,9 @@ Array [
|
|
|
5777
5782
|
"bsc/bep20/easy_v2",
|
|
5778
5783
|
"bsc/bep20/elite_swap_binance_token",
|
|
5779
5784
|
"bsc/bep20/ellipsis",
|
|
5785
|
+
"bsc/bep20/empire_token",
|
|
5780
5786
|
"bsc/bep20/empiricus_token",
|
|
5787
|
+
"bsc/bep20/ev_direct_currency",
|
|
5781
5788
|
"bsc/bep20/exeedme",
|
|
5782
5789
|
"bsc/bep20/extend_finance",
|
|
5783
5790
|
"bsc/bep20/faracrystal",
|
|
@@ -5922,6 +5929,7 @@ Array [
|
|
|
5922
5929
|
"bsc/bep20/seedifyfund",
|
|
5923
5930
|
"bsc/bep20/seven_up_token",
|
|
5924
5931
|
"bsc/bep20/shard",
|
|
5932
|
+
"bsc/bep20/shiba_inu",
|
|
5925
5933
|
"bsc/bep20/shield_protocol",
|
|
5926
5934
|
"bsc/bep20/shirtum",
|
|
5927
5935
|
"bsc/bep20/smart_advertising_transaction_token",
|
|
@@ -5951,6 +5959,7 @@ Array [
|
|
|
5951
5959
|
"bsc/bep20/tenet",
|
|
5952
5960
|
"bsc/bep20/the_force_token",
|
|
5953
5961
|
"bsc/bep20/thugs",
|
|
5962
|
+
"bsc/bep20/tiki",
|
|
5954
5963
|
"bsc/bep20/titanswap",
|
|
5955
5964
|
"bsc/bep20/tixl_token",
|
|
5956
5965
|
"bsc/bep20/tokenpocket_token",
|
package/src/derivation.ts
CHANGED
|
@@ -470,7 +470,7 @@ export const getDerivationModesForCurrency = (
|
|
|
470
470
|
|
|
471
471
|
// taproot logic. FIXME should move per family
|
|
472
472
|
if (currency.family === "bitcoin") {
|
|
473
|
-
if (currency.id === "bitcoin_testnet") {
|
|
473
|
+
if (currency.id === "bitcoin" || currency.id === "bitcoin_testnet") {
|
|
474
474
|
all.push("taproot");
|
|
475
475
|
}
|
|
476
476
|
}
|
package/src/env.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { Account, CryptoCurrency } from "./../../types";
|
|
|
4
4
|
import type { Transaction } from "./types";
|
|
5
5
|
import getFeesForTransaction from "./js-getFeesForTransaction";
|
|
6
6
|
import { isValidRecipient } from "./logic";
|
|
7
|
+
import { Currency, isTaprootAddress } from "./wallet-btc";
|
|
7
8
|
|
|
8
9
|
const getCacheKeyForCalculateFees = ({
|
|
9
10
|
a,
|
|
@@ -41,6 +42,7 @@ export const calculateFees = makeLRUCache(
|
|
|
41
42
|
maxAge: 5 * 60 * 1000, // 5 minutes
|
|
42
43
|
}
|
|
43
44
|
);
|
|
45
|
+
|
|
44
46
|
export const validateRecipient: (
|
|
45
47
|
arg0: CryptoCurrency,
|
|
46
48
|
arg1: string | null | undefined
|
|
@@ -74,3 +76,13 @@ export const validateRecipient: (
|
|
|
74
76
|
},
|
|
75
77
|
(currency, recipient) => `${currency.id}_${recipient || ""}`
|
|
76
78
|
);
|
|
79
|
+
|
|
80
|
+
export const isTaprootRecipient: (
|
|
81
|
+
arg0: CryptoCurrency,
|
|
82
|
+
arg1: string
|
|
83
|
+
) => Promise<boolean> = makeLRUCache(
|
|
84
|
+
async (currency, recipient) => {
|
|
85
|
+
return isTaprootAddress(recipient, <Currency>currency.id);
|
|
86
|
+
},
|
|
87
|
+
(currency, recipient) => `${currency.id}_${recipient || ""}`
|
|
88
|
+
);
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
} from "@ledgerhq/errors";
|
|
10
10
|
import type { Account, TransactionStatus } from "./../../types";
|
|
11
11
|
import type { Transaction } from "./types";
|
|
12
|
-
import { calculateFees, validateRecipient } from "./cache";
|
|
12
|
+
import { calculateFees, validateRecipient, isTaprootRecipient } from "./cache";
|
|
13
|
+
import { TaprootNotActivated } from "./errors";
|
|
13
14
|
|
|
14
15
|
const getTransactionStatus = async (
|
|
15
16
|
a: Account,
|
|
@@ -31,6 +32,19 @@ const getTransactionStatus = async (
|
|
|
31
32
|
warnings.recipient = recipientWarning;
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
// Safeguard before Taproot activation
|
|
36
|
+
if (
|
|
37
|
+
t.recipient &&
|
|
38
|
+
!errors.recipient &&
|
|
39
|
+
a.currency.id === "bitcoin" &&
|
|
40
|
+
a.blockHeight <= 709632
|
|
41
|
+
) {
|
|
42
|
+
const isTaproot = await isTaprootRecipient(a.currency, t.recipient);
|
|
43
|
+
if (isTaproot) {
|
|
44
|
+
errors.recipient = new TaprootNotActivated();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
34
48
|
let txInputs;
|
|
35
49
|
let txOutputs;
|
|
36
50
|
let estimatedFees = new BigNumber(0);
|
|
@@ -342,8 +342,8 @@ const getAccountShape: GetAccountShape = async (info) => {
|
|
|
342
342
|
spendableBalance: balance,
|
|
343
343
|
operations,
|
|
344
344
|
operationsCount: operations.length,
|
|
345
|
-
freshAddress: walletAccount.xpub.freshAddress
|
|
346
|
-
freshAddressPath: `${accountPath}/0/${walletAccount.xpub.freshAddressIndex
|
|
345
|
+
freshAddress: walletAccount.xpub.freshAddress,
|
|
346
|
+
freshAddressPath: `${accountPath}/0/${walletAccount.xpub.freshAddressIndex}`,
|
|
347
347
|
blockHeight,
|
|
348
348
|
bitcoinResources: {
|
|
349
349
|
utxos,
|
|
@@ -27,6 +27,9 @@ export function fallbackValidateAddress(address: string): boolean {
|
|
|
27
27
|
class Base implements ICrypto {
|
|
28
28
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
29
|
network: any;
|
|
30
|
+
protected static publickeyCache = {}; // xpub + account + index to publicKey
|
|
31
|
+
protected static addressCache = {}; // derivationMode + xpub + account + index to address
|
|
32
|
+
protected static bech32Cache = {}; // xpub to bech32 interface
|
|
30
33
|
|
|
31
34
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
35
|
constructor({ network }: { network: any }) {
|
|
@@ -37,9 +40,26 @@ class Base implements ICrypto {
|
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
protected getPubkeyAt(xpub: string, account: number, index: number): Buffer {
|
|
40
|
-
|
|
41
|
-
.
|
|
43
|
+
if (!Base.bech32Cache[xpub]) {
|
|
44
|
+
Base.bech32Cache[xpub] = bip32.fromBase58(xpub, this.network);
|
|
45
|
+
}
|
|
46
|
+
if (Base.publickeyCache[`${xpub}-${account}-${index}`]) {
|
|
47
|
+
return Base.publickeyCache[`${xpub}-${account}-${index}`];
|
|
48
|
+
}
|
|
49
|
+
if (Base.publickeyCache[`${xpub}-${account}`]) {
|
|
50
|
+
const publicKey =
|
|
51
|
+
Base.publickeyCache[`${xpub}-${account}`].derive(index).publicKey;
|
|
52
|
+
Base.publickeyCache[`${xpub}-${account}-${index}`] = publicKey;
|
|
53
|
+
return publicKey;
|
|
54
|
+
}
|
|
55
|
+
Base.publickeyCache[`${xpub}-${account}`] =
|
|
56
|
+
Base.bech32Cache[xpub].derive(account);
|
|
57
|
+
const publicKey =
|
|
58
|
+
Base.publickeyCache[`${xpub}-${account}`].derive(index).publicKey;
|
|
59
|
+
Base.publickeyCache[`${xpub}-${account}-${index}`] = publicKey;
|
|
60
|
+
return publicKey;
|
|
42
61
|
}
|
|
62
|
+
|
|
43
63
|
// derive legacy address at account and index positions
|
|
44
64
|
getLegacyAddress(xpub: string, account: number, index: number): string {
|
|
45
65
|
const { address } = bjs.payments.p2pkh({
|
|
@@ -78,16 +98,26 @@ class Base implements ICrypto {
|
|
|
78
98
|
account: number,
|
|
79
99
|
index: number
|
|
80
100
|
): string {
|
|
101
|
+
if (Base.addressCache[`${derivationMode}-${xpub}-${account}-${index}`]) {
|
|
102
|
+
return Base.addressCache[`${derivationMode}-${xpub}-${account}-${index}`];
|
|
103
|
+
}
|
|
81
104
|
switch (derivationMode) {
|
|
82
105
|
case DerivationModes.LEGACY:
|
|
83
|
-
|
|
106
|
+
Base.addressCache[`${derivationMode}-${xpub}-${account}-${index}`] =
|
|
107
|
+
this.getLegacyAddress(xpub, account, index);
|
|
108
|
+
break;
|
|
84
109
|
case DerivationModes.SEGWIT:
|
|
85
|
-
|
|
110
|
+
Base.addressCache[`${derivationMode}-${xpub}-${account}-${index}`] =
|
|
111
|
+
this.getSegWitAddress(xpub, account, index);
|
|
112
|
+
break;
|
|
86
113
|
case DerivationModes.NATIVE_SEGWIT:
|
|
87
|
-
|
|
114
|
+
Base.addressCache[`${derivationMode}-${xpub}-${account}-${index}`] =
|
|
115
|
+
this.getNativeSegWitAddress(xpub, account, index);
|
|
116
|
+
break;
|
|
88
117
|
default:
|
|
89
118
|
throw new Error(`Invalid derivation Mode: ${derivationMode}`);
|
|
90
119
|
}
|
|
120
|
+
return Base.addressCache[`${derivationMode}-${xpub}-${account}-${index}`];
|
|
91
121
|
}
|
|
92
122
|
|
|
93
123
|
// infer address type from its syntax
|
|
@@ -119,6 +149,10 @@ class Base implements ICrypto {
|
|
|
119
149
|
(res[0] === this.network.pubKeyHash || res[0] === this.network.scriptHash)
|
|
120
150
|
);
|
|
121
151
|
}
|
|
152
|
+
|
|
153
|
+
isTaprootAddress(address: string): boolean {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
122
156
|
}
|
|
123
157
|
|
|
124
158
|
export default Base;
|
|
@@ -124,9 +124,16 @@ class Bitcoin extends Base {
|
|
|
124
124
|
account: number,
|
|
125
125
|
index: number
|
|
126
126
|
): string {
|
|
127
|
+
if (Base.addressCache[`${derivationMode}-${xpub}-${account}-${index}`]) {
|
|
128
|
+
return Base.addressCache[`${derivationMode}-${xpub}-${account}-${index}`];
|
|
129
|
+
}
|
|
127
130
|
switch (derivationMode) {
|
|
128
131
|
case DerivationModes.TAPROOT:
|
|
129
|
-
|
|
132
|
+
Base.addressCache[`${derivationMode}-${xpub}-${account}-${index}`] =
|
|
133
|
+
this.getTaprootAddress(xpub, account, index);
|
|
134
|
+
return Base.addressCache[
|
|
135
|
+
`${derivationMode}-${xpub}-${account}-${index}`
|
|
136
|
+
];
|
|
130
137
|
default:
|
|
131
138
|
return super.getAddress(derivationMode, xpub, account, index);
|
|
132
139
|
}
|
|
@@ -202,6 +209,19 @@ class Bitcoin extends Base {
|
|
|
202
209
|
// Create address
|
|
203
210
|
return toBech32(outputSchnorrKey, 1, this.network.bech32);
|
|
204
211
|
}
|
|
212
|
+
|
|
213
|
+
isTaprootAddress(address: string): boolean {
|
|
214
|
+
// This prefix check is to avoid returning false in cases where a valid base58 address also happens
|
|
215
|
+
// to be a valid bech32(m) string (but invalid segwit address).
|
|
216
|
+
if (address.toLowerCase().startsWith(`${this.network.bech32}1`)) {
|
|
217
|
+
try {
|
|
218
|
+
bjs.address.fromBech32(address);
|
|
219
|
+
} catch {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
205
225
|
}
|
|
206
226
|
|
|
207
227
|
export default Bitcoin;
|
|
@@ -70,6 +70,11 @@ class BitcoinCash implements ICrypto {
|
|
|
70
70
|
validateAddress(address: string): boolean {
|
|
71
71
|
return bchaddr.isValidAddress(address);
|
|
72
72
|
}
|
|
73
|
+
|
|
74
|
+
// eslint-disable-next-line class-methods-use-this
|
|
75
|
+
isTaprootAddress(address: string): boolean {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
73
78
|
}
|
|
74
79
|
|
|
75
80
|
export default BitcoinCash;
|
|
@@ -74,6 +74,11 @@ class ZCash implements ICrypto {
|
|
|
74
74
|
validateAddress(address: string): boolean {
|
|
75
75
|
return zec.Address.isValid(address, "livenet");
|
|
76
76
|
}
|
|
77
|
+
|
|
78
|
+
// eslint-disable-next-line class-methods-use-this
|
|
79
|
+
isTaprootAddress(address: string): boolean {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
export default ZCash;
|
|
@@ -102,6 +102,11 @@ class Zen implements ICrypto {
|
|
|
102
102
|
(res[1] === 0x89 || res[1] === 0x96)
|
|
103
103
|
);
|
|
104
104
|
}
|
|
105
|
+
|
|
106
|
+
// eslint-disable-next-line class-methods-use-this
|
|
107
|
+
isTaprootAddress(address: string): boolean {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
export default Zen;
|
|
@@ -285,12 +285,7 @@ class BitcoinLikeExplorer extends EventEmitter implements IExplorer {
|
|
|
285
285
|
|
|
286
286
|
// faster than mapping
|
|
287
287
|
res.txs.forEach((tx) => {
|
|
288
|
-
if (!tx.block) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
288
|
this.hydrateTx(address, tx);
|
|
293
|
-
|
|
294
289
|
hydratedTxs.push(tx);
|
|
295
290
|
});
|
|
296
291
|
|
|
@@ -11,7 +11,7 @@ import { TX, Input, Output } from "./storage/types";
|
|
|
11
11
|
import { CoinSelect } from "./pickingstrategies/CoinSelect";
|
|
12
12
|
import { DeepFirst } from "./pickingstrategies/DeepFirst";
|
|
13
13
|
import { Merge } from "./pickingstrategies/Merge";
|
|
14
|
-
import { isValidAddress } from "./utils";
|
|
14
|
+
import { isValidAddress, isTaprootAddress } from "./utils";
|
|
15
15
|
|
|
16
16
|
import type { Account as WalletAccount } from "./account";
|
|
17
17
|
import type { Account as LiveAccount } from "./../../../types";
|
|
@@ -32,16 +32,16 @@ export {
|
|
|
32
32
|
DeepFirst,
|
|
33
33
|
Merge,
|
|
34
34
|
isValidAddress,
|
|
35
|
+
isTaprootAddress,
|
|
35
36
|
Currency,
|
|
36
37
|
};
|
|
37
38
|
|
|
38
39
|
let wallet: BitcoinLikeWallet | null = null;
|
|
39
40
|
|
|
40
41
|
export const getWalletAccount = (account: LiveAccount): WalletAccount => {
|
|
41
|
-
if (account.id.startsWith("libcore")) throw new AccountNeedResync();
|
|
42
42
|
const walletAccount = account.bitcoinResources?.walletAccount;
|
|
43
|
-
if (!walletAccount) {
|
|
44
|
-
throw new
|
|
43
|
+
if (account.id.startsWith("libcore") || !walletAccount) {
|
|
44
|
+
throw new AccountNeedResync();
|
|
45
45
|
}
|
|
46
46
|
return walletAccount;
|
|
47
47
|
};
|
|
@@ -156,3 +156,13 @@ export function isValidAddress(address: string, currency?: Currency) {
|
|
|
156
156
|
const crypto = cryptoFactory(currency);
|
|
157
157
|
return crypto.validateAddress(address);
|
|
158
158
|
}
|
|
159
|
+
|
|
160
|
+
export function isTaprootAddress(address: string, currency?: Currency) {
|
|
161
|
+
if (currency === "bitcoin") {
|
|
162
|
+
return cryptoFactory("bitcoin").isTaprootAddress(address);
|
|
163
|
+
} else if (currency === "bitcoin_testnet") {
|
|
164
|
+
return cryptoFactory("bitcoin_testnet").isTaprootAddress(address);
|
|
165
|
+
} else {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { maxBy, range, some } from "lodash";
|
|
2
2
|
import BigNumber from "bignumber.js";
|
|
3
|
-
import { Address, IStorage } from "./storage/types";
|
|
3
|
+
import { TX, Address, IStorage } from "./storage/types";
|
|
4
4
|
import EventEmitter from "./utils/eventemitter";
|
|
5
5
|
import { IExplorer } from "./explorer/types";
|
|
6
6
|
import { ICrypto } from "./crypto/types";
|
|
@@ -20,9 +20,9 @@ class Xpub extends EventEmitter {
|
|
|
20
20
|
|
|
21
21
|
derivationMode: string;
|
|
22
22
|
|
|
23
|
-
freshAddress:
|
|
23
|
+
freshAddress: string;
|
|
24
24
|
|
|
25
|
-
freshAddressIndex:
|
|
25
|
+
freshAddressIndex: number;
|
|
26
26
|
|
|
27
27
|
// https://github.com/bitcoinjs/bitcoinjs-lib/blob/27a840aac4a12338f1e40c54f3759bbd7a559944/src/bufferutils.js#L24
|
|
28
28
|
// only works with number so we need to be sure to pass correct numbers
|
|
@@ -54,6 +54,8 @@ class Xpub extends EventEmitter {
|
|
|
54
54
|
this.crypto = crypto;
|
|
55
55
|
this.xpub = xpub;
|
|
56
56
|
this.derivationMode = derivationMode;
|
|
57
|
+
this.freshAddress = "";
|
|
58
|
+
this.freshAddressIndex = 0;
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
async syncAddress(account: number, index: number) {
|
|
@@ -78,9 +80,7 @@ class Xpub extends EventEmitter {
|
|
|
78
80
|
|
|
79
81
|
// TODO handle eventual reorg case using lastBlock
|
|
80
82
|
|
|
81
|
-
let added = 0;
|
|
82
83
|
let total = 0;
|
|
83
|
-
|
|
84
84
|
try {
|
|
85
85
|
// TODO perf: bad : looping in the tx array
|
|
86
86
|
await this.checkAddressReorg(account, index);
|
|
@@ -95,20 +95,7 @@ class Xpub extends EventEmitter {
|
|
|
95
95
|
if (hasPendings) {
|
|
96
96
|
await this.storage.removePendingTxs({ account, index });
|
|
97
97
|
}
|
|
98
|
-
|
|
99
|
-
// eslint-disable-next-line no-cond-assign,no-await-in-loop
|
|
100
|
-
while (
|
|
101
|
-
(added = await this.fetchHydrateAndStoreNewTxs(address, account, index))
|
|
102
|
-
) {
|
|
103
|
-
total += added;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const pendingTxs = await this.explorer.getPendings({
|
|
107
|
-
address,
|
|
108
|
-
account,
|
|
109
|
-
index,
|
|
110
|
-
});
|
|
111
|
-
await this.storage.appendTxs(pendingTxs);
|
|
98
|
+
total = await this.fetchHydrateAndStoreNewTxs(address, account, index);
|
|
112
99
|
} catch (e) {
|
|
113
100
|
this.emitSyncedFailed(data);
|
|
114
101
|
throw e;
|
|
@@ -120,11 +107,8 @@ class Xpub extends EventEmitter {
|
|
|
120
107
|
account,
|
|
121
108
|
index,
|
|
122
109
|
});
|
|
123
|
-
if (lastTx) {
|
|
124
|
-
this.freshAddressIndex
|
|
125
|
-
this.freshAddressIndex[account],
|
|
126
|
-
index + 1
|
|
127
|
-
);
|
|
110
|
+
if (account === 0 && lastTx) {
|
|
111
|
+
this.freshAddressIndex = Math.max(this.freshAddressIndex, index + 1);
|
|
128
112
|
}
|
|
129
113
|
return !!lastTx;
|
|
130
114
|
}
|
|
@@ -137,13 +121,6 @@ class Xpub extends EventEmitter {
|
|
|
137
121
|
}
|
|
138
122
|
|
|
139
123
|
async syncAccount(account: number) {
|
|
140
|
-
this.freshAddressIndex[account] = 0;
|
|
141
|
-
this.freshAddress[account] = this.crypto.getAddress(
|
|
142
|
-
this.derivationMode,
|
|
143
|
-
this.xpub,
|
|
144
|
-
account,
|
|
145
|
-
0
|
|
146
|
-
);
|
|
147
124
|
await this.whenSynced("account", account.toString());
|
|
148
125
|
|
|
149
126
|
this.emitSyncing({
|
|
@@ -174,26 +151,19 @@ class Xpub extends EventEmitter {
|
|
|
174
151
|
account,
|
|
175
152
|
index,
|
|
176
153
|
});
|
|
177
|
-
this.freshAddress[account] = this.crypto.getAddress(
|
|
178
|
-
this.derivationMode,
|
|
179
|
-
this.xpub,
|
|
180
|
-
account,
|
|
181
|
-
this.freshAddressIndex[account]
|
|
182
|
-
);
|
|
183
154
|
return index;
|
|
184
155
|
}
|
|
185
156
|
|
|
186
157
|
// TODO : test fail case + incremental
|
|
187
158
|
async sync() {
|
|
188
159
|
await this.whenSynced("all");
|
|
189
|
-
|
|
190
160
|
this.emitSyncing({ type: "all" });
|
|
191
|
-
|
|
161
|
+
this.freshAddressIndex = 0;
|
|
192
162
|
let account = 0;
|
|
193
|
-
|
|
194
163
|
try {
|
|
195
164
|
// eslint-disable-next-line no-await-in-loop
|
|
196
|
-
while (await this.syncAccount(account)) {
|
|
165
|
+
while (account < 2 && (await this.syncAccount(account))) {
|
|
166
|
+
// account=0 for receive address; account=1 for change address. No need to handle account>1
|
|
197
167
|
account += 1;
|
|
198
168
|
}
|
|
199
169
|
} catch (e) {
|
|
@@ -202,7 +172,12 @@ class Xpub extends EventEmitter {
|
|
|
202
172
|
}
|
|
203
173
|
|
|
204
174
|
this.emitSynced({ type: "all", account });
|
|
205
|
-
|
|
175
|
+
this.freshAddress = this.crypto.getAddress(
|
|
176
|
+
this.derivationMode,
|
|
177
|
+
this.xpub,
|
|
178
|
+
0,
|
|
179
|
+
this.freshAddressIndex
|
|
180
|
+
);
|
|
206
181
|
return account;
|
|
207
182
|
}
|
|
208
183
|
|
|
@@ -440,18 +415,27 @@ class Xpub extends EventEmitter {
|
|
|
440
415
|
account: number,
|
|
441
416
|
index: number
|
|
442
417
|
) {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
418
|
+
let pendingTxs: TX[] = [];
|
|
419
|
+
let txs: TX[] = [];
|
|
420
|
+
let inserted = 0;
|
|
421
|
+
do {
|
|
422
|
+
const lastTx = await this.storage.getLastTx({
|
|
423
|
+
account,
|
|
424
|
+
index,
|
|
425
|
+
confirmed: true,
|
|
426
|
+
});
|
|
448
427
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
428
|
+
txs = await this.explorer.getAddressTxsSinceLastTxBlock(
|
|
429
|
+
this.txsSyncArraySize,
|
|
430
|
+
{ address, account, index },
|
|
431
|
+
lastTx
|
|
432
|
+
);
|
|
433
|
+
if (pendingTxs.length === 0) {
|
|
434
|
+
pendingTxs = txs.filter((tx) => !tx.block);
|
|
435
|
+
}
|
|
436
|
+
inserted += await this.storage.appendTxs(txs.filter((tx) => tx.block)); // only insert not pending tx
|
|
437
|
+
} 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);
|
|
455
439
|
return inserted;
|
|
456
440
|
}
|
|
457
441
|
|
|
@@ -32,6 +32,10 @@ const getTransactionStatus = async (
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
const estimatedFees = t.fees || new BigNumber(0);
|
|
35
|
+
if (estimatedFees.gt(a.balance)) {
|
|
36
|
+
errors.amount = new NotEnoughBalance();
|
|
37
|
+
}
|
|
38
|
+
|
|
35
39
|
const totalSpent = useAllAmount
|
|
36
40
|
? a.balance
|
|
37
41
|
: new BigNumber(t.amount).plus(estimatedFees);
|
|
@@ -15,7 +15,9 @@ const buildOptimisticOperation = (
|
|
|
15
15
|
fee: BigNumber
|
|
16
16
|
): Operation => {
|
|
17
17
|
const type = "OUT";
|
|
18
|
-
const value =
|
|
18
|
+
const value = transaction.useAllAmount
|
|
19
|
+
? account.balance.minus(fee)
|
|
20
|
+
: new BigNumber(transaction.amount);
|
|
19
21
|
const operation: Operation = {
|
|
20
22
|
id: encodeOperationId(account.id, "", type),
|
|
21
23
|
hash: "",
|
|
@@ -445,8 +445,55 @@ const bsc: AppSpec<Transaction> = {
|
|
|
445
445
|
]),
|
|
446
446
|
};
|
|
447
447
|
|
|
448
|
+
const polygon: AppSpec<Transaction> = {
|
|
449
|
+
name: "Polygon",
|
|
450
|
+
currency: getCryptoCurrencyById("polygon"),
|
|
451
|
+
appQuery: {
|
|
452
|
+
model: DeviceModelId.nanoS,
|
|
453
|
+
appName: "Polygon",
|
|
454
|
+
},
|
|
455
|
+
testTimeout: 2 * 60 * 1000,
|
|
456
|
+
transactionCheck: ({ maxSpendable }) => {
|
|
457
|
+
invariant(
|
|
458
|
+
maxSpendable.gt(
|
|
459
|
+
parseCurrencyUnit(getCryptoCurrencyById("polygon").units[0], "0.005")
|
|
460
|
+
),
|
|
461
|
+
"balance is too low"
|
|
462
|
+
);
|
|
463
|
+
},
|
|
464
|
+
mutations: ethereumBasicMutations({ maxAccount: 8 }).concat([
|
|
465
|
+
{
|
|
466
|
+
name: "move some ERC20",
|
|
467
|
+
maxRun: 1,
|
|
468
|
+
// @ts-expect-error rxjs stuff
|
|
469
|
+
transaction: ({ account, siblings, bridge }) => {
|
|
470
|
+
const erc20Account = sample(
|
|
471
|
+
(account.subAccounts || []).filter((a) => a.balance.gt(0))
|
|
472
|
+
);
|
|
473
|
+
invariant(erc20Account, "no erc20 account");
|
|
474
|
+
const sibling = pickSiblings(siblings, 3);
|
|
475
|
+
const recipient = sibling.freshAddress;
|
|
476
|
+
return {
|
|
477
|
+
transaction: bridge.createTransaction(account),
|
|
478
|
+
updates: [
|
|
479
|
+
{ recipient, subAccountId: erc20Account.id },
|
|
480
|
+
Math.random() < 0.5
|
|
481
|
+
? { useAllAmount: true }
|
|
482
|
+
: {
|
|
483
|
+
amount: erc20Account.balance
|
|
484
|
+
.times(Math.random())
|
|
485
|
+
.integerValue(),
|
|
486
|
+
},
|
|
487
|
+
],
|
|
488
|
+
};
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
]),
|
|
492
|
+
};
|
|
493
|
+
|
|
448
494
|
export default {
|
|
449
495
|
bsc,
|
|
496
|
+
polygon,
|
|
450
497
|
ethereum,
|
|
451
498
|
ethereumClassic,
|
|
452
499
|
ethereumRopsten,
|