Skip to content

Commit

Permalink
feat: writeContract
Browse files Browse the repository at this point in the history
  • Loading branch information
jxom committed Feb 3, 2023
1 parent 83b1e92 commit ac69d16
Show file tree
Hide file tree
Showing 23 changed files with 634 additions and 403 deletions.
5 changes: 5 additions & 0 deletions .changeset/honest-dots-impress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": patch
---

Added `writeContract`.
5 changes: 5 additions & 0 deletions .changeset/hungry-countries-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": patch
---

**Breaking**: Replaced `callContract` with `simulateContract`.
10 changes: 5 additions & 5 deletions site/.vitepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,10 +392,6 @@ export const sidebar: DefaultTheme.Sidebar = {
{
text: 'Actions',
items: [
{
text: 'callContract',
link: '/docs/contract/callContract',
},
{
text: 'deployContract',
link: '/docs/contract/deployContract',
Expand All @@ -417,7 +413,11 @@ export const sidebar: DefaultTheme.Sidebar = {
link: '/docs/contract/readContract',
},
{
text: 'writeContract 🚧',
text: 'simulateContract',
link: '/docs/contract/simulateContract',
},
{
text: 'writeContract',
link: '/docs/contract/writeContract',
},
{
Expand Down
2 changes: 1 addition & 1 deletion site/docs/contract/multicall.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# multicall

Similar to [`callContract`](/docs/contract/callContract), but batches up & calls multiple functions on a contract in a single RPC call via the [`multicall3` contract](https://github.com/mds1/multicall).
Similar to [`readContract`](/docs/contract/readContract), but batches up & calls multiple functions on a contract in a single RPC call via the [`multicall3` contract](https://github.com/mds1/multicall).

## Import

Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,35 @@
# callContract
# simulateContract

The `callContract` function allows for the execution of a **read** or **write** function on a contract, and returns the response.
The `simulateContract` function **simulates**/**validates** a contract interaction. This is useful for retrieving **return data** and **revert reasons** of contract write functions.

It is similar to [`readContract`](/docs/contract/readContract), in that it does not require gas to execute and _**does not**_ change the state of the blockchain, but also supports **contract write** functions.
This function does not require gas to execute and _**does not**_ change the state of the blockchain. It is almost identical to [`readContract`](/docs/contracts/readContract), but also supports contract write functions.

It is useful for:

- **simulating** or **validating** a contract interaction.
- retrieving **return data** (and **revert reasons**) of write functions (via `writeContract`).

Internally, `callContract` uses a [Public Client](/docs/clients/public) to call the [`call` action](/docs/actions/public/call) with [ABI-encoded `data`](/docs/contract/encodeFunctionData).
Internally, `simulateContract` uses a [Public Client](/docs/clients/public) to call the [`call` action](/docs/actions/public/call) with [ABI-encoded `data`](/docs/contract/encodeFunctionData).

## Import

```ts
import { callContract } from 'viem'
import { simulateContract } from 'viem'
```

## Usage

Below is a very basic example of how to call a write function on a contract (with no arguments).
Below is a very basic example of how to simulate a write function on a contract (with no arguments).

The `mint` function accepts no arguments, and returns a token ID.

::: code-group

```ts [example.ts]
import { callContract } from 'viem'
import { simulateContract } from 'viem'
import { publicClient } from './client'
import { wagmiAbi } from './abi'

const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
})
// 69420
```
Expand Down Expand Up @@ -75,15 +71,16 @@ For example, the `mint` function name below requires a **tokenId** argument, and
::: code-group

```ts {9} [example.ts]
import { callContract } from 'viem'
import { simulateContract } from 'viem'
import { publicClient } from './client'
import { wagmiAbi } from './abi'

const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420]
args: [69420],
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
})
// 69420
```
Expand Down Expand Up @@ -114,6 +111,54 @@ export const publicClient = createPublicClient({

:::

### Pairing with `writeContract`

The `simulateContract` function also pairs well with `writeContract`.

In the example below, we are **validating** if the contract write will be successful via `simulateContract`. If no errors are thrown, then we are all good. After that, we perform a contract write to execute the transaction.

::: code-group

```ts [example.ts]
import { simulateContract } from 'viem'
import { walletClient, publicClient } from './client'
import { wagmiAbi } from './abi'

const { request } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
})
const hash = await writeContract(walletClient, request)
```

```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [{ name: "", type: "uint32" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```

```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'

export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```

:::

## Return Value

The response from the contract. Type is inferred.
Expand All @@ -127,10 +172,11 @@ The response from the contract. Type is inferred.
The contract address.

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'mint',
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
})
```

Expand All @@ -141,10 +187,11 @@ const data = await callContract(publicClient, {
The contract's ABI.

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'mint',
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
})
```

Expand All @@ -155,10 +202,26 @@ const data = await callContract(publicClient, {
A function to extract from the ABI.

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint', // [!code focus]
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
})
```

### from

- **Type:** `Address`

The sender of the call.

```ts
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' // [!code focus]
})
```

Expand All @@ -169,7 +232,7 @@ const data = await callContract(publicClient, {
The access list.

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
Expand All @@ -178,6 +241,7 @@ const data = await callContract(publicClient, {
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
storageKeys: ['0x1'],
}],
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
})
```

Expand All @@ -189,26 +253,12 @@ const data = await callContract(publicClient, {
Arguments to pass to function call.

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'] // [!code focus]
})
```

### from (optional)

- **Type:** `Address`

Optional sender override.

```ts
const data = await callContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' // [!code focus]
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'], // [!code focus]
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
})
```

Expand All @@ -219,11 +269,12 @@ const data = await callContract(publicClient, {
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#TODO).

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
gasPrice: parseGwei('20'), // [!code focus]
})
```
Expand All @@ -235,11 +286,12 @@ const data = await callContract(publicClient, {
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#TODO)

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
Expand All @@ -251,11 +303,12 @@ const data = await callContract(publicClient, {
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#TODO)

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
Expand All @@ -268,11 +321,12 @@ const data = await callContract(publicClient, {
Unique number identifying this transaction.

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
nonce: 69 // [!code focus]
})
```
Expand All @@ -284,11 +338,12 @@ const data = await callContract(publicClient, {
Value in wei sent with this transaction.

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
value: parseEther('1') // [!code focus]
})
```
Expand All @@ -302,10 +357,11 @@ const data = await callContract(publicClient, {
The block number to perform the read against.

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
blockNumber: 15121123n, // [!code focus]
})
```
Expand All @@ -318,10 +374,11 @@ const data = await callContract(publicClient, {
The block tag to perform the read against.

```ts
const data = await callContract(publicClient, {
const { result } = await simulateContract(publicClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
blockTag: 'safe', // [!code focus]
})
```
Loading

3 comments on commit ac69d16

@vercel
Copy link

@vercel vercel bot commented on ac69d16 Feb 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

viem-playground – ./playgrounds/dev

viem-playground-git-main-wagmi-dev.vercel.app
viem-playground.vercel.app
viem-playground-wagmi-dev.vercel.app

@vercel
Copy link

@vercel vercel bot commented on ac69d16 Feb 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

viem-benchmark – ./playgrounds/benchmark

viem-benchmark-git-main-wagmi-dev.vercel.app
viem-benchmark-wagmi-dev.vercel.app
viem-benchmark.vercel.app

@vercel
Copy link

@vercel vercel bot commented on ac69d16 Feb 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

viem-site – ./site

viem-site.vercel.app
viem-site-wagmi-dev.vercel.app
viem-site-git-main-wagmi-dev.vercel.app

Please sign in to comment.