@@ -4,7 +4,11 @@ import {
4
4
useQuery ,
5
5
} from "@tanstack/react-query" ;
6
6
import type { Abi , AbiFunction , ExtractAbiFunctionNames } from "abitype" ;
7
- import type { ThirdwebContract } from "../../../../contract/contract.js" ;
7
+ import type {
8
+ AbiOfLength ,
9
+ AsyncGetAbiFunctionFromContract ,
10
+ } from "../../../../contract/types.js" ;
11
+ import type { Extension } from "../../../../extensions/types.js" ;
8
12
import {
9
13
type ReadContractOptions ,
10
14
type ReadContractResult ,
@@ -17,17 +21,13 @@ import type {
17
21
import type { PreparedMethod } from "../../../../utils/abi/prepare-method.js" ;
18
22
import { getFunctionId } from "../../../../utils/function-id.js" ;
19
23
import { stringify } from "../../../../utils/json.js" ;
20
-
21
- type PickedQueryOptions = {
22
- enabled ?: boolean ;
23
- refetchInterval ?: number ;
24
- retry ?: number ;
25
- } ;
24
+ import type { WithPickedOnceQueryOptions } from "../types.js" ;
26
25
27
26
/**
28
27
* A hook to read state from a contract that automatically updates when the contract changes.
29
28
*
30
- * You can use raw read calls or read [extensions](https://portal.thirdweb.com/react/v5/extensions) to read from a contract.
29
+ * You can use raw read calls or read [extensions](https://portal.thirdweb.com/react/v5/extensions) to read from a
30
+ * contract.
31
31
*
32
32
* @param options - The options for reading from a contract
33
33
* @returns a UseQueryResult object.
@@ -52,20 +52,19 @@ type PickedQueryOptions = {
52
52
* @contract
53
53
*/
54
54
export function useReadContract <
55
- const abi extends Abi ,
56
- const method extends abi extends { length : 0 }
55
+ const TAbi extends Abi ,
56
+ const TMethod extends TAbi extends AbiOfLength < 0 >
57
57
? AbiFunction | string
58
- : ExtractAbiFunctionNames < abi > ,
58
+ : ExtractAbiFunctionNames < TAbi > ,
59
59
> (
60
- options : ReadContractOptions < abi , method > & {
61
- queryOptions ?: PickedQueryOptions ;
62
- } ,
60
+ options : WithPickedOnceQueryOptions < ReadContractOptions < TAbi , TMethod > > ,
63
61
) : UseQueryResult <
64
- ReadContractResult < PreparedMethod < ParseMethod < abi , method > > [ 2 ] >
62
+ ReadContractResult < PreparedMethod < ParseMethod < TAbi , TMethod > > [ 2 ] >
65
63
> ;
66
64
/**
67
65
* A hook to read state from a contract that automatically updates when the contract changes.
68
- * You can use raw read calls or read [extensions](https://portal.thirdweb.com/react/v5/extensions) to read from a contract.
66
+ * You can use raw read calls or read [extensions](https://portal.thirdweb.com/react/v5/extensions) to read from a
67
+ * contract.
69
68
*
70
69
* @param extension - An extension to call.
71
70
* @param options - The read extension params.
@@ -82,38 +81,41 @@ export function useReadContract<
82
81
* ```
83
82
*/
84
83
export function useReadContract <
85
- const abi extends Abi ,
86
- const params extends object ,
87
- result ,
84
+ const TAbi extends Abi ,
85
+ const TParams extends object ,
86
+ TResult ,
88
87
> (
89
- extension : ( options : BaseTransactionOptions < params , abi > ) => Promise < result > ,
90
- options : BaseTransactionOptions < params , abi > & {
91
- queryOptions ?: PickedQueryOptions ;
92
- } ,
93
- ) : UseQueryResult < result > ;
88
+ extension : Extension < TAbi , TParams , TResult > ,
89
+ options : WithPickedOnceQueryOptions < BaseTransactionOptions < TParams , TAbi > > ,
90
+ ) : UseQueryResult < TResult > ;
94
91
95
92
export function useReadContract <
96
- const abi extends Abi ,
97
- const method extends abi extends {
98
- length : 0 ;
99
- }
100
- ?
101
- | AbiFunction
102
- | `function ${string } `
103
- | ( ( contract : ThirdwebContract < abi > ) => Promise < AbiFunction > )
104
- : ExtractAbiFunctionNames < abi > ,
105
- const params extends object ,
106
- result ,
93
+ const TAbi extends Abi ,
94
+ const TMethod extends TAbi extends AbiOfLength < 0 >
95
+ ? AbiFunction | `function ${string } ` | AsyncGetAbiFunctionFromContract < TAbi >
96
+ : ExtractAbiFunctionNames < TAbi > ,
97
+ const TParams extends object ,
98
+ TResult ,
107
99
> (
108
100
extensionOrOptions :
109
- | ( ( options : BaseTransactionOptions < params , abi > ) => Promise < result > )
110
- | ( ReadContractOptions < abi , method > & {
111
- queryOptions ?: PickedQueryOptions ;
112
- } ) ,
113
- options ?: BaseTransactionOptions < params , abi > & {
114
- queryOptions ?: PickedQueryOptions ;
115
- } ,
101
+ | Extension < TAbi , TParams , TResult >
102
+ | WithPickedOnceQueryOptions < ReadContractOptions < TAbi , TMethod > > ,
103
+ options ?: WithPickedOnceQueryOptions < BaseTransactionOptions < TParams , TAbi > > ,
116
104
) {
105
+ type QueryKey = readonly [
106
+ "readContract" ,
107
+ number | string ,
108
+ string ,
109
+ string | PreparedMethod < ParseMethod < TAbi , TMethod > > ,
110
+ string ,
111
+ ] ;
112
+ type QueryFn = ( ) => Promise <
113
+ TResult | ReadContractResult < PreparedMethod < ParseMethod < TAbi , TMethod > > [ 2 ] >
114
+ > ;
115
+
116
+ let queryKey : QueryKey | undefined ;
117
+ let queryFn : QueryFn | undefined ;
118
+
117
119
// extension case
118
120
if ( typeof extensionOrOptions === "function" ) {
119
121
if ( ! options ) {
@@ -123,45 +125,45 @@ export function useReadContract<
123
125
}
124
126
const { queryOptions, contract, ...params } = options ;
125
127
126
- const query = defineQuery ( {
127
- queryKey : [
128
- "readContract" ,
129
- contract . chain . id ,
130
- contract . address ,
131
- getFunctionId ( extensionOrOptions ) ,
132
- stringify ( params ) ,
133
- ] as const ,
134
- // @ts -expect-error - TODO: clean up the type issues here
135
- queryFn : ( ) => extensionOrOptions ( { ...params , contract } ) ,
136
- ...queryOptions ,
137
- } ) ;
128
+ queryKey = [
129
+ "readContract" ,
130
+ contract . chain . id ,
131
+ contract . address ,
132
+ getFunctionId ( extensionOrOptions ) ,
133
+ stringify ( params ) ,
134
+ ] as const ;
138
135
139
- // TODO - FIX LATER
140
- // biome-ignore lint/correctness/useHookAtTopLevel: <explanation>
141
- return useQuery ( query ) ;
136
+ queryFn = ( ) =>
137
+ extensionOrOptions ( {
138
+ ...( params as TParams ) ,
139
+ contract,
140
+ } ) ;
142
141
}
143
142
// raw tx case
144
143
if ( "method" in extensionOrOptions ) {
145
144
const { queryOptions, ...tx } = extensionOrOptions ;
146
145
147
- const query = defineQuery ( {
148
- queryKey : [
149
- "readContract" ,
150
- tx . contract . chain . id ,
151
- tx . contract . address ,
152
- tx . method ,
153
- stringify ( tx . params ) ,
154
- ] as const ,
155
- queryFn : ( ) => readContract ( extensionOrOptions ) ,
156
- ...queryOptions ,
157
- } ) ;
146
+ queryKey = [
147
+ "readContract" ,
148
+ tx . contract . chain . id ,
149
+ tx . contract . address ,
150
+ tx . method ,
151
+ stringify ( tx . params ) ,
152
+ ] as const ;
153
+
154
+ queryFn = ( ) => readContract ( extensionOrOptions ) ;
155
+ }
158
156
159
- // TODO - FIX LATER
160
- // biome-ignore lint/correctness/useHookAtTopLevel: <explanation>
161
- return useQuery ( query ) ;
157
+ if ( ! queryKey || ! queryFn ) {
158
+ throw new Error (
159
+ `Invalid "useReadContract" options. Expected either a read extension or a transaction object.` ,
160
+ ) as never ;
162
161
}
163
162
164
- throw new Error (
165
- `Invalid "useReadContract" options. Expected either a read extension or a transaction object.` ,
166
- ) as never ;
163
+ return useQuery (
164
+ defineQuery ( {
165
+ queryKey : queryKey as QueryKey ,
166
+ queryFn : queryFn as QueryFn ,
167
+ } ) ,
168
+ ) ;
167
169
}
0 commit comments