Skip to content

Commit

Permalink
fix(react,vue): useReadContract deployless reads (#4260)
Browse files Browse the repository at this point in the history
* fix(react,vue): deployless reads

* chore: changeset
  • Loading branch information
tmm committed Sep 10, 2024
1 parent f47ce8f commit 969a208
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 12 deletions.
6 changes: 6 additions & 0 deletions .changeset/dirty-poems-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"wagmi": patch
"@wagmi/vue": patch
---

Fixed `useReadContract` deployless reads support.
22 changes: 22 additions & 0 deletions packages/core/src/actions/readContract.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,25 @@ test('overloads', async () => {
// @ts-ignore – TODO: Fix https://github.com/wevm/viem/issues/1916
}>(result4)
})

test('deployless read (bytecode)', async () => {
const result = await readContract(config, {
code: '0x',
abi: abi.erc20,
functionName: 'balanceOf',
args: ['0x'],
})
expectTypeOf(result).toEqualTypeOf<bigint>()
})

test('deployless read (factory)', async () => {
const result = await readContract(config, {
address: '0x',
abi: abi.erc20,
functionName: 'balanceOf',
args: ['0x'],
factory: '0x',
factoryData: '0x',
})
expectTypeOf(result).toEqualTypeOf<bigint>()
})
12 changes: 11 additions & 1 deletion packages/core/src/actions/readContract.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { abi, address, chain, config } from '@wagmi/test'
import { abi, address, bytecode, chain, config } from '@wagmi/test'
import { expect, test } from 'vitest'

import { readContract } from './readContract.js'
Expand All @@ -25,3 +25,13 @@ test('parameters: chainId', async () => {
}),
).resolves.toMatchInlineSnapshot('4n')
})

test('parameters: deployless read (bytecode)', async () => {
await expect(
readContract(config, {
abi: abi.wagmiMintExample,
functionName: 'name',
code: bytecode.wagmiMintExample,
}),
).resolves.toMatchInlineSnapshot(`"wagmi"`)
})
17 changes: 12 additions & 5 deletions packages/core/src/query/readContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,22 @@ export function readContractQueryOptions<
async queryFn({ queryKey }) {
const abi = options.abi as Abi
if (!abi) throw new Error('abi is required')
const { address, functionName, scopeKey: _, ...parameters } = queryKey[1]
if (!address) throw new Error('address is required')

const { functionName, scopeKey: _, ...parameters } = queryKey[1]
const addressOrCodeParams = (() => {
const params = queryKey[1] as unknown as ReadContractParameters
if (params.address) return { address: params.address }
if (params.code) return { code: params.code }
throw new Error('address or code is required')
})()

if (!functionName) throw new Error('functionName is required')
const args = parameters.args as readonly unknown[]

return readContract(config, {
abi,
address,
functionName,
args,
args: parameters.args as readonly unknown[],
...addressOrCodeParams,
...parameters,
}) as Promise<ReadContractData<abi, functionName, args>>
},
Expand Down
10 changes: 10 additions & 0 deletions packages/react/src/hooks/useReadContract.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,13 @@ test('overloads', () => {
// @ts-ignore – TODO: Fix https://github.com/wevm/viem/issues/1916
>(result4.data)
})

test('deployless read (bytecode)', () => {
const result = useReadContract({
code: '0x',
abi: abi.erc20,
functionName: 'balanceOf',
args: ['0x'],
})
expectTypeOf(result.data).toEqualTypeOf<bigint | undefined>()
})
16 changes: 15 additions & 1 deletion packages/react/src/hooks/useReadContract.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { QueryClientProvider } from '@tanstack/react-query'
import { abi, address, chain, config, wait } from '@wagmi/test'
import { abi, address, bytecode, chain, config, wait } from '@wagmi/test'
import { queryClient, renderHook, waitFor } from '@wagmi/test/react'
import { createElement } from 'react'
import { expect, test } from 'vitest'
Expand Down Expand Up @@ -172,6 +172,20 @@ test('parameters: config', async () => {
`)
})

test('parameters: deployless read (bytecode)', async () => {
const { result } = renderHook(() =>
useReadContract({
abi: abi.wagmiMintExample,
functionName: 'name',
code: bytecode.wagmiMintExample,
}),
)

await waitFor(() => expect(result.current.isSuccess).toBeTruthy())

expect(result.current.data).toMatchInlineSnapshot(`"wagmi"`)
})

test('behavior: disabled when properties missing', async () => {
const { result } = renderHook(() => useReadContract())

Expand Down
6 changes: 4 additions & 2 deletions packages/react/src/hooks/useReadContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
readContractQueryOptions,
structuralSharing,
} from '@wagmi/core/query'
import type { Abi, ContractFunctionArgs, ContractFunctionName } from 'viem'
import type { Abi, ContractFunctionArgs, ContractFunctionName, Hex } from 'viem'

import type { ConfigParameter, QueryParameter } from '../types/properties.js'
import { type UseQueryReturnType, useQuery } from '../utils/query.js'
Expand Down Expand Up @@ -76,6 +76,8 @@ export function useReadContract<
> = {} as any,
): UseReadContractReturnType<abi, functionName, args, selectData> {
const { abi, address, functionName, query = {} } = parameters
// @ts-ignore
const code = parameters.code as Hex | undefined

const config = useConfig(parameters)
const chainId = useChainId({ config })
Expand All @@ -85,7 +87,7 @@ export function useReadContract<
{ ...(parameters as any), chainId: parameters.chainId ?? chainId },
)
const enabled = Boolean(
address && abi && functionName && (query.enabled ?? true),
(address || code) && abi && functionName && (query.enabled ?? true),
)

return useQuery({
Expand Down
2 changes: 2 additions & 0 deletions packages/test/src/constants.ts

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions packages/vue/src/composables/useReadContract.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,13 @@ test('overloads', () => {
// @ts-ignore – TODO: Fix https://github.com/wevm/viem/issues/1916
>(result4.data)
})

test('deployless read (bytecode)', () => {
const result = useReadContract({
code: '0x',
abi: abi.erc20,
functionName: 'balanceOf',
args: ['0x'],
})
expectTypeOf(result.data.value).toEqualTypeOf<bigint | undefined>()
})
16 changes: 15 additions & 1 deletion packages/vue/src/composables/useReadContract.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { abi, address, chain, wait } from '@wagmi/test'
import { abi, address, bytecode, chain, wait } from '@wagmi/test'
import { renderComposable, waitFor } from '@wagmi/test/vue'
import { expect, test } from 'vitest'
import { ref } from 'vue'
Expand Down Expand Up @@ -62,6 +62,20 @@ test('parameters: chainId', async () => {
`)
})

test('parameters: deployless read (bytecode)', async () => {
const [result] = renderComposable(() =>
useReadContract({
abi: abi.wagmiMintExample,
functionName: 'name',
code: bytecode.wagmiMintExample,
}),
)

await waitFor(result.isSuccess)

expect(result.data.value).toMatchInlineSnapshot(`"wagmi"`)
})

test.skip('behavior: disabled when missing properties', async () => {
const addressRef = ref()
const abiRef = ref()
Expand Down
3 changes: 2 additions & 1 deletion packages/vue/src/composables/useReadContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export function useReadContract<
abi,
address,
chainId = configChainId.value,
code,
functionName,
query = {},
} = parameters.value
Expand All @@ -96,7 +97,7 @@ export function useReadContract<
{ ...parameters.value, chainId },
)
const enabled = Boolean(
address && abi && functionName && (query.enabled ?? true),
(address || code) && abi && functionName && (query.enabled ?? true),
)
return {
...query,
Expand Down
2 changes: 1 addition & 1 deletion site/core/api/actions/call.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ await call(config, {

### data

`0x${string} | undefined`
`` `0x${string}` | undefined ``

A contract hashed method call with encoded args.

Expand Down

0 comments on commit 969a208

Please sign in to comment.