Skip to content

Commit

Permalink
fix: regtest addresses, closes #4223
Browse files Browse the repository at this point in the history
  • Loading branch information
kyranjamie committed Oct 6, 2023
1 parent 4341cbd commit eedbed5
Show file tree
Hide file tree
Showing 16 changed files with 59 additions and 44 deletions.
10 changes: 7 additions & 3 deletions src/app/store/accounts/blockchain/bitcoin/bitcoin-keychain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useMemo } from 'react';
import { createSelector } from '@reduxjs/toolkit';
import { HDKey, Versions } from '@scure/bip32';

import { NetworkModes } from '@shared/constants';
import { BitcoinNetworkModes } from '@shared/constants';
import { getBtcSignerLibNetworkConfigByMode } from '@shared/crypto/bitcoin/bitcoin.network';
import {
BitcoinAccount,
Expand All @@ -25,11 +25,11 @@ import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
export function bitcoinAccountBuilderFactory(
softwareKeychainDerivationFn: (
key: HDKey,
network: NetworkModes
network: BitcoinNetworkModes
) => (accountIndex: number) => BitcoinAccount,
ledgerKeychainLookupFn: (
keyMap: Record<string, { policy: string } | undefined>,
network: NetworkModes
network: BitcoinNetworkModes
) => (accountIndex: number) => BitcoinAccount | undefined
) {
return createSelector(
Expand All @@ -42,12 +42,16 @@ export function bitcoinAccountBuilderFactory(
return {
mainnet: ledgerKeychainLookupFn(bitcoinLedgerKeys, 'mainnet'),
testnet: ledgerKeychainLookupFn(bitcoinLedgerKeys, 'testnet'),
signet: ledgerKeychainLookupFn(bitcoinLedgerKeys, 'signet'),
regtest: ledgerKeychainLookupFn(bitcoinLedgerKeys, 'regtest'),
};
}
if (!rootKeychain) throw new Error('No in-memory key found');
return {
mainnet: softwareKeychainDerivationFn(rootKeychain, 'mainnet'),
testnet: softwareKeychainDerivationFn(rootKeychain, 'testnet'),
signet: softwareKeychainDerivationFn(rootKeychain, 'signet'),
regtest: softwareKeychainDerivationFn(rootKeychain, 'regtest'),
};
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { useSelector } from 'react-redux';
import { createSelector } from '@reduxjs/toolkit';

import {
bitcoinNetworkModeToCoreNetworkMode,
deriveAddressIndexZeroFromAccount,
lookUpLedgerKeysByPath,
} from '@shared/crypto/bitcoin/bitcoin.utils';
Expand Down Expand Up @@ -36,8 +35,7 @@ const selectNativeSegwitAccountBuilder = bitcoinAccountBuilderFactory(
const selectCurrentNetworkNativeSegwitAccountBuilder = createSelector(
selectNativeSegwitAccountBuilder,
selectCurrentNetwork,
(nativeSegwitKeychain, network) =>
nativeSegwitKeychain[bitcoinNetworkModeToCoreNetworkMode(network.chain.bitcoin.network)]
(nativeSegwitKeychains, network) => nativeSegwitKeychains[network.chain.bitcoin.network]
);

export function useNativeSegwitAccountBuilder() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import { useSelector } from 'react-redux';
import { createSelector } from '@reduxjs/toolkit';

import { BitcoinNetworkModes } from '@shared/constants';
import {
bitcoinNetworkModeToCoreNetworkMode,
lookUpLedgerKeysByPath,
} from '@shared/crypto/bitcoin/bitcoin.utils';
import { lookUpLedgerKeysByPath } from '@shared/crypto/bitcoin/bitcoin.utils';
import {
deriveTaprootAccount,
getTaprootAccountDerivationPath,
Expand Down Expand Up @@ -35,8 +32,7 @@ const selectTaprootAccountBuilder = bitcoinAccountBuilderFactory(
const selectCurrentNetworkTaprootAccountBuilder = createSelector(
selectTaprootAccountBuilder,
selectCurrentNetwork,
(taprootKeychain, network) =>
taprootKeychain[bitcoinNetworkModeToCoreNetworkMode(network.chain.bitcoin.network)]
(taprootKeychains, network) => taprootKeychains[network.chain.bitcoin.network]
);
const selectCurrentTaprootAccount = createSelector(
selectCurrentNetworkTaprootAccountBuilder,
Expand Down
4 changes: 2 additions & 2 deletions src/app/store/accounts/blockchain/stacks/stacks-accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { deriveStxPrivateKey, generateWallet } from '@stacks/wallet-sdk';
import { atom } from 'jotai';

import { DATA_DERIVATION_PATH, deriveStacksSalt } from '@shared/crypto/stacks/stacks-address-gen';
import { defaultWalletKeyId } from '@shared/utils';

import { derivePublicKey } from '@app/common/keychain/keychain';
import { createNullArrayOfLength } from '@app/common/utils';
Expand All @@ -25,7 +26,6 @@ import {
import { selectLedgerKey } from '@app/store/keys/key.selectors';
import { addressNetworkVersionState } from '@app/store/transactions/transaction';

import { defaultKeyId } from '../../../keys/key.slice';
import {
HardwareStacksAccount,
SoftwareStacksAccount,
Expand Down Expand Up @@ -62,7 +62,7 @@ const selectStacksWalletState = createSelector(
selectStacksChain,
(keychain, chain) => {
if (!keychain) return;
const { highestAccountIndex, currentAccountIndex } = chain[defaultKeyId];
const { highestAccountIndex, currentAccountIndex } = chain[defaultWalletKeyId];
const numberOfAccountsToDerive = Math.max(highestAccountIndex, currentAccountIndex) + 1;
return createNullArrayOfLength(numberOfAccountsToDerive).map((_, index) =>
initalizeStacksAccount(keychain, index)
Expand Down
6 changes: 4 additions & 2 deletions src/app/store/chains/stx-chain.slice.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { PayloadAction, createSlice } from '@reduxjs/toolkit';

import { defaultKeyId, keySlice } from '../keys/key.slice';
import { defaultWalletKeyId } from '@shared/utils';

import { keySlice } from '../keys/key.slice';

interface StxChainKeyState {
highestAccountIndex: number;
currentAccountIndex: number;
}

const initialState: Record<string, StxChainKeyState> = {
[defaultKeyId]: {
[defaultWalletKeyId]: {
highestAccountIndex: 0,
currentAccountIndex: 0,
},
Expand Down
5 changes: 3 additions & 2 deletions src/app/store/in-memory-key/in-memory-key.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ import { useSelector } from 'react-redux';

import { createSelector } from '@reduxjs/toolkit';

import { defaultWalletKeyId } from '@shared/utils';

import { mnemonicToRootNode } from '@app/common/keychain/keychain';

import { RootState } from '..';
import { defaultKeyId } from '../keys/key.slice';

const selectInMemoryKey = (state: RootState) => state.inMemoryKeys;

export const selectDefaultWalletKey = createSelector(
selectInMemoryKey,
state => state.keys[defaultKeyId]
state => state.keys[defaultWalletKeyId]
);

export const selectRootKeychain = createSelector(selectDefaultWalletKey, key => {
Expand Down
9 changes: 5 additions & 4 deletions src/app/store/in-memory-key/in-memory-key.slice.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { PayloadAction, createSlice } from '@reduxjs/toolkit';

import { logger } from '@shared/logger';
import { defaultWalletKeyId } from '@shared/utils';

import { defaultKeyId, keySlice } from '../keys/key.slice';
import { keySlice } from '../keys/key.slice';

interface InMemoryKeyState {
hasRestoredKeys: boolean;
Expand All @@ -20,15 +21,15 @@ export const inMemoryKeySlice = createSlice({

reducers: {
generateWalletKey(state, action: PayloadAction<string>) {
if (state.keys[defaultKeyId]) {
if (state.keys[defaultWalletKeyId]) {
logger.warn('Not generating another wallet, already exists.');
return;
}
state.keys[defaultKeyId] = action.payload;
state.keys[defaultWalletKeyId] = action.payload;
},

saveUsersSecretKeyToBeRestored(state, action: PayloadAction<string>) {
state.keys[defaultKeyId] = action.payload;
state.keys[defaultWalletKeyId] = action.payload;
},

setKeysInMemory(state, action: PayloadAction<Record<string, string>>) {
Expand Down
5 changes: 3 additions & 2 deletions src/app/store/keys/key.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AddressVersion } from '@stacks/transactions';

import { decryptMnemonic, encryptMnemonic } from '@shared/crypto/mnemonic-encryption';
import { logger } from '@shared/logger';
import { defaultWalletKeyId } from '@shared/utils';
import { identifyUser } from '@shared/utils/analytics';

import { recurseAccountsForActivity } from '@app/common/account-restoration/account-restore';
Expand All @@ -19,7 +20,7 @@ import { stxChainSlice } from '../chains/stx-chain.slice';
import { selectDefaultWalletKey } from '../in-memory-key/in-memory-key.selectors';
import { inMemoryKeySlice } from '../in-memory-key/in-memory-key.slice';
import { selectCurrentKey } from './key.selectors';
import { defaultKeyId, keySlice } from './key.slice';
import { keySlice } from './key.slice';

function setWalletEncryptionPassword(args: {
password: string;
Expand Down Expand Up @@ -86,7 +87,7 @@ function setWalletEncryptionPassword(args: {
dispatch(
keySlice.actions.createStacksSoftwareWalletComplete({
type: 'software',
id: defaultKeyId,
id: defaultWalletKeyId,
salt,
encryptedSecretKey,
})
Expand Down
7 changes: 4 additions & 3 deletions src/app/store/keys/key.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import { useSelector } from 'react-redux';

import { createSelector } from '@reduxjs/toolkit';

import { defaultWalletKeyId } from '@shared/utils';

import { initialSearchParams } from '@app/common/initial-search-params';
import { initBigNumber } from '@app/common/math/helpers';
import { RootState } from '@app/store';

import { selectStacksChain } from '../chains/stx-chain.selectors';
import { defaultKeyId } from './key.slice';

const selectKeysSlice = (state: RootState) => state.keys;

export const selectCurrentKey = createSelector(
selectKeysSlice,
state => state.entities[defaultKeyId]
state => state.entities[defaultWalletKeyId]
);

export function useCurrentKeyDetails() {
Expand All @@ -25,7 +26,7 @@ export const selectCurrentAccountIndex = createSelector(selectStacksChain, state
if (customAccountIndex && initBigNumber(customAccountIndex).isInteger()) {
return initBigNumber(customAccountIndex).toNumber();
}
return state[defaultKeyId].currentAccountIndex;
return state[defaultWalletKeyId].currentAccountIndex;
});

export const selectLedgerKey = createSelector(selectKeysSlice, keys => {
Expand Down
6 changes: 3 additions & 3 deletions src/app/store/keys/key.slice.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { PayloadAction, createEntityAdapter, createSlice } from '@reduxjs/toolkit';

import { defaultWalletKeyId } from '@shared/utils';

import { StxAndIdentityPublicKeys } from '@app/features/ledger/utils/stacks-ledger-utils';

import { migrateVaultReducerStoreToNewStateStructure } from '../utils/vault-reducer-migration';

export const defaultKeyId = 'default' as const;

interface KeyConfigSoftware {
type: 'software';
id: string;
Expand Down Expand Up @@ -38,7 +38,7 @@ export const keySlice = createSlice({
},

signOut(state) {
keyAdapter.removeOne(state, defaultKeyId);
keyAdapter.removeOne(state, defaultWalletKeyId);
},

debugKillStacks(state) {
Expand Down
5 changes: 3 additions & 2 deletions src/app/store/ledger/bitcoin-key.slice.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { PayloadAction, createEntityAdapter, createSlice } from '@reduxjs/toolkit';

import { defaultWalletKeyId } from '@shared/utils';

import { BitcoinLedgerAccountDetails } from '@app/features/ledger/utils/bitcoin-ledger-utils';

import { RootState } from '..';
import { defaultKeyId } from '../keys/key.slice';

interface PersistedBitcoinKeys extends BitcoinLedgerAccountDetails {
walletId: string;
Expand All @@ -19,7 +20,7 @@ export const bitcoinKeysSlice = createSlice({
bitcoinKeyAdapter.addMany(
state,
// While we only support a single wallet, we default to the `default` walletId
payload.map(key => ({ ...key, walletId: defaultKeyId }))
payload.map(key => ({ ...key, walletId: defaultWalletKeyId }))
);
},
},
Expand Down
9 changes: 5 additions & 4 deletions src/app/store/utils/vault-reducer-migration.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { LocalStorageMock } from '@tests/unit/local-storage-mock';
import { vi } from 'vitest';

import { defaultKeyId } from '../keys/key.slice';
import { defaultWalletKeyId } from '@shared/utils';

import { migrateVaultReducerStoreToNewStateStructure } from './vault-reducer-migration';

(globalThis as any).localStorage = new LocalStorageMock();
Expand Down Expand Up @@ -32,11 +33,11 @@ describe(migrateVaultReducerStoreToNewStateStructure.name, () => {
test('that it returns a migrated state object when wallet values are detected', () => {
const returnedValue = migrateVaultReducerStoreToNewStateStructure({} as any);
expect(returnedValue).toEqual({
ids: [defaultKeyId],
ids: [defaultWalletKeyId],
entities: {
[defaultKeyId]: {
[defaultWalletKeyId]: {
type: 'software',
id: defaultKeyId,
id: defaultWalletKeyId,
encryptedSecretKey: 'test-encrypted-key',
salt: 'test-salt',
},
Expand Down
4 changes: 2 additions & 2 deletions src/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export const KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g;

export const MICROBLOCKS_ENABLED = !IS_TEST_ENV && true;

export const GITHUB_ORG = 'hirosystems';
export const GITHUB_REPO = 'wallet';
export const GITHUB_ORG = 'leather-wallet';
export const GITHUB_REPO = 'extension';

export enum WalletDefaultNetworkConfigurationIds {
mainnet = 'mainnet',
Expand Down
12 changes: 8 additions & 4 deletions src/shared/crypto/bitcoin/bitcoin.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as btc from '@scure/btc-signer';

import { BitcoinNetworkModes, NetworkModes } from '@shared/constants';
import { whenNetwork } from '@shared/utils';
import { defaultWalletKeyId } from '@shared/utils';

import { DerivationPathDepth } from '../derivation-path.utils';
import { BtcSignerNetwork } from './bitcoin.network';
Expand Down Expand Up @@ -173,13 +174,16 @@ export function getHdKeyVersionsFromNetwork(network: NetworkModes) {
// Ledger wallets are keyed by their derivation path. To reuse the look up logic
// between payment types, this factory fn accepts a fn that generates the path
export function lookUpLedgerKeysByPath(
derivationPathFn: (network: BitcoinNetworkModes, accountIndex: number) => string
getDerivationPath: (network: BitcoinNetworkModes, accountIndex: number) => string
) {
return (keyMap: Record<string, { policy: string } | undefined>, network: NetworkModes) =>
return (
ledgerKeyMap: Record<string, { policy: string } | undefined>,
network: BitcoinNetworkModes
) =>
(accountIndex: number) => {
const path = derivationPathFn(network, accountIndex);
const path = getDerivationPath(network, accountIndex);
// Single wallet mode, hardcoded default walletId
const account = keyMap[path.replace('m', 'default')];
const account = ledgerKeyMap[path.replace('m', defaultWalletKeyId)];
if (!account) return;
return initBitcoinAccount(path, account.policy);
};
Expand Down
7 changes: 5 additions & 2 deletions src/shared/crypto/bitcoin/p2wpkh-address-gen.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HDKey } from '@scure/bip32';
import * as btc from '@scure/btc-signer';

import { BitcoinNetworkModes, NetworkModes } from '@shared/constants';
import { BitcoinNetworkModes } from '@shared/constants';

import { DerivationPathDepth } from '../derivation-path.utils';
import { getBtcSignerLibNetworkConfigByMode } from './bitcoin.network';
Expand All @@ -26,7 +26,10 @@ export function getNativeSegwitAddressIndexDerivationPath(
return getNativeSegwitAccountDerivationPath(network, accountIndex) + `/0/${addressIndex}`;
}

export function deriveNativeSegwitAccountFromRootKeychain(keychain: HDKey, network: NetworkModes) {
export function deriveNativeSegwitAccountFromRootKeychain(
keychain: HDKey,
network: BitcoinNetworkModes
) {
if (keychain.depth !== DerivationPathDepth.Root) throw new Error('Keychain passed is not a root');
return (accountIndex: number): BitcoinAccount => ({
type: 'p2wpkh',
Expand Down
2 changes: 2 additions & 0 deletions src/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,5 @@ export function whenNetwork(mode: NetworkModes) {
export function isEmptyArray(data: unknown[]) {
return data.length === 0;
}

export const defaultWalletKeyId = 'default' as const;

0 comments on commit eedbed5

Please sign in to comment.