Skip to content

Commit

Permalink
fix(wallet): Upgrade beignet
Browse files Browse the repository at this point in the history
Upgrades beignet to 0.0.18.
Allows users to set p2tr addresses as their default, but only in dev mode.
Adds taproot support to AddressViewer without need for dev mode.
Adds addressTypesToMonitor to reduce bandwidth for unused address types.
Removed unused create-hmac dependency.
  • Loading branch information
coreyphillips committed Jan 31, 2024
1 parent d62e7a2 commit 2d5acc4
Show file tree
Hide file tree
Showing 22 changed files with 265 additions and 868 deletions.
759 changes: 0 additions & 759 deletions __tests__/utils/dummy-wallet.ts

Large diffs are not rendered by default.

19 changes: 15 additions & 4 deletions nodejs-assets/nodejs-project/bitcoin-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ const ecc = require('@bitcoinerlab/secp256k1');
const BIP32Factory = require('bip32').BIP32Factory;
const bip32 = BIP32Factory(ecc);
const bitcoin = require('bitcoinjs-lib');
const { sha256 } = require('./utils');
const { getTapRootAddressFromPublicKey} = require('./utils');
bitcoin.initEccLib(ecc);

class BitcoinActions {
constructor() {
Expand Down Expand Up @@ -133,6 +134,16 @@ class BitcoinActions {
//Get Legacy Address (1)
address = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network }).address;
break;
case 'p2tr':
//Get Taproot (bc1p) addresses
const res = getTapRootAddressFromPublicKey({
publicKey: keyPair.publicKey,
network
});
if (res.error === false) {
address = res.address;
}
break;
}
const value = {
address,
Expand All @@ -154,16 +165,16 @@ class BitcoinActions {
return new Promise((resolve) => {
try {
if (!address || !selectedNetwork) {
return resolve({ error: true, value: 'No address or network provided.' });
return resolve({ id, method, error: true, value: 'No address or network provided.' });
}
const network = networks[selectedNetwork];
const script = bitcoin.address.toOutputScript(address, network);
const hash = sha256(script);
const hash = bitcoin.crypto.sha256(script);
const reversedHash = Buffer.from(hash.reverse());
const value = reversedHash.toString('hex');
return resolve({ id, method, error: false, value });
} catch (e) {
return resolve({ error: true, value: e });
return resolve({ id, method, error: true, value: e });
}
});
}
Expand Down
3 changes: 1 addition & 2 deletions nodejs-assets/nodejs-project/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"@bitcoinerlab/secp256k1": "1.0.5",
"bip32": "4.0.0",
"bip39": "3.1.0",
"bitcoinjs-lib": "6.1.5",
"create-hmac": "^1.1.7"
"bitcoinjs-lib": "6.1.5"
}
}
25 changes: 21 additions & 4 deletions nodejs-assets/nodejs-project/utils.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
const bitcoin = require("bitcoinjs-lib");
const { toXOnly } = require("bitcoinjs-lib/src/psbt/bip371");

const getTapRootAddressFromPublicKey = ({
publicKey,
network
})=> {
try {
const internalPubkey = toXOnly(publicKey);
const { address, output } = bitcoin.payments.p2tr({
internalPubkey,
network
});
if (!address) return { error: true, value: 'Unable to get address from key pair.' };
if (!output) return { error: true, value: 'Unable to get output from key pair.' };
return { error: false, address, output };
} catch (e) {
console.log(e);
return { error: true, value: e };
}
};

const sha256 = (str) => {
return bitcoin.crypto.sha256(str);
}

module.exports = {
sha256,
getTapRootAddressFromPublicKey,
}
18 changes: 3 additions & 15 deletions nodejs-assets/nodejs-project/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ bs58check@^3.0.1:
"@noble/hashes" "^1.2.0"
bs58 "^5.0.0"

cipher-base@^1.0.1, cipher-base@^1.0.3:
cipher-base@^1.0.1:
version "1.0.4"
resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz"
integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==
Expand All @@ -126,18 +126,6 @@ create-hash@^1.1.0:
ripemd160 "^2.0.1"
sha.js "^2.4.0"

create-hmac@^1.1.7:
version "1.1.7"
resolved "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz"
integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
dependencies:
cipher-base "^1.0.3"
create-hash "^1.1.0"
inherits "^2.0.1"
ripemd160 "^2.0.0"
safe-buffer "^5.0.1"
sha.js "^2.4.8"

hash-base@^3.0.0:
version "3.1.0"
resolved "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz"
Expand Down Expand Up @@ -170,7 +158,7 @@ readable-stream@^3.6.0:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"

ripemd160@^2.0.0, ripemd160@^2.0.1:
ripemd160@^2.0.1:
version "2.0.2"
resolved "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz"
integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==
Expand All @@ -183,7 +171,7 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0,
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==

sha.js@^2.4.0, sha.js@^2.4.8:
sha.js@^2.4.0:
version "2.4.11"
resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz"
integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"@synonymdev/web-relay": "1.0.7",
"backpack-client": "github:synonymdev/bitkit-backup-client#f08fdb28529d8a3f8bfecc789443c43b966a7581",
"bech32": "2.0.0",
"beignet": "0.0.16",
"beignet": "0.0.18",
"bip21": "2.0.3",
"bip32": "4.0.0",
"bip39": "3.0.4",
Expand Down
16 changes: 14 additions & 2 deletions src/screens/Settings/AddressTypePreference/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,30 @@ import { updateSelectedAddressType } from '../../../store/actions/wallet';
import { addressTypeSelector } from '../../../store/reselect/wallet';
import { addressTypes } from '../../../store/shapes/wallet';
import type { SettingsScreenProps } from '../../../navigation/types';
import { enableDevOptionsSelector } from '../../../store/reselect/settings';
import { EAddressType } from 'beignet';

const AddressTypeSettings = ({
navigation,
}: SettingsScreenProps<'AddressTypePreference'>): ReactElement => {
const { t } = useTranslation('settings');
const selectedAddressType = useAppSelector(addressTypeSelector);
const isDeveloperMode = useAppSelector(enableDevOptionsSelector);

const availableAddressTypes = useMemo(() => {
if (isDeveloperMode) {
return Object.values(addressTypes);
}
return Object.values(addressTypes).filter(
(addressType) => addressType.type !== EAddressType.p2tr,
);
}, [isDeveloperMode]);

const listData: IListData[] = useMemo(
() => [
{
title: t('adv.address_type'),
data: Object.values(addressTypes).map((addressType) => ({
data: Object.values(availableAddressTypes).map((addressType) => ({
type: EItemType.button,
title: `${addressType.name} ${addressType.example}`,
subtitle: addressType.description,
Expand All @@ -35,7 +47,7 @@ const AddressTypeSettings = ({
})),
},
],
[selectedAddressType, navigation, t],
[t, availableAddressTypes, selectedAddressType, navigation],
);

return (
Expand Down
77 changes: 48 additions & 29 deletions src/screens/Settings/AddressViewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import React, {
useRef,
useState,
} from 'react';
import { FlatList, StyleSheet, View } from 'react-native';
import { FlatList, StyleSheet, View, ScrollView } from 'react-native';
import { useAppDispatch, useAppSelector } from '../../../hooks/redux';
import { useTranslation } from 'react-i18next';
import QRCode from 'react-native-qrcode-svg';
Expand Down Expand Up @@ -36,12 +36,7 @@ import {
selectedNetworkSelector,
selectedWalletSelector,
} from '../../../store/reselect/wallet';
import {
EAddressType,
IAddress,
IUtxo,
TWalletName,
} from '../../../store/types/wallet';
import { IAddress, IUtxo, TWalletName } from '../../../store/types/wallet';
import Button from '../../../components/Button';
import {
defaultAddressContent,
Expand Down Expand Up @@ -74,8 +69,13 @@ import { setupLdk } from '../../../utils/lightning';
import { startWalletServices } from '../../../utils/startup';
import { updateOnchainFeeEstimates } from '../../../store/utils/fees';
import { viewControllerIsOpenSelector } from '../../../store/reselect/ui';
import { EAddressType } from 'beignet';

export type TAddressViewerData = {
[EAddressType.p2tr]: {
addresses: IAddress[];
changeAddresses: IAddress[];
};
[EAddressType.p2wpkh]: {
addresses: IAddress[];
changeAddresses: IAddress[];
Expand Down Expand Up @@ -104,6 +104,10 @@ const defaultConfig: TAddressViewerConfig = {
selectedNetwork: EAvailableNetwork.bitcoin,
};
const defaultAllAddressesData: TAddressViewerData = {
[EAddressType.p2tr]: {
addresses: [],
changeAddresses: [],
},
[EAddressType.p2wpkh]: {
addresses: [],
changeAddresses: [],
Expand Down Expand Up @@ -239,7 +243,7 @@ const AddressViewer = ({
);

const flatListRef = useRef<FlatList>(null);

const scrollViewRef = useRef<ScrollView>(null);
const [config, setConfig] = useState({
...defaultConfig,
selectedNetwork,
Expand Down Expand Up @@ -1000,27 +1004,42 @@ const AddressViewer = ({
)}
{!searchTxt && (
<View style={styles.row}>
<Button
color={getAddressTypeButtonColor(EAddressType.p2pkh)}
text={EAddressType.p2pkh}
onPress={(): void => {
updateAddressType(EAddressType.p2pkh).then();
}}
/>
<Button
color={getAddressTypeButtonColor(EAddressType.p2sh)}
text={EAddressType.p2sh}
onPress={(): void => {
updateAddressType(EAddressType.p2sh).then();
}}
/>
<Button
color={getAddressTypeButtonColor(EAddressType.p2wpkh)}
text={EAddressType.p2wpkh}
onPress={(): void => {
updateAddressType(EAddressType.p2wpkh).then();
}}
/>
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={false}
ref={scrollViewRef}
onContentSizeChange={(): void =>
scrollViewRef?.current?.scrollToEnd({ animated: false })
}>
<Button
color={getAddressTypeButtonColor(EAddressType.p2pkh)}
text={EAddressType.p2pkh}
onPress={(): void => {
updateAddressType(EAddressType.p2pkh).then();
}}
/>
<Button
color={getAddressTypeButtonColor(EAddressType.p2sh)}
text={EAddressType.p2sh}
onPress={(): void => {
updateAddressType(EAddressType.p2sh).then();
}}
/>
<Button
color={getAddressTypeButtonColor(EAddressType.p2wpkh)}
text={EAddressType.p2wpkh}
onPress={(): void => {
updateAddressType(EAddressType.p2wpkh).then();
}}
/>
<Button
color={getAddressTypeButtonColor(EAddressType.p2tr)}
text={EAddressType.p2tr}
onPress={(): void => {
updateAddressType(EAddressType.p2tr).then();
}}
/>
</ScrollView>
</View>
)}
{!searchTxt && (
Expand Down
27 changes: 21 additions & 6 deletions src/store/actions/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { err, ok, Result } from '@synonymdev/result';

import actions from './actions';
import {
EAddressType,
EBoostType,
IAddress,
ICreateWallet,
Expand Down Expand Up @@ -32,11 +31,12 @@ import {
import { EAvailableNetwork } from '../../utils/networks';
import { removeKeyFromObject } from '../../utils/helpers';
import { IHeader } from '../../utils/types/electrum';
import { addressTypes, getDefaultWalletShape } from '../shapes/wallet';
import { getDefaultWalletShape } from '../shapes/wallet';
import { TGetImpactedAddressesRes } from '../types/checks';
import { getFakeTransaction } from '../../utils/wallet/testing';
import { updateActivityList } from '../utils/activity';
import {
EAddressType,
EAvailableNetworks,
EFeeId,
getDefaultWalletData,
Expand Down Expand Up @@ -69,7 +69,7 @@ export const updateWallet = (
* @param {string} mnemonic
* @param {string} [wallet]
* @param {string} [bip39Passphrase]
* @param {Partial<IAddressTypes>} [addressTypesToCreate]
* @param {EAddressType[]} [addressTypesToCreate]
* @return {Promise<Result<string>>}
*/
export const createWallet = async ({
Expand All @@ -81,10 +81,17 @@ export const createWallet = async ({
selectedNetwork = getSelectedNetwork(),
servers,
}: ICreateWallet): Promise<Result<string>> => {
if (!addressTypesToCreate) {
addressTypesToCreate = addressTypes;
}
try {
if (!addressTypesToCreate && restore) {
// If restoring a wallet, create and monitor all address types
addressTypesToCreate = Object.values(EAddressType);
dispatch({
type: actions.UPDATE_WALLET,
payload: {
addressTypesToMonitor: Object.values(EAddressType),
},
});
}
const response = await createDefaultWallet({
walletName,
mnemonic,
Expand Down Expand Up @@ -451,6 +458,14 @@ export const updateSelectedAddressType = async ({
addressType: EAddressType;
}): Promise<void> => {
const wallet = getOnChainWallet();
const addressTypesToMonitor = wallet.addressTypesToMonitor;
if (!addressTypesToMonitor.includes(addressType)) {
// Append the new address type so we monitor it in subsequent sessions.
addressTypesToMonitor.push(addressType);
}
updateWallet({
addressTypesToMonitor,
});
return await wallet.updateAddressType(addressType);
};

Expand Down
2 changes: 1 addition & 1 deletion src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const persistConfig = {
key: 'root',
storage: mmkvStorage,
// increase version after store shape changes
version: 33,
version: 34,
stateReconciler: autoMergeLevel2,
blacklist: ['receive', 'ui'],
migrate: createMigrate(migrations, { debug: __ENABLE_MIGRATION_DEBUG__ }),
Expand Down
Loading

0 comments on commit 2d5acc4

Please sign in to comment.