refactor: key derivation, closes #3725

This commit is contained in:
kyranjamie
2023-05-18 14:24:18 +02:00
committed by kyranjamie
parent c329a69a52
commit 11f9461a68
37 changed files with 225 additions and 338 deletions

View File

@@ -16,14 +16,8 @@ import { useAuthRequestParams } from '@app/common/hooks/auth/use-auth-request-pa
import { useOnboardingState } from '@app/common/hooks/auth/use-onboarding-state';
import { useKeyActions } from '@app/common/hooks/use-key-actions';
import { useWalletType } from '@app/common/use-wallet-type';
import {
useAllBitcoinNativeSegWitNetworksByAccount,
useCurrentBitcoinNativeSegwitAddressIndexPublicKeychain,
} from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import {
useAllBitcoinTaprootNetworksByAccount,
useCurrentTaprootAddressIndexKeychain,
} from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { useNativeSegwitNetworkSigners } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useTaprootNetworkSigners } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { useStacksWallet } from '@app/store/accounts/blockchain/stacks/stacks-keychain';
@@ -38,11 +32,9 @@ export function useFinishAuthRequest() {
// TODO: It would be good to separate out finishing auth by the wallet vs an app
// so that the additional data we provide apps can be removed from our onboarding.
// Currently, these create errors unless early returns are used in the keychain code.
const deriveNativeSegWitAccountAtIndex = useAllBitcoinNativeSegWitNetworksByAccount();
const deriveTaprootAccountAtIndex = useAllBitcoinTaprootNetworksByAccount();
const currentBitcoinNativeSegwitAddressIndexKeychain =
useCurrentBitcoinNativeSegwitAddressIndexPublicKeychain();
const currentBitcoinTaprootAddressIndexKeychain = useCurrentTaprootAddressIndexKeychain();
// const deriveTaprootAccountAtIndex = useAllBitcoinTaprootNetworksByAccount();
const deriveAllNativeSegWitNetworkSigners = useNativeSegwitNetworkSigners();
const deriveAllTaprootNetworkSigners = useTaprootNetworkSigners();
return useCallback(
async (accountIndex: number) => {
@@ -88,6 +80,9 @@ export function useFinishAuthRequest() {
},
});
const taprootAccount = deriveAllTaprootNetworkSigners(accountIndex);
const nativeSegwitAccount = deriveAllNativeSegWitNetworkSigners(accountIndex);
const authResponse = await makeAuthResponse({
gaiaHubUrl: gaiaUrl,
appDomain: appURL.origin,
@@ -96,12 +91,18 @@ export function useFinishAuthRequest() {
account: legacyAccount,
additionalData: {
btcAddress: {
p2tr: deriveTaprootAccountAtIndex(accountIndex),
p2wpkh: deriveNativeSegWitAccountAtIndex(accountIndex),
p2tr: {
mainnet: taprootAccount.mainnet.payment.address,
testnet: taprootAccount.testnet.payment.address,
},
p2wpkh: {
mainnet: nativeSegwitAccount.mainnet.payment.address,
testnet: nativeSegwitAccount.testnet.payment.address,
},
},
btcPublicKey: {
p2tr: bytesToHex(currentBitcoinTaprootAddressIndexKeychain?.publicKey!),
p2wpkh: bytesToHex(currentBitcoinNativeSegwitAddressIndexKeychain?.publicKey!),
p2tr: bytesToHex(taprootAccount.mainnet.publicKeychain.publicKey!),
p2wpkh: bytesToHex(nativeSegwitAccount.mainnet.publicKeychain.publicKey!),
},
walletProvider: 'hiro-wallet',
},
@@ -126,10 +127,8 @@ export function useFinishAuthRequest() {
walletType,
appIcon,
appName,
deriveTaprootAccountAtIndex,
deriveNativeSegWitAccountAtIndex,
currentBitcoinTaprootAddressIndexKeychain?.publicKey,
currentBitcoinNativeSegwitAddressIndexKeychain?.publicKey,
deriveAllTaprootNetworkSigners,
deriveAllNativeSegWitNetworkSigners,
keyActions,
]
);

View File

@@ -5,14 +5,14 @@ import type { AllTransferableCryptoAssetBalances } from '@shared/models/crypto-a
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useTransferableStacksFungibleTokenAssetBalances } from '@app/query/stacks/balance/stacks-ft-balances.hooks';
import { createStacksCryptoCurrencyAssetTypeWrapper } from '@app/query/stacks/balance/stacks-ft-balances.utils';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { useStxBalance } from './balance/stx/use-stx-balance';
export function useAllTransferableCryptoAssetBalances(): AllTransferableCryptoAssetBalances[] {
const account = useCurrentStacksAccount();
const currentBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const currentBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const btcCryptoCurrencyAssetBalance = useNativeSegwitBalance(currentBtcAddress);
const { availableBalance: availableStxBalance } = useStxBalance();

View File

@@ -10,9 +10,9 @@ import { useGetUtxosByAddressQuery } from '@app/query/bitcoin/address/utxos-by-a
import { useIsStampedTx } from '@app/query/bitcoin/stamps/use-is-stamped-tx';
import { useBitcoinScureLibNetworkConfig } from '@app/store/accounts/blockchain/bitcoin/bitcoin-keychain';
import {
useCurrentAccountNativeSegwitAddressIndexZero,
useCurrentAccountNativeSegwitSigner,
useCurrentBitcoinNativeSegwitAddressIndexPublicKeychain,
useCurrentBtcNativeSegwitAccountAddressIndexZero,
} from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
interface GenerateBitcoinTxValues {
@@ -21,7 +21,7 @@ interface GenerateBitcoinTxValues {
}
export function useGenerateSignedBitcoinTx() {
const currentAccountBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const currentAccountBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const { data: utxos } = useGetUtxosByAddressQuery(currentAccountBtcAddress);
const currentAddressIndexKeychain = useCurrentBitcoinNativeSegwitAddressIndexPublicKeychain();
const createSigner = useCurrentAccountNativeSegwitSigner();

View File

@@ -10,7 +10,7 @@ import { determineUtxosForSpend } from '@app/common/transactions/bitcoin/coinsel
import { useGetUtxosByAddressQuery } from '@app/query/bitcoin/address/utxos-by-address.query';
import { useAverageBitcoinFeeRates } from '@app/query/bitcoin/fees/fee-estimates.hooks';
import { useCryptoCurrencyMarketData } from '@app/query/common/market-data/market-data.hooks';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { FeesListItem } from './bitcoin-fees-list';
@@ -19,7 +19,7 @@ interface UseBitcoinFeesListArgs {
recipient: string;
}
export function useBitcoinFeesList({ amount, recipient }: UseBitcoinFeesListArgs) {
const currentAccountBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const currentAccountBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const { data: utxos } = useGetUtxosByAddressQuery(currentAccountBtcAddress);
const btcMarketData = useCryptoCurrencyMarketData('BTC');

View File

@@ -11,7 +11,7 @@ import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { StxAvatar } from '@app/components/crypto-assets/stacks/components/stx-avatar';
import { OrdinalIcon } from '@app/components/icons/ordinal-icon';
import { useZeroIndexTaprootAddress } from '@app/query/bitcoin/ordinals/use-zero-index-taproot-address';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountStxAddressState } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { ReceiveCollectibleItem } from './receive-collectible-item';
@@ -21,7 +21,7 @@ export function ReceiveCollectible() {
const location = useLocation();
const navigate = useNavigate();
const accountIndex = get(location.state, 'accountIndex', undefined);
const btcAddressNativeSegwit = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const btcAddressNativeSegwit = useCurrentAccountNativeSegwitAddressIndexZero();
const btcAddressTaproot = useZeroIndexTaprootAddress(accountIndex);
// TODO: Reuse later for privacy mode

View File

@@ -6,7 +6,7 @@ import { useGetBitcoinTransactionsByAddressQuery } from '@app/query/bitcoin/addr
import { useConfigBitcoinEnabled } from '@app/query/common/hiro-config/hiro-config.query';
import { useStacksPendingTransactions } from '@app/query/stacks/mempool/mempool.hooks';
import { useGetAccountTransactionsWithTransfersQuery } from '@app/query/stacks/transactions/transactions-with-transfers.query';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useSubmittedTransactions } from '@app/store/submitted-transactions/submitted-transactions.selectors';
import { convertBitcoinTxsToListType, convertStacksTxsToListType } from './activity-list.utils';
@@ -16,7 +16,7 @@ import { SubmittedTransactionList } from './components/submitted-transaction-lis
import { TransactionList } from './components/transaction-list/transaction-list';
export function ActivityList() {
const bitcoinAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const bitcoinAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const { isInitialLoading: isInitialLoadingBitcoinTransactions, data: bitcoinTransactions } =
useGetBitcoinTransactionsByAddressQuery(bitcoinAddress);
const bitcoinPendingTxs = useBitcoinPendingTransactions(bitcoinAddress);

View File

@@ -7,7 +7,7 @@ import { BitcoinTransaction } from '@shared/models/transactions/bitcoin-transact
import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { useExplorerLink } from '@app/common/hooks/use-explorer-link';
import { TransactionTitle } from '@app/components/transaction/transaction-title';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { BitcoinTransactionCaption } from './bitcoin-transaction-caption';
import { BitcoinTransactionIcon } from './bitcoin-transaction-icon';
@@ -20,7 +20,7 @@ interface BitcoinTransactionItemProps extends BoxProps {
transaction?: BitcoinTransaction;
}
export function BitcoinTransactionItem({ transaction, ...rest }: BitcoinTransactionItemProps) {
const bitcoinAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const bitcoinAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const { handleOpenTxLink } = useExplorerLink();
const analytics = useAnalytics();
const caption = useMemo(() => getBitcoinTxCaption(transaction), [transaction]);

View File

@@ -2,13 +2,13 @@ import {
Brc20Token,
useBrc20TokensByAddressQuery,
} from '@app/query/bitcoin/ordinals/brc20-tokens.query';
import { useCurrentBtcTaprootAccountAddressIndexZeroPayment } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { useCurrentAccountTaprootAddressIndexZeroPayment } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
interface Brc20TokensLoaderProps {
children(brc20Tokens: Brc20Token[]): JSX.Element;
}
export function Brc20TokensLoader({ children }: Brc20TokensLoaderProps) {
const { address: bitcoinAddressTaproot } = useCurrentBtcTaprootAccountAddressIndexZeroPayment();
const { address: bitcoinAddressTaproot } = useCurrentAccountTaprootAddressIndexZeroPayment();
const { data: brc20Tokens } = useBrc20TokensByAddressQuery(bitcoinAddressTaproot);
if (!bitcoinAddressTaproot || !brc20Tokens || !brc20Tokens.result) return null;
return children(brc20Tokens.result.list);

View File

@@ -2,12 +2,12 @@ import { useEffect } from 'react';
import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { useStampsByAddressQuery } from '@app/query/bitcoin/stamps/stamps-by-address.query';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { Stamp } from './stamp';
export function Stamps() {
const currentAccountBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const currentAccountBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const { data: stamps } = useStampsByAddressQuery(currentAccountBtcAddress);
const analytics = useAnalytics();

View File

@@ -18,7 +18,7 @@ import {
useCurrentTaprootAccountUninscribedUtxos,
} from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useBitcoinBroadcastTransaction } from '@app/query/bitcoin/transaction/use-bitcoin-broadcast-transaction';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { RetrieveTaprootToNativeSegwitLayout } from './components/retrieve-taproot-to-native-segwit.layout';
import { useGenerateRetrieveTaprootFundsTx } from './use-generate-retrieve-taproot-funds-tx';
@@ -27,7 +27,7 @@ export function RetrieveTaprootToNativeSegwit() {
const navigate = useNavigate();
const { setActiveTabActivity } = useHomeTabs();
const balance = useCurrentTaprootAccountBalance();
const recipient = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const recipient = useCurrentAccountNativeSegwitAddressIndexZero();
const uninscribedUtxos = useCurrentTaprootAccountUninscribedUtxos();
const analytics = useAnalytics();
const { generateRetrieveTaprootFundsTx, fee } = useGenerateRetrieveTaprootFundsTx();

View File

@@ -13,7 +13,7 @@ import { useLoading } from '@app/common/hooks/use-loading';
import { AccountTotalBalance } from '@app/components/account-total-balance';
import { AccountListItemLayout } from '@app/components/account/account-list-item-layout';
import { usePressable } from '@app/components/item-hover';
import { useBtcNativeSegwitAccountIndexAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useNativeSegwitAccountIndexAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
import { AccountAvatarItem } from '../../../components/account/account-avatar';
@@ -31,7 +31,7 @@ export const SwitchAccountListItem = memo(
const name = useAccountDisplayName(account);
const navigate = useNavigate();
const btcAddress = useBtcNativeSegwitAccountIndexAddressIndexZero(account.index);
const btcAddress = useNativeSegwitAccountIndexAddressIndexZero(account.index);
const handleClick = async () => {
setIsLoading();

View File

@@ -24,7 +24,7 @@ import { Title } from '@app/components/typography';
import { useCryptoCurrencyMarketData } from '@app/query/common/market-data/market-data.hooks';
import { useAnchoredStacksAccountBalances } from '@app/query/stacks/balance/stx-balance.hooks';
import { useHasCreatedAccount } from '@app/store/accounts/account';
import { useBtcNativeSegwitAccountIndexAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useNativeSegwitAccountIndexAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
@@ -69,7 +69,7 @@ const ChooseAccountItem = memo((props: ChooseAccountItemProps) => {
const { data: balances, isLoading: isBalanceLoading } = useAnchoredStacksAccountBalances(
account.address
);
const btcAddress = useBtcNativeSegwitAccountIndexAddressIndexZero(account.index);
const btcAddress = useNativeSegwitAccountIndexAddressIndexZero(account.index);
const stxMarketData = useCryptoCurrencyMarketData('STX');
const showLoadingProps = !!selectedAddress || !decodedAuthRequest;

View File

@@ -4,14 +4,14 @@ import { Stack, StackProps } from '@stacks/ui';
import { CurrentAccountAvatar } from '@app/features/current-account/current-account-avatar';
import { CurrentAccountName } from '@app/features/current-account/current-account-name';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { AccountTotalBalance } from '../../../components/account-total-balance';
export const CurrentAccount = memo((props: StackProps) => {
const currentAccount = useCurrentStacksAccount();
const btcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const btcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
if (!currentAccount) return null;
return (

View File

@@ -1,8 +1,8 @@
import * as btc from '@scure/btc-signer';
import { Stack, color } from '@stacks/ui';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentBtcTaprootAccountAddressIndexZeroPayment } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountTaprootAddressIndexZeroPayment } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { PsbtInput, usePsbtDecodedRequest } from '../../hooks/use-psbt-decoded-request';
import { PsbtDecodedRequestAdvanced } from './psbt-decoded-request-views/psbt-decoded-request-advanced';
@@ -13,8 +13,8 @@ interface PsbtDecodedRequestProps {
psbt: any;
}
export function PsbtDecodedRequest({ psbt }: PsbtDecodedRequestProps) {
const bitcoinAddressNativeSegwit = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const { address: bitcoinAddressTaproot } = useCurrentBtcTaprootAccountAddressIndexZeroPayment();
const bitcoinAddressNativeSegwit = useCurrentAccountNativeSegwitAddressIndexZero();
const { address: bitcoinAddressTaproot } = useCurrentAccountTaprootAddressIndexZeroPayment();
const psbtInputs: PsbtInput[] = psbt.inputs;
const unsignedInputs: btc.TransactionInputRequired[] = psbt.global.unsignedTx.inputs;
const unsignedOutputs: btc.TransactionOutputRequired[] = psbt.global.unsignedTx.outputs;

View File

@@ -11,7 +11,7 @@ import {
OrdApiInscriptionTxOutput,
useOrdinalsAwareUtxoQueries,
} from '@app/query/bitcoin/ordinals/ordinals-aware-utxo.query';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
import { buildPsbtInputsForUi } from './build-psbt-input-for-ui';
@@ -70,7 +70,7 @@ export function usePsbtDecodedRequest({
}: UsePsbtDecodedRequestArgs) {
const [showAdvancedView, setShowAdvancedView] = useState(false);
const network = useCurrentNetwork();
const bitcoinAddressNativeSegwit = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const bitcoinAddressNativeSegwit = useCurrentAccountNativeSegwitAddressIndexZero();
const unsignedUtxos = useOrdinalsAwareUtxoQueries(unsignedInputs).map(query => query.data);
const inputs = useMemo(() => {

View File

@@ -6,7 +6,7 @@ import get from 'lodash.get';
import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { useCurrentAccountIndex } from '@app/store/accounts/account';
import { useBtcNativeSegwitAccountIndexAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useNativeSegwitAccountIndexAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { ReceiveBtcModalWarning } from './components/receive-btc-warning';
import { ReceiveTokensLayout } from './components/receive-tokens.layout';
@@ -18,7 +18,7 @@ export function ReceiveBtcModal() {
const currentAccountIndex = useCurrentAccountIndex();
const accountIndex = get(state, 'accountIndex', currentAccountIndex);
const activeAccountBtcAddress = useBtcNativeSegwitAccountIndexAddressIndexZero(accountIndex);
const activeAccountBtcAddress = useNativeSegwitAccountIndexAddressIndexZero(accountIndex);
const btcAddress = get(state, 'btcAddress', activeAccountBtcAddress);
const { onCopy } = useClipboard(btcAddress);

View File

@@ -16,13 +16,13 @@ import { Flag } from '@app/components/layout/flag';
import { QrCodeIcon } from '@app/components/qr-code-icon';
import { ReceiveCollectible } from '@app/components/receive/receive-collectible';
import { Caption } from '@app/components/typography';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountStxAddressState } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
export function ReceiveModal() {
const analytics = useAnalytics();
const navigate = useNavigate();
const btcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const btcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const stxAddress = useCurrentAccountStxAddressState();
const { onCopy: onCopyStacks } = useClipboard(stxAddress);

View File

@@ -8,8 +8,8 @@ import { makeRpcSuccessResponse } from '@shared/rpc/rpc-methods';
import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { useDefaultRequestParams } from '@app/common/hooks/use-default-request-search-params';
import { initialSearchParams } from '@app/common/initial-search-params';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentBtcTaprootAccountAddressIndexZeroPayment } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountTaprootAddressIndexZeroPayment } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks';
import { useAppPermissions } from '@app/store/app-permissions/app-permissions.slice';
@@ -30,8 +30,8 @@ export function useGetAddresses() {
const permissions = useAppPermissions();
const { tabId, origin, requestId } = useRpcRequestParams();
const nativeSegwitAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const taprootPayment = useCurrentBtcTaprootAccountAddressIndexZeroPayment();
const nativeSegwitAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const taprootPayment = useCurrentAccountTaprootAddressIndexZeroPayment();
const stacksAccount = useCurrentStacksAccount();
const taprootAddressResponse: BtcAddress = {

View File

@@ -16,7 +16,7 @@ import { satToBtc } from '@app/common/money/unit-conversion';
import { useCurrentNativeSegwitUtxos } from '@app/query/bitcoin/address/address.hooks';
import { useBitcoinBroadcastTransaction } from '@app/query/bitcoin/transaction/use-bitcoin-broadcast-transaction';
import { useCryptoCurrencyMarketData } from '@app/query/common/market-data/market-data.hooks';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { SendTransferActions } from './components/send-transfer-actions';
import { SendTransferConfirmationDetails } from './components/send-transfer-confirmation-details';
@@ -39,7 +39,7 @@ export function RpcSendTransferConfirmation() {
const navigate = useNavigate();
const { origin, requestId, tabId } = useRpcSendTransferRequestParams();
const { fee, recipient, time, tx } = useRpcSendTransferConfirmationState();
const bitcoinAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const bitcoinAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const { broadcastTx, isBroadcasting } = useBitcoinBroadcastTransaction();
const { refetch } = useCurrentNativeSegwitUtxos();
const btcMarketData = useCryptoCurrencyMarketData('BTC');

View File

@@ -3,7 +3,7 @@ import BigNumber from 'bignumber.js';
import { createMoney } from '@shared/models/money.model';
import { formatMoneyPadded } from '@app/common/money/format-money';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { SendTransferActions } from './components/send-transfer-actions';
import { SendTransferDetails } from './components/send-transfer-details';
@@ -11,7 +11,7 @@ import { SendTransferHeader } from './components/send-transfer-header';
import { useRpcSendTransfer } from './use-rpc-send-transfer';
export function RpcSendTransfer() {
const bitcoinAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const bitcoinAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const { address, amount, onChooseTransferFee, origin } = useRpcSendTransfer();
const amountAsMoney = createMoney(new BigNumber(amount), 'BTC');

View File

@@ -23,7 +23,7 @@ import {
} from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import {
useCurrentAccountTaprootSigner,
useCurrentTaprootAccountKeychain,
useTaprootCurrentAccountPrivateKeychain,
} from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
@@ -114,7 +114,7 @@ function useSignBip322MessageFactory({ address, signPsbt }: SignBip322MessageFac
function useSignBip322MessageTaproot() {
const createTaprootSigner = useCurrentAccountTaprootSigner();
if (!createTaprootSigner) throw new Error('No taproot signer for current account');
const currentAccountTaprootKeychain = useCurrentTaprootAccountKeychain();
const currentAccountTaprootKeychain = useTaprootCurrentAccountPrivateKeychain();
if (!currentAccountTaprootKeychain) throw new Error('No keychain for current account');
const signer = createTaprootSigner(0);

View File

@@ -10,7 +10,7 @@ import { AccountAvatarItem } from '@app/components/account/account-avatar';
import { AccountListItemLayout } from '@app/components/account/account-list-item-layout';
import { AccountName } from '@app/components/account/account-name';
import { usePressable } from '@app/components/item-hover';
import { useBtcNativeSegwitAccountIndexAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useNativeSegwitAccountIndexAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { StacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.models';
interface AccountListItemProps {
@@ -24,7 +24,7 @@ export const AccountListItem = memo(({ account, onClose }: AccountListItemProps)
const [component, bind] = usePressable(true);
const name = useAccountDisplayName(account);
const btcAddress = useBtcNativeSegwitAccountIndexAddressIndexZero(account.index);
const btcAddress = useNativeSegwitAccountIndexAddressIndexZero(account.index);
const onSelectAccount = () => {
const isBitcoin = values.symbol === 'BTC';

View File

@@ -10,10 +10,10 @@ import { BtcSizeFeeEstimator } from '@app/common/transactions/bitcoin/fees/btc-s
import { useGetUtxosByAddressQuery } from '@app/query/bitcoin/address/utxos-by-address.query';
import { useCurrentNativeSegwitAddressBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useAverageBitcoinFeeRates } from '@app/query/bitcoin/fees/fee-estimates.hooks';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
export function useCalculateMaxBitcoinSpend() {
const currentAccountBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const currentAccountBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const balance = useCurrentNativeSegwitAddressBalance();
const { data: utxos } = useGetUtxosByAddressQuery(currentAccountBtcAddress);
const { avgApiFeeRates: feeRates } = useAverageBitcoinFeeRates();

View File

@@ -10,7 +10,7 @@ import { BtcIcon } from '@app/components/icons/btc-icon';
import { HighFeeDrawer } from '@app/features/high-fee-drawer/high-fee-drawer';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useCryptoCurrencyMarketData } from '@app/query/common/market-data/market-data.hooks';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { AmountField } from '../../components/amount-field';
import { FormFooter } from '../../components/form-footer';
@@ -28,7 +28,7 @@ export function BtcSendForm() {
const routeState = useSendFormRouteState();
const btcMarketData = useCryptoCurrencyMarketData('BTC');
const currentAccountBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const currentAccountBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const btcBalance = useNativeSegwitBalance(currentAccountBtcAddress);
const {

View File

@@ -24,7 +24,7 @@ import {
} from '@app/common/validation/forms/currency-validators';
import { useUpdatePersistedSendFormValues } from '@app/features/popup-send-form-restoration/use-update-persisted-send-form-values';
import { useNativeSegwitBalance } from '@app/query/bitcoin/balance/bitcoin-balances.query';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
import { useCalculateMaxBitcoinSpend } from '../../family/bitcoin/hooks/use-calculate-max-spend';
@@ -33,7 +33,7 @@ import { useSendFormNavigate } from '../../hooks/use-send-form-navigate';
export function useBtcSendForm() {
const formRef = useRef<FormikProps<BitcoinSendFormValues>>(null);
const currentNetwork = useCurrentNetwork();
const currentAccountBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const currentAccountBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const btcCryptoCurrencyAssetBalance = useNativeSegwitBalance(currentAccountBtcAddress);
const { whenWallet } = useWalletType();
const sendFormNavigate = useSendFormNavigate();

View File

@@ -1,8 +1,8 @@
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useGetUtxosByAddressQuery } from './utxos-by-address.query';
export function useCurrentNativeSegwitUtxos() {
const currentAccountBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const currentAccountBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
return useGetUtxosByAddressQuery(currentAccountBtcAddress);
}

View File

@@ -6,7 +6,7 @@ import { createMoney } from '@shared/models/money.model';
import { isDefined } from '@shared/utils';
import { sumNumbers } from '@app/common/math/helpers';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { createBitcoinCryptoCurrencyAssetTypeWrapper } from '../address/address.utils';
import { useGetUtxosByAddressQuery } from '../address/utxos-by-address.query';
@@ -29,7 +29,7 @@ export function useNativeSegwitBalance(address: string) {
}
export function useCurrentNativeSegwitAddressBalance() {
const currentAccountBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const currentAccountBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
return useGetBitcoinBalanceByAddress(currentAccountBtcAddress);
}

View File

@@ -7,7 +7,7 @@ import { InscriptionResponseItem } from '@shared/models/inscription.model';
import { createNumArrayOfRange } from '@app/common/utils';
import { QueryPrefixes } from '@app/query/query-prefixes';
import { useCurrentAccountIndex } from '@app/store/accounts/account';
import { useCurrentTaprootAccountKeychain } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { useTaprootCurrentAccountPrivateKeychain } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
import { getTaprootAddress } from './utils';
@@ -46,7 +46,7 @@ async function fetchInscriptions(addresses: string, offset = 0) {
*/
export function useInscriptionsInfiniteQuery() {
const network = useCurrentNetwork();
const keychain = useCurrentTaprootAccountKeychain();
const keychain = useTaprootCurrentAccountPrivateKeychain();
const currentAccountIndex = useCurrentAccountIndex();
// TO-DO remove code for testing purposes before merge

View File

@@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query';
import { createCounter } from '@app/common/utils/counter';
import { useCurrentAccountIndex } from '@app/store/accounts/account';
import { useCurrentTaprootAccountKeychain } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { useTaprootCurrentAccountPrivateKeychain } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks';
import { useBitcoinClient } from '@app/store/common/api-clients.hooks';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
@@ -22,7 +22,7 @@ export interface TaprootUtxo extends UtxoResponseItem {
*/
export function useTaprootAccountUtxosQuery() {
const network = useCurrentNetwork();
const keychain = useCurrentTaprootAccountKeychain();
const keychain = useTaprootCurrentAccountPrivateKeychain();
const client = useBitcoinClient();
const currentAccountIndex = useCurrentAccountIndex();

View File

@@ -16,6 +16,7 @@ interface GetTaprootAddressArgs {
}
export function getTaprootAddress({ index, keychain, network }: GetTaprootAddressArgs) {
if (!keychain) throw new Error('Expected keychain to be provided');
if (keychain.depth !== DerivationPathDepth.Account)
throw new Error('Expects keychain to be on the account index');

View File

@@ -1,11 +1,11 @@
import { useCallback } from 'react';
import { useCurrentBtcNativeSegwitAccountAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useCurrentAccountNativeSegwitAddressIndexZero } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks';
import { useStampsByAddressQuery } from './stamps-by-address.query';
export function useIsStampedTx() {
const currentAccountBtcAddress = useCurrentBtcNativeSegwitAccountAddressIndexZero();
const currentAccountBtcAddress = useCurrentAccountNativeSegwitAddressIndexZero();
const { data: stamps = [] } = useStampsByAddressQuery(currentAccountBtcAddress);
return useCallback((txid: string) => stamps.some(stamp => stamp.tx_hash === txid), [stamps]);

View File

@@ -1,41 +0,0 @@
import { HDKey } from '@scure/bip32';
import { DerivationPathDepth } from '@shared/crypto/derivation-path.utils';
interface SoftwareBitcoinAccount {
type: 'software';
xpub: string;
index: number;
keychain: HDKey;
}
// TODO: complete with bitcoin ledger support
interface HardwareBitcoinAccount {
type: 'ledger';
path: string;
index: number;
xpub: string;
}
// ts-unused-exports:disable-next-line
export type BitcoinAccount = SoftwareBitcoinAccount | HardwareBitcoinAccount;
export const tempHardwareAccountForTesting: HardwareBitcoinAccount = {
type: 'ledger',
index: 0,
path: '',
xpub: '',
};
export function formatBitcoinAccount(keychain: HDKey) {
if (keychain.depth !== DerivationPathDepth.Account)
throw new Error('Can only format from account keychain');
return (index: number): SoftwareBitcoinAccount => ({
type: 'software',
index,
// The rationale for wrapping the keychain is so we pass around the xpub
// rather than the private-key containing HDKey
xpub: keychain.publicExtendedKey,
keychain: HDKey.fromExtendedKey(keychain.publicExtendedKey),
});
}

View File

@@ -1,14 +1,19 @@
import { useCallback } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import { HDKey } from '@scure/bip32';
import * as btc from '@scure/btc-signer';
import { BitcoinNetworkModes, NetworkModes } from '@shared/constants';
import { getBtcSignerLibNetworkConfigByMode } from '@shared/crypto/bitcoin/bitcoin.network';
import { deriveAddressIndexZeroFromAccount } from '@shared/crypto/bitcoin/bitcoin.utils';
import {
deriveAddressIndexKeychainFromAccount,
deriveAddressIndexZeroFromAccount,
} from '@shared/crypto/bitcoin/bitcoin.utils';
import { deriveTaprootAccountFromRootKeychain } from '@shared/crypto/bitcoin/p2tr-address-gen';
import {
deriveNativeSegWitAccountKeychain,
getNativeSegWitPaymentFromKeychain,
getNativeSegWitPaymentFromAddressIndex,
} from '@shared/crypto/bitcoin/p2wpkh-address-gen';
import { mnemonicToRootNode } from '@app/common/keychain/keychain';
@@ -20,7 +25,7 @@ import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
// This factory selector extends from the wallet root keychain to derive child
// keychains. It accepts a curried fn that takes a keychain and returns a fn
// accepting an account index, to further derive a nested layer of derivation.
// We use this approach to reuse code between both native segwit and taproot
// This approach allow us to reuse code between both native segwit and taproot
// keychains.
function bitcoinKeychainSelectorFactory(
keychainFn: (hdkey: HDKey, network: NetworkModes) => (index: number) => HDKey,
@@ -39,7 +44,7 @@ export function getNativeSegwitMainnetAddressFromMnemonic(secretKey: string) {
return (accountIndex: number) => {
const rootNode = mnemonicToRootNode(secretKey);
const account = deriveNativeSegWitAccountKeychain(rootNode, 'mainnet')(accountIndex);
return getNativeSegWitPaymentFromKeychain(
return getNativeSegWitPaymentFromAddressIndex(
deriveAddressIndexZeroFromAccount(account),
'mainnet'
);
@@ -72,15 +77,19 @@ export function useBitcoinScureLibNetworkConfig() {
}
interface BitcoinSignerFactoryArgs {
addressIndexKeychainFn(addressIndex: number): HDKey;
accountKeychain: HDKey;
paymentFn(keychain: HDKey, network: BitcoinNetworkModes): unknown;
network: BitcoinNetworkModes;
}
export function bitcoinSignerFactory<T extends BitcoinSignerFactoryArgs>(args: T) {
const { network, paymentFn, addressIndexKeychainFn } = args;
const { network, paymentFn, accountKeychain } = args;
return (addressIndex: number) => {
const addressIndexKeychain = addressIndexKeychainFn(addressIndex);
const addressIndexKeychain =
deriveAddressIndexKeychainFromAccount(accountKeychain)(addressIndex);
return {
addressIndex,
publicKeychain: HDKey.fromExtendedKey(addressIndexKeychain.publicExtendedKey),
payment: paymentFn(addressIndexKeychain, network) as ReturnType<T['paymentFn']>,
sign(tx: btc.Transaction) {
if (!addressIndexKeychain.privateKey)
@@ -97,3 +106,56 @@ export function bitcoinSignerFactory<T extends BitcoinSignerFactoryArgs>(args: T
};
};
}
interface CreateSignersForAllNetworkTypesArgs {
mainnetKeychainFn: (accountIndex: number) => HDKey;
testnetKeychainFn: (accountIndex: number) => HDKey;
paymentFn: (keychain: HDKey, network: BitcoinNetworkModes) => unknown;
}
function createSignersForAllNetworkTypes<T extends CreateSignersForAllNetworkTypesArgs>({
mainnetKeychainFn,
testnetKeychainFn,
paymentFn,
}: T) {
return ({ accountIndex, addressIndex }: { accountIndex: number; addressIndex: number }) => {
const mainnetAccount = mainnetKeychainFn(accountIndex);
const testnetAccount = testnetKeychainFn(accountIndex);
function makeNetworkSigner(keychain: HDKey, network: BitcoinNetworkModes) {
return bitcoinSignerFactory({
accountKeychain: keychain,
paymentFn: paymentFn as T['paymentFn'],
network,
})(addressIndex);
}
return {
mainnet: makeNetworkSigner(mainnetAccount, 'mainnet'),
testnet: makeNetworkSigner(testnetAccount, 'testnet'),
regtest: makeNetworkSigner(testnetAccount, 'regtest'),
signet: makeNetworkSigner(testnetAccount, 'signet'),
};
};
}
export function useMakeBitcoinNetworkSignersForPaymentType<T>(
mainnetKeychainFn: ((index: number) => HDKey) | undefined,
testnetKeychainFn: ((index: number) => HDKey) | undefined,
paymentFn: (keychain: HDKey, network: BitcoinNetworkModes) => T
) {
return useCallback(
(accountIndex: number) => {
if (!mainnetKeychainFn || !testnetKeychainFn)
throw new Error('Cannot derive addresses in non-software mode');
const zeroIndex = 0;
return createSignersForAllNetworkTypes({
mainnetKeychainFn,
testnetKeychainFn,
paymentFn,
})({ accountIndex, addressIndex: zeroIndex });
},
[mainnetKeychainFn, paymentFn, testnetKeychainFn]
);
}

View File

@@ -1,23 +1,8 @@
import { useCallback, useMemo } from 'react';
import { useSelector } from 'react-redux';
import { HDKey } from '@scure/bip32';
import {
deriveAddressIndexKeychainFromAccount,
deriveAddressIndexZeroFromAccount,
} from '@shared/crypto/bitcoin/bitcoin.utils';
import {
deriveNativeSegWitReceiveAddressIndex,
getNativeSegWitPaymentFromKeychain,
} from '@shared/crypto/bitcoin/p2wpkh-address-gen';
import { isUndefined } from '@shared/utils';
import { getNativeSegWitPaymentFromAddressIndex } from '@shared/crypto/bitcoin/p2wpkh-address-gen';
import { bitcoinNetworkModeToCoreNetworkMode, whenNetwork } from '@app/common/utils';
import {
formatBitcoinAccount,
tempHardwareAccountForTesting,
} from '@app/store/accounts/blockchain/bitcoin/bitcoin-account.models';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
import { useCurrentAccountIndex } from '../../account';
@@ -25,9 +10,10 @@ import {
bitcoinSignerFactory,
selectMainnetNativeSegWitKeychain,
selectTestnetNativeSegWitKeychain,
useMakeBitcoinNetworkSignersForPaymentType,
} from './bitcoin-keychain';
function useNativeSegwitAccountKeychain() {
function useNativeSegwitActiveNetworkAccountPrivateKeychain() {
const network = useCurrentNetwork();
return useSelector(
whenNetwork(bitcoinNetworkModeToCoreNetworkMode(network.chain.bitcoin.network))({
@@ -38,100 +24,53 @@ function useNativeSegwitAccountKeychain() {
}
export function useNativeSegwitCurrentAccountPrivateKeychain() {
const keychain = useNativeSegwitAccountKeychain();
const keychain = useNativeSegwitActiveNetworkAccountPrivateKeychain();
const currentAccountIndex = useCurrentAccountIndex();
return keychain?.(currentAccountIndex);
}
function useCurrentBitcoinNativeSegwitAccountPublicKeychain() {
const { xpub } = useCurrentBitcoinNativeSegwitAccountInfo();
if (!xpub) return; // TODO: Revisit this return early
const keychain = HDKey.fromExtendedKey(xpub);
if (!keychain.publicKey) throw new Error('No public key for given keychain');
if (!keychain.pubKeyHash) throw new Error('No pub key hash for given keychain');
return keychain;
}
export function useNativeSegwitNetworkSigners() {
const mainnetKeychainFn = useSelector(selectMainnetNativeSegWitKeychain);
const testnetKeychainFn = useSelector(selectTestnetNativeSegWitKeychain);
// Concept of current address index won't exist with privacy mode
export function useCurrentBitcoinNativeSegwitAddressIndexPublicKeychain() {
const keychain = useCurrentBitcoinNativeSegwitAccountPublicKeychain();
if (!keychain) return; // TODO: Revisit this return early
return deriveAddressIndexZeroFromAccount(keychain);
}
export function useAllBitcoinNativeSegWitNetworksByAccount() {
const mainnetKeychainAtAccount = useSelector(selectMainnetNativeSegWitKeychain);
const testnetKeychainAtAccount = useSelector(selectTestnetNativeSegWitKeychain);
return useCallback(
(accountIndex: number) => {
if (!mainnetKeychainAtAccount || !testnetKeychainAtAccount)
throw new Error('Cannot derive addresses in non-software mode');
return {
mainnet: deriveNativeSegWitReceiveAddressIndex({
xpub: mainnetKeychainAtAccount(accountIndex).publicExtendedKey,
network: 'mainnet',
})?.address,
testnet: deriveNativeSegWitReceiveAddressIndex({
xpub: testnetKeychainAtAccount(accountIndex).publicExtendedKey,
network: 'testnet',
})?.address,
regtest: deriveNativeSegWitReceiveAddressIndex({
xpub: testnetKeychainAtAccount(accountIndex).publicExtendedKey,
network: 'regtest',
})?.address,
};
},
[mainnetKeychainAtAccount, testnetKeychainAtAccount]
return useMakeBitcoinNetworkSignersForPaymentType(
mainnetKeychainFn,
testnetKeychainFn,
getNativeSegWitPaymentFromAddressIndex
);
}
function useBitcoinNativeSegwitAccountInfo(index: number) {
const keychain = useNativeSegwitAccountKeychain();
return useMemo(() => {
// TODO: Remove with bitcoin Ledger integration
if (isUndefined(keychain)) return tempHardwareAccountForTesting;
return formatBitcoinAccount(keychain(index))(index);
}, [keychain, index]);
function useCurrentAccountNativeSegwitSignerIndexZero() {
return useCurrentAccountNativeSegwitSigner()?.(0);
}
function useCurrentBitcoinNativeSegwitAccountInfo() {
const currentAccountIndex = useCurrentAccountIndex();
return useBitcoinNativeSegwitAccountInfo(currentAccountIndex);
}
function useDeriveNativeSegWitAccountIndexAddressIndexZero(xpub: string) {
function useNativeSegwitSigner(accountIndex: number) {
const network = useCurrentNetwork();
return useMemo(
() =>
deriveNativeSegWitReceiveAddressIndex({
xpub,
network: network.chain.bitcoin.network,
}),
[xpub, network]
);
}
export function useCurrentBtcNativeSegwitAccountAddressIndexZero() {
const { xpub } = useCurrentBitcoinNativeSegwitAccountInfo();
return useDeriveNativeSegWitAccountIndexAddressIndexZero(xpub)?.address as string;
}
export function useBtcNativeSegwitAccountIndexAddressIndexZero(accountIndex: number) {
const { xpub } = useBitcoinNativeSegwitAccountInfo(accountIndex);
return useDeriveNativeSegWitAccountIndexAddressIndexZero(xpub)?.address as string;
}
export function useCurrentAccountNativeSegwitSigner() {
const network = useCurrentNetwork();
const index = useCurrentAccountIndex();
const accountKeychain = useNativeSegwitAccountKeychain()?.(index);
const accountKeychain = useNativeSegwitActiveNetworkAccountPrivateKeychain()?.(accountIndex);
if (!accountKeychain) return;
const addressIndexKeychainFn = deriveAddressIndexKeychainFromAccount(accountKeychain);
return bitcoinSignerFactory({
addressIndexKeychainFn,
paymentFn: getNativeSegWitPaymentFromKeychain,
accountKeychain,
paymentFn: getNativeSegWitPaymentFromAddressIndex,
network: network.chain.bitcoin.network,
});
}
export function useCurrentAccountNativeSegwitSigner() {
const currentAccountIndex = useCurrentAccountIndex();
return useNativeSegwitSigner(currentAccountIndex);
}
export function useCurrentAccountNativeSegwitAddressIndexZero() {
const signer = useCurrentAccountNativeSegwitSignerIndexZero();
return signer?.payment.address as string;
}
export function useNativeSegwitAccountIndexAddressIndexZero(accountIndex: number) {
const signer = useNativeSegwitSigner(accountIndex)?.(0);
return signer?.payment.address as string;
}
export function useCurrentBitcoinNativeSegwitAddressIndexPublicKeychain() {
const signer = useCurrentAccountNativeSegwitSignerIndexZero();
return signer?.publicKeychain;
}

View File

@@ -1,28 +1,20 @@
import { useCallback, useMemo } from 'react';
import { useSelector } from 'react-redux';
import {
deriveAddressIndexKeychainFromAccount,
deriveAddressIndexZeroFromAccount,
} from '@shared/crypto/bitcoin/bitcoin.utils';
import {
deriveTaprootReceiveAddressIndex,
getTaprootPaymentFromAddressIndex,
} from '@shared/crypto/bitcoin/p2tr-address-gen';
import { isUndefined } from '@shared/utils';
import { BitcoinNetworkModes } from '@shared/constants';
import { getTaprootPaymentFromAddressIndex } from '@shared/crypto/bitcoin/p2tr-address-gen';
import { bitcoinNetworkModeToCoreNetworkMode, whenNetwork } from '@app/common/utils';
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
import { useCurrentAccountIndex } from '../../account';
import { formatBitcoinAccount, tempHardwareAccountForTesting } from './bitcoin-account.models';
import {
bitcoinSignerFactory,
selectMainnetTaprootKeychain,
selectTestnetTaprootKeychain,
useMakeBitcoinNetworkSignersForPaymentType,
} from './bitcoin-keychain';
function useTaprootCurrentNetworkAccountPrivateKeychain() {
function useTaprootActiveNetworkAccountPrivateKeychain() {
const network = useCurrentNetwork();
return useSelector(
whenNetwork(bitcoinNetworkModeToCoreNetworkMode(network.chain.bitcoin.network))({
@@ -32,97 +24,49 @@ function useTaprootCurrentNetworkAccountPrivateKeychain() {
);
}
export function useCurrentTaprootAccountKeychain() {
export function useTaprootCurrentAccountPrivateKeychain() {
const currentAccountIndex = useCurrentAccountIndex();
return useTaprootAccountKeychain(currentAccountIndex);
}
export function useTaprootAccountKeychain(accountIndex: number) {
const accountKeychain = useTaprootCurrentNetworkAccountPrivateKeychain();
const accountKeychain = useTaprootActiveNetworkAccountPrivateKeychain();
if (!accountKeychain) return; // TODO: Revisit this return early
return accountKeychain(accountIndex);
}
// Concept of current address index won't exist with privacy mode
export function useCurrentTaprootAddressIndexKeychain() {
const keychain = useCurrentTaprootAccountKeychain();
if (!keychain) return; // TODO: Revisit this return early
return deriveAddressIndexZeroFromAccount(keychain);
}
export function useTaprootNetworkSigners() {
const mainnetKeychainFn = useSelector(selectMainnetTaprootKeychain);
const testnetKeychainFn = useSelector(selectTestnetTaprootKeychain);
function useBitcoinTaprootAccountInfo(index: number) {
const keychain = useTaprootCurrentNetworkAccountPrivateKeychain();
return useMemo(() => {
// TODO: Remove with bitcoin Ledger integration
if (isUndefined(keychain)) return tempHardwareAccountForTesting;
return formatBitcoinAccount(keychain(index))(index);
}, [keychain, index]);
}
function useCurrentBitcoinTaprootAccountInfo() {
const currentAccountIndex = useCurrentAccountIndex();
return useBitcoinTaprootAccountInfo(currentAccountIndex);
}
function useDeriveTaprootAccountIndexAddressIndexZero(xpub: string) {
const network = useCurrentNetwork();
return useMemo(
() =>
deriveTaprootReceiveAddressIndex({
xpub,
index: 0,
network: network.chain.bitcoin.network,
}),
[xpub, network]
return useMakeBitcoinNetworkSignersForPaymentType(
mainnetKeychainFn,
testnetKeychainFn,
getTaprootPaymentFromAddressIndex
);
}
export function useCurrentBtcTaprootAccountAddressIndexZeroPayment() {
const { xpub } = useCurrentBitcoinTaprootAccountInfo();
const payment = useDeriveTaprootAccountIndexAddressIndexZero(xpub);
if (!payment?.address) throw new Error('No address found');
// Creating new object to have known property types
return { address: payment.address, type: payment.type };
}
function useTaprootSigner(accountIndex: number, network: BitcoinNetworkModes) {
const accountKeychain = useTaprootAccountKeychain(accountIndex);
if (!accountKeychain) return; // TODO: Revisit this return early
// TODO: Address index 0 is hardcoded here bc this is only used to pass the first
// taproot address to the app thru the auth response. This is only temporary, it
// should be removed once the request address api is in place.
export function useAllBitcoinTaprootNetworksByAccount() {
const mainnetKeychainAtAccount = useSelector(selectMainnetTaprootKeychain);
const testnetKeychainAtAccount = useSelector(selectTestnetTaprootKeychain);
return useCallback(
(accountIndex: number) => {
if (!mainnetKeychainAtAccount || !testnetKeychainAtAccount)
throw new Error('Cannot derive addresses in non-software mode');
return {
mainnet: deriveTaprootReceiveAddressIndex({
xpub: mainnetKeychainAtAccount(accountIndex).publicExtendedKey,
index: 0,
network: 'mainnet',
})?.address,
testnet: deriveTaprootReceiveAddressIndex({
xpub: testnetKeychainAtAccount(accountIndex).publicExtendedKey,
index: 0,
network: 'testnet',
})?.address,
};
},
[mainnetKeychainAtAccount, testnetKeychainAtAccount]
);
return bitcoinSignerFactory({
accountKeychain,
paymentFn: getTaprootPaymentFromAddressIndex,
network,
});
}
export function useCurrentAccountTaprootSigner() {
const currentAccountIndex = useCurrentAccountIndex();
const network = useCurrentNetwork();
const accountKeychain = useCurrentTaprootAccountKeychain();
if (!accountKeychain) return; // TODO: Revisit this return early
const addressIndexKeychainFn = deriveAddressIndexKeychainFromAccount(accountKeychain);
return bitcoinSignerFactory({
addressIndexKeychainFn,
paymentFn: getTaprootPaymentFromAddressIndex,
network: network.chain.bitcoin.network,
});
return useTaprootSigner(currentAccountIndex, network.chain.bitcoin.network);
}
export function useCurrentAccountTaprootAddressIndexZeroPayment() {
const createSigner = useCurrentAccountTaprootSigner();
const indexZeroSigner = createSigner?.(0);
if (!indexZeroSigner?.payment.address) throw new Error('No address found');
// Creating new object to have known property types
return { address: indexZeroSigner.payment.address, type: indexZeroSigner.payment.type };
}

View File

@@ -5,11 +5,7 @@ import { BitcoinNetworkModes, NetworkModes } from '@shared/constants';
import { DerivationPathDepth } from '../derivation-path.utils';
import { getBtcSignerLibNetworkConfigByMode } from './bitcoin.network';
import {
deriveAddressIndexKeychainFromAccount,
ecdsaPublicKeyToSchnorr,
getBitcoinCoinTypeIndexByNetwork,
} from './bitcoin.utils';
import { ecdsaPublicKeyToSchnorr, getBitcoinCoinTypeIndexByNetwork } from './bitcoin.utils';
function getTaprootAccountDerivationPath(network: NetworkModes, accountIndex: number) {
return `m/86'/${getBitcoinCoinTypeIndexByNetwork(network)}'/${accountIndex}'`;
@@ -38,19 +34,3 @@ export function getTaprootPaymentFromAddressIndex(keychain: HDKey, network: Bitc
return getTaprootPayment(keychain.publicKey, network);
}
interface DeriveTaprootReceiveAddressIndexArgs {
xpub: string;
index: number;
network: BitcoinNetworkModes;
}
export function deriveTaprootReceiveAddressIndex({
xpub,
index,
network,
}: DeriveTaprootReceiveAddressIndexArgs) {
if (!xpub) return;
const keychain = HDKey.fromExtendedKey(xpub);
const addressIndexKeychain = deriveAddressIndexKeychainFromAccount(keychain)(index);
return getTaprootPayment(addressIndexKeychain.publicKey!, network);
}

View File

@@ -19,7 +19,10 @@ export function deriveNativeSegWitAccountKeychain(keychain: HDKey, network: Netw
return (index: number) => keychain.derive(getNativeSegWitAccountDerivationPath(network, index));
}
export function getNativeSegWitPaymentFromKeychain(keychain: HDKey, network: BitcoinNetworkModes) {
export function getNativeSegWitPaymentFromAddressIndex(
keychain: HDKey,
network: BitcoinNetworkModes
) {
if (keychain.depth !== DerivationPathDepth.AddressIndex)
throw new Error('Keychain passed is not an address index');
@@ -40,5 +43,5 @@ export function deriveNativeSegWitReceiveAddressIndex({
const keychain = HDKey.fromExtendedKey(xpub);
if (!keychain) return;
const zeroAddressIndex = deriveAddressIndexZeroFromAccount(keychain);
return getNativeSegWitPaymentFromKeychain(zeroAddressIndex, network);
return getNativeSegWitPaymentFromAddressIndex(zeroAddressIndex, network);
}