Skip to content

Commit

Permalink
core: refresh pending contract calls
Browse files Browse the repository at this point in the history
  • Loading branch information
fracek committed Jan 12, 2024
1 parent 5844a7a commit 3f7bf39
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changeset/new-pillows-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@starknet-react/core": patch
---

Refresh pending contract call
10 changes: 10 additions & 0 deletions packages/core/src/hooks/useContractRead.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { useContract } from "./useContract";
import { useInvalidateOnBlock } from "./useInvalidateOnBlock";
import { useNetwork } from "./useNetwork";

const DEFAULT_FETCH_INTERVAL = 5_000;

type ContractReadArgs = {
/** The contract's function name. */
functionName: string;
Expand Down Expand Up @@ -58,6 +60,7 @@ export function useContractRead({
blockIdentifier = BlockTag.latest,
parseArgs,
parseResult,
refetchInterval: refetchInterval_,
watch = false,
enabled: enabled_ = true,
...props
Expand All @@ -75,6 +78,12 @@ export function useContractRead({
[enabled_, contract, functionName, args],
);

const refetchInterval =
refetchInterval_ ??
(blockIdentifier === BlockTag.pending && watch
? DEFAULT_FETCH_INTERVAL
: undefined);

useInvalidateOnBlock({
enabled: Boolean(enabled && watch),
queryKey: queryKey_,
Expand All @@ -90,6 +99,7 @@ export function useContractRead({
parseArgs,
parseResult,
}),
refetchInterval,
...props,
});
}
Expand Down
93 changes: 93 additions & 0 deletions website/components/demos/contract-read.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"use client";
import React, { useState } from "react";

import { BlockTag } from "starknet";
import { useContractRead, useNetwork } from "@starknet-react/core";

import { StarknetProvider } from "@/components/starknet/provider";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Button } from "@/components/ui/button";

function ContractRead() {
const [blockIdentifier, setBlockIdentifier] = useState("latest");
const { chain } = useNetwork();

const { data, refetch, fetchStatus, status } = useContractRead({
abi: [
{
inputs: [],
name: "symbol",
outputs: [
{
name: "symbol",
type: "felt",
},
],
stateMutability: "view",
type: "function",
},
],
functionName: "symbol",
address: chain.nativeCurrency.address,
args: [],
watch: true,
blockIdentifier:
blockIdentifier === "latest" ? BlockTag.latest : BlockTag.pending,
});

return (
<Card className="max-w-[400px] mx-auto">
<CardHeader>
<CardTitle>Contract read</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-1">
<Label>Block identifier</Label>
<Select value={blockIdentifier} onValueChange={setBlockIdentifier}>
<SelectTrigger className="w[200px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="latest">Latest</SelectItem>
<SelectItem value="pending">Pending</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<div className="space-y-1">
<Label>Fetch status</Label>
<p>{fetchStatus}</p>
</div>
<div className="space-y-1">
<Label>Status</Label>
<p>{status}</p>
</div>
<div className="space-y-1">
<Label>Call result</Label>
<p>{JSON.stringify(data)}</p>
</div>
<div className="space-y-1">
<Button onClick={() => refetch()}>Refetch data</Button>
</div>
</CardContent>
</Card>
);
}

export function ContractReadDemo() {
return (
<StarknetProvider>
<ContractRead />
</StarknetProvider>
);
}
2 changes: 2 additions & 0 deletions website/components/mdx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { SendTransactionDemo } from "@/components/demos/send-transaction";
import { ExplorersDemo } from "@/components/demos/explorers";
import { SignMessageDemo } from "@/components/demos/sign-message";
import { TokenBalanceDemo } from "@/components/demos/balance";
import { ContractReadDemo } from "@/components/demos/contract-read";
import { StarknetIDDemo } from "@/components/demos/starknetid";
import { TransactionManagerDemo } from "@/components/demos/transaction-manager";
import { DemoContainer } from "@/components/demo-container";
Expand All @@ -24,6 +25,7 @@ const components = {
ExplorersDemo,
StarknetIDDemo,
TokenBalanceDemo,
ContractReadDemo,
TransactionManagerDemo,
DemoContainer,

Expand Down
61 changes: 61 additions & 0 deletions website/content/demos/contract-read.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
title: Contract Read
priority: 90
---

This example shows how to make a contract call.

<DemoContainer>
<ContractReadDemo />
</DemoContainer>

## The `useContractRead` hook

The `useContractRead` hook is used to make a read-only call to a smart contract.

The hook takes the following parameters:

- `abi`: the smart contract ABI. Generated by Scarb and available from block explorers.
- `address`: the smart contract address.
- `functionName`: the function being invoked.
- `args`: function arguments.
- `blockIdentifier`: make a call against a specific block number, or the latest or pending block.

```tsx
const { chain } = useNetwork();

const { data, refetch, fetchStatus, status } = useContractRead({
abi: [
{
inputs: [],
name: "symbol",
outputs: [
{
name: "symbol",
type: "felt",
},
],
stateMutability: "view",
type: "function",
},
],
functionName: "symbol",
address: chain.nativeCurrency.address,
args: [],
watch: true,
blockIdentifier:
blockIdentifier === "latest" ? BlockTag.latest : BlockTag.pending,
});
```

## Refreshing data

You can refresh data either manually or automatically.

- Manually: call the `refetch` function.
- Automatically (default): if `watch` is true and the `blockIdentifier` is `BlockTag.latest`, the hook will
refresh data on every new block. If it's `BlockTag.pending`, data is refreshed
every few seconds.
- Automatically (custom): set `watch` to true and use the `refetchInterval` parameter to change
how data is refreshed. Set it to `false` to always disable refreshing data, or
specify a custom interval.
21 changes: 11 additions & 10 deletions website/content/hooks/query/useContractRead.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ priority: 197
hookType: query
---

Perform a read-only contract call.
Perform a read-only contract call. If the specified block identifier
is pending, the hook will periodically refetch data automatically.

## Usage

Expand Down Expand Up @@ -70,27 +71,27 @@ export default function Component() {

## Options

- __functionName__`: string`
- **functionName**`: string`
- The contract's function name.
- __args__`: string[]`
- **args**`: string[]`
- The contract's arguments array.
- __blockIdentifier?__`: BlockNumber`
- **blockIdentifier?**`: BlockNumber`
- Block identifier used when performing call.
- BlockNumber from starknet.js
- __parseArgs?__`: boolean`
- **parseArgs?**`: boolean`
- If true, parse arguments before passing to contract.
- __parseResult?__`: boolean`
- **parseResult?**`: boolean`
- If true, parse result after calling contract.
- __abi__`: Abi`
- **abi**`: Abi`
- The target contract's ABI.
- Abi from starknet.js
- __address__`: string`
- **address**`: string`
- Which block to fetch.
- __watch?__`: boolean`
- **watch?**`: boolean`
- If true, refresh data at every block.

## Returns

- __data?__`: Result`
- **data?**`: Result`
- The contract
- Result from starknet.js

0 comments on commit 3f7bf39

Please sign in to comment.