Skip to content

Commit

Permalink
feat: add getFeeRate function, add feerate api endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
Polybius93 committed Mar 25, 2024
1 parent ae68600 commit 69eef49
Show file tree
Hide file tree
Showing 3 changed files with 5,641 additions and 8 deletions.
49 changes: 42 additions & 7 deletions src/app/hooks/use-bitcoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ interface UTXO {
value: number;
}

interface FeeRates {
fastestFee: number;
halfHourFee: number;
hourFee: number;
economyFee: number;
minimumFee: number;
}

interface BitcoinNativeSegwitAddress {
address: string;
derivationPath: string;
Expand Down Expand Up @@ -88,7 +96,8 @@ interface UseBitcoinReturnType {
}

export function useBitcoin(): UseBitcoinReturnType {
const { bitcoinNetwork, bitcoinNetworkName, bitcoinBlockchainAPIURL } = useEndpoints();
const { bitcoinNetwork, bitcoinNetworkName, bitcoinBlockchainAPIURL, mempoolSpaceAPIFeeURL } =
useEndpoints();
const { getAttestorGroupPublicKey, sendClosingTransactionToAttestors } = useAttestors();

/**
Expand Down Expand Up @@ -132,6 +141,22 @@ export function useBitcoin(): UseBitcoinReturnType {
}
}

/**
* Fetches the fee rate from the mempool.space API.
*
* @returns A promise that resolves to the hour fee rate.
*/
async function getFeeRate(): Promise<number> {
try {
const response = await fetch(mempoolSpaceAPIFeeURL);
const feeRates: FeeRates = await response.json();

return feeRates.hourFee;
} catch (error) {
throw new BitcoinError(`Error getting Fee Rate: ${error}`);
}
}

/**
* Fetches the UTXOs for the user's native segwit address.
Expand Down Expand Up @@ -174,6 +199,7 @@ export function useBitcoin(): UseBitcoinReturnType {
*
* @param userPublicKey - The user's public key.
* @param attestorGroupPublicKey - The attestor group's public key.
* @param bitcoinNetwork - The bitcoin network.
* @returns A promise that resolves to the multisig transaction.
*/
function createMultisigTransaction(
Expand All @@ -191,23 +217,25 @@ export function useBitcoin(): UseBitcoinReturnType {
* Creates the first PSBT, which is the funding transaction.
* Uses the selected UTXOs to fund the transaction.
*
* @param selectedUTXOs - The UTXOs selected for funding the transaction.
* @param multisigAddress - The multisig address.
* @param bitcoinAmount - The amount of bitcoin.
* @param multisigAddress - The multisig address created from the multisig transaction between the user and the attestor group.
* @param utxos - The user's UTXOs.
* @param feeRate - The fee rate.
* @param bitcoinAmount - The amount of bitcoin to be used in the transaction.
* @param bitcoinNetwork - The bitcoin network.
* @returns A promise that resolves to the funding PSBT.
*/ function createFundingTransaction(
multisigAddress: string,
userChangeAddress: string,
utxos: any[],
feeRate: bigint,
bitcoinAmount: number,
bitcoinNetwork: BitcoinNetwork
): Uint8Array {
const outputs = [{ address: multisigAddress, amount: BigInt(bitcoinAmount) }];

const selected = btc.selectUTXO(utxos, outputs, 'default', {
changeAddress: userChangeAddress,
feePerByte: 2n,
feePerByte: feeRate,
bip69: false,
createTx: true,
network: bitcoinNetwork,
Expand All @@ -228,9 +256,9 @@ export function useBitcoin(): UseBitcoinReturnType {
* The closing transaction is sent to the user's native segwit address.
*
* @param fundingTransactionID - The ID of the funding transaction.
* @param multisigTransaction - The multisig transaction.
* @param multisigTransaction - The multisig transaction between the user and the attestor group.
* @param userNativeSegwitAddress - The user's native segwit address.
* @param bitcoinAmount - The amount of bitcoin.
* @param bitcoinAmount - The amount of bitcoin to be used in the transaction.
* @param bitcoinNetwork - The bitcoin network.
* @returns A promise that resolves to the closing PSBT.
*/
Expand Down Expand Up @@ -294,6 +322,10 @@ export function useBitcoin(): UseBitcoinReturnType {
body: bytesToHex(transaction.extract()),
});

if (!response.ok) {
throw new Error(`HTTP Error! Status: ${response.status}`);
}

const transactionID = await response.text();
return transactionID;
} catch (error) {
Expand Down Expand Up @@ -330,10 +362,13 @@ export function useBitcoin(): UseBitcoinReturnType {
const multisigAddress = multisigTransaction.address;
if (!multisigAddress) throw new BitcoinError('Could not create multisig address');

const feeRate = BigInt(await getFeeRate());

const fundingTransaction = createFundingTransaction(
multisigAddress,
userNativeSegwitAddress,
userUTXOs,
feeRate,
bitcoinAmount,
bitcoinNetwork
);
Expand Down
16 changes: 15 additions & 1 deletion src/app/hooks/use-endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface NetworkEndpoints {
ethereumAttestorChainID: string;
bitcoinExplorerAPIURL: string;
bitcoinBlockchainAPIURL: string;
mempoolSpaceAPIFeeURL: string;
bitcoinNetwork: BitcoinNetwork;
bitcoinNetworkName: string;
}
Expand All @@ -23,6 +24,8 @@ export function useEndpoints(): NetworkEndpoints {
const [ethereumAttestorChainID, setEthereumAttestorChainID] = useState<string>('');
const [bitcoinExplorerAPIURL, setBitcoinExplorerAPIURL] = useState<string>('');
const [bitcoinBlockchainAPIURL, setBitcoinBlockchainAPIURL] = useState<string>('');
const [mempoolSpaceAPIFeeURL, setMempoolSpaceAPIFeeURL] = useState<string>('');

const [bitcoinNetwork, setBitcoinNetwork] = useState<BitcoinNetwork>(regtest);
const [bitcoinNetworkName, setBitcoinNetworkName] = useState<string>('');

Expand All @@ -35,6 +38,7 @@ export function useEndpoints(): NetworkEndpoints {
ethereumAttestorChainID,
bitcoinExplorerAPIURL,
bitcoinBlockchainAPIURL,
mempoolSpaceAPIFeeURL,
bitcoinNetwork,
bitcoinNetworkName,
} = getEndpoints();
Expand All @@ -44,6 +48,7 @@ export function useEndpoints(): NetworkEndpoints {
setEthereumAttestorChainID(ethereumAttestorChainID);
setBitcoinExplorerAPIURL(bitcoinExplorerAPIURL);
setBitcoinBlockchainAPIURL(bitcoinBlockchainAPIURL);
setMempoolSpaceAPIFeeURL(mempoolSpaceAPIFeeURL);
setBitcoinNetwork(bitcoinNetwork);
setBitcoinNetworkName(bitcoinNetworkName);
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand All @@ -55,17 +60,22 @@ export function useEndpoints(): NetworkEndpoints {
const bitcoinNetworkName = import.meta.env.VITE_BITCOIN_NETWORK;
const bitcoinBlockchainAPIURL = import.meta.env.VITE_BITCOIN_BLOCKCHAIN_API_URL;
const bitcoinExplorerAPIURL = import.meta.env.VITE_BITCOIN_EXPLORER_API_URL;
let bitcoinNetwork;

let bitcoinNetwork: BitcoinNetwork;
let mempoolSpaceAPIFeeURL: string;

switch (bitcoinNetworkName) {
case 'mainnet':
bitcoinNetwork = bitcoin;
mempoolSpaceAPIFeeURL = 'https://mempool.space/api/v1/fees/recommended';
break;
case 'testnet':
bitcoinNetwork = testnet;
mempoolSpaceAPIFeeURL = 'https://mempool.space/testnet/api/v1/fees/recommended';
break;
default:
bitcoinNetwork = regtest;
mempoolSpaceAPIFeeURL = 'https://mempool.space/testnet/api/v1/fees/recommended';
}

switch (network?.id) {
Expand All @@ -76,6 +86,7 @@ export function useEndpoints(): NetworkEndpoints {
ethereumAttestorChainID: 'evm-sepolia',
bitcoinExplorerAPIURL,
bitcoinBlockchainAPIURL,
mempoolSpaceAPIFeeURL,
bitcoinNetwork,
bitcoinNetworkName,
};
Expand All @@ -86,6 +97,7 @@ export function useEndpoints(): NetworkEndpoints {
ethereumAttestorChainID: 'evm-goerli',
bitcoinExplorerAPIURL,
bitcoinBlockchainAPIURL,
mempoolSpaceAPIFeeURL,
bitcoinNetwork,
bitcoinNetworkName,
};
Expand All @@ -96,6 +108,7 @@ export function useEndpoints(): NetworkEndpoints {
ethereumAttestorChainID: 'evm-x1-test',
bitcoinExplorerAPIURL,
bitcoinBlockchainAPIURL,
mempoolSpaceAPIFeeURL,
bitcoinNetwork,
bitcoinNetworkName,
};
Expand All @@ -109,6 +122,7 @@ export function useEndpoints(): NetworkEndpoints {
ethereumAttestorChainID,
bitcoinExplorerAPIURL,
bitcoinBlockchainAPIURL,
mempoolSpaceAPIFeeURL,
bitcoinNetwork,
bitcoinNetworkName,
};
Expand Down
Loading

0 comments on commit 69eef49

Please sign in to comment.