From ebedf9fbf54579397dc151c6ba634b0dc9e27094 Mon Sep 17 00:00:00 2001 From: Polybius93 <99192647+Polybius93@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:07:47 +0100 Subject: [PATCH] feat: update use endpoints hook (#52) --- src/app/hooks/use-bitcoin.ts | 37 ++++++++----------- src/app/hooks/use-endpoints.ts | 42 ++++++++++++++-------- src/shared/models/bitcoin-network.ts | 53 ++++++++++++++-------------- 3 files changed, 68 insertions(+), 64 deletions(-) diff --git a/src/app/hooks/use-bitcoin.ts b/src/app/hooks/use-bitcoin.ts index bc472f29..fc1bf96b 100644 --- a/src/app/hooks/use-bitcoin.ts +++ b/src/app/hooks/use-bitcoin.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; -import { BitcoinNetwork, regtest } from '@models/bitcoin-network'; +import { BitcoinNetwork } from '@models/bitcoin-network'; import { BitcoinError } from '@models/error-types'; import { bytesToHex, hexToBytes } from '@noble/hashes/utils'; import { hex } from '@scure/base'; @@ -8,14 +8,10 @@ import * as btc from '@scure/btc-signer'; import { useEndpoints } from './use-endpoints'; -const networkModes = ['mainnet', 'testnet'] as const; +const networkModes = ['mainnet', 'testnet', 'regtest'] as const; type NetworkModes = (typeof networkModes)[number]; -// type BitcoinTestnetModes = 'testnet' | 'regtest' | 'signet'; - -// type BitcoinNetworkModes = NetworkModes | BitcoinTestnetModes; - declare enum SignatureHash { ALL = 1, NONE = 2, @@ -27,7 +23,7 @@ declare enum SignatureHash { interface SignPsbtRequestParams { hex: string; allowedSighash?: SignatureHash[]; - signAtIndex?: number | number[]; + signAtIndex?: number | number[]; // default is all inputs network?: NetworkModes; // default is user's current network account?: number; // default is user's current account broadcast?: boolean; // default is false - finalize/broadcast tx @@ -94,9 +90,8 @@ export interface UseBitcoinReturnType { } export function useBitcoin(): UseBitcoinReturnType { - const { attestorAPIURLs, bitcoinBlockchainAPIURL } = useEndpoints(); + const { attestorAPIURLs, bitcoinNetwork, bitcoinBlockchainAPIURL } = useEndpoints(); const [bitcoinPrice, setBitcoinPrice] = useState(0); - const [btcNetwork, setBTCNetwork] = useState(regtest); useEffect(() => { const getBitcoinPrice = async () => { @@ -121,7 +116,7 @@ export function useBitcoin(): UseBitcoinReturnType { ); const allUTXOs = await response.json(); const userPublicKey = hexToBytes(bitcoinNativeSegwitAddress.publicKey); - const spend = btc.p2wpkh(userPublicKey, regtest); + const spend = btc.p2wpkh(userPublicKey, bitcoinNetwork); const utxos = await Promise.all( allUTXOs.map(async (utxo: UTXO) => { @@ -198,7 +193,6 @@ export function useBitcoin(): UseBitcoinReturnType { uuid: string, userNativeSegwitAddress: string ): Promise { - setBTCNetwork(regtest); const createPSBTURLs = attestorAPIURLs.map(url => `${url}/app/create-psbt-event`); const requests = createPSBTURLs.map(async url => { fetch(url, { @@ -238,11 +232,9 @@ export function useBitcoin(): UseBitcoinReturnType { return closingPSBT; } - async function signPSBT(psbt: Uint8Array, shouldBroadcast: boolean): Promise { + async function signPSBT(psbt: Uint8Array): Promise { const requestParams: SignPsbtRequestParams = { hex: bytesToHex(psbt), - signAtIndex: [0], - broadcast: shouldBroadcast, }; const result = await window.btc.request('signPsbt', requestParams); return result.result.hex; @@ -254,7 +246,7 @@ export function useBitcoin(): UseBitcoinReturnType { utxos: any[], btcAmount: number, btcNetwork: BitcoinNetwork - ): Promise<{ fundingTransactionHex: string; fundingTransactionID: string }> { + ): Promise { const fundingTransaction = createFundingTransaction( multisigAddress, userChangeAddress, @@ -262,7 +254,7 @@ export function useBitcoin(): UseBitcoinReturnType { btcAmount, btcNetwork ); - const fundingTransactionHex = await signPSBT(fundingTransaction, false); + const fundingTransactionHex = await signPSBT(fundingTransaction); const transaction = btc.Transaction.fromPSBT(hexToBytes(fundingTransactionHex)); transaction.finalize(); @@ -273,7 +265,7 @@ export function useBitcoin(): UseBitcoinReturnType { }).then(async response => { fundingTransactionID = await response.text(); }); - return { fundingTransactionHex, fundingTransactionID }; + return fundingTransactionID; } async function handleClosingTransaction( @@ -291,7 +283,7 @@ export function useBitcoin(): UseBitcoinReturnType { btcAmount, btcNetwork ); - const closingTransactionHex = await signPSBT(closingTransaction, false); + const closingTransactionHex = await signPSBT(closingTransaction); await sendPSBT(closingTransactionHex, uuid, userAddress); return closingTransactionHex; @@ -316,17 +308,16 @@ export function useBitcoin(): UseBitcoinReturnType { const { multisigTransaction, multisigAddress } = createMultisigTransactionAndAddress( hex.decode(userPublicKey), hex.decode(attestorPublicKey), - btcNetwork + bitcoinNetwork ); - const { fundingTransactionHex, fundingTransactionID } = await handleFundingTransaction( + const fundingTransactionID = await handleFundingTransaction( multisigAddress, userNativeSegwitAddress, userUTXOs, btcAmount, - btcNetwork + bitcoinNetwork ); - console.log('fundingTransactionHex', fundingTransactionHex); return { fundingTransactionID, multisigTransaction, userNativeSegwitAddress, btcAmount }; } @@ -347,7 +338,7 @@ export function useBitcoin(): UseBitcoinReturnType { userNativeSegwitAddress, uuid, btcAmount, - btcNetwork + bitcoinNetwork ); } diff --git a/src/app/hooks/use-endpoints.ts b/src/app/hooks/use-endpoints.ts index 959c162e..d587010f 100644 --- a/src/app/hooks/use-endpoints.ts +++ b/src/app/hooks/use-endpoints.ts @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; +import { BitcoinNetwork, bitcoin, regtest, testnet } from '@models/bitcoin-network'; import { EthereumNetwork } from '@models/network'; import { RootState } from '@store/index'; @@ -9,6 +10,7 @@ interface NetworkEndpoints { ethereumExplorerAPIURL: string; bitcoinExplorerAPIURL: string; bitcoinBlockchainAPIURL: string; + bitcoinNetwork: BitcoinNetwork; } export function useEndpoints(): NetworkEndpoints { @@ -18,6 +20,7 @@ export function useEndpoints(): NetworkEndpoints { const [ethereumExplorerAPIURL, setEthereumExplorerAPIURL] = useState(''); const [bitcoinExplorerAPIURL, setBitcoinExplorerAPIURL] = useState(''); const [bitcoinBlockchainAPIURL, setBitcoinBlockchainAPIURL] = useState(''); + const [bitcoinNetwork, setBitcoinNetwork] = useState(regtest); useEffect(() => { if (!network) return; @@ -33,42 +36,50 @@ export function useEndpoints(): NetworkEndpoints { setEthereumExplorerAPIURL(ethereumExplorerAPIURL); setBitcoinExplorerAPIURL(bitcoinExplorerAPIURL); setBitcoinBlockchainAPIURL(bitcoinBlockchainAPIURL); + setBitcoinNetwork(bitcoinNetwork); }, [network]); function getEndpoints(): NetworkEndpoints { + const attestorAPIURLs: string[] = import.meta.env.VITE_ATTESTOR_API_URLS.split(','); + + const bitcoinNetworkName = import.meta.env.VITE_BITCOIN_NETWORK; + let bitcoinNetwork; + + switch (bitcoinNetworkName) { + case 'mainnet': + bitcoinNetwork = bitcoin; + break; + case 'testnet': + bitcoinNetwork = testnet; + break; + default: + bitcoinNetwork = regtest; + } + switch (network?.id) { case EthereumNetwork.Sepolia: return { - attestorAPIURLs: [ - 'https://devnet.dlc.link/attestor-1', - 'https://devnet.dlc.link/attestor-2', - 'https://devnet.dlc.link/attestor-3', - ], + attestorAPIURLs, ethereumExplorerAPIURL: 'https://sepolia.etherscan.io/tx/', bitcoinExplorerAPIURL: 'http://devnet.dlc.link/electrs/tx/', bitcoinBlockchainAPIURL: 'https://devnet.dlc.link/electrs', + bitcoinNetwork, }; case EthereumNetwork.Goerli: return { - attestorAPIURLs: [ - 'http://localhost:8811', - 'http://localhost:8812', - 'http://localhost:8813', - ], + attestorAPIURLs, ethereumExplorerAPIURL: 'https://goerli.etherscan.io/tx/', bitcoinExplorerAPIURL: 'https://blockstream.info/testnet/tx/', bitcoinBlockchainAPIURL: 'https://devnet.dlc.link/electrs', + bitcoinNetwork, }; case EthereumNetwork.X1Testnet: return { - attestorAPIURLs: [ - 'http://localhost:8811', - 'http://localhost:8812', - 'http://localhost:8813', - ], + attestorAPIURLs, ethereumExplorerAPIURL: 'https://www.oklink.com/x1-test/tx/', bitcoinExplorerAPIURL: 'http://devnet.dlc.link/electrs/tx/', bitcoinBlockchainAPIURL: 'https://devnet.dlc.link/electrs', + bitcoinNetwork, }; default: throw new Error(`Unsupported network: ${network?.name}`); @@ -79,5 +90,6 @@ export function useEndpoints(): NetworkEndpoints { ethereumExplorerAPIURL, bitcoinExplorerAPIURL, bitcoinBlockchainAPIURL, + bitcoinNetwork, }; } diff --git a/src/shared/models/bitcoin-network.ts b/src/shared/models/bitcoin-network.ts index 9aa42b6e..40583ecc 100644 --- a/src/shared/models/bitcoin-network.ts +++ b/src/shared/models/bitcoin-network.ts @@ -14,19 +14,19 @@ export interface BitcoinNetwork { versionBytes: number; } -// export const bitcoin: BitcoinNetwork = { -// messagePrefix: '\x18Bitcoin Signed Message:\n', -// bech32: 'bc', -// bip32: { -// public: 0x0488b21e, -// private: 0x0488ade4, -// }, -// pubKeyHash: 0x00, -// scriptHash: 0x05, -// wif: 0x80, -// bytes: 21, -// versionBytes: 1, -// }; +export const bitcoin: BitcoinNetwork = { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bc', + bip32: { + public: 0x0488b21e, + private: 0x0488ade4, + }, + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80, + bytes: 21, + versionBytes: 1, +}; export const regtest: BitcoinNetwork = { messagePrefix: '\x18Bitcoin Signed Message:\n', @@ -41,16 +41,17 @@ export const regtest: BitcoinNetwork = { bytes: 21, versionBytes: 1, }; -// export const testnet: BitcoinNetwork = { -// messagePrefix: '\x18Bitcoin Signed Message:\n', -// bech32: 'tb', -// bip32: { -// public: 0x043587cf, -// private: 0x04358394, -// }, -// pubKeyHash: 0x6f, -// scriptHash: 0xc4, -// wif: 0xef, -// bytes: 21, -// versionBytes: 1, -// }; + +export const testnet: BitcoinNetwork = { + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'tb', + bip32: { + public: 0x043587cf, + private: 0x04358394, + }, + pubKeyHash: 0x6f, + scriptHash: 0xc4, + wif: 0xef, + bytes: 21, + versionBytes: 1, +};