Skip to content

Commit

Permalink
Feat: useEstimateFees hook (#422)
Browse files Browse the repository at this point in the history
## Context
As described in the issue #411, dapps sometimes needs fees estimation
before doing the actual contract call. For this, I've created the
useEstimateFees hook.

## Changes in this Pull Request
- Added useEstimateFees custom hook.
- Added relevant documentation in the docs with usage example.
  • Loading branch information
fracek committed Apr 3, 2024
2 parents b7868d9 + 78b124d commit cca5816
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/six-crews-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@starknet-react/core": minor
---

Add useEstimateFees hook to estimate smart contract calls fees
1 change: 1 addition & 0 deletions packages/core/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export * from "./useStarkAddress";
export * from "./useStarkName";
export * from "./useWaitForTransaction";
export * from "./useStarkProfile";
export * from "./useEstimateFees";
92 changes: 92 additions & 0 deletions packages/core/src/hooks/useEstimateFees.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { useMemo } from "react";
import {
AccountInterface,
Call,
EstimateFeeDetails,
EstimateFeeResponse,
} from "starknet";

import { UseQueryProps, UseQueryResult, useQuery } from "~/query";

import { useAccount } from "./useAccount";
import { useInvalidateOnBlock } from "./useInvalidateOnBlock";

type EstimateFeesArgs = {
/** List of smart contract calls to estimate. */
calls?: Call[];
/** Estimate Fee options. */
options?: EstimateFeeDetails;
};

/** Options for `useEstimateFees`. */
export type UseEstimateFeesProps = EstimateFeesArgs &
UseQueryProps<EstimateFeeResponse, Error, EstimateFeeResponse, ReturnType<typeof queryKey>> & {
/** Refresh data at every block. */
watch?: boolean;
};

/** Value returned from `useEstimateFees`. */
export type UseEstimateFeesResult = UseQueryResult<EstimateFeeResponse, Error>;

/**
* Hook to estimate fees for smart contract calls.
*
* @remarks
*
* The hook only performs estimation if the `calls` is not undefined.
*/
export function useEstimateFees({
calls,
options,
watch = false,
enabled: enabled_ = true,
...props
}: UseEstimateFeesProps): UseEstimateFeesResult {
const { account } = useAccount();

const queryKey_ = useMemo(
() => queryKey({ calls, options }),
[calls, options]
);

const enabled = useMemo(
() => Boolean(enabled_ && calls),
[enabled_, calls],
);

useInvalidateOnBlock({
enabled: Boolean(enabled && watch),
queryKey: queryKey_,
});

return useQuery({
queryKey: queryKey_,
queryFn: queryFn({
account,
calls,
options,
}),
...props,
});
}

function queryKey({
calls,
options,
}: EstimateFeesArgs) {
return [
{
entity: "estimateInvokeFee",
calls,
options,
},
] as const;
}

function queryFn({ account, calls, options }: { account?: AccountInterface } & EstimateFeesArgs) {
return async function () {
if (!account) throw new Error("account is required");
if (!calls || calls.length === 0) throw new Error("calls are required");
return account?.estimateInvokeFee(calls, options);
};
}
53 changes: 53 additions & 0 deletions website/content/hooks/query/useEstimateFees.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
title: useEstimateFees
priority: 194
hookType: query
---

Perform fee estimation for smart contract calls. Estimation then later can be used to specify the `maxFee` for the actual contract call.

## Usage

```ts
import { useAccount, useContract, useEstimateFees } from "@starknet-react/core";

export default function Component() {
const { address } = useAccount();

const { contract } = useContract({
abi: erc20ABI,
address: chain.nativeCurrency.address,
});

const calls = useMemo(() => {
if (!address || !contract) return [];
return contract.populateTransaction["transfer"]!(address, { low: 1, high: 0 });
}, [contract, address]);

const { data, isError, isLoading, error } = useEstimateFees({
calls,
watch: true,
});

if (isLoading) return <div>Loading ...</div>;
if (isError || !data) return <div>{error?.message}</div>;

return <div>Suggested Max Fee: {data.suggestedMaxFee}</div>;
}
```

## Options

- **calls**`: string`
- The contract calls to estimate fees for.
- **options**`: string`
- Estimation options.
- EstimateFeeDetails from starknet.js
- **watch?**`: boolean`
- If true, refresh data at every block.

## Returns

- **data?**`: EstimateFeeResponse`
- Estimated fees for the contract calls.
- EstimateFeeResponse from starknet.js

0 comments on commit cca5816

Please sign in to comment.