Skip to content

Commit d43f0ea

Browse files
authored
Merge pull request #3592 from hirosystems/release/warm-bustling-meerkat
Release/warm bustling meerkat
2 parents 9da27c8 + 6d12445 commit d43f0ea

File tree

94 files changed

+1199
-724
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+1199
-724
lines changed

.eslintrc.js

+22-10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ module.exports = {
1515
browser: true,
1616
context: true,
1717
},
18+
extends: [
19+
'plugin:@typescript-eslint/recommended',
20+
'plugin:react/recommended',
21+
'plugin:react/jsx-runtime',
22+
'plugin:react-hooks/recommended',
23+
],
1824
plugins: ['react', 'react-hooks', '@typescript-eslint', 'deprecation'],
1925
rules: {
2026
// This rule helps highlight areas of the code that use deprecated
@@ -41,25 +47,31 @@ module.exports = {
4147
message: avoidWindowOpenMsg,
4248
},
4349
],
44-
'@typescript-eslint/no-floating-promises': [1],
45-
'@typescript-eslint/no-unnecessary-type-assertion': [0],
50+
'@typescript-eslint/no-floating-promises': ['warn'],
51+
'@typescript-eslint/no-unnecessary-type-assertion': ['warn'],
52+
4653
'@typescript-eslint/no-unsafe-assignment': [0],
4754
'@typescript-eslint/no-unsafe-return': [0],
4855
'@typescript-eslint/no-unsafe-call': [0],
4956
'@typescript-eslint/no-unsafe-member-access': [0],
50-
'@typescript-eslint/ban-types': [0],
5157
'@typescript-eslint/restrict-template-expressions': [0],
5258
'@typescript-eslint/explicit-module-boundary-types': [0],
59+
'@typescript-eslint/no-unnecessary-type-constraint': ['off'],
60+
'@typescript-eslint/no-non-null-asserted-optional-chain': ['off'],
61+
'@typescript-eslint/no-explicit-any': ['off'],
62+
'@typescript-eslint/no-meaningless-void-operator': 'error',
63+
'@typescript-eslint/ban-types': ['error'],
5364
'@typescript-eslint/no-unnecessary-condition': 'warn',
65+
'@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
5466
'no-warning-comments': [0],
55-
'react/function-component-definition': 'error',
67+
5668
'react-hooks/rules-of-hooks': 'error',
57-
'react-hooks/exhaustive-deps': [
58-
'error',
59-
{
60-
additionalHooks: 'useRecoilCallback',
61-
},
62-
],
69+
'react-hooks/exhaustive-deps': ['error'],
70+
71+
'react/function-component-definition': 'error',
72+
'react/display-name': 'off',
73+
'react/prop-types': 'off',
74+
'react/no-unescaped-entities': 'off',
6375
'react/jsx-uses-react': 'off',
6476
'react/react-in-jsx-scope': 'off',
6577
},

package.json

+5-4
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@
139139
"@scure/bip32": "1.3.0",
140140
"@scure/bip39": "1.2.0",
141141
"@scure/btc-signer": "0.5.1",
142-
"@segment/analytics-next": "1.49.2",
142+
"@segment/analytics-next": "1.51.5",
143143
"@sentry/react": "7.35.0",
144144
"@sentry/tracing": "7.35.0",
145145
"@stacks/auth": "6.1.1",
@@ -164,6 +164,7 @@
164164
"@tanstack/react-query-devtools": "4.24.4",
165165
"@tanstack/react-query-persist-client": "4.24.4",
166166
"@tippyjs/react": "4.2.6",
167+
"@typescript-eslint/eslint-plugin": "5.59.0",
167168
"@vkontakte/vk-qr": "2.0.13",
168169
"@zondax/ledger-stacks": "1.0.3",
169170
"are-passive-events-supported": "1.1.1",
@@ -220,7 +221,7 @@
220221
"@babel/core": "7.20.12",
221222
"@babel/preset-react": "7.18.6",
222223
"@babel/preset-typescript": "7.18.6",
223-
"@btckit/types": "0.0.13",
224+
"@btckit/types": "0.0.16",
224225
"@emotion/babel-plugin": "11.10.5",
225226
"@emotion/babel-preset-css-prop": "11.10.0",
226227
"@emotion/cache": "11.10.5",
@@ -232,7 +233,6 @@
232233
"@schemastore/web-manifest": "0.0.5",
233234
"@sentry/webpack-plugin": "1.20.0",
234235
"@stacks/connect-react": "22.0.1",
235-
"@stacks/eslint-config": "1.2.0",
236236
"@stacks/prettier-config": "0.0.10",
237237
"@stacks/stacks-blockchain-api-types": "6.3.4",
238238
"@swc-node/jest": "1.5.6",
@@ -265,6 +265,7 @@
265265
"@types/webextension-polyfill": "0.10.0",
266266
"@types/webpack": "5.28.0",
267267
"@types/zxcvbn": "4.4.1",
268+
"@typescript-eslint/parser": "5.59.0",
268269
"@vitest/coverage-istanbul": "0.28.3",
269270
"audit-ci": "6.6.1",
270271
"babel-loader": "9.1.2",
@@ -285,7 +286,7 @@
285286
"dotenv-webpack": "8.0.1",
286287
"esbuild": "0.17.5",
287288
"esbuild-loader": "2.21.0",
288-
"eslint-plugin-deprecation": "1.3.3",
289+
"eslint-plugin-deprecation": "1.4.1",
289290
"eslint-plugin-react": "7.32.2",
290291
"eslint-plugin-react-hooks": "4.6.0",
291292
"file-loader": "6.2.0",
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import { useMemo } from 'react';
1+
import { useEffect, useMemo } from 'react';
22
import { useLocation } from 'react-router-dom';
33

44
import {
55
EventParams,
66
PageParams,
77
} from '@segment/analytics-next/dist/types/core/arguments-resolver';
88

9-
import { IS_TEST_ENV } from '@shared/environment';
9+
import { IS_TEST_ENV, SEGMENT_WRITE_KEY } from '@shared/environment';
1010
import { logger } from '@shared/logger';
11-
import { analytics } from '@shared/utils/analytics';
11+
import { analytics, initAnalytics } from '@shared/utils/analytics';
1212

1313
import { flow, origin } from '@app/common/initial-search-params';
1414
import { useWalletType } from '@app/common/use-wallet-type';
@@ -25,13 +25,20 @@ function isHiroApiUrl(url: string) {
2525
return /^https:\/\/.*\.stacks.co/.test(url);
2626
}
2727

28+
export function useInitalizeAnalytics() {
29+
const hasUserDeclinedAnalytics = useHasUserExplicitlyDeclinedAnalytics();
30+
31+
useEffect(() => {
32+
if (hasUserDeclinedAnalytics || !SEGMENT_WRITE_KEY || IS_TEST_ENV) return;
33+
initAnalytics();
34+
}, [hasUserDeclinedAnalytics]);
35+
}
36+
2837
export function useAnalytics() {
2938
const currentNetwork = useCurrentNetworkState();
3039
const location = useLocation();
3140
const { walletType } = useWalletType();
3241

33-
const hasDeclined = useHasUserExplicitlyDeclinedAnalytics();
34-
3542
return useMemo(() => {
3643
const defaultProperties = {
3744
network: currentNetwork.name.toLowerCase(),
@@ -48,37 +55,29 @@ export function useAnalytics() {
4855
};
4956

5057
return {
58+
async identify(properties: object) {
59+
return analytics.identify(properties).catch(logger.error);
60+
},
61+
5162
async page(...args: PageParams) {
5263
const [category, name, properties, options, ...rest] = args;
5364
const prop = { ...defaultProperties, ...properties };
5465
const opts = { ...defaultOptions, ...options };
5566
logger.info(`Analytics page view: ${name}`, properties);
5667

57-
if (!analytics) return;
58-
if (hasDeclined) return;
59-
if (IS_TEST_ENV) return;
6068
if (typeof name === 'string' && isIgnoredPath(name)) return;
6169

6270
return analytics.page(category, name, prop, opts, ...rest).catch(logger.error);
6371
},
72+
6473
async track(...args: EventParams) {
6574
const [eventName, properties, options, ...rest] = args;
6675
const prop = { ...defaultProperties, ...properties };
6776
const opts = { ...defaultOptions, ...options };
6877
logger.info(`Analytics event: ${eventName}`, properties);
6978

70-
if (!analytics) return;
71-
if (hasDeclined) return;
72-
if (IS_TEST_ENV) return;
73-
7479
return analytics.track(eventName, prop, opts, ...rest).catch(logger.error);
7580
},
7681
};
77-
}, [
78-
currentNetwork.chain.stacks.url,
79-
currentNetwork.name,
80-
location.pathname,
81-
walletType,
82-
hasDeclined,
83-
]);
82+
}, [currentNetwork.chain.stacks.url, currentNetwork.name, location.pathname, walletType]);
8483
}

src/app/common/hooks/balance/use-total-balance.tsx

+10-6
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@ import { baseCurrencyAmountInQuote } from '@app/common/money/calculate-money';
44
import { i18nFormatCurrency } from '@app/common/money/format-money';
55
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
66
import { useCryptoCurrencyMarketData } from '@app/query/common/market-data/market-data.hooks';
7-
import { useCurrentStacksAccountAnchoredBalances } from '@app/query/stacks/balance/stx-balance.hooks';
8-
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
7+
import { useAnchoredStacksAccountBalances } from '@app/query/stacks/balance/stx-balance.hooks';
98

10-
export function useTotalBalance() {
9+
interface UseTotalBalanceArgs {
10+
btcAddress: string;
11+
stxAddress: string;
12+
}
13+
14+
export function useTotalBalance({ btcAddress, stxAddress }: UseTotalBalanceArgs) {
1115
// get market data
1216
const btcMarketData = useCryptoCurrencyMarketData('BTC');
1317
const stxMarketData = useCryptoCurrencyMarketData('STX');
1418

1519
// get stx balance
16-
const { data: balances } = useCurrentStacksAccountAnchoredBalances();
20+
const { data: balances, isLoading } = useAnchoredStacksAccountBalances(stxAddress);
1721

1822
// get btc balance
19-
const btcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
2023
const btcBalance = useNativeSegwitBalance(btcAddress);
2124

2225
return useMemo(() => {
@@ -30,6 +33,7 @@ export function useTotalBalance() {
3033
return {
3134
totalBalance,
3235
totalUsdBalance: i18nFormatCurrency(totalBalance),
36+
isLoading,
3337
};
34-
}, [btcBalance, balances, btcMarketData, stxMarketData]);
38+
}, [btcBalance, balances, btcMarketData, stxMarketData, isLoading]);
3539
}

src/app/common/hooks/use-scroll-lock.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,28 @@ declare global {
55
// tslint:disable-next-line: interface-name
66
interface Window {
77
__useScrollLockStyle: string | undefined | null;
8-
__useScrollLockInstances: Set<{}> | undefined | null;
8+
__useScrollLockInstances: Set<Record<string, unknown>> | undefined | null;
99
}
1010
}
1111

12-
let instances: Set<{}> = new Set();
12+
let instances: Set<Record<string, unknown>> = new Set();
1313

1414
if (typeof window !== 'undefined') {
1515
// this is necessary because we may share instances of this file on a page so we store these globally
16-
window.__useScrollLockInstances = window.__useScrollLockInstances || new Set<{}>();
16+
window.__useScrollLockInstances =
17+
window.__useScrollLockInstances || new Set<Record<string, unknown>>();
1718
instances = window.__useScrollLockInstances;
1819
}
1920

20-
const registerInstance = (instance: {}) => {
21+
const registerInstance = (instance: Record<string, unknown>) => {
2122
if (instances.size === 0) {
2223
setBodyOverflow(true);
2324
}
2425

2526
instances.add(instance);
2627
};
2728

28-
const unregisterInstance = (instance: {}) => {
29+
const unregisterInstance = (instance: Record<string, unknown>) => {
2930
instances.delete(instance);
3031

3132
if (instances.size === 0) {

src/app/common/theme-provider.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { createContext, useContext, useEffect, useState } from 'react';
22

3+
import { noop } from '@shared/utils';
4+
35
import { store } from '@app/store';
46
import { settingsActions } from '@app/store/settings/settings.actions';
57
import { useUserSelectedTheme } from '@app/store/settings/settings.selectors';
@@ -25,7 +27,7 @@ const ThemeContext = createContext<{
2527
// These values are not used, but are set to satisfy the context's value type.
2628
theme: 'light',
2729
userSelectedTheme: 'system',
28-
setUserSelectedTheme: () => {},
30+
setUserSelectedTheme: noop,
2931
});
3032

3133
const getSystemTheme = () =>

src/app/common/transactions/bitcoin/fees/btc-size-fee-estimator.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// https://github.com/argvil19/bitcoin-transaction-size-calculator/blob/master/index.js
2+
import BigNumber from 'bignumber.js';
23

34
type InputScriptTypes =
45
| 'p2pkh'
@@ -84,7 +85,7 @@ export class BtcSizeFeeEstimator {
8485
return 3;
8586
} else if (length < 4294967295) {
8687
return 5;
87-
} else if (length < 18446744073709551615) {
88+
} else if (new BigNumber(length).isLessThan('18446744073709551615')) {
8889
return 9;
8990
} else {
9091
throw new Error('Invalid let int');

src/app/pages/send/send-crypto-asset-form/family/bitcoin/hooks/use-generate-bitcoin-tx.ts src/app/common/transactions/bitcoin/use-generate-bitcoin-tx.ts

+26-12
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,52 @@ import { useCallback } from 'react';
22

33
import * as btc from '@scure/btc-signer';
44

5-
import { BitcoinSendFormValues } from '@shared/models/form.model';
5+
import { logger } from '@shared/logger';
6+
import { Money } from '@shared/models/money.model';
67

7-
import { btcToSat } from '@app/common/money/unit-conversion';
88
import { determineUtxosForSpend } from '@app/common/transactions/bitcoin/coinselect/local-coin-selection';
99
import { useGetUtxosByAddressQuery } from '@app/query/bitcoin/address/utxos-by-address.query';
1010
import { useBitcoinLibNetworkConfig } from '@app/store/accounts/blockchain/bitcoin/bitcoin-keychain';
1111
import {
12+
useCurrentAccountNativeSegwitSigner,
1213
useCurrentBitcoinNativeSegwitAddressIndexPublicKeychain,
1314
useCurrentBtcNativeSegwitAccountAddressIndexZero,
14-
useSignBitcoinNativeSegwitTx,
1515
} from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
1616

17+
interface GenerateBitcoinTxValues {
18+
amount: Money;
19+
recipient: string;
20+
}
21+
1722
export function useGenerateSignedBitcoinTx() {
1823
const currentAccountBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
1924
const { data: utxos } = useGetUtxosByAddressQuery(currentAccountBtcAddress);
2025
const currentAddressIndexKeychain = useCurrentBitcoinNativeSegwitAddressIndexPublicKeychain();
21-
const signTx = useSignBitcoinNativeSegwitTx();
26+
const createSigner = useCurrentAccountNativeSegwitSigner();
2227
const networkMode = useBitcoinLibNetworkConfig();
2328

2429
return useCallback(
25-
(values: BitcoinSendFormValues, feeRate: number) => {
30+
(values: GenerateBitcoinTxValues, feeRate: number) => {
2631
if (!utxos) return;
2732
if (!feeRate) return;
33+
if (!createSigner) return;
2834

2935
try {
36+
const signer = createSigner(0);
37+
3038
const tx = new btc.Transaction();
3139

3240
const { inputs, outputs, fee } = determineUtxosForSpend({
3341
utxos,
3442
recipient: values.recipient,
35-
amount: btcToSat(values.amount).toNumber(),
43+
amount: values.amount.amount.toNumber(),
3644
feeRate,
3745
});
3846

39-
// eslint-disable-next-line no-console
40-
console.log('coinselect', { inputs, outputs, fee });
47+
logger.info('coinselect', { inputs, outputs, fee });
4148

42-
if (!inputs) throw new Error('No inputs to sign');
43-
if (!outputs) throw new Error('No outputs to sign');
49+
if (!inputs.length) throw new Error('No inputs to sign');
50+
if (!outputs.length) throw new Error('No outputs to sign');
4451

4552
if (outputs.length > 2)
4653
throw new Error('Address reuse mode: wallet should have max 2 outputs');
@@ -66,15 +73,22 @@ export function useGenerateSignedBitcoinTx() {
6673
}
6774
tx.addOutputAddress(values.recipient, BigInt(output.value), networkMode);
6875
});
69-
signTx(tx);
76+
signer.sign(tx);
7077
tx.finalize();
78+
7179
return { hex: tx.hex, fee };
7280
} catch (e) {
7381
// eslint-disable-next-line no-console
7482
console.log('Error signing bitcoin transaction', e);
7583
return null;
7684
}
7785
},
78-
[currentAccountBtcAddress, currentAddressIndexKeychain?.publicKey, networkMode, signTx, utxos]
86+
[
87+
createSigner,
88+
currentAccountBtcAddress,
89+
currentAddressIndexKeychain?.publicKey,
90+
networkMode,
91+
utxos,
92+
]
7993
);
8094
}

src/app/common/utils/counter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export function createCounter(startPosition: number = 0) {
1+
export function createCounter(startPosition = 0) {
22
let count = startPosition;
33
return {
44
getValue() {

src/app/common/utils/use-interval.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { useEffect, useRef } from 'react';
22

3+
import { noop } from '@shared/utils';
4+
35
export function useInterval(callback: () => void, delay: number | null) {
4-
const savedCallback = useRef(() => {});
6+
const savedCallback = useRef(noop);
57

68
// Remember the latest callback.
79
useEffect(() => {

0 commit comments

Comments
 (0)