mirror of
https://github.com/zhigang1992/wallet.git
synced 2026-03-23 22:50:57 +08:00
feat: add signet support, closes #3771
This commit is contained in:
@@ -291,14 +291,8 @@ export function whenNetwork(mode: NetworkModes) {
|
||||
return <T>(networkMap: NetworkMap<T>): T => networkMap[mode];
|
||||
}
|
||||
|
||||
const bitcoinNetworkToCoreNetworkMap: Record<BitcoinNetworkModes, NetworkModes> = {
|
||||
mainnet: 'mainnet',
|
||||
testnet: 'testnet',
|
||||
regtest: 'testnet',
|
||||
signet: 'testnet',
|
||||
};
|
||||
export function bitcoinNetworkModeToCoreNetworkMode(mode: BitcoinNetworkModes) {
|
||||
return bitcoinNetworkToCoreNetworkMap[mode];
|
||||
export function whenBitcoinNetwork(mode: BitcoinNetworkModes) {
|
||||
return <T>(networkMap: Record<BitcoinNetworkModes, T>): T => networkMap[mode];
|
||||
}
|
||||
|
||||
export function logAndThrow(msg: string, args: any[] = []) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { AddressType, Network, getAddressInfo, validate } from 'bitcoin-address-
|
||||
import * as yup from 'yup';
|
||||
|
||||
import { BitcoinNetworkModes, NetworkConfiguration } from '@shared/constants';
|
||||
import { bitcoinNetworkModeToCoreNetworkMode } from '@shared/crypto/bitcoin/bitcoin.utils';
|
||||
import { isString } from '@shared/utils';
|
||||
|
||||
import { FormErrorMessages } from '@app/common/error-messages';
|
||||
@@ -46,7 +47,7 @@ export function btcTaprootAddressValidator() {
|
||||
function btcAddressNetworkValidatorFactory(network: BitcoinNetworkModes) {
|
||||
return (value?: string) => {
|
||||
if (!isString(value)) return false;
|
||||
return validate(value, network as Network);
|
||||
return validate(value, bitcoinNetworkModeToCoreNetworkMode(network) as Network);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { bitcoinNetworkModeToCoreNetworkMode } from '@shared/crypto/bitcoin/bitcoin.utils';
|
||||
import { getNativeSegWitPaymentFromAddressIndex } from '@shared/crypto/bitcoin/p2wpkh-address-gen';
|
||||
|
||||
import { bitcoinNetworkModeToCoreNetworkMode, whenNetwork } from '@app/common/utils';
|
||||
import { whenNetwork } from '@app/common/utils';
|
||||
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
|
||||
|
||||
import { useCurrentAccountIndex } from '../../account';
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { BitcoinNetworkModes } from '@shared/constants';
|
||||
import { bitcoinNetworkModeToCoreNetworkMode } from '@shared/crypto/bitcoin/bitcoin.utils';
|
||||
import { getTaprootPaymentFromAddressIndex } from '@shared/crypto/bitcoin/p2tr-address-gen';
|
||||
|
||||
import { bitcoinNetworkModeToCoreNetworkMode, whenNetwork } from '@app/common/utils';
|
||||
import { whenNetwork } from '@app/common/utils';
|
||||
import { useCurrentNetwork } from '@app/store/networks/networks.selectors';
|
||||
|
||||
import { useCurrentAccountIndex } from '../../account';
|
||||
|
||||
@@ -4,12 +4,13 @@ import { ChainID } from '@stacks/transactions';
|
||||
|
||||
import {
|
||||
BITCOIN_API_BASE_URL_MAINNET,
|
||||
BITCOIN_API_BASE_URL_SIGNET,
|
||||
BITCOIN_API_BASE_URL_TESTNET,
|
||||
HIRO_API_BASE_URL_MAINNET,
|
||||
HIRO_API_BASE_URL_TESTNET,
|
||||
} from '@shared/constants';
|
||||
|
||||
import { whenStacksChainId } from '@app/common/utils';
|
||||
import { whenBitcoinNetwork, whenStacksChainId } from '@app/common/utils';
|
||||
import { BitcoinClient } from '@app/query/bitcoin/bitcoin-client';
|
||||
import { StacksClient } from '@app/query/stacks/stacks-client';
|
||||
import { TokenMetadataClient } from '@app/query/stacks/token-metadata-client';
|
||||
@@ -24,9 +25,11 @@ import { useCurrentNetworkState } from '../networks/networks.hooks';
|
||||
export function useBitcoinClient() {
|
||||
const network = useCurrentNetworkState();
|
||||
|
||||
const baseUrl = whenStacksChainId(network.chain.stacks.chainId)({
|
||||
[ChainID.Mainnet]: BITCOIN_API_BASE_URL_MAINNET,
|
||||
[ChainID.Testnet]: BITCOIN_API_BASE_URL_TESTNET,
|
||||
const baseUrl = whenBitcoinNetwork(network.chain.bitcoin.network)({
|
||||
mainnet: BITCOIN_API_BASE_URL_MAINNET,
|
||||
testnet: BITCOIN_API_BASE_URL_TESTNET,
|
||||
regtest: BITCOIN_API_BASE_URL_TESTNET,
|
||||
signet: BITCOIN_API_BASE_URL_SIGNET,
|
||||
});
|
||||
|
||||
return new BitcoinClient(baseUrl);
|
||||
|
||||
@@ -32,6 +32,7 @@ export const GITHUB_REPO = 'wallet';
|
||||
export enum WalletDefaultNetworkConfigurationIds {
|
||||
mainnet = 'mainnet',
|
||||
testnet = 'testnet',
|
||||
signet = 'signet',
|
||||
devnet = 'devnet',
|
||||
}
|
||||
|
||||
@@ -73,6 +74,7 @@ export const HIRO_API_BASE_URL_TESTNET = 'https://api.testnet.hiro.so';
|
||||
|
||||
export const BITCOIN_API_BASE_URL_MAINNET = 'https://blockstream.info/api';
|
||||
export const BITCOIN_API_BASE_URL_TESTNET = 'https://blockstream.info/testnet/api';
|
||||
export const BITCOIN_API_BASE_URL_SIGNET = 'https://mempool.space/signet/api';
|
||||
|
||||
const networkMainnet: NetworkConfiguration = {
|
||||
id: WalletDefaultNetworkConfigurationIds.mainnet,
|
||||
@@ -108,6 +110,23 @@ const networkTestnet: NetworkConfiguration = {
|
||||
},
|
||||
};
|
||||
|
||||
const networkSignet: NetworkConfiguration = {
|
||||
id: WalletDefaultNetworkConfigurationIds.signet,
|
||||
name: 'Signet',
|
||||
chain: {
|
||||
stacks: {
|
||||
blockchain: 'stacks',
|
||||
chainId: ChainID.Testnet,
|
||||
url: HIRO_API_BASE_URL_TESTNET,
|
||||
},
|
||||
bitcoin: {
|
||||
blockchain: 'bitcoin',
|
||||
network: 'signet',
|
||||
url: BITCOIN_API_BASE_URL_SIGNET,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const networkDevnet: NetworkConfiguration = {
|
||||
id: WalletDefaultNetworkConfigurationIds.devnet,
|
||||
name: 'Devnet',
|
||||
@@ -133,6 +152,7 @@ export const defaultNetworksKeyedById: Record<
|
||||
> = {
|
||||
[WalletDefaultNetworkConfigurationIds.mainnet]: networkMainnet,
|
||||
[WalletDefaultNetworkConfigurationIds.testnet]: networkTestnet,
|
||||
[WalletDefaultNetworkConfigurationIds.signet]: networkSignet,
|
||||
[WalletDefaultNetworkConfigurationIds.devnet]: networkDevnet,
|
||||
};
|
||||
|
||||
|
||||
@@ -32,18 +32,13 @@ const bitcoinRegtest: BtcSignerNetwork = {
|
||||
wif: 0xef,
|
||||
};
|
||||
|
||||
const bitcoinSignet: BtcSignerNetwork = {
|
||||
bech32: 'sb',
|
||||
pubKeyHash: 0x3f,
|
||||
scriptHash: 0x7f,
|
||||
wif: 0x80,
|
||||
};
|
||||
|
||||
const btcSignerLibNetworks: Record<BitcoinNetworkModes, BtcSignerNetwork> = {
|
||||
mainnet: bitcoinMainnet,
|
||||
testnet: bitcoinTestnet,
|
||||
regtest: bitcoinRegtest,
|
||||
signet: bitcoinSignet,
|
||||
// Signet originally was going to have its own prefix but authors decided to
|
||||
// copy testnet
|
||||
signet: bitcoinTestnet,
|
||||
};
|
||||
|
||||
export function getBtcSignerLibNetworkConfigByMode(network: BitcoinNetworkModes) {
|
||||
@@ -54,8 +49,7 @@ const bitcoinJsLibNetworks: Record<BitcoinNetworkModes, bitcoinJs.Network> = {
|
||||
mainnet: bitcoinJs.networks.bitcoin,
|
||||
testnet: bitcoinJs.networks.testnet,
|
||||
regtest: bitcoinJs.networks.regtest,
|
||||
// Signet doesn't exist in bitcoinjs-lib
|
||||
signet: bitcoinJs.networks.regtest,
|
||||
signet: bitcoinJs.networks.testnet,
|
||||
};
|
||||
|
||||
export function getBitcoinJsLibNetworkConfigByMode(network: BitcoinNetworkModes) {
|
||||
|
||||
@@ -9,13 +9,23 @@ import { logger } from '@shared/logger';
|
||||
import { DerivationPathDepth } from '../derivation-path.utils';
|
||||
import { BtcSignerNetwork, getBtcSignerLibNetworkConfigByMode } from './bitcoin.network';
|
||||
|
||||
const bitcoinNetworkToCoreNetworkMap: Record<BitcoinNetworkModes, NetworkModes> = {
|
||||
mainnet: 'mainnet',
|
||||
testnet: 'testnet',
|
||||
regtest: 'testnet',
|
||||
signet: 'testnet',
|
||||
};
|
||||
export function bitcoinNetworkModeToCoreNetworkMode(mode: BitcoinNetworkModes) {
|
||||
return bitcoinNetworkToCoreNetworkMap[mode];
|
||||
}
|
||||
|
||||
const coinTypeMap: Record<NetworkModes, 0 | 1> = {
|
||||
mainnet: 0,
|
||||
testnet: 1,
|
||||
};
|
||||
|
||||
export function getBitcoinCoinTypeIndexByNetwork(network: NetworkModes) {
|
||||
return coinTypeMap[network];
|
||||
export function getBitcoinCoinTypeIndexByNetwork(network: BitcoinNetworkModes) {
|
||||
return coinTypeMap[bitcoinNetworkModeToCoreNetworkMode(network)];
|
||||
}
|
||||
|
||||
export function deriveAddressIndexKeychainFromAccount(keychain: HDKey) {
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
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';
|
||||
import { ecdsaPublicKeyToSchnorr, getBitcoinCoinTypeIndexByNetwork } from './bitcoin.utils';
|
||||
|
||||
function getTaprootAccountDerivationPath(network: NetworkModes, accountIndex: number) {
|
||||
function getTaprootAccountDerivationPath(network: BitcoinNetworkModes, accountIndex: number) {
|
||||
return `m/86'/${getBitcoinCoinTypeIndexByNetwork(network)}'/${accountIndex}'`;
|
||||
}
|
||||
|
||||
export function deriveTaprootAccountFromRootKeychain(keychain: HDKey, network: NetworkModes) {
|
||||
export function deriveTaprootAccountFromRootKeychain(
|
||||
keychain: HDKey,
|
||||
network: BitcoinNetworkModes
|
||||
) {
|
||||
if (keychain.depth !== DerivationPathDepth.Root)
|
||||
throw new Error('Keychain passed is not an account');
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
getBitcoinCoinTypeIndexByNetwork,
|
||||
} from './bitcoin.utils';
|
||||
|
||||
function getNativeSegWitAccountDerivationPath(network: NetworkModes, accountIndex: number) {
|
||||
function getNativeSegWitAccountDerivationPath(network: BitcoinNetworkModes, accountIndex: number) {
|
||||
return `m/84'/${getBitcoinCoinTypeIndexByNetwork(network)}'/${accountIndex}'`;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,6 @@ describe(`Settings integration tests`, () => {
|
||||
const networkListItems = await wallet.page.$$(
|
||||
createTestSelector(SettingsSelectors.NetworkListItem)
|
||||
);
|
||||
expect(networkListItems).toHaveLength(3);
|
||||
expect(networkListItems).toHaveLength(4);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user