Skip to content

Commit

Permalink
fix: improve fee estimate (#105)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsimao authored Oct 16, 2024
1 parent de744af commit 15407a0
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 24 deletions.
2 changes: 1 addition & 1 deletion packages/sats-wagmi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
},
"dependencies": {
"@bitcoin-js/tiny-secp256k1-asmjs": "^2.2.3",
"@gobob/bob-sdk": "^2.3.3",
"@gobob/bob-sdk": "^2.3.7",
"@metamask/providers": "^12.0.0",
"@scure/base": "^1.1.6",
"@scure/btc-signer": "^1.3.1",
Expand Down
3 changes: 3 additions & 0 deletions packages/sats-wagmi/src/constants/fee-estimate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Confirmation target for fee estimation in Bitcoin blocks

export const CONFIRMATION_TARGET = 6;
1 change: 1 addition & 0 deletions packages/sats-wagmi/src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './local-storage';
export * from './fee-estimate';
9 changes: 5 additions & 4 deletions packages/sats-wagmi/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
export * from './useConnect';
export * from './useAccount';
export * from './useDisconnect';
export * from './useBalance';
export * from './useFeeRate';
export * from './useConnect';
export * from './useDisconnect';
export * from './useFeeEstimate';
export * from './useFeeRate';
export * from './useSendGatewayTransaction';
export * from './useSendTransaction';
export * from './useSignMessage';
export * from './useSendGatewayTransaction';
export * from './useUtxos';
export * from './useWaitForTransactionReceipt';
33 changes: 26 additions & 7 deletions packages/sats-wagmi/src/hooks/useFeeEstimate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,49 @@
import { estimateTxFee } from '@gobob/bob-sdk';
import { UndefinedInitialDataOptions, useQuery } from '@tanstack/react-query';

import { CONFIRMATION_TARGET } from '../constants';
import { INTERVAL } from '../utils';
import { useSatsWagmi } from '../provider';

import { useFeeRate } from './useFeeRate';
import { useAccount } from './useAccount';

type UseFeeEstimateProps = {
query?: Omit<UndefinedInitialDataOptions<bigint, Error, bigint, (string | undefined)[]>, 'queryKey' | 'queryFn'>;
query?: Omit<
UndefinedInitialDataOptions<bigint, Error, bigint, (string | number | undefined)[]>,
'queryKey' | 'queryFn'
>;
amount?: number;
opReturnData?: string;
confirmationTarget?: number;
};

const useFeeEstimate = ({ query }: UseFeeEstimateProps = {}) => {
const { data: feeRate } = useFeeRate();
const useFeeEstimate = ({
amount,
opReturnData,
confirmationTarget = CONFIRMATION_TARGET,
query
}: UseFeeEstimateProps = {}) => {
const { address, publicKey } = useAccount();
const { data: feeRate } = useFeeRate({ confirmationTarget });
const { network } = useSatsWagmi();

const enabled = Boolean(feeRate && address && (query?.enabled !== undefined ? query.enabled : true));

return useQuery({
queryKey: ['sats-fee-estimate', network, feeRate?.toString()],
queryKey: ['sats-fee-estimate', amount, address, opReturnData, network, feeRate?.toString(), confirmationTarget],
queryFn: async () => {
const feeEstimate = estimateTxFee(Number(feeRate));
if (!address || !feeRate || !publicKey) {
throw new Error('Failed to estimate fee');
}

return BigInt(feeEstimate);
return estimateTxFee(address, amount, publicKey, opReturnData, Number(feeRate), confirmationTarget);
},
refetchOnWindowFocus: false,
refetchOnMount: false,
refetchInterval: INTERVAL.MINUTE,
...query
...query,
enabled
});
};

Expand Down
14 changes: 6 additions & 8 deletions packages/sats-wagmi/src/hooks/useFeeRate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,24 @@
import { EsploraClient } from '@gobob/bob-sdk';
import { UndefinedInitialDataOptions, useQuery } from '@tanstack/react-query';

import { CONFIRMATION_TARGET } from '../constants';
import { INTERVAL } from '../utils';
import { useSatsWagmi } from '../provider';

// Confirmation target for fee estimation in Bitcoin blocks
export const CONFIRMATION_TARGET = 3;

type UseFeeRateProps = {
confirmations?: number;
query?: Omit<UndefinedInitialDataOptions<bigint, Error, bigint, string[]>, 'queryKey' | 'queryFn'>;
confirmationTarget?: number;
query?: Omit<UndefinedInitialDataOptions<bigint, Error, bigint, (string | number)[]>, 'queryKey' | 'queryFn'>;
};

const useFeeRate = ({ query, confirmations = CONFIRMATION_TARGET }: UseFeeRateProps = {}) => {
const useFeeRate = ({ query, confirmationTarget = CONFIRMATION_TARGET }: UseFeeRateProps = {}) => {
const { network } = useSatsWagmi();

return useQuery({
queryKey: ['sats-fee-rate', network],
queryKey: ['sats-fee-rate', confirmationTarget, network],
queryFn: async () => {
const esploraClient = new EsploraClient(network);

const feeRate = await esploraClient.getFeeEstimate(confirmations);
const feeRate = await esploraClient.getFeeEstimate(confirmationTarget);

return BigInt(Math.ceil(feeRate));
},
Expand Down
42 changes: 42 additions & 0 deletions packages/sats-wagmi/src/hooks/useUtxos.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use client';

import { UndefinedInitialDataOptions, useQuery } from '@tanstack/react-query';
import { EsploraClient, UTXO } from '@gobob/bob-sdk';

import { INTERVAL } from '../utils';
import { useSatsWagmi } from '../provider';

import { useAccount } from './useAccount';

type UseUTXOSProps = {
query?: Omit<
UndefinedInitialDataOptions<UTXO[], Error, UTXO[], (string | number | undefined)[]>,
'queryKey' | 'queryFn'
>;
confirmed?: boolean;
};

const useUtxos = ({ query, confirmed }: UseUTXOSProps = {}) => {
const { address } = useAccount();
const { network } = useSatsWagmi();

return useQuery({
queryKey: ['sats-utxos', confirmed ? 'confirmed' : 'all', address, network],
queryFn: async () => {
if (!address) {
throw new Error('Failed to get utxos');
}
const esploraClient = new EsploraClient(network);

return esploraClient.getAddressUtxos(address, confirmed);
},
refetchOnWindowFocus: false,
refetchOnMount: false,
refetchInterval: INTERVAL.SECONDS_30,
...query,
enabled: Boolean(address && (query?.enabled !== undefined ? query.enabled : true))
});
};

export { useUtxos };
export type { UseUTXOSProps };
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 15407a0

Please sign in to comment.