Optimized architecture compared to alternative libraries
Typed APIs
Flexible programmatic APIs with extensive TypeScript typing
## Overview
```ts twoslash
// 1. Import modules.
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// 2. Set up your client with desired chain & transport.
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
// 3. Consume an action!
const blockNumber = await client.getBlockNumber()
```
## Features
viem supports all these features out-of-the-box:
* Abstractions over the [JSON-RPC API](https://ethereum.org/en/developers/docs/apis/json-rpc/) to make your life easier
* First-class APIs for interacting with [Smart Contracts](https://ethereum.org/en/glossary/#smart-contract)
* Language closely aligned to official [Ethereum terminology](https://ethereum.org/en/glossary/)
* Import your Browser Extension, WalletConnect or Private Key Wallet
* Browser native [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt), instead of large BigNumber libraries
* Utilities for working with [ABIs](https://ethereum.org/en/glossary/#abi) (encoding/decoding/inspection)
* TypeScript ready ([infer types](/docs/typescript) from ABIs and EIP-712 Typed Data)
* First-class support for [Anvil](https://book.getfoundry.sh/), [Hardhat](https://hardhat.org/) & [Ganache](https://trufflesuite.com/ganache/)
* Test suite running against [forked](https://ethereum.org/en/glossary/#fork) Ethereum network
## Community
Check out the following places for more wagmi-related content:
* Follow [@wevm\_dev](https://twitter.com/wevm_dev), [@\_jxom](https://twitter.com/_jxom), and [@awkweb](https://twitter.com/awkweb) on Twitter for project updates
* Join the [discussions on GitHub](https://github.com/wevm/viem/discussions)
* [Share your project/organization](https://github.com/wevm/viem/discussions/104) that uses viem
## Support
Help support future development and make wagmi a sustainable open-source project:
* [GitHub Sponsors](https://github.com/sponsors/wevm?metadata_campaign=docs_support)
* [Gitcoin Grant](https://wagmi.sh/gitcoin)
* [wevm.eth](https://etherscan.io/enslookup-search?search=wevm.eth)
## Sponsors
# Getting Started with Account Abstraction
**[Account Abstraction (ERC-4337)](https://eips.ethereum.org/EIPS/eip-4337)** is a proposal within the Ethereum ecosystem which aims to standardize Smart Contract Accounts (SCA) and their operations without the need to modify or upgrade the protocol.
Smart Contract Accounts can send calls on the Network via a "meta-transaction" called a **User Operation.** Users can send User Operations to **Bundlers** which aggregate User Operations into single transactions and submit them to the Network via an **EntryPoint** contract.
Key features that Account Abstraction enables are:
* **Batching:** Group multiple calls into a single transaction.
* **Fee Sponsorship:** Allow third parties to pay for gas fees, or pay for gas via ERC20 tokens.
* **Arbitrary Signature Verification:** Smart Contract Accounts can contain arbitrary signature verification logic (e.g. WebAuthn, secp256r1, secp256k1, ed25519, etc).
* **Multi-Owner Wallets:** Enable multiple owners to control a single account, and set rules for the owners.
* **Recovery Mechanisms:** A Smart Contract Account can assign multiple entities or services as trusted recovery agents for the Account.
* and many more...
:::note
**Compatibility Note**
As ERC-4337 is not enshrined on the protocol, this means that Smart Accounts are incompatible with Viem's Transaction APIs such as `sendTransaction` and `writeContract`.
Sending "transactions" can be achieved by broadcasting a **User Operation** to a **Bundler**, which will then broadcast it to the Network shortly after.
The most common Actions for **User Operations** are:
* [`sendUserOperation`](/account-abstraction/actions/bundler/sendUserOperation) (also supports [Contract Writes](/account-abstraction/actions/bundler/sendUserOperation#contract-calls))
* [`estimateUserOperationGas`](/account-abstraction/actions/bundler/estimateUserOperationGas)
* [`getUserOperation`](/account-abstraction/actions/bundler/getUserOperation)
* [`getUserOperationReceipt`](/account-abstraction/actions/bundler/getUserOperationReceipt)
Once Account Abstraction is enshrined on the protocol, we anticipate the above Actions will become redundant in favor of Viem's Transaction APIs.
:::
## Sending your first User Operation
### 1. Set up a Client
A Smart Account needs access to the Network to query for information about its state (e.g. nonce, address, etc). Let's set up a Client that we can use for the Smart Account:
```ts twoslash
// @noErrors
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
[See `createPublicClient` Docs](/docs/clients/public)
### 2. Set up a Bundler Client
Next, we need to set up a Bundler Client. A Bundler is required to submit User Operations to the Network for the Smart Account.
```ts twoslash
import { createPublicClient, http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction' // [!code focus]
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const bundlerClient = createBundlerClient({ // [!code focus]
client, // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc'), // [!code focus]
}) // [!code focus]
```
:::info
The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Bundler](https://www.pimlico.io), [Biconomy's Bundler](https://www.biconomy.io), or another Bundler service.
:::
[See `createBundlerClient` Docs](/account-abstraction/clients/bundler)
### 3. Set up an Owner
We also need to set up an Owner for the Smart Account which will be used to sign User Operations (transactions) for the Smart Account.
```ts twoslash
// @noErrors
import { createPublicClient, http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts' // [!code focus]
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const bundlerClient = createBundlerClient({
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const owner = privateKeyToAccount('0x...') // [!code focus]
```
[See `privateKeyToAccount` Docs](/docs/accounts/local/privateKeyToAccount)
### 4. Create a Smart Account
Next, we instantiate a Smart Account. For this example, we will use [`toCoinbaseSmartAccount`](/account-abstraction/accounts/smart/toCoinbaseSmartAccount) (Coinbase Smart Wallet).
```ts twoslash
// @noErrors
import { createPublicClient, http } from 'viem'
import { // [!code focus]
createBundlerClient, // [!code focus]
toCoinbaseSmartAccount // [!code focus]
} from 'viem/account-abstraction' // [!code focus]
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const bundlerClient = createBundlerClient({
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const owner = privateKeyToAccount('0x...')
const account = await toCoinbaseSmartAccount({ // [!code focus]
client, // [!code focus]
owners: [owner], // [!code focus]
version: '1.1', // [!code focus]
}) // [!code focus]
```
:::tip
**Tip:** `toCoinbaseSmartAccount` also accepts [Passkey (WebAuthn) Accounts](/account-abstraction/accounts/webauthn) as an `owner`.
:::
[See `toCoinbaseSmartAccount` Docs](/account-abstraction/accounts/smart/toCoinbaseSmartAccount)
### 5. Send User Operation
Next, we send a User Operation to the Bundler. For the example below, we will send 0.001 ETH to a random address.
```ts twoslash
import { createPublicClient, http, parseEther } from 'viem'
import {
createBundlerClient,
toCoinbaseSmartAccount
} from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const bundlerClient = createBundlerClient({
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const owner = privateKeyToAccount('0x...')
const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
const hash = await bundlerClient.sendUserOperation({ // [!code focus]
account, // [!code focus]
calls: [{ // [!code focus]
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D', // [!code focus]
value: parseEther('0.001') // [!code focus]
}] // [!code focus]
}) // [!code focus]
const receipt = await bundlerClient.waitForUserOperationReceipt({ hash }) // [!code focus]
```
:::tip
**Tip:** The `calls` property also accepts [Contract Write calls](/account-abstraction/actions/bundler/sendUserOperation).
:::
[See `sendUserOperation` Docs](/account-abstraction/actions/bundler/sendUserOperation)
### 6. Optional: Hoist the Account
If you do not wish to pass an account around to every Action that requires an `account`, you can also hoist the account onto a Bundler Client.
```ts twoslash
import { createPublicClient, http, parseEther } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const owner = privateKeyToAccount('0x...')
const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
const bundlerClient = createBundlerClient({
account, // [!code ++]
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const hash = await bundlerClient.sendUserOperation({
account, // [!code --]
calls: [{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('0.001')
}]
})
```
### 7. Optional: Sponsor User Operation
By using a Paymaster, we can add sponsorship of User Operation fees.
Viem exposes a `paymaster` property on both the **Bundler Client** ("on Client" tab) and **User Operation Action** ("on Action" tab) to add User Operation sponsorship capabilities.
The `paymaster` property accepts a [Paymaster Client](/account-abstraction/clients/paymaster) ([among others](#TODO)), which is used to fetch the necessary data for User Operation sponsorship.
:::info
The example below uses [Pimlico's Paymaster API](https://docs.pimlico.io/infra/paymaster) – allowing consumers to sponsor gas fees for users on over 30+ chains.
:::
:::code-group
```ts twoslash [example.ts (on Client)]
import { http } from 'viem'
import {
createBundlerClient,
createPaymasterClient,
} from 'viem/account-abstraction'
import { account, client } from './config.ts'
const paymasterClient = createPaymasterClient({ // [!code ++]
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}'), // [!code ++]
}) // [!code ++]
const bundlerClient = createBundlerClient({
account,
client,
paymaster: paymasterClient, // [!code ++]
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const hash = await bundlerClient.sendUserOperation({
calls: [{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('0.001')
}]
})
```
```ts twoslash [example.ts (on Action)]
import { http } from 'viem'
import {
createBundlerClient,
createPaymasterClient,
} from 'viem/account-abstraction'
import { account, client } from './config.ts'
const paymasterClient = createPaymasterClient({ // [!code ++]
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}'), // [!code ++]
}) // [!code ++]
const bundlerClient = createBundlerClient({
account,
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const hash = await bundlerClient.sendUserOperation({
calls: [{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('0.001')
}]
paymaster: paymasterClient, // [!code ++]
})
```
```ts twoslash [config.ts] filename="config.ts"
// @noErrors
import { createPublicClient, http, parseEther } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const owner = privateKeyToAccount('0x...')
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
```
:::
::::tip
If your Bundler also accepts Paymaster sponsorship (like [Pimlico](https://www.pimlico.io)), you can set `paymaster: true` instead of declaring a separate Paymaster Client.
:::code-group
```ts twoslash [example.ts (on Client)]
import { http } from 'viem'
import {
createBundlerClient,
createPaymasterClient,
} from 'viem/account-abstraction'
import { account, client } from './config.ts'
const paymasterClient = createPaymasterClient({ // [!code --]
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}'), // [!code --]
}) // [!code --]
const bundlerClient = createBundlerClient({
account,
client,
paymaster: paymasterClient, // [!code --]
paymaster: true, // [!code ++]
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}'),
})
```
```ts twoslash [example.ts (on Action)]
import { http } from 'viem'
import {
createBundlerClient,
createPaymasterClient,
} from 'viem/account-abstraction'
import { account, client } from './config.ts'
const paymasterClient = createPaymasterClient({ // [!code --]
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}'), // [!code --]
}) // [!code --]
const bundlerClient = createBundlerClient({
account,
client,
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}'),
})
const hash = await bundlerClient.sendUserOperation({
calls: [{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('0.001')
}]
paymaster: paymasterClient, // [!code --]
paymaster: true, // [!code ++]
})
```
```ts twoslash [config.ts] filename="config.ts"
// @noErrors
import { createPublicClient, http, parseEther } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const owner = privateKeyToAccount('0x...')
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
```
:::
::::
# USDC (Circle)
:::info
This extension and guides are maintained by [Circle](https://www.circle.com).
:::
[USDC](https://www.circle.com/usdc) is a digital dollar issued by Circle, also known as a stablecoin, running on many of the world's leading blockchains. Designed to represent US dollars on the internet, USDC is backed 100% by highly liquid cash and cash-equivalent assets so that it's always redeemable 1:1 for USD.
This section provides a set of tutorials that demonstrate how to integrate and interact with USDC using the Viem library.
These guides walk through core patterns and advanced capabilities that developers can build on top of USDC — including basic token operations, cross-chain transfers, and gas abstraction via stablecoins.
Whether you're building a wallet, protocol integration, or a developer tool, this section will help you implement USDC support using Viem's type-safe primitives and modern client architecture.
## Included Guides
* [**Integrating USDC into Your Application**](/circle-usdc/guides/integrating)\
Learn how to fetch balances, transfer tokens, approve smart contracts, and listen to USDC events.
* [**Cross-Chain USDC Transfers (CCTP V2)**](/circle-usdc/guides/cross-chain)\
Transfer USDC between chains using Circle's Cross-Chain Transfer Protocol v2. Useful for enabling seamless asset (USDC) movement across ecosystems.
* [**Paying Gas with USDC (Circle Paymaster)**](/circle-usdc/guides/paymaster)\
Use Circle's Paymaster to abstract ETH gas fees and sponsor transactions using USDC. Ideal for onboarding and UX-focused flows.
* [**Circle Smart Account**](/circle-usdc/guides/smart-account)\
Create passkey-based smart accounts using Circle's Modular Wallets SDK and Viem. Supports gasless transactions, bundler integration, and secure WebAuthn authentication.
# Getting Started
Viem provides a set of experimental features through the `viem/experimental` entrypoint. Such features could include:
* implementation of non-finalized EIP proposals.
* features that have not been adopted by the wider ecosystem.
* features that are not considered stable.
:::warning\[Warning]
It is recommended to not solely use experimental features in production. You should always have a fallback mechanism for unsupported features.
:::
# Getting Started with OP Stack
Viem provides first-class support for chains implemented on the [OP Stack](https://docs.optimism.io/stack/getting-started).
The OP Stack is a set of modular open-source software that enable developers to build fast, secure, and scalable Layer 2 Ethereum protocols & applications. [Read more.](https://docs.optimism.io/stack/getting-started)
## Quick Start
### 1. Set up your Client & Transport
Firstly, set up your [Client](/docs/clients/intro) with a desired [Transport](/docs/clients/intro) & [OP Stack Chain](/op-stack/chains).
```ts
import { createPublicClient, http } from 'viem'
import { base } from 'viem/chains'
const client = createPublicClient({ // [!code focus]
chain: base, // [!code focus]
transport: http(), // [!code focus]
}) // [!code focus]
```
:::info
In a production app, it is highly recommended to pass through your authenticated RPC provider URL (Infura, thirdweb, etc). If no URL is provided, viem will default to a public RPC provider. [Read more](/docs/clients/transports/http#usage).
:::
### 2. Extend Client with the OP Stack
Now that you have a Client set up, you can extend it with OP Stack Actions! [Read more.](/op-stack/client)
```ts
import { createPublicClient, http } from 'viem'
import { base } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack' // [!code hl]
const client = createPublicClient({
chain: base,
transport: http(),
}).extend(publicActionsL2()) // [!code hl]
```
### 3. Consume OP Stack Actions
Now that you have an OP Stack Client set up, you can now interact with the OP Stack and consume [Actions](/op-stack/actions/estimateL1Gas)!
```tsx
import { createPublicClient, http, parseEther } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http(),
}).extend(publicActionsL2())
const l1Gas = await client.estimateL1Gas({ // [!code hl]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code hl]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code hl]
value: parseEther('1') // [!code hl]
}) // [!code hl]
```
# Getting Started
## Overview
[Tempo](https://tempo.xyz) is a purpose-built Layer 1 blockchain optimized for payments.
It enshrines features like [token management](https://docs.tempo.xyz/protocol/tip20/overview), [Fee AMM](https://docs.tempo.xyz/protocol/fees), and a [stablecoin DEX](https://docs.tempo.xyz/protocol/exchange) directly into the protocol, as well as a [Tempo transaction type](https://docs.tempo.xyz/protocol/transactions) with support for batch calls, fee sponsorship, configurable fee tokens, concurrent transactions, access keys, and scheduled execution.
## Setup
Setup the Tempo extension for Viem by following the steps below.
::::steps
### Install
To use the Tempo extension, ensure that you have Viem installed.
:::code-group
```bash [npm]
npm i viem
```
```bash [pnpm]
pnpm i viem
```
:::
### Configure
Next, we will configure a [Viem Client](/docs/clients/custom).
In the snippet below, we will set up a Tempo chain, and extend our client with `tempoActions`.
```ts twoslash [viem.config.ts]
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::tip
It is also possible to set up a default fee token by adding a `feeToken` property to the chain.
```ts
export const client = createClient({
chain: tempoModerato.extend({ // [!code hl]
feeToken: '0x20c0000000000000000000000000000000000001', // [!code hl]
}), // [!code hl]
// ...
})
```
:::
### Use Viem Actions
Once we have configured our Viem client with Tempo, we can then use regular Viem actions (e.g. `sendTransactionSync`)
that are decorated with [Tempo properties](https://docs.tempo.xyz/protocol/transactions#properties)
like `calls` (batch transactions), `feePayer` (fee sponsorship), `nonceKey` (concurrent transactions) and more!
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const receipt = await client.sendTransactionSync({
calls: [
{
data: '0xcafebabe00000000000000000000000000000001',
to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'
},
{
data: '0xdeadbeef00000000000000000000000000000002',
to: '0xfeedfacefeedfacefeedfacefeedfacefeedface'
},
{
data: '0xfeedface00000000000000000000000000000003',
to: '0xfeedfacefeedfacefeedfacefeedfacefeedface'
},
],
feePayer: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
nonceKey: 1337n,
})
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
:::tip
[See all Viem Actions](/docs/actions/public/introduction)
:::
### Use Tempo Actions
You can also use [Tempo-specific Actions](/tempo/actions):
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const alphaUsd = '0x20c0000000000000000000000000000000000001'
const metadata = await client.token.getMetadata({
token: alphaUsd
})
console.log(
'Alpha USD Metadata:',
metadata.name,
metadata.symbol,
metadata.decimals,
metadata.totalSupply
)
// @log: Alpha USD Metadata: Alpha USD, AlphaUSD, 6, 1000000000000000000000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
:::tip
[See all Tempo Actions](/tempo/actions)
:::
### Next Steps
After you have set up Tempo with Viem, you can now:
* Follow a guide on how to [use accounts](https://docs.tempo.xyz/guide/use-accounts), [make payments](https://docs.tempo.xyz/guide/payments), [issue stablecoins](https://docs.tempo.xyz/guide/issuance) and [exchange stablecoins](https://docs.tempo.xyz/guide/stablecoin-exchange).
* Use the [suite of Tempo Actions](/tempo/actions)
::::
# Getting Started with ZKsync
:::warning
**Note:** This extension is maintained by ZKsync collaborators.
:::
Viem provides first-class support for the [ZKsync](https://zksync.io) chain.
ZKsync is a Layer-2 protocol that scales Ethereum with cutting-edge ZK tech.
## Quick Start
### 1. Set up your Client & Transport
Firstly, set up your [Client](/docs/clients/intro) with a desired [Transport](/docs/clients/intro) & [ZKsync Chain](./zksync/chains.md) and extend it with ZKsync EIP712 actions.
```ts twoslash
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { eip712WalletActions } from 'viem/zksync'
const walletClient = createWalletClient({ // [!code hl]
chain: zksync, // [!code hl]
transport: custom(window.ethereum!), // [!code hl]
}).extend(eip712WalletActions()) // [!code hl]
```
### 2. Use Actions
Now that you have a Client set up, you can [send a transaction](./zksync/actions/sendTransaction.md) on ZKsync using a [paymaster](https://docs.zksync.io/build/developer-reference/account-abstraction.html#paymasters)!
```ts twoslash
import 'viem/window'
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { eip712WalletActions } from 'viem/zksync'
const walletClient = createWalletClient({
chain: zksync,
transport: custom(window.ethereum!),
}).extend(eip712WalletActions())
// ---cut---
const hash = await walletClient.sendTransaction({
account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
paymaster: '0xFD9aE5ebB0F6656f4b77a0E99dCbc5138d54b0BA',
paymasterInput: '0x123abc...'
})
```
...and even write to contracts:
```ts twoslash
import 'viem/window'
import { createWalletClient, custom, parseAbi } from 'viem'
import { zksync } from 'viem/chains'
import { eip712WalletActions } from 'viem/zksync'
const walletClient = createWalletClient({
account: '0x',
chain: zksync,
transport: custom(window.ethereum!),
}).extend(eip712WalletActions())
// ---cut---
const hash = await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: parseAbi(['function mint(uint32 tokenId) nonpayable']),
functionName: 'mint',
args: [69420],
})
```
# Platform Compatibility \[Platforms compatible with Viem]
**Viem supports all modern browsers (Chrome, Edge, Firefox, etc) & runtime environments (Node 18+, Deno, Bun, etc).**
Viem uses modern EcmaScript features such as:
* [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
* [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
* Error [`cause`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause)
* TextEncoder [`encode`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder/encode)
You can check support for these features on [Can I use...](https://caniuse.com/)
## Polyfills
If your platform does not support one of the required features, it is also possible to import a polyfill.
### `fetch`
* [isomorphic-unfetch](https://github.com/developit/unfetch/tree/main/packages/isomorphic-unfetch)
* [node-fetch](https://github.com/node-fetch/node-fetch#providing-global-access)
### Error `cause`
* [core-js](https://github.com/zloirock/core-js)
### `TextEncoder`
* [FastestSmallestTextEncoderDecoder](https://github.com/anonyco/FastestSmallestTextEncoderDecoder)
# EIP-7702 Overview
EIP-7702 is a proposal to add a new Transaction type to allow an EOA to designate a Smart Contract as its "implementation".
The main difference between an EIP-7702 Transaction and other transactions is the inclusion of a **"authorization list"** property, a set of `(chain_id, contract_address, nonce, y_parity, r, s)` tuples that depict what Contracts should be delegated onto the Externally Owned Account.
:::note
In Viem, you won't need to worry about constructing these Authorization Tuples manually as you can use [`signAuthorization`](/docs/eip7702/signAuthorization) to generate them and use them in [Transaction APIs](/docs/eip7702/contract-writes).
:::
Applications of EIP-7702 include:
* **Batching**: allowing multiple operations from the same user in one atomic transaction. One common example is an ERC-20 approval followed by spending that approval, a common workflow in DEXes that requires two transactions today. Advanced use cases of batching occasionally involve dependencies: the output of the first operation is part of the input to the second operation.
* **Sponsorship**: account X pays for a transaction on behalf of account Y. Account X could be paid in some other ERC-20 for this service, or it could be an application operator including the transactions of its users for free.
* **Privilege de-escalation**: users can sign sub-keys, and give them specific permissions that are much weaker than global access to the account. For example, you could imagine a permission to spend ERC-20 tokens but not ETH, or to spend up to 1% of total balance per day, or to interact only with a specific application.
## Next Steps
* [Contract Writes](/docs/eip7702/contract-writes)
* [Sending Transactions](/docs/eip7702/sending-transactions)
# Error Handling
Every module in viem exports an accompanying error type which you can use to strongly type your `catch` statements.
These types come in the form of `ErrorType`. For example, the `getBlockNumber` action exports a `GetBlockNumberErrorType` type.
Unfortunately, [TypeScript doesn't have an abstraction for typed exceptions](https://github.com/microsoft/TypeScript/issues/13219), so the most pragmatic & vanilla approach would be to explicitly cast error types in the `catch` statement.
:::code-group
```ts [example.ts] twoslash
// @noErrors
// @filename: client.ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http()
})
// @filename: index.ts
// ---cut---
import { type GetBlockNumberErrorType } from 'viem'
import { client } from './client'
try {
const blockNumber = await client.getBlockNumber()
} catch (e) {
const error = e as GetBlockNumberErrorType
error.name
// ^?
if (error.name === 'InternalRpcError')
error.code
// ^?
if (error.name === 'HttpRequestError') {
error.headers
// ^?
error.status
// ^?
}
}
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
# Ethers v5 → viem Migration Guide \[Migrate from Ethers v5 to viem]
This is a long document. Feel free to use the search bar above (⌘ K) or the Table of Contents to the side. If there is an API you need which is missing or cannot find, create a [Parity Request here](https://github.com/wagmi-dev/viem/discussions/new?category=feature-request\&title=Parity%20Request:).
You may notice some of the APIs in viem are a little more verbose than Ethers. We prefer boring code and we want to strongly embrace [clarity & composability](/docs/introduction#developer-experience). We believe that [verbose APIs are more flexible](https://www.youtube.com/watch?v=4anAwXYqLG8\&t=789s) to move, change and remove compared to code that is prematurely abstracted and hard to change.
## Provider → Client
### getDefaultProvider
#### Ethers
```ts
import { getDefaultProvider } from 'ethers'
const provider = getDefaultProvider() // [!code hl]
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ // [!code hl]
chain: mainnet, // [!code hl]
transport: http() // [!code hl]
}) // [!code hl]
```
> We are more verbose here – we want to be explicit and clear what chain you are connecting to & what transport you are using to avoid any confusion. :)
### JsonRpcProvider
#### Ethers
This is also interchangeable with `StaticJsonRpcProvider`.
```ts
import { providers } from 'ethers'
const provider = new providers.JsonRpcProvider('https://cloudflare-eth.com') // [!code hl]
```
Custom Chain:
```ts
import { providers } from 'ethers'
const provider = new providers.JsonRpcProvider('https://250.rpc.thirdweb.com', { // [!code hl]
name: 'Fantom', // [!code hl]
id: 250 // [!code hl]
}) // [!code hl]
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ // [!code hl]
chain: mainnet, // [!code hl]
transport: http('https://cloudflare-eth.com') // [!code hl]
}) // [!code hl]
```
Custom Chain:
```ts
import { createPublicClient, http } from 'viem'
import { fantom } from 'viem/chains'
const client = createPublicClient({ // [!code hl]
chain: fantom, // [!code hl]
transport: http('https://250.rpc.thirdweb.com') // [!code hl]
}) // [!code hl]
```
> viem exports custom EVM chains in the `viem/chains` entrypoint.
### InfuraProvider
#### Ethers
```ts
import { providers } from 'ethers'
const provider = new providers.InfuraProvider('homestead', '') // [!code hl]
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ // [!code hl]
chain: mainnet, // [!code hl]
transport: http('https://mainnet.infura.io/v3/') // [!code hl]
}) // [!code hl]
```
> viem does not have custom API Provider clients – you can just pass in their RPC URL.
### AlchemyProvider
#### Ethers
```ts
import { providers } from 'ethers'
const provider = new providers.AlchemyProvider('homestead', '') // [!code hl]
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ // [!code hl]
chain: mainnet, // [!code hl]
transport: http('https://eth-mainnet.g.alchemy.com/v2/') // [!code hl]
}) // [!code hl]
```
> viem does not have custom API Provider clients – you can just pass in their RPC URL.
### CloudflareProvider
#### Ethers
```ts
import { providers } from 'ethers'
const provider = new providers.CloudflareProvider() // [!code hl]
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ // [!code hl]
chain: mainnet, // [!code hl]
transport: http('https://cloudflare-eth.com/') // [!code hl]
}) // [!code hl]
```
> viem does not have custom API Provider clients – you can just pass in their RPC URL.
### PocketProvider
#### Ethers
```ts
import { providers } from 'ethers'
const provider = new providers.PocketProvider('homestead', '') // [!code hl]
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ // [!code hl]
chain: mainnet, // [!code hl]
transport: http('https://eth-mainnet.gateway.pokt.network/v1/lb/') // [!code hl]
}) // [!code hl]
```
> viem does not have custom API Provider clients – you can just pass in their RPC URL.
### AnkrProvider
#### Ethers
```ts
import { providers } from 'ethers'
const provider = new providers.AnkrProvider('homestead', '') // [!code hl]
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ // [!code hl]
chain: mainnet, // [!code hl]
transport: http('https://rpc.ankr.com/eth/') // [!code hl]
}) // [!code hl]
```
> viem does not have custom API Provider clients – you can just pass in their RPC URL.
### FallbackProvider
#### Ethers
```ts
import { providers } from 'ethers'
const alchemy = new providers.AlchemyProvider('homestead', '') // [!code hl]
const infura = new providers.InfuraProvider('homestead', '') // [!code hl]
const provider = new providers.FallbackProvider([alchemy, infura]) // [!code hl]
```
#### viem
```ts
import { createPublicClient, http, fallback } from 'viem'
import { mainnet } from 'viem/chains'
const alchemy = http('https://eth-mainnet.g.alchemy.com/v2/') // [!code hl]
const infura = http('https://mainnet.infura.io/v3/') // [!code hl]
const client = createPublicClient({
chain: mainnet,
transport: fallback([alchemy, infura]) // [!code hl]
})
```
### IpcProvider
Coming soon.
### JsonRpcBatchProvider
Coming soon.
### Web3Provider
#### Ethers
```ts
import { providers } from 'ethers'
const provider = new providers.Web3Provider(window.ethereum) // [!code hl]
```
#### viem
```ts
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
const client = createWalletClient({ // [!code hl]
chain: mainnet, // [!code hl]
transport: custom(window.ethereum) // [!code hl]
}) // [!code hl]
```
### WebSocketProvider
#### Ethers
```ts
import { providers } from 'ethers'
const provider = new providers.WebSocketProvider('wss://eth-mainnet.g.alchemy.com/v2/') // [!code hl]
```
#### viem
```ts
import { createPublicClient, webSocket } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ // [!code hl]
chain: mainnet, // [!code hl]
transport: webSocket('wss://eth-mainnet.g.alchemy.com/v2/') // [!code hl]
}) // [!code hl]
```
## Signers → Accounts
### JsonRpcSigner
#### Ethers
```ts
import { providers } from 'ethers'
const provider = new providers.Web3Provider(window.ethereum)
const [address] = await provider.listAccounts() // [!code hl]
const signer = provider.getSigner(address) // [!code hl]
signer.sendTransaction({ ... })
```
#### viem
```ts
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' }) // [!code hl]
const client = createWalletClient({
account, // [!code hl]
chain: mainnet,
transport: custom(window.ethereum)
})
client.sendTransaction({ ... })
```
> viem uses the term ["Account"](https://ethereum.org/en/developers/docs/accounts/) rather than "Signer".
### Wallet
#### Ethers
```ts
import { providers, Wallet } from 'ethers'
const provider = new providers.Web3Provider(window.ethereum)
const wallet = new Wallet('0x...', provider) // [!code hl]
wallet.sendTransaction({ ... })
```
#### viem
```ts
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0x...') // [!code hl]
const client = createWalletClient({
account, // [!code hl]
chain: mainnet,
transport: custom(window.ethereum)
})
client.sendTransaction({ ... })
```
> viem uses the term ["Account"](https://ethereum.org/en/developers/docs/accounts/) rather than "Signer".
## Provider Methods
#### Ethers
```ts
import { getDefaultProvider } from 'ethers'
const provider = getDefaultProvider()
provider.getBlock(...) // [!code hl]
provider.getTransaction(...) // [!code hl]
...
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
client.getBlock(...) // [!code hl]
client.getTransaction(...) // [!code hl]
...
```
> Methods that extend off the Public Client are **Public Actions**. [Read more](/docs/actions/public/introduction).
> There are API differences in all of these methods. Use the search bar at the top of the page to learn more about them.
## Signer Methods
### JsonRpcSigner
#### Ethers
```ts
import { providers } from 'ethers'
const provider = new providers.Web3Provider(window.ethereum)
const [address] = await provider.listAccounts()
const signer = provider.getSigner(address)
signer.sendTransaction(...) // [!code hl]
signer.signMessage(...) // [!code hl]
...
```
#### viem
```ts
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' })
const client = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
})
client.sendTransaction({ ... }) // [!code hl]
client.signMessage({ ... }) // [!code hl]
...
```
> Methods that extend off the Wallet Client are **Wallet Actions**. [Read more](/docs/actions/wallet/introduction).
> There are API differences in all of these methods. Use the search bar at the top of the page to learn more about them.
## Contract Interaction
### Reading from Contracts
#### Ethers
```ts
import { getDefaultProvider } from 'ethers'
import { wagmiContractConfig } from './abi'
const provider = getDefaultProvider()
const { abi, address } = wagmiContractConfig // [!code hl]
const contract = new Contract(address, abi, provider) // [!code hl]
const supply = await contract.totalSupply() // [!code hl]
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
const supply = await client.readContract({ // [!code hl]
...wagmiContractConfig, // [!code hl]
functionName: 'totalSupply' // [!code hl]
}) // [!code hl]
```
### Writing to Contracts
#### Ethers
```ts
import { Contract, providers } from 'ethers'
import { wagmiContractConfig } from './abi'
const provider = new providers.Web3Provider(window.ethereum)
const [address] = await provider.listAccounts()
const signer = provider.getSigner(address)
const { abi, address } = wagmiContractConfig // [!code hl]
const contract = new Contract(address, abi, signer) // [!code hl]
const hash = await contract.mint() // [!code hl]
```
#### viem
```ts
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
const [address] = await walletClient.getAddresses()
const hash = await walletClient.writeContract({ // [!code hl]
...wagmiContractConfig, // [!code hl]
functionName: 'mint', // [!code hl]
account: address, // [!code hl]
}) // [!code hl]
```
### Deploying Contracts
#### Ethers
```ts
import { ContractFactory, providers } from 'ethers'
import { abi, bytecode } from './abi'
const provider = new providers.Web3Provider(window.ethereum)
const [address] = await provider.listAccounts()
const signer = provider.getSigner(address)
const contract = new ContractFactory(abi, bytecode, signer) // [!code hl]
await contract.deploy() // [!code hl]
```
#### viem
```ts
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { abi, bytecode } from './abi'
const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
const [address] = await walletClient.getAddresses()
await walletClient.deployContract({ // [!code hl]
abi, // [!code hl]
account: address, // [!code hl]
bytecode, // [!code hl]
}) // [!code hl]
```
### Contract Events
#### Ethers
```ts
import { getDefaultProvider } from 'ethers'
import { wagmiContractConfig } from './abi'
const provider = getDefaultProvider()
const { abi, address } = wagmiContractConfig // [!code hl]
const contract = new Contract(address, abi, provider) // [!code hl]
const listener = (from, to, amount, event) => { // [!code hl]
// ... // [!code hl]
} // [!code hl]
contract.on('Transfer', listener) // [!code hl]
// unsubscribe // [!code hl]
contract.off('Transfer', listener) // [!code hl]
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
const unwatch = client.watchContractEvent({ // [!code hl]
...wagmiContractConfig, // [!code hl]
eventName: 'Transfer', // [!code hl]
onLogs: logs => { // [!code hl]
const { args: { from, to, amount }, eventName } = logs[0] // [!code hl]
// ... // [!code hl]
}, // [!code hl]
}) // [!code hl]
// unsubscribe // [!code hl]
unwatch() // [!code hl]
```
> Note: Logs are batched between polling intervals in viem to avoid excessive callback invocations. You can disable this behavior with `batch: false` however.
### Gas Estimation
#### Ethers
```ts
import { getDefaultProvider } from 'ethers'
import { wagmiContractConfig } from './abi'
const provider = getDefaultProvider()
const { abi, address } = wagmiContractConfig // [!code hl]
const contract = new Contract(address, abi, provider) // [!code hl]
const gas = await contract.estimateGas.mint() // [!code hl]
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
const gas = await client.estimateContractGas({ // [!code hl]
...wagmiContractConfig, // [!code hl]
functionName: 'mint' // [!code hl]
}) // [!code hl]
```
### Call
#### Ethers
```ts
import { getDefaultProvider } from 'ethers'
import { wagmiContractConfig } from './abi'
const provider = getDefaultProvider()
const { abi, address } = wagmiContractConfig // [!code hl]
const contract = new Contract(address, abi, provider) // [!code hl]
await contract.callStatic.mint() // [!code hl]
```
#### viem
```ts
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
await client.simulateContract({ // [!code hl]
...wagmiContractConfig, // [!code hl]
functionName: 'mint' // [!code hl]
}) // [!code hl]
```
### Contract Instances
#### Ethers
```ts
import { getDefaultProvider } from 'ethers'
import { wagmiContractConfig } from './abi'
const provider = getDefaultProvider()
const { abi, address } = wagmiContractConfig // [!code hl]
const contract = new Contract(address, abi, provider) // [!code hl]
const supply = await contract.totalSupply()
const listener = (from, to, amount, event) => {
// ...
}
contract.on('Transfer', listener)
contract.off('Transfer', listener)
```
#### viem
```ts
import { createPublicClient, http, getContract } from 'viem'
import { mainnet } from 'viem/chains'
import { wagmiContractConfig } from './abi'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
const contract = getContract({ // [!code hl]
...wagmiContractConfig, // [!code hl]
client, // [!code hl]
}) // [!code hl]
const supply = await contract.read.totalSupply()
const unwatch = contract.watchEvent.Transfer({
onLogs: logs => {
const { args: { from, to, amount }, eventName } = logs[0]
// ...
},
})
unwatch()
```
## ABI Utilities
### abiCoder.encode
#### Ethers
```ts
import { utils } from 'ethers'
const abiCoder = utils.defaultAbiCoder()
// Object
abiCoder.encode(
[{ type: 'uint', name: 'x' }, { type: 'string', name: 'y' }],
[1234, 'Hello world']
)
// Human Readable
abiCoder.encode(
['uint', 'string'],
[1234, 'Hello World']
);
```
#### viem
```ts
import { encodeAbiParameters, parseAbiParameters } from 'viem'
// Object
encodeAbiParameters(
[{ type: 'uint', name: 'x' }, { type: 'string', name: 'y' }],
[1234, 'Hello world']
)
// Human Readable
encodeAbiParameters(
parseAbiParameters('uint, string'),
[1234, 'Hello world']
)
```
### abiCoder.decode
#### Ethers
```ts
import { utils } from 'ethers'
const abiCoder = utils.defaultAbiCoder()
// Object
abiCoder.decode(
[{ type: 'uint', name: 'x' }, { type: 'string', name: 'y' }],
'0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'
)
// Human Readable
abiCoder.decode(
['uint', 'string'],
'0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'
);
```
#### viem
```ts
import { decodeAbiParameters, parseAbiParameters } from 'viem'
// Object
decodeAbiParameters(
[{ type: 'uint', name: 'x' }, { type: 'string', name: 'y' }],
'0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'
)
// Human Readable
decodeAbiParameters(
parseAbiParameters('uint, string'),
'0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000'
)
```
Notice: different from ethers, viem only supports [standard tuple expression](https://docs.soliditylang.org/en/latest/grammar#a4.SolidityParser.tupleExpression) for Human Readable.
example: `(uint a, string b)` is valid, but `tuple(uint a, string b)` is not.
### Fragments & Interfaces
In viem, there is no concept of "fragments" & "interfaces". We want to stick as close to the wire as possible and not introduce middleware abstractions and extra layers over ABIs. Instead of working with "fragments", we encourage you to work with the ABI itself.
We provide utilities such as `getAbiItem`, `parseAbi` `parseAbiItem`, `parseAbiParameters` and `parseAbiParameter` which covers the use cases of interfaces & fragments.
### Interface.format
viem only supports Human Readable → Object format.
#### Ethers
```ts
import { utils } from 'ethers'
const interface = new Interface([ // [!code hl]
'constructor(string symbol, string name)', // [!code hl]
'function transferFrom(address from, address to, uint amount)', // [!code hl]
'function transferFrom(address from, address to, uint amount, bool x)', // [!code hl]
'function mint(uint amount) payable', // [!code hl]
'function balanceOf(address owner) view returns (uint)' // [!code hl]
]) // [!code hl]
const json = interface.format(utils.FormatTypes.json) // [!code hl]
```
#### viem
```ts
import { parseAbi } from 'viem'
const json = parseAbi([ // [!code hl]
'constructor(string symbol, string name)', // [!code hl]
'function transferFrom(address from, address to, uint amount)', // [!code hl]
'function transferFrom(address from, address to, uint amount, bool x)', // [!code hl]
'function mint(uint amount) payable', // [!code hl]
'function balanceOf(address owner) view returns (uint)', // [!code hl]
'event Transfer(address indexed from, address indexed to, uint256 amount)' // [!code hl]
]) // [!code hl]
```
### Fragment.from
#### ethers
```ts
import { utils } from 'ethers'
const fragment = utils.Fragment.from('function balanceOf(address owner) view returns (uint)') // [!code hl]
```
#### viem
```ts
import { parseAbiItem } from 'viem'
const abiItem = parseAbiItem('function balanceOf(address owner) view returns (uint)') // [!code hl]
```
### ParamType.from
#### ethers
```ts
import { utils } from 'ethers'
const param = utils.ParamType.from('address owner') // [!code hl]
```
#### viem
```ts
import { parseAbiParameter } from 'viem'
const param = parseAbiParameter('address owner') // [!code hl]
```
### Fragment Access
#### Ethers
```ts
import { utils } from 'ethers'
import { abi } from './abi'
const interface = new utils.Interface(abi) // [!code hl]
interface.getFunction('transferFrom') // [!code hl]
interface.getEvent('Transfer') // [!code hl]
```
#### viem
```ts
import { getAbiItem } from 'viem'
import { abi } from './abi'
getAbiItem({ abi, name: 'transferFrom' }) // [!code hl]
getAbiItem({ abi, name: 'Transfer' }) // [!code hl]
```
### Interface.encodeDeploy
#### Ethers
```ts
import { utils } from 'ethers'
import { abi } from './abi'
const iface = new utils.Interface(abi); // [!code hl]
const data = iface.encodeDeploy(['SYM', 'Some Name']) // [!code hl]
```
#### viem
```ts
import { encodeDeployData } from 'viem'
import { abi, bytecode } from './abi'
const data = encodeDeployData({ // [!code hl]
abi, // [!code hl]
bytecode, // [!code hl]
args: ['SYM', 'Some Name'] // [!code hl]
}) // [!code hl]
```
> Note: viem concatenates the contract bytecode onto the ABI encoded data.
### Interface.encodeErrorResult
#### Ethers
```ts
import { utils } from 'ethers'
import { abi } from './abi'
const iface = new utils.Interface(abi); // [!code hl]
const data = iface.encodeErrorResult('AccountLocked', [ // [!code hl]
'0x8ba1f109551bD432803012645Ac136ddd64DBA72', // [!code hl]
utils.parseEther('1.0') // [!code hl]
]); // [!code hl]
```
#### viem
```ts
import { encodeErrorResult, parseEther } from 'viem'
import { abi } from './abi'
const data = encodeErrorResult({ // [!code hl]
abi: wagmiAbi, // [!code hl]
errorName: 'AccountLocked', // [!code hl]
args: [ // [!code hl]
'0x8ba1f109551bD432803012645Ac136ddd64DBA72', // [!code hl]
parseEther('1.0') // [!code hl]
] // [!code hl]
}) // [!code hl]
```
### Interface.encodeFilterTopics
#### Ethers
```ts
import { utils } from 'ethers'
import { abi } from './abi'
const iface = new utils.Interface(abi); // [!code hl]
const data = iface.encodeFilterTopics('Transfer', [ // [!code hl]
null, // [!code hl]
'0x8ba1f109551bD432803012645Ac136ddd64DBA72' // [!code hl]
]) // [!code hl]
```
#### viem
```ts
import { encodeEventTopics } from 'viem'
import { abi } from './abi'
const data = encodeEventTopics({ // [!code hl]
abi, // [!code hl]
eventName: 'Transfer', // [!code hl]
args: { // [!code hl]
to: '0x8ba1f109551bD432803012645Ac136ddd64DBA72' // [!code hl]
} // [!code hl]
}) // [!code hl]
```
### Interface.encodeFunctionData
#### Ethers
```ts
import { utils } from 'ethers'
import { abi } from './abi'
const iface = new utils.Interface(abi); // [!code hl]
const data = iface.encodeFunctionData('transferFrom', [ // [!code hl]
'0x8ba1f109551bD432803012645Ac136ddd64DBA72', // [!code hl]
'0xaB7C8803962c0f2F5BBBe3FA8bf41cd82AA1923C', // [!code hl]
parseEther('1.0') // [!code hl]
]) // [!code hl]
```
#### viem
```ts
import { encodeFunctionData, parseEther } from 'viem'
import { abi } from './abi'
const data = encodeFunctionData({ // [!code hl]
abi, // [!code hl]
functionName: 'transferFrom', // [!code hl]
args: [ // [!code hl]
'0x8ba1f109551bD432803012645Ac136ddd64DBA72', // [!code hl]
'0xaB7C8803962c0f2F5BBBe3FA8bf41cd82AA1923C', // [!code hl]
parseEther('1.0') // [!code hl]
] // [!code hl]
}) // [!code hl]
```
### Interface.encodeFunctionResult
#### Ethers
```ts
import { utils } from 'ethers'
import { abi } from './abi'
const iface = new utils.Interface(abi); // [!code hl]
const data = iface.encodeFunctionResult('balanceOf', [ // [!code hl]
'0x8ba1f109551bD432803012645Ac136ddd64DBA72' // [!code hl]
]) // [!code hl]
```
#### viem
```ts
import { encodeFunctionResult, parseEther } from 'viem'
import { abi } from './abi'
const data = encodeFunctionResult({ // [!code hl]
abi, // [!code hl]
functionName: 'balanceOf', // [!code hl]
value: ['0x8ba1f109551bD432803012645Ac136ddd64DBA72'] // [!code hl]
}) // [!code hl]
```
### Interface.decodeErrorResult
#### Ethers
```ts
import { utils } from 'ethers'
import { abi } from './abi'
const iface = new utils.Interface(abi); // [!code hl]
const result = iface.decodeErrorResult("AccountLocked", '0xf7c3865a0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000de0b6b3a7640000') // [!code hl]
```
#### viem
```ts
import { decodeErrorResult, parseEther } from 'viem'
import { abi } from './abi'
const result = decodeErrorResult({ // [!code hl]
abi, // [!code hl]
data: '0xf7c3865a0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000de0b6b3a7640000' // [!code hl]
}) // [!code hl]
```
### Interface.decodeEventLog
#### Ethers
```ts
import { utils } from 'ethers'
import { abi } from './abi'
const iface = new utils.Interface(abi); // [!code hl]
const result = iface.decodeEventLog( // [!code hl]
'Transfer', // [!code hl]
data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', // [!code hl]
topics: [ // [!code hl]
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // [!code hl]
'0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72', // [!code hl]
'0x000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c' // [!code hl]
] // [!code hl]
); // [!code hl]
```
#### viem
```ts
import { decodeEventLog, parseEther } from 'viem'
import { abi } from './abi'
const result = decodeEventLog({ // [!code hl]
abi, // [!code hl]
data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', // [!code hl]
topics: [ // [!code hl]
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', // [!code hl]
'0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72', // [!code hl]
'0x000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c' // [!code hl]
] // [!code hl]
}) // [!code hl]
```
### Interface.decodeFunctionData
#### Ethers
```ts
import { utils } from 'ethers'
import { abi } from './abi'
const iface = new utils.Interface(abi); // [!code hl]
const result = iface.decodeFunctionData('transferFrom', '0x23b872dd0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c0000000000000000000000000000000000000000000000000de0b6b3a7640000'); // [!code hl]
```
#### viem
```ts
import { decodeFunctionData, parseEther } from 'viem'
import { abi } from './abi'
const result = decodeFunctionData({ // [!code hl]
abi, // [!code hl]
data: '0x23b872dd0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c0000000000000000000000000000000000000000000000000de0b6b3a7640000', // [!code hl]
}) // [!code hl]
```
### Interface.decodeFunctionResult
#### Ethers
```ts
import { utils } from 'ethers'
import { abi } from './abi'
const iface = new utils.Interface(abi); // [!code hl]
const result = iface.decodeFunctionResult('balanceOf', '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000'); // [!code hl]
```
#### viem
```ts
import { decodeFunctionResult, parseEther } from 'viem'
import { abi } from './abi'
const result = decodeFunctionResult({ // [!code hl]
abi, // [!code hl]
functionName: 'balanceOf', // [!code hl]
data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', // [!code hl]
}) // [!code hl]
```
### Interface.getSighash
#### Ethers
```ts
import { Interface, FunctionFragment } from '@ethersproject/abi';
const hash = Interface.getSighash(FunctionFragment.from('function ownerOf(uint256)')); // [!code hl]
```
#### viem
```ts
import { toFunctionHash } from 'viem'
const hash = toFunctionHash('function ownerOf(uint256)') // [!code hl]
```
## Address Utilities
### getAddress
#### Ethers
```ts
import { utils } from 'ethers'
const address = utils.getAddress('0x8ba1f109551bd432803012645ac136ddd64dba72') // [!code hl]
```
#### viem
```ts
import { getAddress } from 'viem'
const address = getAddress('0x8ba1f109551bd432803012645ac136ddd64dba72') // [!code hl]
```
### isAddress
#### Ethers
```ts
import { utils } from 'ethers'
const address = utils.isAddress('0x8ba1f109551bd432803012645ac136ddd64dba72') // [!code hl]
```
#### viem
```ts
import { isAddress } from 'viem'
const address = isAddress('0x8ba1f109551bd432803012645ac136ddd64dba72') // [!code hl]
```
### getContractAddress
#### Ethers
```ts
import { utils } from 'ethers'
const address = utils.getContractAddress({ from: '0x...', nonce: 5 }); // [!code hl]
```
#### viem
```ts
import { getContractAddress } from 'viem'
const address = getContractAddress({ from: '0x...', nonce: 5 }) // [!code hl]
```
### getCreate2Address
#### Ethers
```ts
import { utils } from 'ethers'
const from = '0x8ba1f109551bD432803012645Ac136ddd64DBA72'; // [!code hl]
const salt = '0x7c5ea36004851c764c44143b1dcb59679b11c9a68e5f41497f6cf3d480715331'; // [!code hl]
const initCode = '0x6394198df16000526103ff60206004601c335afa6040516060f3'; // [!code hl]
const initCodeHash = utils.keccak256(initCode); // [!code hl]
const address = utils.getCreate2Address(from, salt, initCodeHash); // [!code hl]
```
#### viem
```ts
import { getContractAddress } from 'viem'
const address = getContractAddress({ // [!code hl]
bytecode: '0x6394198df16000526103ff60206004601c335afa6040516060f3', // [!code hl]
from: '0x8ba1f109551bD432803012645Ac136ddd64DBA72', // [!code hl]
opcode: 'CREATE2', // [!code hl]
salt: '0x7c5ea36004851c764c44143b1dcb59679b11c9a68e5f41497f6cf3d480715331', // [!code hl]
}); // [!code hl]
```
## BigNumber Utilities
### Ethers
Many.
### viem
None. We use browser native [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt).
## Byte Manipulation Utilities
### isBytes
#### Ethers
```ts
import { utils } from 'ethers'
utils.isBytes(new Uint8Array([1, 69, 420])) // [!code hl]
```
#### viem
```ts
import { isBytes } from 'viem'
isBytes(new Uint8Array([1, 69, 420])) // [!code hl]
```
### isHexString
#### Ethers
```ts
import { utils } from 'ethers'
utils.isHexString('0xdeadbeef') // [!code hl]
```
#### viem
```ts
import { isHex } from 'viem'
isHex('0xdeadbeef') // [!code hl]
```
### isBytesLike
#### Ethers
```ts
import { utils } from 'ethers'
utils.isBytesLike('0xdeadbeef') // [!code hl]
```
#### viem
```ts
import { isBytes, isHex } from 'viem'
isBytes('0xdeadbeef') || isHex('0xdeadbeef') // [!code hl]
```
### arrayify
#### Ethers
```ts
import { utils } from 'ethers'
utils.arrayify('0xdeadbeef') // [!code hl]
```
#### viem
```ts
import { toBytes } from 'viem'
toBytes('0xdeadbeef') // [!code hl]
```
### hexlify
#### Ethers
```ts
import { utils } from 'ethers'
utils.hexlify(new Uint8Array([1, 69, 420])) // [!code hl]
```
#### viem
```ts
import { toHex } from 'viem'
toHex(new Uint8Array([1, 69, 420])) // [!code hl]
```
### hexValue
#### Ethers
```ts
import { utils } from 'ethers'
utils.hexValue(1) // [!code hl]
```
#### viem
```ts
import { toHex } from 'viem'
toHex(1) // [!code hl]
```
### formatBytes32String
#### Ethers
```ts
import { utils } from 'ethers'
utils.formatBytes32String('Hello world') // [!code hl]
// 0x48656c6c6f20776f726c642e0000000000000000000000000000000000000000
```
#### viem
```ts
import { stringToHex } from 'viem'
stringToHex('Hello world', { size: 32 }) // [!code hl]
// 0x48656c6c6f20776f726c642e0000000000000000000000000000000000000000
```
### parseBytes32String
#### Ethers
```ts
import { utils } from 'ethers'
utils.parseBytes32String('0x48656c6c6f20776f726c642e0000000000000000000000000000000000000000') // [!code hl]
// "Hello world"
```
#### viem
```ts
import { hexToString } from 'viem'
hexToString('0x48656c6c6f20776f726c642e0000000000000000000000000000000000000000', { size: 32 }) // [!code hl]
// "Hello world"
```
### concat
#### Ethers
```ts
import { utils } from 'ethers'
utils.concat([new Uint8Array([69]), new Uint8Array([420])]) // [!code hl]
```
#### viem
```ts
import { concat, toBytes } from 'viem'
concat([new Uint8Array([69]), new Uint8Array([420])]) // [!code hl]
```
### stripZeros
#### Ethers
```ts
import { utils } from 'ethers'
utils.stripZeros(new Uint8Array([0, 0, 0, 0, 0, 69])) // [!code hl]
```
#### viem
```ts
import { trim } from 'viem'
trim(new Uint8Array([0, 0, 0, 0, 0, 69])) // [!code hl]
```
### zeroPad
#### Ethers
```ts
import { utils } from 'ethers'
utils.zeroPad(new Uint8Array([69]), 32) // [!code hl]
```
#### viem
```ts
import { pad } from 'viem'
pad(new Uint8Array([69]), { size: 32 }) // [!code hl]
```
### hexConcat
#### Ethers
```ts
import { utils } from 'ethers'
utils.hexConcat(['0x00000069', '0x00000420']) // [!code hl]
```
#### viem
```ts
import { concat, toBytes } from 'viem'
concat(['0x00000069', '0x00000420']) // [!code hl]
```
### hexDataLength
#### Ethers
```ts
import { utils } from 'ethers'
utils.hexDataLength('0x00000069') // [!code hl]
```
#### viem
```ts
import { size } from 'viem'
size('0x00000069') // [!code hl]
```
### hexDataSlice
#### Ethers
```ts
import { utils } from 'ethers'
utils.hexDataSlice('0x00000069', 4) // [!code hl]
```
#### viem
```ts
import { slice } from 'viem'
slice('0x00000069', 4) // [!code hl]
```
### hexStripZeros
#### Ethers
```ts
import { utils } from 'ethers'
utils.hexStripZeros('0x00000069') // [!code hl]
```
#### viem
```ts
import { trim } from 'viem'
trim('0x00000069') // [!code hl]
```
### hexZeroPad
#### Ethers
```ts
import { utils } from 'ethers'
utils.hexZeroPad('0x69', 32) // [!code hl]
```
#### viem
```ts
import { pad } from 'viem'
pad('0x69', { size: 32 }) // [!code hl]
```
## Display Logic & Input Utilities
### formatUnits
#### Ethers
```ts
import { utils } from 'ethers'
utils.formatUnits(BigNumber.from('1000000000'), 9) // [!code hl]
```
#### viem
```ts
import { formatUnits } from 'viem'
formatUnits(1000000000n, 9) // [!code hl]
```
### formatEther
#### Ethers
```ts
import { utils } from 'ethers'
utils.formatEther(BigNumber.from('1000000000000000000')) // [!code hl]
```
#### viem
```ts
import { formatEther } from 'viem'
formatEther(1000000000000000000n) // [!code hl]
```
### parseUnits
#### Ethers
```ts
import { utils } from 'ethers'
utils.parseUnits('1.0', 18) // [!code hl]
```
#### viem
```ts
import { parseUnits } from 'viem'
parseUnits('1', 18) // [!code hl]
```
### parseEther
#### Ethers
```ts
import { utils } from 'ethers'
utils.parseEther('1.0') // [!code hl]
```
#### viem
```ts
import { parseEther } from 'viem'
parseEther('1') // [!code hl]
```
## Encoding Utilities
### RLP.encode
#### Ethers
```ts
import { utils } from 'ethers'
utils.RLP.encode('0x12345678') // [!code hl]
```
#### viem
```ts
import { toRlp } from 'viem'
toRlp('0x12345678') // [!code hl]
```
### RLP.decode
#### Ethers
```ts
import { utils } from 'ethers'
utils.RLP.decode('0x8412345678') // [!code hl]
```
#### viem
```ts
import { fromRlp } from 'viem'
fromRlp('0x8412345678') // [!code hl]
```
## Hashing Utilities
### id
#### Ethers
```ts
import { utils } from 'ethers'
utils.id('function ownerOf(uint256 tokenId)') // [!code hl]
// hash utf-8 data
utils.id('hello world') // [!code hl]
```
#### viem
```ts
import { toFunctionSelector, keccak256, toHex } from 'viem'
toFunctionSelector('function ownerOf(uint256 tokenId)') // [!code hl]
// hash utf-8 data
keccak256(toHex('hello world')) // [!code hl]
```
### keccak256
#### Ethers
```ts
import { utils } from 'ethers'
utils.keccak256(utils.toUtf8Bytes('hello world')) // [!code hl]
```
#### viem
```ts
import { keccak256, toBytes } from 'viem'
keccak256(toBytes('hello world')) // [!code hl]
```
### encodeBase64/decodeBase64
viem does not provide Base64 encoding utilities.
You can use browser native [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/atob) and [`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/btoa) instead.
### encodeBase58/decodeBase58
viem does not provide Base58 encoding utilities.
You can use libraries such as [`base58-js`](https://www.npmjs.com/package/base58-js) or [`bs58`](https://github.com/cryptocoinjs/bs58) instead.
### namehash
#### Ethers
```ts
import { utils } from 'ethers'
utils.namehash('awkweb.eth') // [!code hl]
```
#### viem
```ts
import { namehash } from 'viem'
namehash('awkweb.eth') // [!code hl]
```
### solidityPack & solidityKeccak256
#### Ethers
```ts
import { utils } from 'ethers'
utils.solidityPack(['int16', 'uint48'], [-1, 12]) // [!code hl]
utils.solidityKeccak256(['int16', 'uint48'], [-1, 12]) // [!code hl]
```
#### viem
```ts
import { encodePacked, keccak256 } from 'viem'
encodePacked(['int16', 'uint48'], [-1, 12]) // [!code hl]
keccak256(encodePacked(['int16', 'uint48'], [-1, 12])) // [!code hl]
```
## String Utilities
### toUtf8Bytes
#### Ethers
```ts
import { utils } from 'ethers'
utils.toUtf8Bytes('Hello World') // [!code hl]
```
#### viem
```ts
import { stringToBytes } from 'viem'
stringToBytes('Hello World') // [!code hl]
```
### toUtf8String
#### Ethers
```ts
import { utils } from 'ethers'
utils.toUtf8String(new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])) // [!code hl]
```
#### viem
```ts
import { bytesToString } from 'viem'
bytesToString(new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])) // [!code hl]
```
## Transaction Utilities
### serializeTransaction
#### Ethers
```ts
import { utils } from 'ethers'
const serialized = utils.serializeTransaction({
chainId: 1,
maxFeePerGas: utils.parseGwei('20'),
maxPriorityFeePerGas: utils.parseGwei('2'),
nonce: 69,
to: "0x1234512345123451234512345123451234512345",
type: 2,
value: utils.parseEther('0.01'),
})
```
#### viem
```ts
import { serializeTransaction, parseEther, parseGwei } from 'viem'
const serialized = serializeTransaction({
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69,
to: "0x1234512345123451234512345123451234512345",
value: parseEther('0.01'),
})
```
### parseTransaction
#### Ethers
```ts
import { utils } from 'ethers'
const transaction = utils.parseTransaction('0x02ef0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0')
```
#### viem
```ts
import { parseTransaction } from 'viem'
const transaction = parseTransaction('0x02ef0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0')
```
# Frequently Asked Questions
Frequently asked questions related to viem.
**TL;DR: viem tries to avoid creating unnecessary abstractions on top of existing systems.**
Feel free to add to this document if you notice frequently asked questions that are not covered here.
## Why use the terms "Wallet" & "Account" instead of "Signer"
viem attempts to align to the "Wallet" and "Account" [terminology on Ethereum.org](https://ethereum.org/en/glossary/). The term "Signer" was adapted from ethers.js.
Let's clear up on some terms before we dive in.
* Wallet: An application or interface that holds Account(s).
* Account: An object that represents an address, balance, nonce, and optional storage and code.
* Private Key: Proves ownership of an Account, and can sign messages & transactions.
In the context of viem, a Wallet Client is an interface that can hold an Account. The Account may or may not hold a Private Key.
In viem, there are two types of Accounts:
* Local Account: can **synchronously & directly** sign messages and transactions using its Private Key. A signature is guaranteed.
* JSON-RPC Account: **asynchronously requests** signing of messages and transactions from the target Wallet over JSON-RPC (e.g. Browser Extension or WalletConnect). The target Wallet holds the Account & Private Key. A signature is not guaranteed (the target Wallet may not have permitted the Account, or the Wallet may have rejected the request).
We do not use the term "Signer" because there are noticeable behavioral differences between signing locally and signing over JSON-RPC.
## Why are contract function `args` with fully-named inputs represented as unnamed tuple types instead of object types?
Let's look at an example! Suppose I have the following function in my contract:
```solidity
function transferFrom(address sender, address recipient, uint256 amount) returns (bool)
```
All the inputs are named (`sender`, `recipient`, and `amount`) so I might be tempted to represent the parameters as the following TypeScript type:
```ts
type Args = {
sender: `0x${string}`;
recipient: `0x${string}`;
amount: bigint;
}
```
This improves developer experience a bit because now I can see the names of the parameters in my editor.
```ts
import { createWalletClient, parseAbi } from 'viem'
const client = createWalletClient(…)
client.writeContract({
address: '0x…',
abi: parseAbi([
'function transferFrom(address sender, address recipient, uint256 amount) returns (bool)',
]),
functionName: 'transferFrom',
args: {
sender: '0x…',
recipient: '0x…',
amount: 100n,
},
})
```
However, this only works if all the inputs are named (some compilers will strip names from inputs). If any of the inputs are unnamed, then you'll have to use a tuple instead:
```ts
client.writeContract({
address: '0x…',
abi: parseAbi([
'function transferFrom(address, address, uint256) returns (bool)',
]),
functionName: 'transferFrom',
args: ['0x…', '0x…', 100n],
})
```
This can get even more complicated when a function has overloads:
```solidity
function safeTransferFrom(address, address, uint256) {}
function safeTransferFrom(address from, address to, uint256 tokenId, bytes data) {}
```
In this case, the type of the overload parameters start to diverge from each other:
```ts
type Args =
| [`0x${string}`, `0x${string}`, bigint]
| {
from: `0x${string}`;
to: `0x${string}`;
tokenId: bigint;
data: string;
}
```
If you want to switch between the two overloads in your code, you'll need to completely change the type instead of just adding or removing a single positional argument from the end. (Objects also don't enforce type-level ordering so you can put them in whatever order you want. This would also mean that viem would also need to internally validate order during runtime, adding some extra overhead.)
```diff
client.writeContract({
address: '0x…',
abi: parseAbi([
'function safeTransferFrom(address, address, uint256)',
'function safeTransferFrom(address from, address to, uint256 tokenId, bytes data)',
]),
functionName: 'safeTransferFrom',
- args: ['0x…', '0x…', 100n],
+ args: {
+ from: '0x…',
+ to: '0x…',
+ tokenId: 100n,
+ data: '0x…',
+ },
})
```
Even though overloads are an edge case, it would be sufficiently [astonishing](https://en.wikipedia.org/wiki/Principle_of_least_astonishment) to come across this behavior. So what's the best way to represent `args`? Well, they are positional at the contract-level so it makes sense to represent them that way in viem too.
Not all is lost when it comes to developer experience though! Tuple types in TypeScript can have [names](https://www.typescriptlang.org/play?ts=4.0.2#example/named-tuples) attached to them:
```ts
type Args = [from: `0x${string}`, to: `0x${string}`, tokenId: bigint]
```
These names show up in your editor so you get nice developer experience when using autocomplete, etc. Unfortunately, TypeScript doesn't support dynamic named tuples right now, but we are watching [this issue](https://github.com/microsoft/TypeScript/issues/44939) closely and once it is implemented, we will add it to viem. In the meantime, hang tight!
## Why is a contract function return type returning an array instead of an object?
Suppose your ABI looks like this:
```ts
[
{
inputs: [],
name: "latestRoundData",
outputs: [
{ name: "roundId", type: "uint80" },
{ name: "answer", type: "int256" },
{ name: "startedAt", type: "uint256" },
{ name: "updatedAt", type: "uint256" },
{ name: "answeredInRound", type: "uint80" },
],
stateMutability: "view",
type: "function",
}
]
```
You might be confused why the following does not return an object:
```ts
import { createPublicClient, parseAbi } from 'viem'
const client = createPublicClient(…)
const res = await client.readContract({
address: '0x…',
abi: […], // abi from above
functionName: 'latestRoundData',
})
res
// ^? const res: [bigint, bigint, bigint, bigint, bigint]
```
This is expected. `"latestRoundData"` `outputs` is an array of types, so you get an array of decoded values as the return type. viem only maps explicitly typed tuples as objects
Why does viem follow this approach? Here is the contract function definition for `latestRoundData` with two different return types:
```solidity
function latestRoundData() external view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
struct Data {
uint80 roundId;
uint256 answer;
uint256 startedAt;
uint256 updatedAt;
uint80 answeredInRound
}
function latestRoundData() external view returns (Data data);
```
The first function returns a set of five items, so viem maps it to an array. The reason why we don't convert it to an object is because things get ambiguous when we come to decode structs. How do you determine the difference between a "return" tuple (first function) and a "struct" tuple (second function).
Another reason is that folks might expect it to be an array (because it is a set of return items). Other libraries, like ethers, mitigate this by returning a hybrid Array/Object type, but that kind of type is not serializable in JavaScript, and viem prefers to not try and "hack" JavaScript types.
## Why doesn't Wallet Client support public actions?
Wallet Client doesn't support public actions because wallet providers (Injected `window.ethereum`, WalletConnect v2, etc.) may not provide a large majority of "node"/"public" RPC methods like `eth_call`, `eth_newFilter`, `eth_getLogs`, etc. This is because these methods are not required for a wallet provider to function properly. For example, a wallet provider may only support `eth_sendTransaction` and `eth_sign` and nothing else.
# Getting Started \[Get started with viem in just a few lines of code.]
## Overview
viem is a TypeScript interface for Ethereum that provides low-level stateless primitives for interacting with Ethereum. viem is focused on developer experience, stability, bundle size, and performance:
* **Developer experience** Automatic [type safety and inference](/docs/typescript), comprehensive documentation, composable APIs.
* **Stability** Test suite runs against forked Ethereum networks, complete [test coverage](https://app.codecov.io/gh/wevm/viem).
* **Bundle size** Tree-shakable lightweight modules.
* **Performance** Optimized encoding/parsing, async tasks only when necessary.
You can learn more about the rationale behind the project in the [Why viem](/docs/introduction) section.
## Installation
:::code-group
```bash [npm]
npm i viem
```
```bash [pnpm]
pnpm i viem
```
```bash [bun]
bun i viem
```
:::
## Quick Start
### 1. Set up your Client & Transport
Firstly, set up your [Client](/docs/clients/intro) with a desired [Transport](/docs/clients/intro) & [Chain](/docs/chains/introduction).
```ts twoslash
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ // [!code focus]
chain: mainnet, // [!code focus]
transport: http(), // [!code focus]
}) // [!code focus]
```
:::info
In a production app, it is highly recommended to pass through your authenticated RPC provider URL (Infura, thirdweb, etc). If no URL is provided, viem will default to a public RPC provider. [Read more](/docs/clients/transports/http#usage).
:::
### 2. Consume Actions
Now that you have a Client set up, you can now interact with Ethereum and consume [Actions](/docs/actions/public/introduction)!
```ts twoslash
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const blockNumber = await client.getBlockNumber() // [!code focus]
```
## Live example
# Installation
Install Viem via your package manager, a `
```
## Using Unreleased Commits
If you can't wait for a new release to test the latest features, pull requests and commits are continuously released via [pkg.pr.new](https://pkg.pr.new) and can be installed using the pull request number or short commit ID.
:::code-group
```bash [pnpm]
pnpm add https://pkg.pr.new/viem@123
```
```bash [npm]
npm install https://pkg.pr.new/viem@123
```
```bash [yarn]
yarn add https://pkg.pr.new/viem@123
```
```bash [bun]
bun add https://pkg.pr.new/viem@123
```
:::
Or clone the [Viem repo](https://github.com/wevm/viem) to your local machine, build, and link it yourself.
```bash
gh repo clone wevm/viem
cd viem
pnpm install
pnpm build
pnpm link --global
```
Then go to the project where you are using Viem and run `pnpm link --global viem` (or the package manager that you used to link Viem globally).
## Security
Ethereum-related projects are often targeted in attacks to steal users' assets. Make sure you follow security best-practices for your project. Some quick things to get started.
* Pin package versions, upgrade mindfully, and inspect lockfile changes to minimize the risk of [supply-chain attacks](https://nodejs.org/en/guides/security/#supply-chain-attacks).
* Use [npm](https://docs.npmjs.com)'s [`min-release-age`](https://docs.npmjs.com/cli/v11/using-npm/config#min-release-age) or [pnpm](https://pnpm.io)'s [`minimumReleaseAge`](https://pnpm.io/settings#minimumreleaseage) and [`trustPolicy`](https://pnpm.io/settings#trustpolicy) to mitigate against supply-chain attacks.
* Install the [Socket](https://socket.dev) [GitHub App](https://github.com/apps/socket-security) to help detect and block supply-chain attacks.
* Add a [Content Security Policy](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html) to defend against external scripts running in your app.
* Pin [GitHub Action](https://x.com/paulmillr/status/1900948425325031448) versions to commits instead of tags. [Actions Up](https://github.com/azat-io/actions-up) is a good tool for using commits instead of tags.
# Why Viem \[A brief preamble on why we built Viem]
## The Problems
The current state of low-level Ethereum interface abstractions lack in at least one of the following four areas: **developer experience**, **stability**, **bundle size** and/or **performance** — a quadrilemma.
As the authors of [wagmi](https://wagmi.sh), a popular React Hooks library for Ethereum, we struggled to work with the existing low-level TypeScript Ethereum libraries. We wanted to provide the users of wagmi with the best possible developer experience, but we were limited by the underlying technologies wagmi was built on. We knew an *always* stable, predictable implementation with a tiny bundle size and performant modules was paramount to interacting with the world's largest blockchain ecosystem.
So we created **viem**: a TypeScript Interface for Ethereum that provides low-level stateless primitives for interacting with Ethereum. An alternative to ethers.js and web3.js with a focus on reliability, efficiency, and excellent developer experience.
## Developer Experience
viem delivers a great developer experience through modular and composable APIs, comprehensive documentation, and automatic type safety and inference.
It provides developers with intuitive building blocks to build their Ethereum apps and libraries. While viem's APIs may be more verbose than alternative libraries, we believe this is the right trade-off as it makes viem's modular building blocks extremely flexible. Easy to move around, change, and remove. It also allows the developers to better understand Ethereum concepts as well as understand *what* and *why* certain properties are being passed through. Learning how to use viem is a great way to learn how to interact with Ethereum in general.
We aim to provide extensive API documentation and usage for *every* module in viem. viem uses a [documentation](https://gist.github.com/zsup/9434452) and [test driven](https://en.wikipedia.org/wiki/Test-driven_development#:~:text=Test%2Ddriven%20development%20\(TDD\),software%20against%20all%20test%20cases.) development approach to building modules, which leads to predictable and stable APIs.
viem also provides consumers with [strongly typed APIs](/docs/typescript), allowing consumers to get the best possible experience through [autocomplete](https://twitter.com/awkweb/status/1555678944770367493), [type inference](https://twitter.com/_jxom/status/1570244174502588417?s=20), as well as static validation.
## Stability
Stability is a fundamental principle for viem. As the authors of [wagmi](https://wagmi.sh), we have many organizations, large and small, that rely heavily on the library and expect it to be entirely stable for their users.
viem takes the following steps to ensure stability:
* We run our test suite against a forked Ethereum node
* We aim for complete test coverage and test all potential behavioral cases
* We build deterministic and pure APIs
## Bundle Size
Maintaining a low bundle size is critical when building web applications. End users should not be required to download a module of over 100kB in order to interact with Ethereum. On a slow 3G mobile network loading a 100kB library would take at least **two seconds** (plus additional time to establish an HTTP connection).
Furthermore, viem is tree-shakable, meaning only the modules you use are included in your final bundle.
## Performance
In addition to the fast load times mentioned above, viem further tunes performance by only executing heavy asynchronous tasks when required and optimized encoding/parsing algorithms. The benchmarks speak for themselves:
## Opinions & Escape Hatches
Unlike other low-level interfaces that impose opinions on consumers, viem enables consumers to choose their opinions while still maintaining sensible and secure defaults. This allows consumers to create their own opinionated implementations, such as [wagmi](https://wagmi.sh), without the need for tedious workarounds.
***
**viem** will help developers build with a higher level of accuracy and correctness through type safety and developer experience. It will also integrate extremely well with [wagmi](https://wagmi.sh) so folks can start using it without much upfront switching cost.
# Migration Guide
If you are coming from an earlier version of `viem`, you will need to make sure to update the following APIs listed below.
## 2.x.x Breaking changes
The 2.x.x release includes very minor breaking changes to the Contract Instances API, entrypoints, chain modules, and miscellaneous actions + utilities listed below.
Not ready to migrate? [Head to the 1.x.x docs.](https://v1.viem.sh)
### Actions: Modified `getContract` Client API
The `publicClient` and `walletClient` parameters of the `getContract` API has been removed in favour of `client` to support Client's that [extend](/docs/clients/wallet#optional-extend-with-public-actions) (ie. [a Wallet Client extended with Public Actions](/docs/clients/wallet#optional-extend-with-public-actions)).
[Read more.](/docs/contract/getContract)
```tsx
import { getContract } from 'viem'
import { publicClient, walletClient } from './client'
const contract = getContract({
abi,
address,
publicClient, // [!code --]
walletClient, // [!code --]
client: { // [!code ++]
public: publicClient, // [!code ++]
wallet: walletClient, // [!code ++]
} // [!code ++]
})
```
### Removed entrypoints
The following entrypoints have been removed:
* `viem/abi`
* `viem/contract`
* `viem/public`
* `viem/test`
* `viem/wallet`
You can import the entrypoints directly from `viem`:
```ts
import { encodeAbiParameters } from 'viem/abi' // [!code --]
import { getContract } from 'viem/contract' // [!code --]
import { getBlock } from 'viem/public' // [!code --]
import { mine } from 'viem/test' // [!code --]
import { sendTransaction } from 'viem/wallet' // [!code --]
import { // [!code ++]
encodeAbiParameters, // [!code ++]
getContract, // [!code ++]
getBlock, // [!code ++]
mine, // [!code ++]
sendTransaction, // [!code ++]
} from 'viem' // [!code ++]
```
### Moved chain-specific exports in `viem/chains/utils`
Chain-specific exports in `viem/chains/utils` have been moved to `viem/{celo|op-stack|zksync}`:
```ts
import {
parseTransactionCelo,
parseTransaction // [!code ++]
serializeTransactionCelo, // [!code --]
serializeTransaction // [!code ++]
// ...
} from 'viem/chains/utils' // [!code --]
} from 'viem/celo' // [!code ++]
import {
// ...
} from 'viem/chains/utils' // [!code --]
} from 'viem/op-stack' // [!code ++]
import {
parseTransactionZkSync, // [!code --]
parseTransaction, // [!code ++]
serializeTransactionZkSync, // [!code --]
serializeTransaction, // [!code ++]
// ...
} from 'viem/chains/utils' // [!code --]
} from 'viem/zksync' // [!code ++]
```
### Actions: `getBlockNumber`
The `maxAge` parameter has been removed in favor of `cacheTime`.
```ts
const blockNumber = await client.getBlockNumber({
maxAge: 84_600 // [!code --]
cacheTime: 84_600 // [!code ++]
})
```
### Actions: `OnLogFn` & `OnLogParameter` types
The `OnLogFn` & `OnLogParameter` types have been renamed.
```ts
import {
OnLogFn, // [!code --]
WatchEventOnLogsFn, // [!code ++]
OnLogParameter, // [!code --]
WatchEventOnLogsParameter, // [!code ++]
} from 'viem'
```
### Actions: `prepareRequest`
The `prepareRequest` Action has been renamed to `prepareTransactionRequest` and moved to `viem/actions` entrypoint.
```ts
import {
prepareRequest, // [!code --]
prepareTransactionRequest, // [!code ++]
} from 'viem' // [!code --]
} from 'viem/actions' // [!code ++]
```
### Actions: `SimulateContractParameters` & `SimulateContractReturnType` types
Note the following breaking generic slot changes:
```ts
type SimulateContractParameters<
TAbi,
TFunctionName,
TArgs, // Args added to Slot 2 // [!code ++]
TChain,
TChainOverride,
TAccountOverride,
>
type SimulateContractReturnType<
TAbi,
TFunctionName,
TArgs, // Args added to Slot 2 // [!code ++]
TChain,
TAccount, // Account added to Slot 4 // [!code ++]
TChainOverride,
TAccountOverride,
>
```
### Utilities: Removed `extractFunctionParts`, `extractFunctionName`, `extractFunctionParams`, `extractFunctionType`
The `extractFunctionParts`, `extractFunctionName`, `extractFunctionParams`, `extractFunctionType` utility functions have been removed. You can use the [`parseAbiItem` utility function from abitype](https://abitype.dev/api/human#parseabiitem-1) instead.
### Utilities: Renamed `bytesToBigint`
The `bytesToBigint` utility function has been renamed to `bytesToBigInt`.
```ts
import {
bytesToBigint, // [!code --]
bytesToBigInt, // [!code ++]
} from 'viem'
```
### Utilities: Renamed chain types
The following chain types have been renamed:
```ts
import {
Formatter, // [!code --]
ChainFormatter, // [!code ++]
Formatters, // [!code --]
ChainFormatters, // [!code ++]
Serializers, // [!code --]
ChainSerializers, // [!code ++]
ExtractFormatterExclude, // [!code --]
ExtractChainFormatterExclude, // [!code ++]
ExtractFormatterParameters, // [!code --]
ExtractChainFormatterParameters, // [!code ++]
ExtractFormatterReturnType, // [!code --]
ExtractChainFormatterReturnType, // [!code ++]
} from 'viem'
```
### Utilities: `isAddress` & `getAddress` perform checksum validation
The `isAddress` utility function now performs checksum validation by default.
To opt-out of this behavior, you can pass `strict: false` or lowercase the address.
```ts
import { isAddress } from 'viem'
isAddress('0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac', {
strict: false // [!code ++]
})
isAddress(
'0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac'.toLowerCase() // [!code ++]
)
```
## 1.x.x Breaking changes
The 1.x.x release only includes very minor changes to the behavior in event log decoding, and removes the redundant ethers.js Wallet Adapter. If you do not directly use these APIs, you do not need to update any of your code for this version.
### Removed `ethersWalletToAccount`
The `ethersWalletToAccount` adapter has been removed.
This adapter was introduced when viem did not have Private Key & HD Accounts. Since 0.2, viem provides all the utilities needed to create and import [Private Key](https://viem.sh/docs/accounts/local/privateKeyToAccount) & [HD Accounts](https://viem.sh/docs/accounts/local/mnemonicToAccount).
If you still need it, you can copy + paste the [old implementation](https://github.com/wevm/viem/blob/a9a71507032db896295fa1f3fa2dd6c2bdc85137/src/adapters/ethers.ts).
### `logIndex` & `transactionIndex` on Logs
`logIndex` & `transactionIndex` on `Log` now return a `number` instead of a `bigint`.
```ts
const log: Log = {
...
logIndex: 1n, // [!code --]
logIndex: 1, // [!code ++]
transactionIndex: 1n, // [!code --]
transactionIndex: 1, // [!code ++]
...
}
```
### Minor: `decodeEventLog` behavior change
`decodeEventLog` no longer attempts to partially decode events. If the Log does not conform to the ABI (mismatch between the number of indexed/non-indexed arguments to topics/data), it will throw an error.
For example, the following Log will throw an error as there is a mismatch in non-`indexed` arguments & `data` length.
```ts
decodeEventLog({
abi: parseAbi(['event Transfer(address indexed, address, uint256)']), // [!code focus]
// `data` should be 64 bytes, but is only 32 bytes. // [!code focus]
data: '0x0000000000000000000000000000000000000000000000000000000000000001' // [!code focus]
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
]
})
```
Previously, the above would only decode the `indexed` arguments.
If you would like to partially decode event logs (previous behavior), you can turn off `strict` mode:
```ts
decodeEventLog({
abi: parseAbi(['event Transfer(address indexed, address, uint256)']),
data: '0x0000000000000000000000000000000000000000000000000000000000000001'
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
],
strict: false // [!code ++]
})
```
## 0.3.x Breaking changes
The 0.3.x release only includes breaking changes around RPC errors. If you do not directly use the APIs listed below, you do not need to update any of your code for this version.
### Renamed `RequestError` to `RpcError`
`RequestError` was renamed `RpcError` for clarity.
```ts
import { RequestError } from 'viem' // [!code --]
import { RpcError } from 'viem' // [!code ++]
throw new RequestError(new Error('An error occurred.')) // [!code --]
throw new RpcError(new Error('An error occurred.')) // [!code ++]
```
### Removed `RpcRequestError`
`RpcRequestError` was removed. Use `RpcError` instead.
```ts
import { RpcRequestError } from 'viem' // [!code --]
import { RpcError } from 'viem' // [!code ++]
throw new RpcRequestError(new Error('An error occurred.')) // [!code --]
throw new RpcError(new Error('An error occurred.')) // [!code ++]
```
### Renamed `RpcError` to `RpcRequestError`
`RpcError` was renamed `RpcRequestError` for consistency.
```ts
import { RpcError } from 'viem' // [!code --]
import { RpcRequestError } from 'viem' // [!code ++]
const err = new RpcError({ // [!code --]
const err = new RpcRequestError({ // [!code ++]
body: { foo: 'bar' },
error: { code: 420, message: 'Error' },
url: 'https://example-rpc.com',
})
```
## 0.2.x Breaking changes
### `chain` is required for `sendTransaction`, `writeContract`, `deployContract`
A chain is now required for the `sendTransaction`, `writeContract`, `deployContract` Actions.
You can hoist the Chain on the Client:
```ts
import { createWalletClient, custom, getAccount } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet, // [!code ++]
transport: custom(window.ethereum)
})
const account = getAccount('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266')
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
Alternatively, you can pass the Chain directly to the Action:
```ts
import { createWalletClient, custom, getAccount } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet, // [!code --]
transport: custom(window.ethereum)
})
const account = getAccount('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266')
const hash = await walletClient.sendTransaction({
account,
chain: mainnet, // [!code ++]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### `recoverAddress`, `recoverMessageAddress`, `verifyMessage` are now async
The following functions are now `async` functions instead of synchronous functions:
* `recoverAddress`
* `recoverMessageAddress`
* `verifyMessage`
```ts
import { recoverMessageAddress } from 'viem'
recoverMessageAddress({ message: 'hello world', signature: '0x...' }) // [!code --]
await recoverMessageAddress({ message: 'hello world', signature: '0x...' }) // [!code ++]
```
### `assertChain` removed from `sendTransaction`
Removed `assertChain` argument on `sendTransaction`, `writeContract` & `deployContract`. If you wish to bypass the chain check (not recommended unless for testing purposes), you can pass `chain: null`.
```ts
await walletClient.sendTransaction({
assertChain: false, // [!code --]
chain: null, // [!code ++]
...
})
```
### `getAccount` removed
Removed the `getAccount` function.
#### For JSON-RPC Accounts, use the address itself.
You can now pass the address directly to the `account` option.
```ts
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
const address = '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2'
const client = createWalletClient({
account: getAccount(address), // [!code --]
account: address, // [!code ++]
chain: mainnet,
transport: custom(window.ethereum)
})
```
#### For Ethers Wallet Adapter, use `ethersWalletToAccount`.
If you were using the Ethers Wallet adapter, you can use the `ethersWalletToAccount` function.
> Note: viem 0.2.0 now has a [Private Key](/docs/accounts/local/privateKeyToAccount) & [Mnemonic Account](/docs/accounts/local/mnemonicToAccount) implementation. You probably do not need this adapter anymore. This adapter may be removed in a future version.
```ts
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
import { getAccount } from 'viem/ethers' // [!code --]
import { ethersWalletToAccount } from 'viem/ethers' // [!code ++]
import { Wallet } from 'ethers'
const account = getAccount(new Wallet('0x...')) // [!code --]
const account = ethersWalletToAccount(new Wallet('0x...')) // [!code ++]
const client = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
})
```
#### For Local Accounts, use `toAccount`.
If you are using a custom signing implementation, you can use the `toAccount` function.
```ts
import { createWalletClient, http, getAccount } from 'viem' // [!code --]
import { createWalletClient, http } from 'viem' // [!code ++]
import { toAccount } from 'viem/accounts' // [!code ++]
import { mainnet } from 'viem/chains'
import { getAddress, signMessage, signTransaction } from './sign-utils'
const privateKey = '0x...'
const account = getAccount({ // [!code --]
const account = toAccount({ // [!code ++]
address: getAddress(privateKey),
signMessage(message) {
return signMessage(message, privateKey)
},
signTransaction(transaction) {
return signTransaction(transaction, privateKey)
},
signTypedData(typedData) {
return signTypedData(typedData, privateKey)
}
})
const client = createWalletClient({
account,
chain: mainnet,
transport: http()
})
```
### `data` renamed in `signMessage`
Renamed the `data` parameter in `signMessage` to `message`.
```ts
walletClient.signMessage({
data: 'hello world', // [!code --]
message: 'hello world', // [!code ++]
})
```
# TypeScript \[TypeScript support for Viem]
viem is designed to be as type-safe as possible! Things to keep in mind:
* Types currently require using TypeScript v5.0.4 or greater.
* Changes to types in this repository are considered non-breaking and are usually released as patch semver changes (otherwise every type enhancement would be a major version!).
* It is highly recommended that you lock your `viem` package version to a specific patch release and upgrade with the expectation that types may be fixed or upgraded between any release.
* The non-type-related public API of `viem` still follows semver very strictly.
To ensure everything works correctly, make sure that your `tsconfig.json` has [`strict`](https://www.typescriptlang.org/tsconfig#strict) mode set to `true`:
```json [tsconfig.json]
{
"compilerOptions": {
"strict": true // [!code focus]
}
}
```
## Type Inference
viem can infer types based on [ABI](https://docs.soliditylang.org/en/v0.8.24/abi-spec.html#json) and [EIP-712](https://eips.ethereum.org/EIPS/eip-712) Typed Data definitions (powered by [ABIType](https://abitype.dev)), giving you full end-to-end type-safety from your contracts to your frontend and incredible developer experience (e.g. autocomplete ABI function names and catch misspellings, strongly-typed ABI function arguments, etc.).
For this to work, you must either add [const assertions](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4#const-assertions) to specific configuration parameters (more info on those below) or **define them inline**. For example, [`readContract`](/docs/contract/readContract)'s `abi` configuration parameter:
```ts twoslash
import { createPublicClient, http, parseAbi } from 'viem'
const client = createPublicClient({
transport: http()
})
// ---cut---
const abi = [{ // [!code focus]
type: 'function', // [!code focus]
name: 'balanceOf', // [!code focus]
stateMutability: 'view', // [!code focus]
inputs: [{ type: 'address' }], // [!code focus]
outputs: [{ type: 'uint256' }], // [!code focus]
}] as const // [!code focus]
// @log: ↑ const assertion
const result = client.readContract({
address: '0x27a69ffba1e939ddcfecc8c7e0f967b872bac65c',
abi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC']
})
```
```ts twoslash
import { createPublicClient, http, parseAbi } from 'viem'
const client = createPublicClient({
transport: http()
})
// ---cut---
// @log: ↓ defined inline
const result = client.readContract({
address: '0x27a69ffba1e939ddcfecc8c7e0f967b872bac65c',
abi: [{ // [!code focus]
type: 'function', // [!code focus]
name: 'balanceOf', // [!code focus]
stateMutability: 'view', // [!code focus]
inputs: [{ type: 'address' }], // [!code focus]
outputs: [{ type: 'uint256' }], // [!code focus]
}], // [!code focus]
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC']
})
```
If type inference isn't working, it's likely you forgot to add a `const` assertion or define the configuration parameter inline.
:::tip
Unfortunately [TypeScript doesn't support importing JSON as const](https://github.com/microsoft/TypeScript/issues/32063). Check out [`@wagmi/cli`](https://wagmi.sh/cli) to help with this! It can automatically fetch ABIs from Etherscan, resolve ABIs from your Foundry/Hardhat projects, and much more.
:::
### Contract ABIs
The following actions and utilities support type inference when you add a const assertion to `abi` or define `abi` inline:
#### Actions
* [`createEventFilter`](/docs/actions/public/createEventFilter)
* [`watchEvent`](/docs/actions/public/watchEvent)
* [`createContractEventFilter`](/docs/contract/createContractEventFilter)
* [`deployContract`](/docs/contract/deployContract)
* [`estimateContractGas`](/docs/contract/estimateContractGas)
* [`multicall`](/docs/contract/multicall)
* [`readContract`](/docs/contract/readContract)
* [`simulateContract`](/docs/contract/simulateContract)
* [`writeContract`](/docs/contract/writeContract)
* [`watchContractEvent`](/docs/contract/watchContractEvent)
#### Utilities
* [`decodeEventLog` ](/docs/contract/decodeEventLog)
* [`decodeFunctionResult` ](/docs/contract/decodeFunctionResult)
* [`encodeDeployData` ](/docs/contract/encodeDeployData)
* [`encodeErrorResult` ](/docs/contract/encodeErrorResult)
* [`encodeEventTopics` ](/docs/contract/encodeEventTopics)
* [`encodeFunctionData` ](/docs/contract/encodeFunctionData)
* [`encodeFunctionResult` ](/docs/contract/encodeFunctionResult)
* [`getAbiItem` ](/docs/abi/getAbiItem)
For example, `readContract`:
```ts twoslash
// @noErrors
import { createPublicClient, http, erc20Abi, parseAbi } from 'viem'
const client = createPublicClient({
transport: http()
})
// ---cut---
const result = await client.readContract({
// ^?
address: '0xecb504d39723b0be0e3a9aa33d646642d1051ee1',
abi: erc20Abi,
functionName: 'balanceOf',
// ^?
// ↑ Notice how "transfer" is not included since it is not a "read" function
args: ['0x27a69ffba1e939ddcfecc8c7e0f967b872bac65c'],
// ^?
})
```
### EIP-712 Typed Data
Adding a const assertion to `types` or defining `types` inline adds type inference to [`signTypedData`](/docs/actions/wallet/signTypedData)'s `value` configuration parameter:
```ts twoslash
import { createWalletClient, http, erc20Abi, parseAbi } from 'viem'
const client = createWalletClient({
account: '0x',
transport: http()
})
// ---cut---
const result = client.signTypedData({
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
// ^?
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### Other
The following utilities support type inference when you use const assertions or define arguments inline:
* [`decodeAbiParameters` ](/docs/abi/decodeAbiParameters)
* [`encodeAbiParameters` ](/docs/abi/encodeAbiParameters)
* [`encodePacked` ](/docs/abi/encodePacked)
* [`parseAbi` ](/docs/abi/parseAbi)
* [`parseAbiItem` ](/docs/abi/parseAbiItem)
* [`parseAbiParameter` ](/docs/abi/parseAbiParameter)
* [`parseAbiParameters` ](/docs/abi/parseAbiParameters)
## Configuring Internal Types
For advanced use-cases, you may want to configure viem's internal types. Most of viem's types relating to ABIs and EIP-712 Typed Data are powered by [ABIType](https://abitype.dev). See ABIType's [documentation](https://abitype.dev/config) for more info on how to configure types.
## `window` Polyfill
By importing the `viem/window` Polyfill, the global `window.ethereum` will typed as an [`EIP1193Provider`](https://github.com/wagmi-dev/viem/blob/4bdbf15be0d61b52a195e11c97201e707fb616cc/src/types/eip1193.ts#L24-L26) (including a fully-typed `request` function & typed events).
```ts twoslash
// @noErrors
import 'viem/window';
const hash = await window.ethereum.request({
method: 'e
// ^|
})
const hash = await window.ethereum.request({
method: 'eth_getTransactionByHash',
params: [
// ^?
})
```
# Client \[Setting up your Viem Client]
To use the experimental functionality of Viem, you must extend your existing (or new) Viem Client with experimental Actions.
## Extensions
### `eip5792Actions`
A suite of [EIP-5792 Wallet Actions](https://github.com/ethereum/EIPs/blob/815028dc634463e1716fc5ce44c019a6040f0bef/EIPS/eip-5792.md) for suited for development with wallet's that support batch transactions.
```ts
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { eip5792Actions } from 'viem/experimental' // [!code focus]
const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
}).extend(eip5792Actions()) // [!code focus]
const id = await walletClient.sendCalls({/* ... */})
```
# Chains
The following Viem chains are implemented on the OP Stack:
```ts
import {
base, // [!code hl]
baseGoerli, // [!code hl]
baseSepolia, // [!code hl]
fraxtal, // [!code hl]
fraxtalTestnet, // [!code hl]
ink, // [!code hl]
inkSepolia, // [!code hl]
optimism, // [!code hl]
optimismGoerli, // [!code hl]
optimismSepolia, // [!code hl]
soneium, // [!code hl]
soneiumMinato, // [!code hl]
unichain, // [!code hl]
unichainSepolia, // [!code hl]
zircuit, // [!code hl]
zircuitGarfieldTestnet, // [!code hl]
zora, // [!code hl]
zoraSepolia, // [!code hl]
zoraTestnet, // [!code hl]
} from 'viem/chains'
```
## Configuration
Viem exports OP Stack's chain [formatters](/docs/chains/formatters) & [serializers](/docs/chains/serializers) via `chainConfig`. This is useful if you need to define another chain which is implemented on the OP Stack.
```ts
import { defineChain } from 'viem'
import { chainConfig } from 'viem/op-stack'
export const opStackExample = defineChain({
...chainConfig,
name: 'OP Stack Example',
// ...
})
```
# Client \[Setting up your Viem Client with the OP Stack]
To use the OP Stack functionality of Viem, you must extend your existing (or new) Viem Client with OP Stack Actions.
## Usage
### Layer 1 Extensions
```ts
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { walletActionsL1 } from 'viem/op-stack' // [!code hl]
const walletClient = createWalletClient({
chain: mainnet,
transport: http(),
}).extend(walletActionsL1()) // [!code hl]
const hash = await walletClient.depositTransaction({/* ... */})
```
### Layer 2 Extensions
```ts
import { createPublicClient, http } from 'viem'
import { base } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack' // [!code hl]
const publicClient = createPublicClient({
chain: base,
transport: http(),
}).extend(publicActionsL2()) // [!code hl]
const l1Gas = await publicClient.estimateL1Gas({/* ... */})
```
## Extensions
### `walletActionsL1`
A suite of [Wallet Actions](/op-stack/actions/estimateL1Gas) for suited for development with **Layer 1** chains that interact with **Layer 2 (OP Stack)** chains.
```ts
import { walletActionsL1 } from 'viem/op-stack'
```
### `publicActionsL1`
A suite of [Public Actions](/op-stack/actions/getTimeToProve) suited for development with **Layer 1** chains. These actions provide functionalities specific to public clients operating at the Layer 1 level, enabling them to interact seamlessly with Layer 2 protocols.
```ts
import { publicActionsL1 } from 'viem/op-stack'
```
### `walletActionsL2`
A suite of [Wallet Actions](/op-stack/actions/estimateL1Fee) suited for development with **Layer 2 (OP Stack)** chains. These actions are tailored for wallets operating on Layer 2, providing advanced features and integrations necessary for Layer 2 financial operations.
```ts
import { walletActionsL2 } from 'viem/op-stack'
```
### `publicActionsL2`
A suite of [Public Actions](/op-stack/actions/estimateL1Gas) for suited for development with **Layer 2 (OP Stack)** chains.
```ts
import { publicActionsL2 } from 'viem/op-stack'
```
# Accounts
Tempo.ts provides Viem-compatible [Local Accounts](https://viem.sh/docs/accounts/local) that support multiple signature schemes including **secp256k1**, **P256**, and **WebAuthn (passkeys)**.
These accounts are fully backwards compatible with Viem APIs, meaning you can use them any Viem Action that accepts an `account`.
:::code-group
```ts twoslash [example.ts]
import { createWalletClient, http } from 'viem'
import { Account, WebAuthnP256 } from 'viem/tempo'
import { tempoModerato } from 'viem/chains'
// Create a passkey account
const credential = await WebAuthnP256.createCredential({ label: 'Example' })
const account = Account.fromWebAuthnP256(credential)
const client = createWalletClient({
chain: tempoModerato,
transport: http(),
})
// Use with Viem APIs
const hash = await client.sendTransactionSync({
account,
data: '0xcafebabe',
to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
})
```
:::
## Account Types
| Type | Description |
| --- | --- |
| [`fromSecp256k1`](/tempo/accounts/account.fromSecp256k1) | Create an account from a secp256k1 private key (standard Ethereum accounts) |
| [`fromWebAuthnP256`](/tempo/accounts/account.fromWebAuthnP256) | Create an account from a WebAuthn credential (passkeys) |
| [`fromWebCryptoP256`](/tempo/accounts/account.fromWebCryptoP256) | Create an account from a WebCrypto P256 key pair |
| [`fromP256`](/tempo/accounts/account.fromP256) | Create an account from a P256 private key |
# Overview
| Action | Description |
|--------|-------------|
| **Access Key Actions** | |
| [`accessKey.authorize`](/tempo/actions/accessKey.authorize) | Authorizes an access key |
| [`accessKey.getMetadata`](/tempo/actions/accessKey.getMetadata) | Gets access key information |
| [`accessKey.getRemainingLimit`](/tempo/actions/accessKey.getRemainingLimit) | Gets the remaining spending limit for a key-token pair |
| [`accessKey.revoke`](/tempo/actions/accessKey.revoke) | Revokes an authorized access key |
| [`accessKey.signAuthorization`](/tempo/actions/accessKey.signAuthorization) | Signs a key authorization (no transaction sent) |
| [`accessKey.updateLimit`](/tempo/actions/accessKey.updateLimit) | Updates the spending limit for a specific token on an access key |
| **AMM Actions** | |
| [`amm.burn`](/tempo/actions/amm.burn) | Burns liquidity tokens and receives the underlying token pair |
| [`amm.getLiquidityBalance`](/tempo/actions/amm.getLiquidityBalance) | Gets the liquidity balance for an address in a specific pool |
| [`amm.getPool`](/tempo/actions/amm.getPool) | Gets the reserves for a liquidity pool |
| [`amm.mint`](/tempo/actions/amm.mint) | Mints liquidity tokens by providing a token pair |
| [`amm.rebalanceSwap`](/tempo/actions/amm.rebalanceSwap) | Performs a rebalance swap between user and validator tokens |
| [`amm.watchBurn`](/tempo/actions/amm.watchBurn) | Watches for liquidity burn events |
| [`amm.watchMint`](/tempo/actions/amm.watchMint) | Watches for liquidity mint events |
| [`amm.watchRebalanceSwap`](/tempo/actions/amm.watchRebalanceSwap) | Watches for rebalance swap events |
| **Faucet Actions** | |
| [`faucet.fund`](/tempo/actions/faucet.fund) | Funds an account with testnet tokens |
| **Fee Actions** | |
| [`fee.getUserToken`](/tempo/actions/fee.getUserToken) | Gets the user's default fee token preference |
| [`fee.setUserToken`](/tempo/actions/fee.setUserToken) | Sets the user's default fee token preference |
| [`fee.watchSetUserToken`](/tempo/actions/fee.watchSetUserToken) | Watches for user token set events |
| **Nonce Actions** | |
| [`nonce.getNonce`](/tempo/actions/nonce.getNonce) | Gets the nonce for an account and nonce key |
| [`nonce.watchNonceIncremented`](/tempo/actions/nonce.watchNonceIncremented) | Watches for nonce incremented events |
| **Policy Actions** | |
| [`policy.create`](/tempo/actions/policy.create) | Creates a new transfer policy for token access control |
| [`policy.getData`](/tempo/actions/policy.getData) | Gets the data for a transfer policy, including its type and admin address |
| [`policy.isAuthorized`](/tempo/actions/policy.isAuthorized) | Checks if an address is authorized by a transfer policy |
| [`policy.modifyBlacklist`](/tempo/actions/policy.modifyBlacklist) | Modifies the blacklist for a blacklist-type transfer policy |
| [`policy.modifyWhitelist`](/tempo/actions/policy.modifyWhitelist) | Modifies the whitelist for a whitelist-type transfer policy |
| [`policy.setAdmin`](/tempo/actions/policy.setAdmin) | Sets the admin for a transfer policy |
| [`policy.watchAdminUpdated`](/tempo/actions/policy.watchAdminUpdated) | Watches for policy admin update events |
| [`policy.watchBlacklistUpdated`](/tempo/actions/policy.watchBlacklistUpdated) | Watches for blacklist update events |
| [`policy.watchCreate`](/tempo/actions/policy.watchCreate) | Watches for policy creation events |
| [`policy.watchWhitelistUpdated`](/tempo/actions/policy.watchWhitelistUpdated) | Watches for whitelist update events |
| **Reward Actions** | |
| [`reward.claim`](/tempo/actions/reward.claim) | Claims accumulated rewards for the caller |
| [`reward.distribute`](/tempo/actions/reward.distribute) | Distributes rewards to opted-in token holders |
| [`reward.getGlobalRewardPerToken`](/tempo/actions/reward.getGlobalRewardPerToken) | Gets the global reward per token value |
| [`reward.getPendingRewards`](/tempo/actions/reward.getPendingRewards) | Calculates the pending claimable rewards for an account |
| [`reward.getUserRewardInfo`](/tempo/actions/reward.getUserRewardInfo) | Gets reward information for a specific account |
| [`reward.setRecipient`](/tempo/actions/reward.setRecipient) | Sets or changes the reward recipient for a token holder |
| [`reward.watchRewardDistributed`](/tempo/actions/reward.watchRewardDistributed) | Watches for reward distributed events |
| [`reward.watchRewardRecipientSet`](/tempo/actions/reward.watchRewardRecipientSet) | Watches for reward recipient set events |
| **Stablecoin DEX Actions** | |
| [`dex.buy`](/tempo/actions/dex.buy) | Buys a specific amount of tokens from the Stablecoin DEX orderbook |
| [`dex.cancel`](/tempo/actions/dex.cancel) | Cancels an order from the orderbook |
| [`dex.cancelStale`](/tempo/actions/dex.cancelStale) | Cancels a stale order from a blacklisted maker |
| [`dex.createPair`](/tempo/actions/dex.createPair) | Creates a new trading pair on the DEX |
| [`dex.getBalance`](/tempo/actions/dex.getBalance) | Gets a user's token balance on the Stablecoin DEX |
| [`dex.getBuyQuote`](/tempo/actions/dex.getBuyQuote) | Gets the quote for buying a specific amount of tokens |
| [`dex.getOrder`](/tempo/actions/dex.getOrder) | Gets an order's details from the orderbook |
| [`dex.getTickLevel`](/tempo/actions/dex.getTickLevel) | Gets the price level information at a specific tick |
| [`dex.getSellQuote`](/tempo/actions/dex.getSellQuote) | Gets the quote for selling a specific amount of tokens |
| [`dex.place`](/tempo/actions/dex.place) | Places a limit order on the orderbook |
| [`dex.placeFlip`](/tempo/actions/dex.placeFlip) | Places a flip order that automatically flips when filled |
| [`dex.sell`](/tempo/actions/dex.sell) | Sells a specific amount of tokens from the Stablecoin DEX orderbook |
| [`dex.watchFlipOrderPlaced`](/tempo/actions/dex.watchFlipOrderPlaced) | Watches for flip order placed events |
| [`dex.watchOrderCancelled`](/tempo/actions/dex.watchOrderCancelled) | Watches for order cancelled events |
| [`dex.watchOrderFilled`](/tempo/actions/dex.watchOrderFilled) | Watches for order filled events |
| [`dex.watchOrderPlaced`](/tempo/actions/dex.watchOrderPlaced) | Watches for order placed events |
| [`dex.withdraw`](/tempo/actions/dex.withdraw) | Withdraws tokens from the DEX to the caller's wallet |
| **Token Actions** | |
| [`token.approve`](/tempo/actions/token.approve) | Approves a spender to transfer TIP-20 tokens on behalf of the caller |
| [`token.burn`](/tempo/actions/token.burn) | Burns TIP-20 tokens from the caller's balance |
| [`token.burnBlocked`](/tempo/actions/token.burnBlocked) | Burns TIP-20 tokens from a blocked address |
| [`token.changeTransferPolicy`](/tempo/actions/token.changeTransferPolicy) | Changes the transfer policy for a TIP-20 token |
| [`token.create`](/tempo/actions/token.create) | Creates a new TIP-20 token and assigns the admin role to the calling account |
| [`token.getAllowance`](/tempo/actions/token.getAllowance) | Gets the amount of tokens that a spender is approved to transfer on behalf of an owner |
| [`token.getBalance`](/tempo/actions/token.getBalance) | Gets the token balance of an address |
| [`token.getMetadata`](/tempo/actions/token.getMetadata) | Gets the metadata for a TIP-20 token, including name, symbol, decimals, currency, and total supply |
| [`token.grantRoles`](/tempo/actions/token.grantRoles) | Grants one or more roles to an address |
| [`token.mint`](/tempo/actions/token.mint) | Mints new TIP-20 tokens to a recipient |
| [`token.pause`](/tempo/actions/token.pause) | Pauses a TIP-20 token, preventing all transfers |
| [`token.renounceRoles`](/tempo/actions/token.renounceRoles) | Renounces one or more roles from the caller's address |
| [`token.revokeRoles`](/tempo/actions/token.revokeRoles) | Revokes one or more roles from an address |
| [`token.setRoleAdmin`](/tempo/actions/token.setRoleAdmin) | Sets the admin role for another role |
| [`token.setSupplyCap`](/tempo/actions/token.setSupplyCap) | Sets the supply cap for a TIP-20 token |
| [`token.transfer`](/tempo/actions/token.transfer) | Transfers TIP-20 tokens from the caller to a recipient |
| [`token.unpause`](/tempo/actions/token.unpause) | Unpauses a TIP-20 token, allowing transfers to resume |
| [`token.watchAdminRole`](/tempo/actions/token.watchAdminRole) | Watches for role admin update events |
| [`token.watchApprove`](/tempo/actions/token.watchApprove) | Watches for token approval events |
| [`token.watchBurn`](/tempo/actions/token.watchBurn) | Watches for token burn events |
| [`token.watchCreate`](/tempo/actions/token.watchCreate) | Watches for new token creation events |
| [`token.watchMint`](/tempo/actions/token.watchMint) | Watches for token mint events |
| [`token.watchRole`](/tempo/actions/token.watchRole) | Watches for role membership update events |
| [`token.watchTransfer`](/tempo/actions/token.watchTransfer) | Watches for token transfer events |
# Chains
The following Tempo chains are available:
```ts
import {
tempoDevnet, // [!code hl]
tempoLocalnet, // [!code hl]
tempoModerato, // [!code hl]
} from 'viem/chains'
```
## Default Fee Token
It is possible to set a default fee token for a Tempo chain by adding a `feeToken` property as an extension to the chain.
Once set, all transactions will use this token as the default fee token, unless an override is provided at the transaction level.
```ts
import { tempoModerato } from 'viem/chains'
const chain = tempoModerato.extend({
feeToken: '0x20c0000000000000000000000000000000000001',
})
```
# Tempo Transactions
Tempo Transactions are a Tempo-native EIP-2718 transaction type designed for payments. They support configurable fee tokens, fee sponsorship, batched calls, concurrent nonces, access keys, and scheduled execution. They are recommended over Ethereum transactions on Tempo.
[See the full specification](https://docs.tempo.xyz/protocol/transactions#tempo-transactions)
## Setup
In order to use Tempo Transactions, ensure that you have set up your Viem client
with the `tempoModerato` chain.
```ts twoslash [viem.config.ts]
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains' // [!code focus]
export const client = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: tempoModerato, // [!code focus]
transport: http(),
})
```
Now that you have set up your Viem client, you can now start to leverage Tempo Transactions.
Check out the features below on what is enabled with Tempo Transactions.
## Features
### Pay Fees with Stablecoins
Use the `feeToken` field to pay fees in any USD-denominated TIP-20 token. Tempo's Fee AMM automatically swaps to the validator's preferred token.
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const alphaUsd = '0x20c0000000000000000000000000000000000001'
const receipt = await client.sendTransactionSync({
data: '0xdeadbeef',
feeToken: alphaUsd,
to: '0xcafebabecafebabecafebabecafebabecafebabe',
})
```
```tsx twoslash [viem.config.ts] filename="viem.config.ts" filename="viem.config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains'
export const client = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: tempoModerato,
transport: http(),
})
```
:::
:::tip
You can also set a default `feeToken` globally by extending the chain.
```ts twoslash [example.ts]
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains'
export const client = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: tempoModerato.extend({ // [!code focus]
feeToken: '0x20c0000000000000000000000000000000000001' // [!code focus]
}), // [!code focus]
transport: http(),
})
```
:::
:::info
See a full guide on [paying fees in any stablecoin](https://docs.tempo.xyz/guide/payments/pay-fees-in-any-stablecoin).
:::
### Fee Sponsorship
A fee payer can cover gas fees for the sender via the `feePayer` field. You can use a local account or a remote relay service.
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
import { privateKeyToAccount } from 'viem/accounts'
const feePayer = privateKeyToAccount('0x...')
const receipt = await client.sendTransactionSync({
data: '0xdeadbeef',
feePayer,
to: '0xcafebabecafebabecafebabecafebabecafebabe',
})
```
```tsx twoslash [viem.config.ts] filename="viem.config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains'
export const client = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: tempoModerato,
transport: http(),
})
```
:::
:::tip
It is also possible to use a remote [Fee Payer Relay](https://docs.tempo.xyz/guide/payments/sponsor-user-fees#fee-payer-relay) instead of a local account.
:::
:::info
See a full guide on [sponsoring fees](https://docs.tempo.xyz/guide/payments/sponsor-user-fees).
:::
### Batch Calls
Bundle multiple operations atomically with `calls`.
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const receipt = await client.sendTransactionSync({
calls: [
{
to: '0xcafebabecafebabecafebabecafebabecafebabe',
data: '0xdeadbeef0000000000000000000000000000000001',
},
{
to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
data: '0xcafebabe0000000000000000000000000000000001',
},
],
})
```
```tsx twoslash [viem.config.ts] filename="viem.config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains'
export const client = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: tempoModerato,
transport: http(),
})
```
:::
### Access Keys
Access keys enable you to delegate signing authority from a primary account to a secondary key,
such as device-bound non-extractable [WebCrypto key](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKeyPair). The primary account signs a key authorization that grants the access key permission
to sign transactions on its behalf.
This authorization is then attached to the next transaction (that can be signed by either the primary or the access key), then all
transactions thereafter can be signed by the access key.
:::code-group
```tsx twoslash [example.ts]
// @noErrors
import { Account, WebCryptoP256 } from 'viem/tempo'
import { client } from './viem.config'
// 1. Instantiate account.
const account = Account.fromSecp256k1('0x...')
// 2. Generate a non-extractable WebCrypto key pair & instantiate access key.
const keyPair = await WebCryptoP256.createKeyPair()
const accessKey = Account.fromWebCryptoP256(keyPair, {
access: account,
})
// 3. Sign over key authorization with account.
const keyAuthorization = await account.signKeyAuthorization(accessKey)
// 4. Attach key authorization to (next) transaction.
const receipt = await client.sendTransactionSync({
account: accessKey, // sign transaction with access key // [!code hl]
data: '0xdeadbeef0000000000000000000000000000000001',
keyAuthorization, // [!code hl]
to: '0xcafebabecafebabecafebabecafebabecafebabe',
})
```
```tsx twoslash [viem.config.ts] filename="viem.config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains'
export const client = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: tempoModerato,
transport: http(),
})
```
:::
### Concurrent Transactions
Concurrent transactions enable higher throughput by allowing multiple transactions from the same account to be sent
in parallel without waiting for sequential nonce confirmation.
By using different nonce keys, you can submit multiple transactions simultaneously that don't conflict with each other,
enabling parallel execution and significantly improved transaction throughput for high-activity accounts.
You can leverage concurrent transactions in Viem by using `Promise.all`.
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const [receipt1, receipt2, receipt3] = await Promise.all([
client.sendTransactionSync({
data: '0xdeadbeef0000000000000000000000000000000001',
to: '0xcafebabecafebabecafebabecafebabecafebabe',
}),
client.sendTransactionSync({
data: '0xcafebabe0000000000000000000000000000000001',
to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
}),
client.sendTransactionSync({
data: '0xdeadbeef0000000000000000000000000000000001',
to: '0xcafebabecafebabecafebabecafebabecafebabe',
}),
])
```
```tsx twoslash [viem.config.ts] filename="viem.config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains'
export const client = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: tempoModerato,
transport: http(),
})
```
:::
You can also have control over the `nonceKey`s
:::code-group
```tsx twoslash [example.ts]
// @noErrors
import { client } from './viem.config'
const hash1 = await client.sendTransaction({
data: '0xdeadbeef0000000000000000000000000000000001',
nonceKey: 567n, // [!code hl]
to: '0xcafebabecafebabecafebabecafebabecafebabe',
})
const hash2 = await client.sendTransaction({
data: '0xdeadbeef0000000000000000000000000000000001',
nonceKey: 789n, // [!code hl]
to: '0xcafebabecafebabecafebabecafebabecafebabe',
})
```
```tsx twoslash [viem.config.ts] filename="viem.config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains'
export const client = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: tempoModerato,
transport: http(),
})
```
:::
### Scheduled Transactions
Scheduled transactions allow you to sign a transaction in advance and specify a time window for when it can be
executed onchain. By setting `validAfter` and `validBefore` timestamps, you define the earliest and latest times
the transaction can be included in a block.
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const receipt = await client.sendTransactionSync({
data: '0xdeadbeef0000000000000000000000000000000001',
to: '0xcafebabecafebabecafebabecafebabecafebabe',
validAfter: Math.floor(Number(new Date('2026-01-01')) / 1000), // [!code hl]
validBefore: Math.floor(Number(new Date('2026-01-02')) / 1000), // [!code hl]
})
```
```tsx twoslash [viem.config.ts] filename="viem.config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains'
export const client = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: tempoModerato,
transport: http(),
})
```
:::
## More Resources
* Tempo protocol docs: [Tempo Transactions](https://docs.tempo.xyz/protocol/transactions#tempo-transactions)
* Tempo Viem setup: [Getting Started](https://docs.tempo.xyz/tempo)
* Tempo transports: [`withFeePayer`](https://docs.tempo.xyz/tempo/transports/withFeePayer)
# Chains
The following ZKsync chains are supported in Viem:
```ts twoslash
import {
zksync, // [!code hl]
zksyncSepoliaTestnet, // [!code hl]
} from 'viem/chains'
```
## Configuration
Viem exports ZKsync's chain [formatters](/docs/chains/formatters) & [serializers](/docs/chains/serializers) via `chainConfig`. This is useful if you need to define another chain which is implemented on ZKsync.
```ts twoslash
// @noErrors
import { defineChain } from 'viem'
import { chainConfig } from 'viem/zksync'
export const zkStackExample = defineChain({
...chainConfig,
name: 'ZKsync Example',
// ...
})
```
# Client
To use the ZKsync functionality of Viem, you must extend your existing (or new) Viem Client with ZKsync Actions.
## Usage
```ts twoslash
import 'viem/window'
// ---cut---
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { zksync } from 'viem/chains'
import { eip712WalletActions } from 'viem/zksync'
const walletClient = createWalletClient({
chain: zksync,
transport: custom(window.ethereum!),
}).extend(eip712WalletActions()) // [!code hl]
const publicClient = createPublicClient({
chain: zksync,
transport: http()
})
```
## Extensions
### `eip712WalletActions`
A suite of [Wallet Actions](/zksync/actions/sendTransaction) for suited for development with ZKsync chains.
```ts twoslash
import { eip712WalletActions } from 'viem/zksync'
```
#### Sending transactions using paymaster
[Read more](./actions/sendTransaction.md)
```ts
const hash = await walletClient.sendTransaction({
account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
paymaster: '0xFD9aE5ebB0F6656f4b77a0E99dCbc5138d54b0BA',
paymasterInput: '0x123abc...'
})
```
#### Calling contracts
[Read more](../docs/contract/writeContract.md)
```ts
import { simulateContract } from 'viem/contract'
const { request } = await publicClient.simulateContract(walletClient, {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: parseAbi(['function mint(uint32 tokenId) nonpayable']),
functionName: 'mint',
args: [69420],
});
const hash = await walletClient.writeContract(request)
```
### `publicActionsL1`
A suite of [Public Actions](/zksync/actions/getL1Allowance) suited for development with **Layer 1** chains. These actions provide functionalities specific to public clients operating at the Layer 1 level, enabling them to interact seamlessly with Layer 2 protocols.
```ts
import { publicActionsL1 } from 'viem/zksync'
```
# Smart Accounts
A **Smart Account** is an account whose implementation resides in a **Smart Contract**, and implements the [ERC-4337 interface](https://eips.ethereum.org/EIPS/eip-4337#account-contract-interface).
A **Smart Account** can be controlled by one or more **Owners**, which can be a [Local](/docs/accounts/local) or [JSON-RPC Account](/docs/accounts/jsonRpc) (if supported). The **Owner Account** is responsible for signing User Operations (transactions) on behalf of the **Smart Account**, which are then broadcasted to the Network via a [Bundler](https://eips.ethereum.org/EIPS/eip-4337#bundling).
:::note
**Compatibility Note**
As ERC-4337 is not enshrined on the protocol, this means that Smart Accounts are incompatible with Viem's Transaction APIs such as `sendTransaction` and `writeContract`.
Sending "transactions" can be achieved by broadcasting a **User Operation** to a **Bundler**, which will then broadcast it to the Network shortly after.
The most common Actions for **User Operations** are:
* [`sendUserOperation`](/account-abstraction/actions/bundler/sendUserOperation) (also supports [Contract Writes](/account-abstraction/actions/bundler/sendUserOperation#contract-calls))
* [`estimateUserOperationGas`](/account-abstraction/actions/bundler/estimateUserOperationGas)
* [`getUserOperation`](/account-abstraction/actions/bundler/getUserOperation)
* [`getUserOperationReceipt`](/account-abstraction/actions/bundler/getUserOperationReceipt)
Once Account Abstraction is enshrined on the protocol, we anticipate the above Actions will become redundant in favor of Viem's Transaction APIs.
:::
# WebAuthn Account
A WebAuthn Account is nearly identical to a [Local Account](/docs/accounts/local), but with the following differences:
* uses the **secp256r1** curve for signatures
* returns a `signature` as well as `webauthn` data in its signing methods
* cannot sign transactions (transactions do not support **secp256r1** signatures)
* does not have an Ethereum `address`
WebAuthn Accounts are commonly used for **[Smart Account](/account-abstraction/accounts/smart) Owners** to sign User Operations and messages on behalf of the Smart Account.
:::note
WebAuthn Account owners are currently supported on the following Smart Account implementations:
* [`toCoinbaseSmartAccount`](/account-abstraction/accounts/smart/toCoinbaseSmartAccount#owners)
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import {
createWebAuthnCredential,
toWebAuthnAccount,
toCoinbaseSmartAccount
} from 'viem/account-abstraction'
import { client } from './client'
// 1. Register a credential (ie. passkey).
const credential = await createWebAuthnCredential({
name: 'Example',
})
// 2. Create a WebAuthn owner account from the credential.
const owner = toWebAuthnAccount({
credential,
})
// 3. Hook up the owner to a WebAuthn-compatible Smart Account.
const account = toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
# Bundler Client \[A function to create a Bundler Client.]
A Bundler Client is an interface to interact with **ERC-4337 Bundlers** and provides the ability to send and retrieve **User Operations** through **Bundler Actions**.
## Import
```ts twoslash
import { createBundlerClient } from 'viem/account-abstraction'
```
## Usage
```ts twoslash
import { createPublicClient, http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction' // [!code focus]
import { mainnet } from 'viem/chains' // [!code focus]
const client = createPublicClient({
chain: mainnet,
transport: http()
})
const bundlerClient = createBundlerClient({ // [!code focus]
client, // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc') // [!code focus]
}) // [!code focus]
```
:::info
The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Bundler](https://www.pimlico.io), [Biconomy's Bundler](https://www.biconomy.io), or another Bundler service.
:::
## Parameters
### account (optional)
* **Type:** `SmartAccount`
The [Smart Account](/account-abstraction/accounts/smart) to use for the Bundler Client. This will be used for Actions that require an `account` as an argument.
```ts twoslash
import { createPublicClient, http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
// ---cut---
import { toCoinbaseSmartAccount } from 'viem/account-abstraction' // [!code focus]
import { privateKeyToAccount } from 'viem/accounts'
const owner = privateKeyToAccount('0x...')
const account = await toCoinbaseSmartAccount({ // [!code focus]
client, // [!code focus]
owners: [owner], // [!code focus]
version: '1.1', // [!code focus]
}) // [!code focus]
const bundlerClient = createBundlerClient({
account, // [!code focus]
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
```
### chain (optional)
* **Type:** [Chain](/docs/glossary/types#chain)
The [Chain](/docs/chains/introduction) of the Bundler Client.
### dataSuffix (optional)
* **Type:** `Hex`
Data to append to the end of User Operation calldata. Useful for adding [transaction attribution](https://oxlib.sh/ercs/erc8021/Attribution).
The bundler client will also inherit `dataSuffix` from the underlying client (e.g., wallet client) if not explicitly set.
Applies to `prepareUserOperation` and `sendUserOperation` actions.
```ts twoslash
import { createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
// ---cut---
const bundlerClient = createBundlerClient({
dataSuffix: '0xdeadbeef', // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
```ts twoslash
import { createPublicClient, http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
// ---cut---
import { mainnet } from 'viem/chains'
const bundlerClient = createBundlerClient({
chain: mainnet, // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
### client (optional)
* **Type:** `Client`
The [Client](/docs/clients/public) (pointing to execution RPC) of the Bundler Client.
```ts twoslash
import { createBundlerClient } from 'viem/account-abstraction'
// ---cut---
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({ // [!code focus]
chain: mainnet, // [!code focus]
transport: http() // [!code focus]
}) // [!code focus]
const bundlerClient = createBundlerClient({
client, // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
### key (optional)
* **Type:** `string`
* **Default:** `"bundler"`
A key for the Client.
```ts twoslash
import { createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
// ---cut---
const client = createBundlerClient({
key: 'foo', // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
### name (optional)
* **Type:** `string`
* **Default:** `"Bundler Client"`
A name for the Client.
```ts twoslash
import { createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
// ---cut---
const client = createBundlerClient({
name: 'Foo Bundler Client', // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
### paymaster (optional)
* **Type:** `true | PaymasterClient | { getPaymasterData: typeof getPaymasterData, getPaymasterStubData: typeof getPaymasterStubData }`
Sets Paymaster configuration for the Bundler Client to be utilized on User Operations.
* If `paymaster: PaymasterClient`, it will use the provided [Paymaster Client](/account-abstraction/clients/paymaster) for User Operation sponsorship.
* If `paymaster: true`, it will be assumed that the Bundler Client also supports Paymaster RPC methods (e.g. `pm_getPaymasterData`), and use them for User Operation sponsorship.
* If [custom functions](#paymastergetpaymasterdata-optional) are provided to `paymaster`, it will use them for User Operation sponsorship.
#### Using a Paymaster Client
```ts twoslash
// @noErrors
import { createPaymasterClient, createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
import { mainnet } from 'viem/chains'
import { client } from './config'
// ---cut---
const paymasterClient = createPaymasterClient({ // [!code focus]
transport: http('https://public.pimlico.io/v2/11155111/rpc') // [!code focus]
}) // [!code focus]
const bundlerClient = createBundlerClient({
chain: mainnet,
paymaster: paymasterClient, // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
```
#### Using the Bundler Client as Paymaster
```ts twoslash
// @noErrors
import { createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const bundlerClient = createBundlerClient({
chain: mainnet,
paymaster: true, // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
```
#### Using Custom Paymaster Functions
See the [properties below](#paymastergetpaymasterdata-optional) for more information on how to use custom Paymaster functions.
### paymaster.getPaymasterData (optional)
* **Type:** `(userOperation: UserOperation) => Promise`
Retrieves paymaster-related User Operation properties to be used for sending the User Operation.
[Read more](https://github.com/ethereum/ERCs/blob/master/ERCS/erc-7677.md#pm_getpaymasterdata)
```ts twoslash
// @noErrors
import { createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const bundlerClient = createBundlerClient({
chain: mainnet,
paymaster: { // [!code focus]
async getPaymasterData(userOperation) { // [!code focus]
// Retrieve paymaster properties for the User Operation. // [!code focus]
return { // [!code focus]
paymaster: '0x...', // [!code focus]
paymasterData: '0x...', // [!code focus]
paymasterVerificationGasLimit: 69420n, // [!code focus]
paymasterPostOpGasLimit: 69420n, // [!code focus]
} // [!code focus]
} // [!code focus]
} // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
```
### paymaster.getPaymasterStubData (optional)
* **Type:** `(userOperation: UserOperation) => Promise`
Retrieves paymaster-related User Operation properties to be used for gas estimation.
[Read more](https://github.com/ethereum/ERCs/blob/master/ERCS/erc-7677.md#pm_getpaymasterstubdata)
```ts twoslash
// @noErrors
import { createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const bundlerClient = createBundlerClient({
chain: mainnet,
paymaster: {
async getPaymasterStubData(userOperation) { // [!code focus]
// Retrieve paymaster properties for the User Operation. // [!code focus]
return { // [!code focus]
paymaster: '0x...', // [!code focus]
paymasterData: '0x...', // [!code focus]
paymasterVerificationGasLimit: 69420n, // [!code focus]
paymasterPostOpGasLimit: 69420n, // [!code focus]
} // [!code focus]
} // [!code focus]
async getPaymasterData(userOperation) { /* ... */ }
}
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
```
### paymasterContext (optional)
* **Type:** `unknown`
Paymaster specific fields.
```ts twoslash
// @noErrors
import { createPaymasterClient, createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
import { mainnet } from 'viem/chains'
import { client } from './config'
// ---cut---
const paymasterClient = createPaymasterClient({
transport: http('https://public.pimlico.io/v2/1/rpc')
})
const bundlerClient = createBundlerClient({
chain: mainnet,
paymaster: paymasterClient,
paymasterContext: { // [!code focus]
policyId: 'abc123' // [!code focus]
}, // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
```
### pollingInterval (optional)
* **Type:** `number`
* **Default:** `4_000`
Frequency (in ms) for polling enabled Actions.
```ts twoslash
import { createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
// ---cut---
const client = createBundlerClient({
pollingInterval: 10_000, // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
### rpcSchema (optional)
* **Type:** `RpcSchema`
* **Default:** `BundlerRpcSchema`
Typed JSON-RPC schema for the client.
```ts twoslash
import { createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
// @noErrors
// ---cut---
import { rpcSchema } from 'viem'
type CustomRpcSchema = [{ // [!code focus]
Method: 'eth_wagmi', // [!code focus]
Parameters: [string] // [!code focus]
ReturnType: string // [!code focus]
}] // [!code focus]
const client = createBundlerClient({
rpcSchema: rpcSchema(), // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc')
})
const result = await client.request({ // [!code focus]
method: 'eth_wa // [!code focus]
// ^|
params: ['hello'], // [!code focus]
}) // [!code focus]
```
### transport
* **Type:** `Transport`
The Transport of the Bundler Client.
```ts twoslash
import { createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const bundlerClient = createBundlerClient({
chain: mainnet,
transport: http('https://public.pimlico.io/v2/1/rpc'), // [!code focus]
})
```
### userOperation (optional)
Configuration for User Operations.
#### userOperation.estimateFeesPerGas
* **Type:** `({ account: Account, bundlerClient: Client, userOperation: UserOperationRequest }) => Promise<{ maxFeePerGas: bigint, maxPriorityFeePerGas: bigint }>`
Prepares fee properties for the User Operation request.
```ts twoslash
// @noErrors
import { createBundlerClient } from 'viem/account-abstraction'
import { http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const bundlerClient = createBundlerClient({
chain: mainnet,
transport: http('https://public.pimlico.io/v2/1/rpc'),
userOperation: { // [!code focus]
async estimateFeesPerGas({ account, bundlerClient, userOperation }) { // [!code focus]
// Estimate fees per gas for the User Operation. // [!code focus]
return { // [!code focus]
maxFeePerGas: /* ... */, // [!code focus]
maxPriorityFeePerGas: /* ... */, // [!code focus]
} // [!code focus]
} // [!code focus]
} // [!code focus]
})
```
# Paymaster Client \[A function to create a Paymaster Client.]
A Paymaster Client is an interface to interact with **[ERC-7677 compliant Paymasters](https://eips.ethereum.org/EIPS/eip-7677)** and provides the ability to sponsor **User Operation** gas fees.
:::note
Read more on **ERC-7677 Paymasters**:
* [Website](https://erc7677.xyz/)
* [Specification](https://eips.ethereum.org/EIPS/eip-7677)
:::
## Import
```ts twoslash
import { createPaymasterClient } from 'viem/account-abstraction'
```
## Usage
```ts twoslash
import { http } from 'viem'
import {
createBundlerClient,
createPaymasterClient,
} from 'viem/account-abstraction'
import { sepolia } from 'viem/chains'
const paymasterClient = createPaymasterClient({ // [!code focus]
transport: http('https://public.pimlico.io/v2/11155111/rpc'), // [!code focus]
}) // [!code focus]
const bundlerClient = createBundlerClient({
chain: sepolia,
paymaster: paymasterClient, // [!code focus]
transport: http('https://public.pimlico.io/v2/11155111/rpc'),
})
```
:::info
The Paymaster URL above is a public endpoint **for testnets only**. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Paymaster](https://www.pimlico.io) or another Paymaster service.
:::
:::tip
You can see an example of end-to-end Paymaster Client usage on the [Sending User Operations guide](/account-abstraction/guides/sending-user-operations#7-optional-sponsor-user-operation).
:::
## Parameters
### key (optional)
* **Type:** `string`
* **Default:** `"paymaster"`
A key for the Client.
```ts twoslash
import { createPaymasterClient } from 'viem/account-abstraction'
import { http } from 'viem'
// ---cut---
const client = createPaymasterClient({
key: 'foo', // [!code focus]
transport: http('https://public.pimlico.io/v2/11155111/rpc')
})
```
### name (optional)
* **Type:** `string`
* **Default:** `"Paymaster Client"`
A name for the Client.
```ts twoslash
import { createPaymasterClient } from 'viem/account-abstraction'
import { http } from 'viem'
// ---cut---
const client = createPaymasterClient({
name: 'Foo Bundler Client', // [!code focus]
transport: http('https://public.pimlico.io/v2/11155111/rpc')
})
```
### pollingInterval (optional)
* **Type:** `number`
* **Default:** `4_000`
Frequency (in ms) for polling enabled Actions.
```ts twoslash
import { createPaymasterClient } from 'viem/account-abstraction'
import { http } from 'viem'
// ---cut---
const client = createPaymasterClient({
pollingInterval: 10_000, // [!code focus]
transport: http('https://public.pimlico.io/v2/11155111/rpc')
})
```
### rpcSchema (optional)
* **Type:** `RpcSchema`
* **Default:** `PaymasterRpcSchema`
Typed JSON-RPC schema for the client.
```ts twoslash
import { createPaymasterClient } from 'viem/account-abstraction'
import { http } from 'viem'
// @noErrors
// ---cut---
import { rpcSchema } from 'viem'
type CustomRpcSchema = [{ // [!code focus]
Method: 'eth_wagmi', // [!code focus]
Parameters: [string] // [!code focus]
ReturnType: string // [!code focus]
}] // [!code focus]
const client = createPaymasterClient({
rpcSchema: rpcSchema(), // [!code focus]
transport: http('https://public.pimlico.io/v2/11155111/rpc')
})
const result = await client.request({ // [!code focus]
method: 'eth_wa // [!code focus]
// ^|
params: ['hello'], // [!code focus]
}) // [!code focus]
```
### transport
* **Type:** `Transport`
The Transport of the Paymaster Client.
```ts twoslash
import { createPaymasterClient } from 'viem/account-abstraction'
import { http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const paymasterClient = createPaymasterClient({
transport: http('https://public.pimlico.io/v2/11155111/rpc'), // [!code focus]
})
```
# Sending User Operations
The guide below demonstrates how to send User Operations with a [Smart Account](/account-abstraction/accounts/smart).
## Overview
Here is an end-to-end overview of how to broadcast a User Operation with a Smart Account. We will break it down into [Steps](#steps) below.
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { bundlerClient } from './config.js'
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('0.001')
}]
})
const receipt = await bundlerClient.waitForUserOperationReceipt({ hash })
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import {
createBundlerClient,
toCoinbaseSmartAccount
} from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const owner = privateKeyToAccount('0x...')
const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
export const bundlerClient = createBundlerClient({
account,
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
```
:::
## Steps
### 1. Set up a Client
A Smart Account needs access to the Network to query for information about its state (e.g. nonce, address, etc). Let's set up a Client that we can use for the Smart Account:
```ts twoslash
// @noErrors
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
[See `createPublicClient` Docs](/docs/clients/public)
### 2. Set up a Bundler Client
Next, we will need to set up a Bundler Client. A Bundler is required to submit User Operations to the Blockchain for the Smart Account.
```ts twoslash
import { createPublicClient, http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction' // [!code ++] // [!code focus]
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const bundlerClient = createBundlerClient({ // [!code ++] // [!code focus]
client, // [!code ++] // [!code focus]
transport: http('https://public.pimlico.io/v2/1/rpc'), // [!code ++] // [!code focus]
}) // [!code ++] // [!code focus]
```
:::info
The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Bundler](https://www.pimlico.io), [Biconomy's Bundler](https://www.biconomy.io), or another Bundler service.
:::
[See `createBundlerClient` Docs](/account-abstraction/clients/bundler)
### 3. Set up an Owner
We will also need to set up an Owner for the Smart Account which will be used to sign User Operations (transactions) for the Smart Account.
```ts twoslash
// @noErrors
import { createPublicClient, http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts' // [!code ++] // [!code focus]
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const bundlerClient = createBundlerClient({
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const owner = privateKeyToAccount('0x...') // [!code ++] // [!code focus]
```
[See `privateKeyToAccount` Docs](/docs/accounts/local/privateKeyToAccount)
### 4. Create a Smart Account
Next, we will instantiate a Smart Account. For this example, we will use [`toCoinbaseSmartAccount`](/account-abstraction/accounts/smart/toCoinbaseSmartAccount) (Coinbase Smart Wallet).
```ts twoslash
// @noErrors
import { createPublicClient, http } from 'viem'
import { // [!code ++] // [!code focus]
createBundlerClient, // [!code ++] // [!code focus]
toCoinbaseSmartAccount // [!code ++] // [!code focus]
} from 'viem/account-abstraction' // [!code ++] // [!code focus]
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const bundlerClient = createBundlerClient({
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const owner = privateKeyToAccount('0x...')
const account = await toCoinbaseSmartAccount({ // [!code ++] // [!code focus]
client, // [!code ++] // [!code focus]
owners: [owner], // [!code ++] // [!code focus]
version: '1.1', // [!code ++] // [!code focus]
}) // [!code ++] // [!code focus]
```
:::tip
**Tip:** `toCoinbaseSmartAccount` also accepts [Passkey (WebAuthn) Accounts](/account-abstraction/accounts/webauthn) as an `owner`.
:::
[See `toCoinbaseSmartAccount` Docs](/account-abstraction/accounts/smart/toCoinbaseSmartAccount)
### 5. Send User Operation
Next, we will send a User Operation to the Bundler. For the example below, we will send 0.001 ETH to a random address.
```ts twoslash
import { createPublicClient, http, parseEther } from 'viem'
import {
createBundlerClient,
toCoinbaseSmartAccount
} from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const bundlerClient = createBundlerClient({
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const owner = privateKeyToAccount('0x...')
const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
const hash = await bundlerClient.sendUserOperation({ // [!code ++] // [!code focus]
account, // [!code ++] // [!code focus]
calls: [{ // [!code ++] // [!code focus]
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D', // [!code ++] // [!code focus]
value: parseEther('0.001') // [!code ++] // [!code focus]
}] // [!code ++] // [!code focus]
}) // [!code ++] // [!code focus]
const receipt = await bundlerClient.waitForUserOperationReceipt({ hash }) // [!code ++] // [!code focus]
```
:::tip
**Tip:** The `calls` property also accepts [Contract Write calls](/account-abstraction/actions/bundler/sendUserOperation#contract-calls).
:::
[See `sendUserOperation` Docs](/account-abstraction/actions/bundler/sendUserOperation)
### 6. Optional: Hoist the Account
If you do not wish to pass an account around to every Action that requires an `account`, you can also hoist the account onto a Wallet Client.
```ts twoslash
import { createPublicClient, http, parseEther } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const owner = privateKeyToAccount('0x...')
const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
const bundlerClient = createBundlerClient({
account, // [!code ++]
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const hash = await bundlerClient.sendUserOperation({
account, // [!code --]
calls: [{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('0.001')
}]
})
```
### 7. Optional: Sponsor User Operation
By using a Paymaster, we can add sponsorship of User Operation fees.
Viem exposes a `paymaster` property on both the **Bundler Client** ("on Client" tab) and **User Operation Action** ("on Action" tab) to add User Operation sponsorship capabilities.
The `paymaster` property accepts a [Paymaster Client](/account-abstraction/clients/paymaster) ([among others](/account-abstraction/actions/bundler/sendUserOperation#paymaster-optional)), which is used to fetch the necessary data for User Operation sponsorship.
:::info
The example below uses [Pimlico's Paymaster API](https://docs.pimlico.io/infra/paymaster) – allowing consumers to sponsor gas fees for users on over 30+ chains.
:::
:::code-group
```ts twoslash [example.ts (on Client)]
import { http } from 'viem'
import {
createBundlerClient,
createPaymasterClient,
} from 'viem/account-abstraction'
import { account, client } from './config.ts'
const paymasterClient = createPaymasterClient({ // [!code ++]
transport: http('https://public.pimlico.io/v2/11155111/rpc'), // [!code ++]
}) // [!code ++]
const bundlerClient = createBundlerClient({
account,
client,
paymaster: paymasterClient, // [!code ++]
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const hash = await bundlerClient.sendUserOperation({
calls: [{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('0.001')
}]
})
```
```ts twoslash [example.ts (on Action)]
import { http } from 'viem'
import {
createBundlerClient,
createPaymasterClient,
} from 'viem/account-abstraction'
import { account, client } from './config.ts'
const paymasterClient = createPaymasterClient({ // [!code ++]
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}'), // [!code ++]
}) // [!code ++]
const bundlerClient = createBundlerClient({
account,
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const hash = await bundlerClient.sendUserOperation({
calls: [{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('0.001')
}]
paymaster: paymasterClient, // [!code ++]
})
```
```ts twoslash [config.ts] filename="config.ts"
// @noErrors
import { createPublicClient, http, parseEther } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const owner = privateKeyToAccount('0x...')
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
```
:::
::::tip
If your Bundler also supports Paymaster sponsorshop (`pm_` JSON-RPC methods), you can set `paymaster: true` instead of declaring a separate Paymaster Client.
:::code-group
```ts twoslash [example.ts (on Client)]
import { http } from 'viem'
import {
createBundlerClient,
createPaymasterClient,
} from 'viem/account-abstraction'
import { account, client } from './config.ts'
const paymasterClient = createPaymasterClient({ // [!code --]
transport: http('https://public.pimlico.io/v2/1/rpc'), // [!code --]
}) // [!code --]
const bundlerClient = createBundlerClient({
account,
client,
paymaster: paymasterClient, // [!code --]
paymaster: true, // [!code ++]
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
```
```ts twoslash [example.ts (on Action)]
import { http } from 'viem'
import {
createBundlerClient,
createPaymasterClient,
} from 'viem/account-abstraction'
import { account, client } from './config.ts'
const paymasterClient = createPaymasterClient({ // [!code --]
transport: http('https://public.pimlico.io/v2/1/rpc'), // [!code --]
}) // [!code --]
const bundlerClient = createBundlerClient({
account,
client,
transport: http('https://public.pimlico.io/v2/1/rpc'),
})
const hash = await bundlerClient.sendUserOperation({
calls: [{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('0.001')
}]
paymaster: paymasterClient, // [!code --]
paymaster: true, // [!code ++]
})
```
```ts twoslash [config.ts] filename="config.ts"
// @noErrors
import { createPublicClient, http, parseEther } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
const owner = privateKeyToAccount('0x...')
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
```
:::
::::
# Cross Chain USDC Transfers with Bridge Kit
:::info
This guide is maintained by [Circle](https://www.circle.com).
:::
## Overview
This quickstart guide helps you write a script that transfers USDC from Base to Ethereum using [Bridge Kit](https://learn.circle.com/bridge-kit).
Bridge Kit is a high-level SDK that lets you start bridging in just 10 lines of code. It provides:
* **Hundreds of bridge routes** – Transfer between dozens of supported blockchains
* **Simple setup** – Start bridging in 10 lines of code
* **Fee collection** – Monetize your application by collecting fees from end-users
* **Custom configurations** – Specify transfer speeds, custom RPC endpoints, and wallet clients
* **Multiple wallet support** – Works with Viem, Ethers, MetaMask, Phantom, and more
* **Smart retry capabilities** – Automatically identify and recover stuck transactions
By the end, you'll know how to:
* Install Bridge Kit and its dependencies
* Configure your environment with private keys
* Execute a cross-chain USDC transfer from Base to Ethereum
* Verify the transfer on the blockchain
## Steps
::::steps
### Prerequisites
Before you begin, ensure that you've:
* Installed Node.js v22+ and npm
* Created an Ethereum Sepolia wallet and Base Sepolia wallet. You will fund these wallets in this quickstart.
### Set up your development environment
Create a new directory and install Bridge Kit and its dependencies:
```bash
# Setup your directory and initialize a Node.js project
mkdir bridge-kit-quickstart-transfer-base-to-eth
cd bridge-kit-quickstart-transfer-base-to-eth
npm init -y
# Install Bridge Kit and tools
npm install @circle-fin/bridge-kit @circle-fin/adapter-viem-v2 viem typescript tsx dotenv
```
### Initialize and configure the project
First, initialize the project, which creates a `tsconfig.json` file:
```bash
# Initialize a TypeScript project
npx tsc --init
```
Then, edit the `tsconfig.json` file:
```bash
# Replace the contents of the generated file
cat <<'EOF' > tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true
}
}
EOF
```
### Configure environment variables
Create a `.env` file in the project directory and add your wallet private key, replacing `{YOUR_PRIVATE_KEY}` with the private key for your Ethereum Sepolia wallet. (You can find and export your private key in MetaMask.)
```bash
echo "PRIVATE_KEY={YOUR_PRIVATE_KEY}" > .env
```
:::warning
Never commit your private key to version control. Use environment variables or a secure key management system.
:::
### Fund your wallets
For this quickstart, you need both USDC and native tokens in your Ethereum testnet wallet and native tokens in your Base testnet wallet. If you need USDC testnet tokens, use the [Circle Faucet](https://faucet.circle.com) to get 10 USDC in your Ethereum testnet wallet.
Use the following faucets to get testnet native tokens in your wallets:
* [Ethereum Sepolia faucet](https://sepoliafaucet.com)
* [Base Sepolia faucet](https://www.alchemy.com/faucets/base-sepolia)
:::tip
Instead of using the Base Sepolia faucet, you can use the Ethereum Sepolia faucet to transfer some tokens to Base.
:::
### Create the transfer script
Create an `index.ts` file in the project directory and add the following code. This code sets up your script and transfers 10 USDC from Base to Ethereum:
```ts [index.ts]
// Import Bridge Kit and its dependencies
import "dotenv/config";
import { BridgeKit } from "@circle-fin/bridge-kit";
import { createAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2";
import { inspect } from "util";
// Initialize the SDK
const kit = new BridgeKit();
const bridgeUSDC = async (): Promise => {
try {
// Initialize the adapter which lets you transfer tokens from your wallet on any EVM-compatible chain
const adapter = createAdapterFromPrivateKey({
privateKey: process.env.PRIVATE_KEY as string,
});
console.log("---------------Starting Bridging---------------");
// Execute the transfer using the same adapter for both source and destination chain
const result = await kit.bridge({
from: { adapter, chain: "Base_Sepolia" },
to: { adapter, chain: "Ethereum_Sepolia" },
amount: "10",
});
console.log("RESULT", inspect(result, false, null, true));
} catch (err) {
console.log("ERROR", inspect(err, false, null, true));
}
};
void bridgeUSDC();
```
### Run the transfer
Save the `index.ts` file and run the script in your terminal:
```bash
npx tsx index.ts
```
### Verify the transfer
After your script completes, find the returned `steps` array in the terminal output. Each transaction step includes an `explorerUrl` that you can visit to verify that the USDC amount matches the amount you transferred.
The following code is an example of how an `approve` step might look in the terminal output. The values are used in this example only and are not a real transaction:
```bash
steps: [
{
name: "approve",
state: "success",
txHash: "0x...txHash",
data: {
txHash:
"0x...txHash",
status: "success",
cumulativeGasUsed: 24567891n,
gasUsed: 52843n,
blockNumber: 8921456n,
blockHash:
"0x...blockHash",
transactionIndex: 245,
effectiveGasPrice: 1523456n,
explorerUrl:
"https://sepolia.etherscan.io/tx/0x...txHash",
},
},
]
```
:::tip
[Collect a fee on transfers](https://learn.circle.com/bridge-kit/tutorials/collect-a-transfer-fee) and [estimate gas and provider fees](https://learn.circle.com/bridge-kit/tutorials/estimate-costs) before a transfer, only proceeding if the cost is acceptable.
:::
::::
# Cross-Chain USDC Transfers
:::info
This guide is maintained by [Circle](https://www.circle.com).
:::
Cross chain USDC transfers allow you to move USDC between different blockchains using [Circle's Cross-Chain Transfer Protocol (CCTP)](https://developers.circle.com/stablecoins/cctp-getting-started).
Choose your preferred approach below to get started:
## Options
**CCTP Integration with Bridge Kit** – Start bridging in just 10 lines of code using Circle's high-level SDK. Perfect for quick integration with built-in fee collection, retry capabilities, and support for hundreds of bridge routes. Great for building bridging in an embedded wallet experience.
[Learn More →](/circle-usdc/guides/bridge-kit)
**CCTP Integration** – Direct integration with CCTP for complete control over every step of the transfer process. Ideal for developers who need fine-grained control and understanding of the underlying protocol.
[Learn More →](/circle-usdc/guides/manual-cctp)
# Integrating USDC into Your Application
## Overview
:::info
This guide is maintained by [Circle](https://www.circle.com).
:::
This guide walks you through how to integrate **USDC** into your application using [Viem](https://viem.sh).
We'll demonstrate how to interact with the USDC token contract to enable key functionality such as reading balances, transferring funds, approving third-party spenders, monitoring transfer events, and optimizing contract reads.
You'll be using the [Public Client](/docs/clients/public) to read blockchain state and [Wallet Client](/docs/clients/wallet) to sign and send transactions.
We'll be working on the **Sepolia testnet**, but the steps apply to any USDC-supported EVM-compatible network.
By the end of this guide, you'll know how to:
* Set up Viem clients and securely manage accounts
* Read and display USDC balances
* Send USDC between wallets
* Approve contracts (e.g., Uniswap) to spend USDC on your behalf
* Monitor on-chain Transfer events in real-time
* Optimize data loading with batched readContract calls
Each step is self-contained and modular — designed to be easily copied into your own project, whether you're building a wallet, a dashboard, a DeFi tool, or anything else powered by stable digital dollars.
Let's get started.
## Steps
::::steps
### Set up Clients
In this step, we'll configure a **Public Client** for reading blockchain data, and a **Wallet Client** for signing and sending transactions with USDC. You'll also set up your account using a private key.
We'll be using the Sepolia testnet, but you can easily swap this for any EVM-compatible chain.
```ts twoslash [example.ts]
import { createPublicClient, createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { sepolia } from 'viem/chains'
export const account = privateKeyToAccount('0x...')
export const publicClient = createPublicClient({
chain: sepolia,
transport: http(),
})
export const walletClient = createWalletClient({
account,
chain: sepolia,
transport: http(),
})
```
### Initialize the USDC Contract
Now we'll define the **USDC token contract** by providing its address and ABI. This allows us to interact with functions like balanceOf, transfer, and approve.
You can use any USDC address from [Circle's official registry](https://developers.circle.com/stablecoins/usdc-contract-addresses), but for this guide, we're using the Sepolia testnet version.
```ts twoslash [contract.ts]
import { erc20Abi } from 'viem'
export const usdcAbi = erc20Abi
export const usdcAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'
```
### Check a Wallet's USDC Balance
Let's check the USDC balance of your account. This is useful for verifying holdings before transfers, or displaying token balances in a wallet UI.
:::code-group
```ts twoslash [example.ts]
import { formatUnits } from 'viem'
import { publicClient, account } from './config'
import { usdcAddress, usdcAbi } from './contract'
const balance = await publicClient.readContract({
address: usdcAddress,
abi: usdcAbi,
functionName: 'balanceOf',
args: [account.address],
})
console.log(`Your USDC balance: ${formatUnits(balance, 6)} USDC`)
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { sepolia } from 'viem/chains'
export const account = privateKeyToAccount('0x...')
export const publicClient = createPublicClient({
chain: sepolia,
transport: http(),
})
export const walletClient = createWalletClient({
account,
chain: sepolia,
transport: http(),
})
```
```ts twoslash [contract.ts] filename="contract.ts"
import { erc20Abi } from 'viem'
export const usdcAbi = erc20Abi
export const usdcAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'
```
:::
Note: USDC uses 6 decimals — unlike ETH which uses 18. Always remember to format your values accordingly.
### Transfer USDC
Now we'll transfer USDC from your wallet to another address. This is the most common action in USDC-based apps — whether it's sending payments, tipping, or moving funds between accounts.
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { walletClient } from './config'
import { usdcAddress, usdcAbi } from './contract'
const recipient = '0x...'
const hash = await walletClient.writeContract({
address: usdcAddress,
abi: usdcAbi,
functionName: 'transfer',
args: [
recipient,
parseUnits('100', 6), // 100 USDC
],
})
console.log(`Sent 100 USDC. Tx Hash: ${hash}`)
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { sepolia } from 'viem/chains'
export const account = privateKeyToAccount('0x...')
export const publicClient = createPublicClient({
chain: sepolia,
transport: http(),
})
export const walletClient = createWalletClient({
account,
chain: sepolia,
transport: http(),
})
```
```ts twoslash [contract.ts] filename="contract.ts"
import { erc20Abi } from 'viem'
export const usdcAbi = erc20Abi
export const usdcAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'
```
:::
### Approve a Contract to Spend USDC
To interact with DeFi protocols like Uniswap, Compound, or payment processors, you'll often need to **approve a contract** to spend tokens on your behalf.
In this step, we'll approve the Uniswap Router to spend up to 1000 USDC from your wallet.
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { walletClient } from './config'
import { usdcAddress, usdcAbi } from './contract'
const hash = await walletClient.writeContract({
address: usdcAddress,
abi: usdcAbi,
functionName: 'approve',
args: [
'0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
parseUnits('1000', 6),
],
})
console.log(`Approved 1000 USDC for Uniswap. Tx Hash: ${hash}`)
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { sepolia } from 'viem/chains'
export const account = privateKeyToAccount('0x...')
export const publicClient = createPublicClient({
chain: sepolia,
transport: http(),
})
export const walletClient = createWalletClient({
account,
chain: sepolia,
transport: http(),
})
```
```ts twoslash [contract.ts] filename="contract.ts"
import { erc20Abi } from 'viem'
export const usdcAbi = erc20Abi
export const usdcAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'
```
:::
### Check the Allowance for a Spender
Once you've approved a spender (like Uniswap), you may want to verify how much USDC they're allowed to use.
Let's fetch the allowance for the Uniswap Router.
:::code-group
```ts twoslash [example.ts]
import { formatUnits } from 'viem'
import { publicClient, account } from './config'
import { usdcAddress, usdcAbi } from './contract'
const allowance = await publicClient.readContract({
address: usdcAddress,
abi: usdcAbi,
functionName: 'allowance',
args: [
account.address,
'0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
],
})
console.log(`Remaining allowance: ${formatUnits(allowance, 6)} USDC`)
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { sepolia } from 'viem/chains'
export const account = privateKeyToAccount('0x...')
export const publicClient = createPublicClient({
chain: sepolia,
transport: http(),
})
export const walletClient = createWalletClient({
account,
chain: sepolia,
transport: http(),
})
```
```ts twoslash [contract.ts] filename="contract.ts"
import { erc20Abi } from 'viem'
export const usdcAbi = erc20Abi
export const usdcAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'
```
:::
### Watch for USDC Transfers
Let's subscribe to real-time "Transfer events" emitted by the USDC contract. This is useful for building wallet UIs, dashboards, or backend listeners.
:::code-group
```ts twoslash [example.ts]
import { formatUnits } from 'viem'
import { publicClient } from './config'
import { usdcAddress, usdcAbi } from './contract'
const unwatch = publicClient.watchContractEvent({
address: usdcAddress,
abi: usdcAbi,
eventName: 'Transfer',
onLogs: (logs) => {
logs.forEach((log) => {
const { from, to, value } = log.args
console.log(`Transfer: ${from} → ${to} (${formatUnits(value, 6)} USDC)`)
})
},
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { sepolia } from 'viem/chains'
export const account = privateKeyToAccount('0x...')
export const publicClient = createPublicClient({
chain: sepolia,
transport: http(),
})
export const walletClient = createWalletClient({
account,
chain: sepolia,
transport: http(),
})
```
```ts twoslash [contract.ts] filename="contract.ts"
import { erc20Abi } from 'viem'
export const usdcAbi = erc20Abi
export const usdcAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'
```
:::
::::
# Cross Chain USDC Transfers (CCTP Integration)
## Overview
:::info
This guide is maintained by [Circle](https://www.circle.com).
:::
Let's set up a cross-chain USDC transfer using [Circle's Cross-Chain Transfer Protocol (CCTP V2)](https://developers.circle.com/stablecoins/cctp-getting-started) and Viem.
In this guide, we'll build a TypeScript script that burns USDC on the **Optimism Sepolia** testnet and mints the equivalent USDC on the **Ethereum Sepolia** testnet – all with just a few steps.
We'll use Viem's wallet client to interact with both chains, and the Circle CCTP Attestation API to retrieve the attestation needed to mint USDC on the destination chain.
By the end, you'll know how to:
* Approve the Circle TokenMessenger contract to spend USDC on the source chain (Optimism Sepolia).
* Burn USDC on the source chain to initiate a cross-chain transfer.
* Fetch an attestation from Circle verifying the burn event.
* Mint USDC on the destination chain (Ethereum Sepolia) using the attestation.
* Verify that the USDC balance moved from the source chain to the destination chain.
## Steps
::::steps
### Set up Viem Clients
First, we need to configure our environment and connect to both blockchains. We'll use **Viem** to create wallet clients for signing transactions and public clients for reading blockchain data.
```ts twoslash [config.ts]
import { createClient, http, publicActions, walletActions } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { sepolia, optimismSepolia } from 'viem/chains';
export const account = privateKeyToAccount('0x...');
export const client = {
optimismSepolia: createClient({
account,
chain: optimismSepolia,
transport: http(),
})
.extend(publicActions)
.extend(walletActions),
sepolia: createClient({
account,
chain: sepolia,
transport: http(),
})
.extend(publicActions)
.extend(walletActions),
}
```
:::note
Ensure your test wallet is funded with Sepolia ETH (for gas) on both networks and some Sepolia USDC on Optimism.
:::
### Define constants
Next, let's define all the constants we'll need: contract addresses, domains, and transfer parameters.
CCTP uses specific contracts on each chain for messaging and token minting/burning, and uses [**domain IDs**](https://developers.circle.com/stablecoins/supported-domains) to identify each blockchain in the protocol. The domain ID for Ethereum (Sepolia) is 0, and for Optimism (Sepolia) it's 2.
We'll also specify the amount of USDC to transfer (in USDC's smallest unit, 6 decimal places) and the max fee for a **Fast** transfer.
```ts [constants.ts]
import { erc20Abi } from 'viem'
export const domain = {
optimismSepolia: 2,
mainnet: 0,
}
export const tokenMessengerAbi = [{
type: 'function',
name: 'depositForBurn',
stateMutability: 'nonpayable',
inputs: [
{ name: 'amount', type: 'uint256' },
{ name: 'destinationDomain', type: 'uint32' },
{ name: 'mintRecipient', type: 'bytes32' },
{ name: 'burnToken', type: 'address' },
{ name: 'destinationCaller', type: 'bytes32' },
{ name: 'maxFee', type: 'uint256' },
{ name: 'minFinalityThreshold', type: 'uint32' },
],
outputs: [],
}, {
type: 'function',
name: 'receiveMessage',
stateMutability: 'nonpayable',
inputs: [
{ name: 'message', type: 'bytes' },
{ name: 'attestation', type: 'bytes' }
],
outputs: [],
}] as const
export const tokenMessengerAddress = {
optimismSepolia: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
mainnet: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
}
export const usdcAbi = erc20Abi
export const usdcAddress = {
optimismSepolia: '0x5fd84259d66cd46123540766be93dfe6d43130d7',
mainnet: '0x1c7d4b196cb0c7b01d743fbc6116a902379c7238',
}
```
### Approve USDC for transfer
Before we can burn USDC, we must approve the TokenMessenger contract to spend it.\
To prevent a race condition, we call waitForTransactionReceipt to ensure the approval transaction is confirmed before we proceed to the next step.
```ts
import { parseUnits } from 'viem'
import { client } from './config'
import { tokenMessengerAddress, usdcAddress, usdcAbi } from './constants'
async function approveUSDC() {
// approve 1 USDC
const hash = await client.optimismSepolia.writeContract({
abi: usdcAbi,
address: usdcAddress.optimismSepolia,
functionName: 'approve',
args: [tokenMessengerAddress.optimismSepolia, parseUnits('1', 6)],
});
await client.optimismSepolia.waitForTransactionReceipt({ hash });
}
```
### Burn USDC to initiate the transfer
Now comes the core of CCTP: **burning** USDC on the source chain to initiate the transfer.
We'll call the TokenMessenger's `depositForBurn(...)` function on Optimism Sepolia.\
This will burn the specified USDC from our wallet and emit a message that Circle's infrastructure will pick up.
Our function burnUSDC will handle this and return the transaction result, which we'll need for the next step (to retrieve the attestation).
```ts
import { erc20Abi, padHex, parseUnits } from 'viem'
import { client } from './config'
import { domain, tokenMessengerAddress, usdcAddress, usdcAbi } from './constants'
const destinationAddress = '0x...'
async function burnUSDC() {
return await client.optimismSepolia.writeContract({
abi: tokenMessengerAbi,
address: tokenMessengerAddress.optimismSepolia,
functionName: 'depositForBurn',
args: [
parseUnits('1', 6),
domain.sepolia,
padHex(destinationAddress, { dir: 'left', size: 32 }),
usdcAddress.optimismSepolia,
'0x0000000000000000000000000000000000000000000000000000000000000000',
parseUnits('0.0005', 6),
1000,
],
})
}
```
### Retrieve the attestation from Circle
After burning USDC on the source chain, Circle's CCTP service needs to provide an **attestation** – basically a signed confirmation that the burn event happened and is valid.
The attestation will later be used to authorize minting on the destination chain. Circle provides a public API endpoint to fetch this attestation by the source domain and transaction hash.
```ts
import { Hex } from 'viem'
import { domain } from './constants'
async function retrieveAttestation(burnTx: Hex) {
const url = `https://iris-api-sandbox.circle.com/v2/messages/${domain.optimismSepolia}?transactionHash=${burnTx}`;
return new Promise((resolve, reject) => {
const interval = setInterval(async () => {
try {
const response = await fetch(url)
if (!response.ok) return
const data = await response.json()
if (!data?.messages?.[0]) return
if (data.messages[0].status !== 'complete') return
clearInterval(interval)
resolve(data.messages[0])
} catch (error: any) {
clearInterval(interval)
reject(error)
}
}, 5000);
});
}
```
### Mint USDC on the destination chain
With the attestation, we call the receiveMessage function on the MessageTransmitter contract on Ethereum Sepolia. This function verifies the attestation and mints the USDC to our destination address.
```ts
import { client } from './config'
import { tokenMessengerAddress, tokenMessengerAbi } from './constants'
async function mintUSDC(attestation: { attestation: Hex, message: Hex }) {
return await client.sepolia.writeContract({
to: tokenMessengerAddress.sepolia,
abi: tokenMessengerAbi,
functionName: 'receiveMessage',
args: [attestation.message, attestation.attestation],
});
}
```
### Execute the transfer
Finally, we execute the steps in sequence and verify the final balances on both chains.
```ts
import { client } from './config'
// 1. Approve USDC on source chain
await approveUSDC();
// 2. Burn USDC on source (initiates transfer)
const burnTx = await burnUSDC();
// 3. Retrieve attestation for the burn transaction
const attestation = await retrieveAttestation(burnTx);
// 4. Mint USDC on destination chain using the attestation
await mintUSDC(attestation);
const sourceBalance = await client.optimismSepolia.readContract({
address: usdcAddress.optimismSepolia,
abi: usdcAbi,
functionName: 'balanceOf',
args: [account.address],
});
const destBalance = await client.sepolia.readContract({
address: usdcAddress.sepolia,
abi: usdcAbi,
functionName: 'balanceOf',
args: [account.address],
});
console.log(`USDC on Optimism Sepolia: ${formatUnits(sourceBalance, 6)}`);
console.log(`USDC on Ethereum Sepolia: ${formatUnits(destBalance, 6)}`);
```
::::
# Gasless USDC Transfers with Circle Paymaster
## Overview
:::info
This guide is maintained by [Circle](https://www.circle.com).
:::
In this guide, we'll show how to send USDC on the Arbitrum Sepolia testnet **without needing any ETH for gas**, using [Circle's Paymaster service](https://developers.circle.com/stablecoins/paymaster-overview) with Viem's Account Abstraction.
We'll use a Smart Account (via EIP-7702) to perform a USDC transfer. The Circle Paymaster will sponsor the gas in exchange for a small USDC fee, authorized by our signed permit.
By the end of this tutorial, you'll know how to:
* Set up a **Viem Client** and a **Smart Account** on Arbitrum Sepolia
* **Check the USDC balance** for the smart account
* Create an **EIP-2612 permit signature** authorizing the Paymaster to spend USDC for gas fees
* Configure a **Paymaster and Bundler** (using Pimlico's bundler) to handle gas payment in USDC
* **Send a User Operation** that transfers USDC to a recipient, with gas fees paid in USDC via the Paymaster
Let's get started with the environment setup, then walk through each step of the gasless USDC transfer.
::::steps
## Set up Client and Smart Account
```ts twoslash [config.ts] filename="config.ts"
import { createClient, http, publicActions, walletActions } from 'viem'
import { arbitrumSepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
import { toSimple7702SmartAccount } from 'viem/account-abstraction'
export const owner = privateKeyToAccount('0x...')
export const client = createClient({
account: owner,
chain: arbitrumSepolia,
transport: http()
})
.extend(publicActions)
.extend(walletActions)
export const account = await toSimple7702SmartAccount({ client, owner })
export const paymasterAddress = '0x3BA9A96eE3eFf3A69E2B18886AcF52027EFF8966'
export const usdcAddress = '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d'
```
## Verify USDC Balance
Before sending a gasless transaction, ensure the smart account has enough USDC to cover the transfer and the gas fee (in USDC).
We will read the USDC token balance of our smart account. If it is below a threshold (here we require at least **1 USDC**), the script will prompt you to fund the account via Circle's [USDC testnet faucet](https://faucet.circle.com) and then exit:
```ts [paymaster.ts]
const usdc = getContract({ client, address: usdcAddress, abi: erc20Abi })
const usdcBalance = await usdc.read.balanceOf([account.address])
if (usdcBalance < 1000000n) {
console.log(
`Fund ${account.address} with USDC on ${client.chain.name} using https://faucet.circle.com, then run this again.`,
)
process.exit(1)
}
```
## Create an EIP-2612 Permit
Circle's Paymaster requires a **permit signature** from the user to authorize it to spend USDC for gas. We'll use the EIP-2612 permit standard (supported by USDC) to allow the Paymaster contract to pull a certain amount of USDC from our account to cover gas fees.
```ts twoslash [utils.ts]
// @noErrors
import {
Address,
erc20Abi,
maxUint256,
getContract,
parseErc6492Signature,
} from 'viem'
import { account, client } from './config'
const eip2612Abi = [
...erc20Abi,
{
inputs: [
{
internalType: 'address',
name: 'owner',
type: 'address',
},
],
stateMutability: 'view',
type: 'function',
name: 'nonces',
outputs: [
{
internalType: 'uint256',
name: '',
type: 'uint256',
},
],
},
{
inputs: [],
name: 'version',
outputs: [{ internalType: 'string', name: '', type: 'string' }],
stateMutability: 'view',
type: 'function',
},
] as const
export async function signPermit({
permitAmount,
spenderAddress,
tokenAddress,
}: {
permitAmount: bigint,
spenderAddress: Address,
tokenAddress: Address,
}) {
const token = getContract({
client,
address: tokenAddress,
abi: eip2612Abi,
})
const signature = await account.signTypedData(permitData)
const [name, version, nonce] = await Promise.all([
token.read.name(),
token.read.version(),
token.read.nonces([ownerAddress])
])
const isValid = await client.verifyTypedData({
address: account.address,
types: {
Permit: [
{ name: 'owner', type: 'address' },
{ name: 'spender', type: 'address' },
{ name: 'value', type: 'uint256' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
},
primaryType: 'Permit',
domain: {
chainId: chain.id,
name,
verifyingContract: token.address,
version,
},
message: {
owner: ownerAddress,
spender: spenderAddress,
value,
nonce,
deadline: maxUint256,
},
signature,
})
if (!isValid)
throw new Error(
`Invalid permit signature for ${account.address}: ${wrappedPermitSignature}`,
)
const { signature: unwrappedSignature } = parseErc6492Signature(wrappedPermitSignature)
return unwrappedSignature
}
```
## Set up the Paymaster Configuration
Now we configure the Paymaster configuration for our User Operation using the permit we just prepared.
Viem's account abstraction allows us to provide a custom **Paymaster** object with a getPaymasterData method.
The bundler will call this method to attach the necessary paymaster info to our User Operation. In this method, we'll generate the permit signature on the fly and pack it into the required format:
```ts twoslash [paymaster.ts]
// @noErrors
import { parseUnits } from 'viem'
import { BundlerClientConfig } from 'viem/account-abstraction'
import { paymasterAddress } from './config'
import { signPermit } from './utils'
export const paymaster: BundlerClientConfig['paymaster'] = {
async getPaymasterData(parameters) {
const permitAmount = parseUnits('10', 6) // 10 USDC
const permitSignature = await signPermit({
permitAmount,
spenderAddress: paymasterAddress,
tokenAddress: usdcAddress,
})
const paymasterData = encodePacked(
['uint8', 'address', 'uint256', 'bytes'],
[0, usdcAddress, permitAmount, permitSignature],
)
return {
paymaster: paymasterAddress,
paymasterData,
paymasterVerificationGasLimit: 200_000n,
paymasterPostOpGasLimit: 15_000n,
isFinal: true,
}
},
}
```
## Initialize Bundler Client
Next, set up the Bundler Client that will send our User Operation.
We'll use **Pimlico's Public Bundler** for Arbitrum Sepolia:
```ts twoslash [example.ts]
// @noErrors
import { createBundlerClient, http } from 'viem/account-abstraction'
import { account, client } from './config'
import { paymaster } from './paymaster'
const bundlerClient = createBundlerClient({
account,
client,
paymaster,
transport: http(`https://public.pimlico.io/v2/${client.chain.id}/rpc`),
userOperation: {
estimateFeesPerGas: async ({ account, bundlerClient, userOperation }) => {
const { standard: fees } = await bundlerClient.request({
method: 'pimlico_getUserOperationGasPrice',
})
const maxFeePerGas = hexToBigInt(fees.maxFeePerGas)
const maxPriorityFeePerGas = hexToBigInt(fees.maxPriorityFeePerGas)
return { maxFeePerGas, maxPriorityFeePerGas }
},
},
})
```
## Send the User Operation
Finally, we create the User Operation to transfer USDC from our smart account to the recipient, and send it via the bundler. There are two parts here: **signing the smart account authorization** and **sending the User Operation** with the USDC transfer call.
```ts twoslash [example.ts]
import { erc20Abi, parseUnits } from 'viem'
import { account, client, usdcAddress } from './config'
import { paymaster } from './paymaster'
const bundlerClient = createBundlerClient({
account,
client,
paymaster,
transport: http(`https://public.pimlico.io/v2/${client.chain.id}/rpc`),
userOperation: {
estimateFeesPerGas: async ({ account, bundlerClient, userOperation }) => {
const { standard: fees } = await bundlerClient.request({
method: 'pimlico_getUserOperationGasPrice',
})
const maxFeePerGas = hexToBigInt(fees.maxFeePerGas)
const maxPriorityFeePerGas = hexToBigInt(fees.maxPriorityFeePerGas)
return { maxFeePerGas, maxPriorityFeePerGas }
},
},
})
const authorization = await client.signAuthorization(account.authorization) // [!code focus:99]
const hash = await bundlerClient.sendUserOperation({
account,
authorization,
calls: [
{
to: usdcAddress,
abi: erc20Abi,
functionName: 'transfer',
args: ['0x{recipient}', parseUnits('10', 6)], // 10 USDC
},
],
})
const receipt = await bundlerClient.waitForUserOperationReceipt({ hash })
```
**Congratulations!** You've successfully sent a USDC transfer on Arbitrum Sepolia without using any ETH for gas.
::::
# Circle Smart Account
## Install
:::info
This package & guide is maintained by [Circle](https://www.circle.com).
:::
Make sure to add [Circle's Modular Wallets](https://developers.circle.com/w3s/modular-wallets) SDK to your project:
```sh
npm install @circle-fin/modular-wallets-core
```
This package provides utilities for passkey authentication and smart account creation.
## Prerequisites
Before you start, make sure you have:
* Set up and retrieved your **Client Key and Client URL** [by following this step](https://developers.circle.com/w3s/modular-wallets-setup)
* Configured a domain for WebAuthn credential (Passkey) registration
* Familiarize yourself with [Circle's API Key and Client Key authentication](https://developers.circle.com/w3s/web3-services-api-client-keys-auth)
::::steps
## Create a Passkey Credential
First, register a new **Passkey** (WebAuthn credential) or use an existing one for your user.
The Circle SDK uses a **Passkey server** to handle WebAuthn registration and login.
We need to initialize a Passkey Transport with the Circle **Client Key** and **Client URL** (obtained from the Circle Modular Wallets console setup), then create a credential:
```ts
import {
toPasskeyTransport,
toWebAuthnCredential,
WebAuthnMode
} from '@circle-fin/modular-wallets-core'
const clientKey = '...'
const clientUrl = 'https://...'
const passkeyTransport = toPasskeyTransport(clientUrl, clientKey)
const credential = await toWebAuthnCredential({
transport: passkeyTransport,
mode: WebAuthnMode.Register,
username: 'user-example',
})
```
This will trigger the WebAuthn flow in the browser (e.g. biometric prompt) and yield a `credential` object for the passkey.
## Create Client
Next, create a Viem **Public Client** configured to use Circle's infrastructure.
Circle provides custom RPC endpoints (via the Client URL) for each supported network.
Use `toModularTransport` to get a Viem transport for your target chain, and then initialize the client.
For example, to connect to the Polygon Amoy testnet (a Circle test network):
```ts
import { toModularTransport } from '@circle-fin/modular-wallets-core'
import { createPublicClient } from 'viem'
import { polygonAmoy } from 'viem/chains'
const transport = toModularTransport(
`${clientUrl}/polygonAmoy`,
clientKey,
)
const client = createPublicClient({
chain: polygonAmoy,
transport,
})
```
:::note
When calling `toModularTransport`, specify a supported network path. Circle's Modular Wallet service supports major EVM chains (Ethereum, Polygon, Base, Optimism, Arbitrum, etc., including their testnets). For example, use `${clientUrl}/baseSepolia` for Base Sepolia, `${clientUrl}/optimism` for Optimism, and so on.
:::
## Create a Circle Smart Account
With the client ready and a passkey credential available, you can create the **Circle Smart Account**. This smart account is a contract wallet (an ERC-4337 & ERC-6900 compatible smart contract) controlled by the passkey. We'll transform the WebAuthn credential into a Viem account object and then generate the smart account:
```ts
import { toCircleSmartAccount } from '@circle-fin/modular-wallets-core'
import { toWebAuthnAccount } from 'viem/account-abstraction'
const owner = toWebAuthnAccount({
credential,
})
const account = await toCircleSmartAccount({
client,
owner,
})
```
## Set up a Bundler Client
To send transactions from a smart account, we use an ERC-4337 **Bundler**. Viem provides a Bundler client that interfaces with bundler RPC endpoints. Using Circle's Modular transport, we can create a Bundler client that will forward User Operations to Circle's bundler.
```ts
import { createBundlerClient } from 'viem/account-abstraction'
import { polygonAmoy } from 'viem/chains'
const bundlerClient = createBundlerClient({
account,
chain: polygonAmoy,
transport,
})
```
## Send a Gasless USDC Transaction
Finally, let's send a token transfer from the smart account **without requiring the user to pay gas**. In this example, we'll transfer **1 USDC** on the test network to an arbitrary address. Circle's bundler and paymaster will sponsor the gas fees as long as a Gas Station policy is in place (on testnet, a default policy is usually already configured).
We will use the Circle SDK's helper to encode an ERC-20 transfer call and then send a User Operation via the bundler client:
```ts
import { encodeTransfer } from '@circle-fin/modular-wallets-core'
import { parseUnits } from 'viem'
const usdcAddress = '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582'
const hash = await bundlerClient.sendUserOperation({
calls: [
encodeTransfer(
'0x{recipient}',
usdcAddress,
parseUnits('1', 6)
)
],
paymaster: true,
})
```
The bundler returns a User Operation `hash` for the submitted operation. You can then wait for the transaction to be included:
```ts
const { receipt } = await bundlerClient.waitForUserOperationReceipt({ hash: userOpHash })
```
::::
That's it!
You have created a Circle Smart Account with a passkey and sent a gasless USDC transfer using Viem.
The Circle Modular Wallets SDK seamlessly handles the account abstraction flow – from passkey-based signing to sponsored gas payments – allowing you to build a user-friendly dApp without exposing the complexity of gas fees to your users.
## Example Apps
The Circle team has prepared working demos to help you get started quickly with Modular Wallets:
* [Modular Wallet + Passkey (Replit)](https://replit.com/@buildoncircle/modular-wallet-passkey) – A simple web demo showcasing passkey login and gasless USDC transfer.
* [Modular Wallets Web SDK Example (GitHub)](https://github.com/circlefin/modularwallets-web-sdk/tree/master/examples/circle-smart-account) – A full React implementation using Circle Smart Accounts, bundler, and paymaster.
Use these as references when building or testing your own integration.
# decodeAbiParameters \[Decodes ABI encoded data.]
Decodes ABI encoded data using the [ABI specification](https://solidity.readthedocs.io/en/latest/abi-spec), given a set of ABI parameters (`inputs`/`outputs`) and the encoded ABI data.
The `decodeAbiParameters` function is used by the other contract decoding utilities (ie. `decodeFunctionData`, `decodeEventLog`, etc).
## Install
```ts
import { decodeAbiParameters } from 'viem'
```
## Usage
The `decodeAbiParameters` function takes in two parameters:
* a set of ABI Parameters (`params`), that can be in the shape of the `inputs` or `outputs` attribute of an ABI Item.
* the ABI encoded data (`data`) that correspond to the given `params`.
```ts
import { decodeAbiParameters } from 'viem'
const values = decodeAbiParameters(
[
{ name: 'x', type: 'string' },
{ name: 'y', type: 'uint' },
{ name: 'z', type: 'bool' }
],
'0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000057761676d69000000000000000000000000000000000000000000000000000000',
)
// ['wagmi', 420n, true]
```
### Human Readable
You can also pass in [Human Readable](/docs/glossary/terms#human-readable-abi) parameters with the [`parseAbiParameters` utility](/docs/abi/parseAbiParameters).
```ts
import { decodeAbiParameters, parseAbiParameters } from 'viem'
const values = decodeAbiParameters(
parseAbiParameters('string x, uint y, bool z'),
'0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000057761676d69000000000000000000000000000000000000000000000000000000'
)
// ['wagmi', 420n, true]
```
## Return Value
The decoded data. Type is inferred from the ABI.
## Parameters
### params
* **Type**: [`AbiParameter[]`](/docs/glossary/types#abiparameter)
The set of ABI parameters to decode against `data`, in the shape of the `inputs` or `outputs` attribute of an ABI event/function.
These parameters must include valid [ABI types](https://docs.soliditylang.org/en/develop/abi-spec#types).
```ts
const values = decodeAbiParameters(
[{ name: 'x', type: 'uint32' }], // [!code focus]
'0x0000000000000000000000000000000000000000000000000000000000010f2c',
)
```
### data
* **Type:** [`Hex`](/docs/glossary/types#hex)
The ABI encoded data.
```ts
const values = decodeAbiParameters(
[{ name: 'x', type: 'uint32' }],
'0x0000000000000000000000000000000000000000000000000000000000010f2c', // [!code focus]
)
```
## More Examples
### Simple struct
:::code-group
```ts [example.ts]
import { abi } from './abi'
const values = decodeAbiParameters(
abi[0].outputs,
'0x00000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac',
)
// { x: 420n, y: true, z: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC' }
```
```ts [abi.ts]
export const abi = [
{
name: 'staticStruct',
outputs: [
{
components: [
{
name: 'x',
type: 'uint256',
},
{
name: 'y',
type: 'bool',
},
{
name: 'z',
type: 'address',
},
],
name: 'foo',
type: 'tuple',
},
],
}
] as const
```
```solidity [Example.sol]
contract Example {
struct Foo {
uint256 x;
bool y;
address z;
}
function staticStruct(...) returns (Foo calldata foo) {
...
return foo;
}
}
```
:::
### Simple bytes
A simple `bytes` that contains an ABI-encoded `uint256` value.
:::code-group
```ts [example.ts]
const values = decodeAbiParameters(
[
{ name: "response", type: "bytes" },
],
'0x' +
'0000000000000000000000000000000000000000000000000000000000000020' + // offset pointer
'0000000000000000000000000000000000000000000000000000000000000020' + // length
'0000000000000000000000000000000000000000000000000000000000000001', // data
)
// 0x0000000000000000000000000000000000000000000000000000000000000001
```
```solidity [Example.sol]
contract Example {
function simpleBytes() public pure returns (bytes memory) {
bytes memory value = abi.encode(1);
return abi.encode(value);
}
}
```
:::
# encodeAbiParameters
Generates ABI encoded data using the [ABI specification](https://docs.soliditylang.org/en/latest/abi-spec.html), given a set of ABI parameters (`inputs`/`outputs`) and their corresponding values.
The `encodeAbiParameters` function is used by the other contract encoding utilities (ie. `encodeFunctionData`, `encodeEventTopics`, etc).
## Import
```ts
import { encodeAbiParameters } from 'viem'
```
## Usage
The `encodeAbiParameters` function takes in two parameters:
* a set of ABI Parameters (`params`), that can be in the shape of the `inputs` or `outputs` attribute of an ABI Item.
* a set of values (`values`) that correspond to the given `params`.
```ts
import { encodeAbiParameters } from 'viem'
const encodedData = encodeAbiParameters(
[
{ name: 'x', type: 'string' },
{ name: 'y', type: 'uint' },
{ name: 'z', type: 'bool' }
],
['wagmi', 420n, true]
)
// 0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000057761676d69000000000000000000000000000000000000000000000000000000
```
### Human Readable
You can also pass in [Human Readable](/docs/glossary/terms#human-readable-abi) parameters with the [`parseAbiParameters` utility](/docs/abi/parseAbiParameters).
```ts
import { encodeAbiParameters, parseAbiParameters } from 'viem'
const encodedData = encodeAbiParameters(
parseAbiParameters('string x, uint y, bool z'),
['wagmi', 420n, true]
)
// 0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000057761676d69000000000000000000000000000000000000000000000000000000
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The ABI encoded data.
## Parameters
### params
* **Type**: [`AbiParameter[]`](/docs/glossary/terms#abiparameter)
The set of ABI parameters to encode, in the shape of the `inputs` or `outputs` attribute of an ABI event/function.
These parameters must include valid [ABI types](https://docs.soliditylang.org/en/develop/abi-spec#types).
```ts
encodeAbiParameters(
[{ name: 'x', type: 'uint32' }], // [!code focus]
[69420]
)
```
### values
* **Type**: [`AbiParametersToPrimitiveTypes`](/docs/glossary/terms#abiparameterstoprimitivetypes)
The set of primitive values that correspond to the ABI types defined in `params`.
```ts
encodeAbiParameters(
[{ name: 'x', type: 'uint32' }],
[69420] // [!code focus]
)
```
## More Examples
### Simple struct
:::code-group
```ts [example.ts]
import { abi } from './abi'
const encodedData = encodeAbiParameters(
abi[0].inputs,
[{
x: 420n,
y: true,
z: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
}],
)
// 0x00000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac
```
```ts [abi.ts]
export const abi = [
{
name: 'staticStruct',
inputs: [
{
components: [
{
name: 'x',
type: 'uint256',
},
{
name: 'y',
type: 'bool',
},
{
name: 'z',
type: 'address',
},
],
name: 'foo',
type: 'tuple',
},
],
}
] as const
```
```solidity [Example.sol]
contract Example {
struct Foo {
uint256 x;
bool y;
address z;
}
function staticStruct(Foo calldata foo) { ... }
}
```
:::
# encodePacked
Generates [ABI non-standard packed encoded data](https://docs.soliditylang.org/en/v0.8.18/abi-spec#non-standard-packed-mode) given a set of solidity types compatible with packed encoding.
## Import
```ts
import { encodePacked } from 'viem'
```
## Usage
```ts
encodePacked(
['address', 'string', 'bytes16[]'],
[
'0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
'hello world',
['0xdeadbeefdeadbeefdeadbeefdeadbeef', '0xcafebabecafebabecafebabecafebabe']
]
)
// 0xd8da6bf26964af9d7eed9e03e53415d37aa9604568656c6c6f20776f726c64deadbeefdeadbeefdeadbeefdeadbeef00000000000000000000000000000000cafebabecafebabecafebabecafebabe00000000000000000000000000000000
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The encoded packed data.
## Parameters
### types
* **Type**: `PackedAbiType[]`
Set of ABI types to pack encode.
```ts
encodePacked(
['address', 'string', 'bytes16[]'], // [!code focus]
[
'0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
'hello world',
['0xdeadbeefdeadbeefdeadbeefdeadbeef', '0xcafebabecafebabecafebabecafebabe']
]
)
```
### values
* **Type**: [`AbiParametersToPrimitiveTypes`](/docs/glossary/terms#abiparameterstoprimitivetypes)
The set of primitive values that correspond to the ABI types defined in `types`.
```ts
encodePacked(
['address', 'string', 'bytes16[]'],
[ // [!code focus:5]
'0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
'hello world',
['0xdeadbeefdeadbeefdeadbeefdeadbeef', '0xcafebabecafebabecafebabecafebabe']
]
)
```
# getAbiItem
Retrieves an item from the ABI.
## Import
```ts
import { getAbiItem } from 'viem'
```
## Usage
```ts
import { getAbiItem } from 'viem'
const encodedData = getAbiItem({
abi: [
{
name: 'x',
type: 'function',
inputs: [{ type: 'uint256' }],
outputs: [],
stateMutability: 'payable'
},
{
name: 'y',
type: 'event',
inputs: [{ type: 'address' }],
outputs: [{ type: 'uint256' }],
stateMutability: 'view'
},
{
name: 'z',
type: 'function',
inputs: [{ type: 'string' }],
outputs: [{ type: 'uint256' }],
stateMutability: 'view'
}
],
name: 'y',
})
/**
* {
* name: 'y',
* type: 'event',
* inputs: [{ type: 'address' }],
* outputs: [{ type: 'uint256' }],
* stateMutability: 'view'
* }
*/
```
## Returns
`AbiItem`
The ABI item.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const encodedData = getAbiItem({
abi: [...], // [!code focus]
name: 'x',
})
```
### name
* **Type:** `string`
Name of the ABI item to extract.
```ts
const encodedData = getAbiItem({
abi: [...],
name: 'x', // [!code focus]
})
```
You can also provide the ABI item's 4byte selector:
```ts
const encodedData = getAbiItem({
abi: [...],
name: '0x70a08231', // [!code focus]
})
```
### args (optional)
* **Type:** Inferred.
Optional arguments to identify function overrides.
```ts
const encodedData = getAbiItem({
abi: [...],
name: 'y',
args: ['0x0000000000000000000000000000000000000000'], // [!code focus]
})
```
# parseAbi
Parses human-readable ABI into JSON [`Abi`](/docs/glossary/types#abi). Re-exported from [ABIType](https://abitype.dev/api/human#parseabi-1).
## Import
```ts
import { parseAbi } from 'viem'
```
## Usage
```ts
import { parseAbi } from 'viem'
const abi = parseAbi([
// ^? const abi: readonly [{ name: "balanceOf"; type: "function"; stateMutability:...
'function balanceOf(address owner) view returns (uint256)',
'event Transfer(address indexed from, address indexed to, uint256 amount)',
])
```
## Returns
[`Abi`](/docs/glossary/types#abi)
The JSON ABI.
## Parameters
### signatures
* **Type:** `string[]`
Human-readable ABI.
```ts
import { parseAbi } from 'viem'
const abi = parseAbi([
// ^? const abi: readonly [{ name: "balanceOf"; type: "function"; stateMutability:...
'function balanceOf(address owner) view returns (uint256)',
'event Transfer(address indexed from, address indexed to, uint256 amount)',
])
```
# parseAbiItem
Parses human-readable ABI item (e.g. error, event, function) into ABI item. Re-exported from [ABIType](https://abitype.dev/api/human#parseabiitem-1).
## Import
```ts
import { parseAbiItem } from 'viem'
```
## Usage
```ts
import { parseAbiItem } from 'viem'
const abiItem = parseAbiItem(
// ^? const abiItem: { name: "balanceOf"; type: "function"; stateMutability: "view";...
'function balanceOf(address owner) view returns (uint256)',
)
```
## Returns
[`Abi`](/docs/glossary/types#abi)
Parsed ABI item.
## Parameters
### signatures
* **Type:** `string[]`
Human-Readable ABI item.
```ts
import { parseAbiItem } from 'viem'
const abiItem = parseAbiItem([
// ^? const abiItem: { name: "foo"; type: "function"; stateMutability: "view"; inputs:...
'function foo(Baz bar) view returns (string)',
'struct Baz { string name; }',
])
```
# parseAbiParameter
Parses human-readable ABI parameter into [`AbiParameter`](/docs/glossary/types#abiparameter). Re-exported from [ABIType](https://abitype.dev/api/human#parseabiparameter-1).
## Import
```ts
import { parseAbiParameter } from 'viem'
```
## Usage
```ts
import { parseAbiParameter } from 'viem'
const abiParameter = parseAbiParameter('address from')
// ^? const abiParameter: { type: "address"; name: "from"; }
```
## Returns
[`Abi`](/docs/glossary/types#abi)
Parsed ABI parameter.
## Parameters
### signature
* **Type:** `string | string[]`
Human-Readable ABI parameter.
```ts
import { parseAbiParameter } from 'viem'
const abiParameter = parseAbiParameter([
// ^? const abiParameter: { type: "tuple"; components: [{ type: "string"; name:...
'Baz bar',
'struct Baz { string name; }',
])
```
# parseAbiParameters
Parses human-readable ABI parameters into [`AbiParameter`s](/docs/glossary/types#abiparameter). Re-exported from [ABIType](https://abitype.dev/api/human#parseabiparameters-1).
## Import
```ts
import { parseAbiParameters } from 'viem'
```
## Usage
```ts
import { parseAbiParameters } from 'viem'
const abiParameters = parseAbiParameters(
// ^? const abiParameters: [{ type: "address"; name: "from"; }, { type: "address";...
'address from, address to, uint256 amount',
)
```
## Returns
[`Abi`](/docs/glossary/types#abi)
Parsed ABI parameters.
## Parameters
### params
* **Type:** `string | string[]`
Human-Readable ABI parameters.
```ts
import { parseAbiParameters } from 'viem'
const abiParameters = parseAbiParameters([
// ^? const abiParameters: [{ type: "tuple"; components: [{ type: "string"; name:...
'Baz bar',
'struct Baz { string name; }',
])
```
# JSON-RPC Account \[A function to create a JSON-RPC Account.]
A JSON-RPC Account is an Account whose signing keys are stored on the external Wallet. It **defers** signing of transactions & messages to the target Wallet over JSON-RPC. An example of such Wallet could be a Browser Extension Wallet, or Mobile Wallet over WalletConnect.
## Usage
A JSON-RPC Account can just be initialized as an [Address](/docs/glossary/types#address) string. In the usage below, we are extracting the address from a Browser Extension Wallet (e.g. MetaMask) with the `window.ethereum` Provider via `eth_requestAccounts`:
```ts twoslash
// @noErrors
import 'viem/window'
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
const [address] = await window.ethereum.request({ // [!code focus:3]
method: 'eth_requestAccounts'
})
const client = createWalletClient({
account: address, // [!code focus]
chain: mainnet,
transport: custom(window.ethereum!)
})
```
# Local Accounts (Private Key, Mnemonic, etc)
A Local Account is an Account whose signing keys are stored on the consuming user's machine. It performs signing of transactions & messages with a private key **before** broadcasting the transaction or message over JSON-RPC.
There are three types of Local Accounts in viem:
* [Private Key Account](/docs/accounts/local/privateKeyToAccount)
* [Mnemonic Account](/docs/accounts/local/mnemonicToAccount)
* [Hierarchical Deterministic (HD) Account](/docs/accounts/local/hdKeyToAccount)
## Instantiation
### 1. Initialize a Wallet Client
Before we set up our Account and start consuming Wallet Actions, we will need to set up our Wallet Client with the [`http` Transport](/docs/clients/transports/http):
```ts twoslash
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createWalletClient({
chain: mainnet,
transport: http()
})
```
### 2. Set up your Local Account
Next, we will instantiate a Private Key Account using `privateKeyToAccount`:
```ts twoslash
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts' // [!code focus]
import { mainnet } from 'viem/chains'
const client = createWalletClient({
chain: mainnet,
transport: http()
})
const account = privateKeyToAccount('0x...') // [!code focus:1]
```
### 3. Consume [Wallet Actions](/docs/actions/wallet/introduction)
Now you can use that Account within Wallet Actions that need a signature from the user:
```ts twoslash
import { createWalletClient, http, parseEther } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const client = createWalletClient({
chain: mainnet,
transport: http()
})
const account = privateKeyToAccount('0x...')
const hash = await client.sendTransaction({ // [!code focus:5]
account,
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
value: parseEther('0.001')
})
```
### 4. Optional: Hoist the Account
If you do not wish to pass an account around to every Action that requires an `account`, you can also hoist the account into the Wallet Client.
```ts twoslash
import { createWalletClient, http, parseEther } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0x...')
const client = createWalletClient({ // [!code focus:99]
account, // [!code ++]
chain: mainnet,
transport: http()
})
const hash = await client.sendTransaction({
account, // [!code --]
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
value: parseEther('0.001')
})
```
### 5. Optional: Extend with Public Actions
When using a Local Account, you may be finding yourself using a [Public Client](/docs/clients/public) instantiated with the same parameters (`transport`, `chain`, etc) as your Wallet Client.
In this case, you can extend your Wallet Client with [Public Actions](/docs/actions/public/introduction) to avoid having to handle multiple Clients.
```ts twoslash {12}
// @noErrors
import { createWalletClient, http, publicActions } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0x...')
const client = createWalletClient({
account,
chain: mainnet,
transport: http()
}).extend(publicActions) // [!code ++]
const { request } = await client.simulateContract({ ... }) // Public Action
const hash = await client.writeContract(request) // Wallet Action
```
# Celo \[Integrating with Celo in Viem]
Viem provides first-class support for chains implemented on [Celo](https://celo.org/).
## Chains
The following Viem chains are implemented on Celo:
```ts
import {
celo, // [!code hl]
celoSepolia // [!code hl]
} from 'viem/chains'
```
### Configuration
Viem exports Celo's chain [formatters](/docs/chains/formatters) & [serializers](/docs/chains/serializers) via `chainConfig`. This is useful if you need to define another chain which is implemented on Celo.
```ts
import { defineChain } from 'viem'
import { chainConfig } from 'viem/celo'
export const celoExample = defineChain({
...chainConfig,
name: 'Celo Example',
// ...
})
```
## Utilities
### `parseTransaction`
Parses a serialized RLP-encoded transaction. Supports signed & unsigned CIP-64, EIP-1559, EIP-2930 and Legacy Transactions.
Celo-flavored version of [Viem's `parseTransaction`](/docs/utilities/parseTransaction).
#### Parameters
* `serializedTransaction` (`Hex`): The serialized transaction.
```ts
import { parseTransaction } from 'viem/celo'
const transaction = parseTransaction('0x7cf84682a4ec80847735940084773594008094765de816845861e75a25fca122bb6898b8b1282a808094f39fd6e51aad88f6f4ce6ab8827279cfffb92266880de0b6b3a764000080c0')
```
### `serializeTransaction`
Serializes a transaction object. Supports CIP-64, EIP-1559, EIP-2930, and Legacy transactions.
Celo-flavored version of [Viem's `serializeTransaction`](/docs/utilities/serializeTransaction).
#### Parameters
* `transaction` (`TransactionSerializable`): The transaction object to serialize.
* `signature` (`Signature`): Optional signature to include.
```ts
import { serializeTransaction } from 'viem/celo'
const serialized = serializeTransaction({
chainId: 42220,
gas: 21001n,
feeCurrency: "0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B" // whitelisted adapter for USDC
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69,
to: '0x1234512345123451234512345123451234512345',
value: parseEther('0.01'),
})
```
# Fees \[Configure chain-based fee data in Viem]
You can modify how fees are derived by using the `fees` property on the Chain.
## Usage
```tsx
import { defineChain } from 'viem'
export const example = defineChain({
/* ... */
fees: {
baseFeeMultiplier: 1.2,
defaultPriorityFee: parseGwei('0.01'),
}
})
```
## API
### `fees.baseFeeMultiplier`
* **Type**: `number`
* **Default**: `1.2`
The fee multiplier to use to account for fee fluctuations. Used in the [`estimateFeesPerGas` Action](/docs/actions/public/estimateFeesPerGas) against the latest block's base fee per gas to derive a final `maxFeePerGas` (EIP-1193), or gas price to derive a final `gasPrice` (Legacy).
**Parameters**
* `block`: The latest block.
* `client`: The Client instance.
* `request`: The transaction request (if exists).
```ts
import { defineChain } from 'viem'
const example = defineChain({
/* ... */
fees: { // [!code focus:8]
baseFeeMultiplier: 1.2,
// or
async baseFeeMultiplier({ block, request }) {
// some async work
return // ...
},
},
})
```
### `fees.defaultPriorityFee`
* **Type**: `number | ((args: FeesFnParameters) => Promise | bigint)`
The default `maxPriorityFeePerGas` to use when a priority fee is not defined upon sending a transaction.
Also overrides the return value in the [`estimateMaxPriorityFeePerGas` Action](/docs/actions/public/estimateMaxPriorityFeePerGas) and `maxPriorityFeePerGas` value in [`estimateFeesPerGas`](/docs/actions/public/estimateFeesPerGas).
**Parameters**
* `block`: The latest block.
* `client`: The Client instance.
* `request`: The transaction request (if exists).
```ts
import { defineChain } from 'viem'
const example = defineChain({
/* ... */
fees: { // [!code focus:8]
defaultPriorityFee: parseGwei('0.01'),
// or
async defaultPriorityFee({ block, request }) {
// some async work
return // ...
},
},
})
```
### `fees.estimateFeesPerGas`
* **Type**: `(args: FeesFnParameters) => Promise`
Allows customization of fee per gas values (ie. `maxFeePerGas`, `maxPriorityFeePerGas`, `gasPrice`).
Also overrides the return value in [`estimateFeesPerGas`](/docs/actions/public/estimateFeesPerGas).
**Parameters**
* `block`: The latest block.
* `client`: The Client instance.
* `multiply`: A function to apply the `baseFeeMultiplier` to the provided value.
* `request`: The transaction request (if exists).
* `type`: The transaction type (ie. `legacy` or `eip1559`).
```ts
import { defineChain } from 'viem'
const example = defineChain({
/* ... */
fees: { // [!code focus:13]
async estimateFeesPerGas({ client, multiply, type }) {
const gasPrice = // ...
const baseFeePerGas = // ...
const maxPriorityFeePerGas = // ...
if (type === 'legacy') return { gasPrice: multiply(gasPrice) }
return {
maxFeePerGas: multiply(baseFeePerGas) + maxPriorityFeePerGas,
maxPriorityFeePerGas
},
},
},
})
```
# Formatters \[Configure chain-based formatters in Viem]
You can modify how Blocks & Transactions are formatted by using the `formatters` property on the Chain.
This is useful for chains that have a different Block or Transaction structure than Mainnet (e.g. Celo & OP Stack chains).
## Usage
```tsx
import {
defineBlock,
defineChain,
defineTransaction,
defineTransactionReceipt,
defineTransactionRequest
} from 'viem'
export const example = defineChain({
/* ... */
formatters: {
block: defineBlock(/* ... */),
transaction: defineTransaction(/* ... */),
transactionReceipt: defineTransactionReceipt(/* ... */),
transactionRequest: defineTransactionRequest(/* ... */),
}
})
```
## API
### `formatters.block`
You can modify how Blocks are formatted by using the `formatters.block` property on the Chain.
You can either pass in the Block overrides, or the whole Block itself to the `format` function of `defineBlock`. You can also exclude certain properties with `exclude`.
```ts
import { defineBlock, defineChain, hexToBigInt } from 'viem'
type RpcBlockOverrides = { // [!code focus:6]
secondaryFee: `0x${string}`
}
type BlockOverrides = {
secondaryFee: bigint
}
const example = defineChain({
/* ... */
formatters: { // [!code focus:10]
block: defineBlock({
exclude: ['difficulty'],
format(args: RpcBlockOverrides): BlockOverrides {
return {
secondaryFee: hexToBigInt(args.secondaryFee)
}
},
}),
},
})
const block = await client.getBlock() // [!code focus:2]
// ^? { ..., difficulty: never, secondaryFee: bigint, ... }
```
### `formatters.transaction`
You can modify how Transactions are formatted by using the `formatters.transaction` property on the Chain.
You can either pass in the Transaction overrides, or the whole Transaction itself to the `format` function of `defineTransaction`. You can also exclude certain properties with `exclude`.
```ts
import { defineTransaction, defineChain, hexToBigInt } from 'viem'
type RpcTransactionOverrides = { // [!code focus:6]
mint: `0x${string}`
}
type TransactionOverrides = {
mint: bigint
}
const example = defineChain({
/* ... */
formatters: { // [!code focus:10]
transaction: defineTransaction({
exclude: ['gasPrice'],
format(args: RpcTransactionOverrides): TransactionOverrides {
return {
mint: hexToBigInt(args.mint)
}
},
}),
},
})
const transaction = await client.getTransaction({ hash: '0x...' }) // [!code focus:2]
// ^? { ..., gasPrice: never, mint: bigint, ... }
```
### `formatters.transactionReceipt`
You can modify how Transaction Receipts are formatted by using the `formatters.transactionReceipt` property on the Chain.
You can either pass in the Transaction Receipt overrides, or the whole Transaction Receipt itself to the `format` function of `defineTransactionReceipt`. You can also exclude certain properties with `exclude`.
```ts
import { defineTransactionReceipt, defineChain, hexToBigInt } from 'viem'
type RpcTransactionReceiptOverrides = { // [!code focus:6]
l1Fee: `0x${string}`
}
type TransactionReceiptOverrides = {
l1Fee: bigint
}
const example = defineChain({
/* ... */
formatters: { // [!code focus:11]
transactionReceipt: defineTransactionReceipt({
exclude: ['effectiveGasPrice'],
format(args: RpcTransactionReceiptOverrides):
TransactionReceiptOverrides {
return {
l1Fee: hexToBigInt(args.l1Fee)
}
},
}),
},
})
const receipt = await client.getTransactionReceipt({ hash: '0x...' }) // [!code focus:2]
// ^? { ..., effectiveGasPrice: never, l1Fee: bigint, ... }
```
### `formatters.transactionRequest`
You can modify how Transaction Requests are formatted by using the `formatters.transactionRequest` property on the Chain.
You can either pass in the Transaction Request overrides, or the whole Transaction Request itself to the `format` function of `defineTransactionRequest`. You can also exclude certain properties with `exclude`.
```ts
import { defineTransactionRequest, defineChain, hexToBigInt } from 'viem'
type RpcTransactionRequestOverrides = { // [!code focus:6]
secondaryFee: `0x${string}`
}
type TransactionRequestOverrides = {
secondaryFee: bigint
}
const example = defineChain({
/* ... */
formatters: { // [!code focus:11]
transactionRequest: defineTransactionRequest({
exclude: ['effectiveGasPrice'],
format(args: TransactionRequestOverrides):
RpcTransactionRequestOverrides {
return {
secondaryFee: numberToHex(args.secondaryFee)
}
},
}),
},
})
const receipt = await client.getTransactionReceipt({ hash: '0x...' }) // [!code focus:2]
// ^? { ..., effectiveGasPrice: never, l1Fee: bigint, ... }
```
# Chains
The `viem/chains` entrypoint contains references to popular EVM-compatible chains such as: Polygon, Optimism, Avalanche, Base, Zora, and more.
## Usage
Import your chain from the entrypoint and use them in the consuming viem code:
```tsx
import { createPublicClient, http } from 'viem'
import { zora } from 'viem/chains' // [!code focus]
const client = createPublicClient({
chain: zora, // [!code focus]
transport: http()
})
```
[See here for a list of supported chains](https://github.com/wagmi-dev/viem/tree/main/src/chains/index.ts).
> Want to add a chain that's not listed in viem? Read the [Contributing Guide](https://github.com/wagmi-dev/viem/blob/main/.github/CONTRIBUTING.md#chains), and then open a Pull Request with your chain.
## Custom Chains
You can also extend viem to support other EVM-compatible chains by building your own chain object that inherits the `Chain` type.
```ts
import { defineChain } from 'viem'
export const zora = defineChain({
id: 7777777,
name: 'Zora',
nativeCurrency: {
decimals: 18,
name: 'Ether',
symbol: 'ETH',
},
rpcUrls: {
default: {
http: ['https://rpc.zora.energy'],
webSocket: ['wss://rpc.zora.energy'],
},
},
blockExplorers: {
default: { name: 'Explorer', url: 'https://explorer.zora.energy' },
},
contracts: {
multicall3: {
address: '0xcA11bde05977b3631167028862bE2a173976CA11',
blockCreated: 5882,
},
},
})
```
# Serializers \[Configure chain-based serializers in Viem]
## Usage
```ts
import { defineChain, serializeTransaction } from 'viem'
const example = defineChain({
/* ... */
serializers: {
transaction(transaction, signature) {
return serializeTransaction(transaction, signature)
},
},
})
```
## API
### `serializers.transaction`
* **Type**: `(transaction: Transaction, signature?: Signature) => "0x${string}"`
You can modify how Transactions are serialized by using the `serializers.transaction` property on the Chain.
**Parameters**
* `transaction`: The transaction to serialize.
* `signature`: The transaction signature (if exists).
```ts
import { defineChain, serializeTransaction } from 'viem'
const example = defineChain({
/* ... */
serializers: { // [!code focus:5]
transaction(transaction, signature) {
return serializeTransaction(transaction, signature)
},
},
})
```
# ZKsync \[Integrating with ZKsync in Viem]
Viem provides first-class support for chains implemented on [ZKsync](https://zksync.io/).
## Chains
The following Viem chains are implemented on ZKsync:
```ts
import {
zksync, // [!code hl]
zksyncSepoliaTestnet, // [!code hl]
} from 'viem/chains'
```
### Configuration
Viem exports ZKsync's chain [formatters](/docs/chains/formatters) & [serializers](/docs/chains/serializers) via `chainConfig`. This is useful if you need to define another chain which is implemented on ZKsync.
```ts
import { defineChain } from 'viem'
import { chainConfig } from 'viem/zksync'
export const zkSyncExample = defineChain({
...chainConfig,
name: 'ZKsync Example',
// ...
})
```
## Utilities
### `serializeTransaction`
Serializes a transaction object. Supports EIP-712, EIP-1559, EIP-2930, and Legacy transactions.
ZKsync-flavored version of [Viem's `serializeTransaction`](/docs/utilities/serializeTransaction).
#### Parameters
* `transaction` (`TransactionSerializable`): The transaction object to serialize.
* `signature` (`Signature`): Optional signature to include.
```ts
import { serializeTransaction } from 'viem/zksync'
const serialized = serializeTransaction({
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69,
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021',
paymasterInput:
'0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000',
to: '0x1234512345123451234512345123451234512345',
type: 'eip712',
value: parseEther('0.01'),
})
```
# Build your own Client
You can build your own viem Client by using the `createClient` function and optionally extending (`.extend`) it – this is how viem's internal Clients ([Public](/docs/clients/public), [Wallet](/docs/clients/wallet), and [Test](/docs/clients/test)) are built.
Building your own Client is useful if you have specific requirements for how the Client should behave, and if you want to extend that Client with custom functionality (ie. create a [geth Debug](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug) Client).
The `createClient` function sets up a base viem Client with a given [Transport](/docs/clients/intro) configured with a [Chain](/docs/chains/introduction). After that, you can extend the Client with custom properties (that could be Actions or other configuration).
## Import
```ts twoslash
import { createClient } from 'viem'
```
## Usage
Initialize a Client with your desired [Chain](/docs/chains/introduction) (e.g. `mainnet`) and [Transport](/docs/clients/intro) (e.g. `http`).
```ts twoslash
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createClient({
chain: mainnet,
transport: http()
})
```
Next, you can either [extend your Client with Actions or configuration](#extending-with-actions-or-configuration), or you can use it as-is for the purpose of [maximizing tree-shaking in your app](#tree-shaking).
### Extending with Actions or configuration
You can extend your Client with custom Actions or configuration by using the `.extend` function.
Below is a naive implementation of implementing a [geth Debug](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug) Client with a `traceCall` Action that uses the `debug_traceCall` RPC method.
```ts twoslash {12-21,23-29}
// @noErrors
import {
createClient,
http,
formatTransactionRequest,
type CallParameters
} from 'viem'
import { mainnet } from 'viem/chains'
const debugClient = createClient({
chain: mainnet,
transport: http(),
}).extend(client => ({
// ...
async traceCall(args: CallParameters) {
return client.request({
method: 'debug_traceCall',
params: [formatTransactionRequest(args), 'latest', {}]
})
},
// ...
}))
const response = await debugClient.traceCall({
account: '0xdeadbeef29292929192939494959594933929292',
to: '0xde929f939d939d393f939393f93939f393929023',
gas: 69420n,
data: '0xf00d4b5d00000000000000000000000001291230982139282304923482304912923823920000000000000000000000001293123098123928310239129839291010293810'
})
// { failed: false, gas: 69420, returnValue: '...', structLogs: [] }
```
For a more succinct implementation of using `.extend`, check out viem's [Public Client implementation](https://github.com/wagmi-dev/viem/blob/29c053f5069a5b44e3791972c221368a2c71a254/src/clients/createPublicClient.ts#L48-L68) extended with [Public Actions](https://github.com/wagmi-dev/viem/blob/29c053f5069a5b44e3791972c221368a2c71a254/src/clients/decorators/public.ts#L1377-L1425).
### Tree-shaking
You can use the Client as-is, with no decorated Actions, to maximize tree-shaking in your app. This is useful if you are pedantic about bundle size and want to only include the Actions you use.
In the example below, instead of calling `getBlock` from the Public Client, we are importing the Action directly from `viem` and then injecting our Client as the first parameter to the Action.
```ts twoslash {3,10-11}
// @noErrors
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { getBlock, sendTransaction } from 'viem/actions'
const client = createClient({
chain: mainnet,
transport: http()
})
const blockNumber = await getBlock(client, { blockTag: 'latest' })
const hash = await sendTransaction(client, { ... })
```
## Parameters
### transport
* **Type:** [Transport](/docs/glossary/types#transport)
The [Transport](/docs/clients/intro) of the Public Client.
```ts twoslash
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createClient({
chain: mainnet,
transport: http(), // [!code focus]
})
```
### account (optional)
* **Type:** `Account | Address`
The Account to use for the Client. This will be used for Actions that require an `account` as an argument.
Accepts a [JSON-RPC Account](/docs/accounts/jsonRpc) or [Local Account (Private Key, etc)](/docs/accounts/local/privateKeyToAccount).
```ts twoslash
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
import { privateKeyToAccount } from 'viem/accounts'
const client = createClient({
account: privateKeyToAccount('0x...'), // [!code focus]
chain: mainnet,
transport: http(),
})
```
### chain (optional)
* **Type:** [Chain](/docs/glossary/types#chain)
The [Chain](/docs/chains/introduction) of the Public Client.
```ts twoslash
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createClient({
chain: mainnet, // [!code focus]
transport: http(),
})
```
### batch (optional)
Flags for batch settings.
### batch.multicall (optional)
* **Type:** `boolean | MulticallBatchOptions`
* **Default:** `false`
Toggle to enable `eth_call` multicall aggregation.
```ts twoslash
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createClient({
batch: {
multicall: true, // [!code focus]
},
chain: mainnet,
transport: http(),
})
```
### batch.multicall.batchSize (optional)
* **Type:** `number`
* **Default:** `1_024`
The maximum size (in bytes) for each multicall (`aggregate3`) calldata chunk.
> Note: Some RPC Providers limit the amount of calldata that can be sent in a single request. It is best to check with your RPC Provider to see if there are any calldata size limits to `eth_call` requests.
```ts twoslash
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createClient({
batch: {
multicall: {
batchSize: 512, // [!code focus]
},
},
chain: mainnet,
transport: http(),
})
```
### batch.multicall.wait (optional)
* **Type:** `number`
* **Default:** `0` ([zero delay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop#zero_delays))
The maximum number of milliseconds to wait before sending a batch.
```ts twoslash
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createClient({
batch: {
multicall: {
wait: 16, // [!code focus]
},
},
chain: mainnet,
transport: http(),
})
```
### key (optional)
* **Type:** `string`
* **Default:** `"public"`
A key for the Client.
```ts twoslash
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createClient({
chain: mainnet,
key: 'public', // [!code focus]
transport: http(),
})
```
### name (optional)
* **Type:** `string`
* **Default:** `"Public Client"`
A name for the Client.
```ts twoslash
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createClient({
chain: mainnet,
name: 'Public Client', // [!code focus]
transport: http(),
})
```
### pollingInterval (optional)
* **Type:** `number`
* **Default:** `4_000`
Frequency (in ms) for polling enabled Actions.
```ts twoslash
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createClient({
chain: mainnet,
pollingInterval: 10_000, // [!code focus]
transport: http(),
})
```
### rpcSchema (optional)
* **Type:** `RpcSchema`
* **Default:** `WalletRpcSchema`
Typed JSON-RPC schema for the client.
```ts twoslash
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// @noErrors
// ---cut---
import { rpcSchema } from 'viem'
type CustomRpcSchema = [{ // [!code focus]
Method: 'eth_wagmi', // [!code focus]
Parameters: [string] // [!code focus]
ReturnType: string // [!code focus]
}] // [!code focus]
const client = createClient({
chain: mainnet,
rpcSchema: rpcSchema(), // [!code focus]
transport: http()
})
const result = await client.request({ // [!code focus]
method: 'eth_wa // [!code focus]
// ^|
params: ['hello'], // [!code focus]
}) // [!code focus]
```
# Introduction to Clients & Transports \[A brief introduction to Clients & Transports.]
## Clients
A **Client** provides access to a subset of **Actions**.
> A **Client** in the context of viem is similar to an [Ethers.js Provider](https://docs.ethers.org/v5/api/providers/).
There are three types of **Clients** in viem:
* A [Public Client](/docs/clients/public) which provides access to [Public Actions](/docs/actions/public/introduction), such as `getBlockNumber` and `getBalance`.
* A [Wallet Client](/docs/clients/wallet) which provides access to [Wallet Actions](/docs/actions/wallet/introduction), such as `sendTransaction` and `signMessage`.
* A [Test Client](/docs/clients/test) which provides access to [Test Actions](/docs/actions/test/introduction), such as `mine` and `impersonate`.
## Transports
A **Client** is instantiated with a **Transport**, which is the intermediary layer that is responsible for executing outgoing requests (ie. RPC requests).
There are three types of Transports in viem:
* A [HTTP Transport](/docs/clients/transports/http) that executes requests via a HTTP JSON-RPC API.
* A [WebSocket Transport](/docs/clients/transports/websocket) that executes requests via a WebSocket JSON-RPC API.
* A [Custom Transport](/docs/clients/transports/custom) that executes requests via an [EIP-1193 `request` function](https://eips.ethereum.org/EIPS/eip-1193).
# Public Client \[A function to create a Public Client]
A Public Client is an interface to "public" [JSON-RPC API](https://ethereum.org/en/developers/docs/apis/json-rpc/) methods such as retrieving block numbers, transactions, reading from smart contracts, etc through [Public Actions](/docs/actions/public/introduction).
The `createPublicClient` function sets up a Public Client with a given [Transport](/docs/clients/intro) configured for a [Chain](/docs/chains/introduction).
## Import
```ts twoslash
import { createPublicClient } from 'viem'
```
## Usage
Initialize a Client with your desired [Chain](/docs/chains/introduction) (e.g. `mainnet`) and [Transport](/docs/clients/intro) (e.g. `http`).
```ts twoslash
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
Then you can consume [Public Actions](/docs/actions/public/introduction):
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const blockNumber = await publicClient.getBlockNumber() // [!code focus:10]
```
## Optimization
The Public Client also supports [`eth_call` Aggregation](#multicall) for improved performance.
### `eth_call` Aggregation (via Multicall)
The Public Client supports the aggregation of `eth_call` requests into a single multicall (`aggregate3`) request.
This means for every Action that utilizes an `eth_call` request (ie. `readContract`), the Public Client will batch the requests (over a timed period) and send it to the RPC Provider in a single multicall request. This can dramatically improve network performance, and decrease the amount of [Compute Units (CU)](https://docs.alchemy.com/reference/compute-units) used by RPC Providers like Alchemy, Infura, etc.
The Public Client schedules the aggregation of `eth_call` requests over a given time period. By default, it executes the batch request at the end of the current [JavaScript message queue](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop#queue) (a [zero delay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop#zero_delays)), however, consumers can specify a custom `wait` period (in ms).
You can enable `eth_call` aggregation by setting the `batch.multicall` flag to `true`:
```ts twoslash
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const publicClient = createPublicClient({
batch: {
multicall: true, // [!code focus]
},
chain: mainnet,
transport: http(),
})
```
> You can also [customize the `multicall` options](#batchmulticallbatchsize-optional).
Now, when you start to utilize `readContract` Actions, the Public Client will batch and send over those requests at the end of the message queue (or custom time period) in a single `eth_call` multicall request:
:::code-group
```ts twoslash [example.ts]
// @filename: client.ts
// [!include ~/snippets/publicClient.ts]
// @filename: abi.ts
// [!include ~/snippets/erc20Abi.ts]
// @filename: example.ts
const address = '0x'
// ---cut---
import { getContract } from 'viem'
import { abi } from './abi'
import { publicClient } from './client'
const contract = getContract({ address, abi, client: publicClient })
// The below will send a single request to the RPC Provider.
const [name, totalSupply, symbol, balance] = await Promise.all([
contract.read.name(),
contract.read.totalSupply(),
contract.read.symbol(),
contract.read.balanceOf([address]),
])
```
```ts twoslash [client.ts]
// [!include ~/snippets/publicClient.ts]
```
```ts twoslash [abi.ts]
// [!include ~/snippets/erc20Abi.ts]
```
:::
> Read more on [Contract Instances](/docs/contract/getContract).
## Parameters
### transport
* **Type:** [Transport](/docs/glossary/types#transport)
The [Transport](/docs/clients/intro) of the Public Client.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
chain: mainnet,
transport: http(), // [!code focus]
})
```
### chain (optional)
* **Type:** [Chain](/docs/glossary/types#chain)
The [Chain](/docs/chains/introduction) of the Public Client.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
chain: mainnet, // [!code focus]
transport: http(),
})
```
### batch (optional)
Flags for batch settings.
### batch.multicall (optional)
* **Type:** `boolean | MulticallBatchOptions`
* **Default:** `false`
Toggle to enable `eth_call` multicall aggregation.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
batch: {
multicall: true, // [!code focus]
},
chain: mainnet,
transport: http(),
})
```
### batch.multicall.batchSize (optional)
* **Type:** `number`
* **Default:** `1_024`
The maximum size (in bytes) for each multicall (`aggregate3`) calldata chunk.
> Note: Some RPC Providers limit the amount of calldata that can be sent in a single request. It is best to check with your RPC Provider to see if there are any calldata size limits to `eth_call` requests.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
batch: {
multicall: {
batchSize: 512, // [!code focus]
},
},
chain: mainnet,
transport: http(),
})
```
### batch.multicall.deployless (optional)
* **Type:** `boolean`
* **Default:** `false`
Enable deployless multicall.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
batch: {
multicall: {
deployless: true, // [!code focus]
},
},
chain: mainnet,
transport: http(),
})
```
### batch.multicall.wait (optional)
* **Type:** `number`
* **Default:** `0` ([zero delay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop#zero_delays))
The maximum number of milliseconds to wait before sending a batch.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
batch: {
multicall: {
wait: 16, // [!code focus]
},
},
chain: mainnet,
transport: http(),
})
```
### cacheTime (optional)
* **Type:** `number`
* **Default:** `client.pollingInterval`
Time (in ms) that cached data will remain in memory.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
cacheTime: 10_000, // [!code focus]
chain: mainnet,
transport: http(),
})
```
### ccipRead (optional)
* **Type:** `(parameters: CcipRequestParameters) => Promise | false`
* **Default:** `true`
[CCIP Read](https://eips.ethereum.org/EIPS/eip-3668) configuration.
CCIP Read is enabled by default, but if set to `false`, the client will not support offchain CCIP lookups.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
ccipRead: false, // [!code focus]
chain: mainnet,
transport: http(),
})
```
### ccipRead.request (optional)
* **Type:** `(parameters: CcipRequestParameters) => Promise`
A function that will be called to make the [offchain CCIP lookup request](https://eips.ethereum.org/EIPS/eip-3668#client-lookup-protocol).
```ts twoslash
// @noErrors
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
ccipRead: { // [!code focus]
async request({ data, sender, urls }) { // [!code focus]
// ... // [!code focus]
} // [!code focus]
}, // [!code focus]
chain: mainnet,
transport: http(),
})
```
### experimental\_blockTag (optional)
* **Type:** `BlockTag`
* **Default:** `'latest'`
The default block tag to use for Actions.
This will be used as the default block tag for the following Actions:
* `call`
* `estimateGas`
* `getBalance`
* `getBlock`
* `simulateBlocks`
* `waitForTransactionReceipt`
* `watchBlocks`
:::note
If the chain supports a pre-confirmation mechanism (set via `chain.experimental_preconfirmationTime`),
the default block tag will be `'pending'`.
:::
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
experimental_blockTag: 'pending', // [!code focus]
chain: mainnet,
transport: http(),
})
```
### key (optional)
* **Type:** `string`
* **Default:** `"public"`
A key for the Client.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
chain: mainnet,
key: 'public', // [!code focus]
transport: http(),
})
```
### name (optional)
* **Type:** `string`
* **Default:** `"Public Client"`
A name for the Client.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
chain: mainnet,
name: 'Public Client', // [!code focus]
transport: http(),
})
```
### pollingInterval (optional)
* **Type:** `number`
* **Default:** `4_000`
Frequency (in ms) for polling enabled Actions.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
chain: mainnet,
pollingInterval: 10_000, // [!code focus]
transport: http(),
})
```
### rpcSchema (optional)
* **Type:** `RpcSchema`
* **Default:** `PublicRpcSchema`
Typed JSON-RPC schema for the client.
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// @noErrors
// ---cut---
import { rpcSchema } from 'viem'
type CustomRpcSchema = [{ // [!code focus]
Method: 'eth_wagmi', // [!code focus]
Parameters: [string] // [!code focus]
ReturnType: string // [!code focus]
}] // [!code focus]
const publicClient = createPublicClient({
chain: mainnet,
rpcSchema: rpcSchema(), // [!code focus]
transport: http(),
})
const result = await publicClient.request({ // [!code focus]
method: 'eth_wa // [!code focus]
// ^|
params: ['hello'], // [!code focus]
}) // [!code focus]
```
### dataSuffix (optional)
* **Type:** `Hex | { value: Hex; required?: boolean }`
Data to append to the end of transaction calldata. Useful for adding [transaction attribution](https://oxlib.sh/ercs/erc8021/Attribution).
When a simple hex string is provided, the suffix is appended on a best-effort basis. When using the object form with `required: true`, transactions will fail if the suffix cannot be appended.
Applies to `simulateContract` and `estimateContractGas` actions. For transaction-sending actions like `sendTransaction`, see [Wallet Client](/docs/clients/wallet#datasuffix-optional).
```ts twoslash
// [!include ~/snippets/publicClient.ts:imports]
// ---cut---
const publicClient = createPublicClient({
chain: mainnet,
dataSuffix: '0xdeadbeef', // [!code focus]
transport: http(),
})
```
## Live Example
Check out the usage of `createPublicClient` in the live [Public Client Example](https://stackblitz.com/github/wagmi-dev/viem/tree/main/examples/clients_public-client) below.
# Test Client \[A function to create a Test Client]
A Test Client is an interface to "test" JSON-RPC API methods accessible through a local Ethereum test node such as [Anvil](https://getfoundry.sh/anvil/overview) or [Hardhat](https://hardhat.org/) such as mining blocks, impersonating accounts, setting fees, etc through [Test Actions](/docs/actions/test/introduction).
The `createTestClient` function sets up a Test RPC Client with a given [Transport](/docs/clients/intro).
## Import
```ts twoslash
import { createTestClient } from 'viem'
```
## Usage
Initialize a Client with your desired [Chain](/docs/chains/introduction), [Transport](/docs/clients/intro) (e.g. `http`) and [mode](#mode) (e.g. `"anvil"`).
```ts twoslash
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
const client = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
Then you can consume [Test Actions](/docs/actions/test/introduction):
```ts twoslash
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
const client = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
// ---cut---
const mine = await client.mine({ blocks: 1 }) // [!code focus:10]
```
### Extending with Public & Wallet Actions
When interacting with a Ethereum test node, you may also find yourself wanting to interact with [Public Actions](/docs/actions/public/introduction) and [Wallet Actions](/docs/actions/wallet/introduction) with the same `chain` and `transport`. Instead of creating three different Clients, you can instead just extend the Test Client with those actions:
```ts twoslash
// @noErrors
import { createTestClient, http, publicActions, walletActions } from 'viem'
import { foundry } from 'viem/chains'
const client = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
.extend(publicActions) // [!code hl]
.extend(walletActions) // [!code hl]
const blockNumber = await client.getBlockNumber() // Public Action
const hash = await client.sendTransaction({ ... }) // Wallet Action
const mine = await client.mine({ blocks: 1 }) // Test Action
```
## Parameters
### mode
* **Type:** `"anvil" | "hardhat" | "ganache"`
Mode of the Test Client.
```ts twoslash
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
// ---cut---
const client = createTestClient({
chain: foundry,
mode: 'anvil', // [!code focus]
transport: http(),
})
```
### transport
* **Type:** [Transport](/docs/glossary/types#transport)
[Transport](/docs/clients/intro) of the Test Client.
```ts twoslash
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
// ---cut---
const client = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(), // [!code focus]
})
```
### account (optional)
* **Type:** `Account | Address`
The Account to use for the Client. This will be used for Actions that require an `account` as an argument.
Accepts a [JSON-RPC Account](/docs/accounts/jsonRpc) or [Local Account (Private Key, etc)](/docs/accounts/local/privateKeyToAccount).
```ts twoslash
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
// ---cut---
import { privateKeyToAccount } from 'viem/accounts'
const client = createTestClient({
account: privateKeyToAccount('0x...'), // [!code focus]
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
### chain (optional)
* **Type:** [Chain](/docs/glossary/types#chain)
[Chain](/docs/chains/introduction) of the Test Client.
```ts twoslash
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
// ---cut---
const client = createTestClient({
chain: foundry, // [!code focus]
mode: 'anvil',
transport: http(),
})
```
### cacheTime (optional)
* **Type:** `number`
* **Default:** `client.pollingInterval`
Time (in ms) that cached data will remain in memory.
```ts twoslash
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
// ---cut---
const client = createTestClient({
cacheTime: 10_000, // [!code focus]
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
### name (optional)
* **Type:** `string`
* **Default:** `"Test Client"`
A name for the Client.
```ts twoslash
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
// ---cut---
const client = createTestClient({
chain: foundry,
mode: 'anvil',
name: 'Anvil Client', // [!code focus]
transport: http(),
})
```
### pollingInterval (optional)
* **Type:** `number`
* **Default:** `4_000`
Frequency (in ms) for polling enabled Actions.
```ts twoslash
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
// ---cut---
const client = createTestClient({
chain: foundry,
mode: 'anvil',
pollingInterval: 10_000, // [!code focus]
transport: http(),
})
```
### rpcSchema (optional)
* **Type:** `RpcSchema`
* **Default:** `TestRpcSchema`
Typed JSON-RPC schema for the client.
```ts twoslash
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
// @noErrors
// ---cut---
import { rpcSchema } from 'viem'
type CustomRpcSchema = [{ // [!code focus]
Method: 'eth_wagmi', // [!code focus]
Parameters: [string] // [!code focus]
ReturnType: string // [!code focus]
}] // [!code focus]
const client = createTestClient({
chain: foundry,
rpcSchema: rpcSchema(), // [!code focus]
transport: http()
})
const result = await client.request({ // [!code focus]
method: 'eth_wa // [!code focus]
// ^|
params: ['hello'], // [!code focus]
}) // [!code focus]
```
# Wallet Client \[A function to create a Wallet Client.]
A Wallet Client is an interface to interact with [Ethereum Account(s)](https://ethereum.org/en/glossary/#account) and provides the ability to retrieve accounts, execute transactions, sign messages, etc through [Wallet Actions](/docs/actions/wallet/introduction).
The `createWalletClient` function sets up a Wallet Client with a given [Transport](/docs/clients/intro).
The Wallet Client supports signing over:
* [JSON-RPC Accounts](#json-rpc-accounts) (e.g. Browser Extension Wallets, WalletConnect, etc.).
* [Local Accounts](#local-accounts-private-key-mnemonic-etc) (e.g. private key/mnemonic wallets).
## Import
```ts
import { createWalletClient } from 'viem'
```
## JSON-RPC Accounts
A [JSON-RPC Account](/docs/accounts/jsonRpc) **defers** signing of transactions & messages to the target Wallet over JSON-RPC. An example could be sending a transaction via a Browser Extension Wallet (e.g. MetaMask) with the `window.ethereum` Provider.
Below is an example of how you can set up a JSON-RPC Account.
#### 1: Initialize a Wallet Client
Before we set up our Account and start consuming Wallet Actions, we will need to set up our Wallet Client with the [`custom` Transport](/docs/clients/transports/custom), where we will pass in the `window.ethereum` Provider:
```ts twoslash
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
const client = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!)
})
```
#### 2: Set up your JSON-RPC Account
We will want to retrieve an address that we can access in our Wallet (e.g. MetaMask).
```ts twoslash
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
const client = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!)
})
const [address] = await client.getAddresses() // [!code focus:10]
// or: const [address] = await client.requestAddresses() // [!code focus:10]
```
> Note: Some Wallets (like MetaMask) may require you to request access to Account addresses via [`client.requestAddresses`](/docs/actions/wallet/requestAddresses) first.
#### 3: Consume [Wallet Actions](/docs/actions/wallet/introduction)
Now you can use that address within Wallet Actions that require a signature from the user:
```ts twoslash
import 'viem/window'
// ---cut---
import { createWalletClient, custom, parseEther } from 'viem'
import { mainnet } from 'viem/chains'
const client = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!)
})
const [address] = await client.getAddresses()
const hash = await client.sendTransaction({ // [!code focus:10]
account: address,
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
value: parseEther('0.001')
})
```
#### Optional: Hoist the Account
If you do not wish to pass an account around to every Action that requires an `account`, you can also hoist the account into the Wallet Client.
```ts twoslash
import 'viem/window'
// ---cut---
import { createWalletClient, http, parseEther } from 'viem'
import { mainnet } from 'viem/chains'
const [account] = await window.ethereum!.request({ method: 'eth_requestAccounts' })
const client = createWalletClient({ // [!code focus:99]
account, // [!code ++]
chain: mainnet,
transport: http()
})
const hash = await client.sendTransaction({
account, // [!code --]
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
value: parseEther('0.001')
})
```
## Local Accounts (Private Key, Mnemonic, etc)
A Local Account performs signing of transactions & messages with a private key **before** executing a method over JSON-RPC.
There are three types of Local Accounts in viem:
* [Private Key Account](/docs/accounts/local/privateKeyToAccount)
* [Mnemonic Account](/docs/accounts/local/mnemonicToAccount)
* [Hierarchical Deterministic (HD) Account](/docs/accounts/local/hdKeyToAccount)
Below are the steps to integrate a **Private Key Account**, but the same steps can be applied to **Mnemonic & HD Accounts**.
#### 1: Initialize a Wallet Client
Before we set up our Account and start consuming Wallet Actions, we will need to set up our Wallet Client with the [`http` Transport](/docs/clients/transports/http):
```ts twoslash
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createWalletClient({
chain: mainnet,
transport: http()
})
```
#### 2: Set up your Local Account
Next, we will instantiate a Private Key Account using `privateKeyToAccount`:
```ts twoslash
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts' // [!code focus]
import { mainnet } from 'viem/chains'
const client = createWalletClient({
chain: mainnet,
transport: http()
})
const account = privateKeyToAccount('0x...') // [!code focus:1]
```
#### 3: Consume [Wallet Actions](/docs/actions/wallet/introduction)
Now you can use that Account within Wallet Actions that need a signature from the user:
```ts twoslash
import { createWalletClient, http, parseEther } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const client = createWalletClient({
chain: mainnet,
transport: http()
})
const account = privateKeyToAccount('0x...')
const hash = await client.sendTransaction({ // [!code focus:5]
account,
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
value: parseEther('0.001')
})
```
#### Optional: Hoist the Account
If you do not wish to pass an account around to every Action that requires an `account`, you can also hoist the account into the Wallet Client.
```ts twoslash
import { createWalletClient, http, parseEther } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0x...')
const client = createWalletClient({ // [!code focus:99]
account, // [!code ++]
chain: mainnet,
transport: http()
})
const hash = await client.sendTransaction({
account, // [!code --]
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
value: parseEther('0.001')
})
```
#### Optional: Extend with Public Actions
When using a Local Account, you may be finding yourself using a [Public Client](/docs/clients/public) instantiated with the same parameters (`transport`, `chain`, etc) as your Wallet Client.
In this case, you can extend your Wallet Client with [Public Actions](/docs/actions/public/introduction) to avoid having to handle multiple Clients.
```ts twoslash
// @noErrors
import { createWalletClient, http, publicActions } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0x...')
const client = createWalletClient({ // [!code focus]
account,
chain: mainnet,
transport: http()
}).extend(publicActions) // [!code ++] // [!code focus]
const { request } = await client.simulateContract({ ... }) // Public Action // [!code focus]
const hash = await client.writeContract(request) // Wallet Action // [!code focus]
```
## Parameters
### account (optional)
* **Type:** `Account | Address`
The Account to use for the Wallet Client. This will be used for Actions that require an `account` as an argument.
Accepts a [JSON-RPC Account](#json-rpc-accounts) or [Local Account (Private Key, etc)](#local-accounts-private-key-mnemonic-etc).
```ts twoslash
import 'viem/window'
// ---cut---
import { createWalletClient, custom, parseEther } from 'viem'
import { mainnet } from 'viem/chains'
const client = createWalletClient({
account: '0x...', // [!code focus]
chain: mainnet,
transport: custom(window.ethereum!)
})
const hash = await client.sendTransaction({
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
value: parseEther('0.001')
})
```
### chain (optional)
* **Type:** [Chain](/docs/glossary/types#chain)
The [Chain](/docs/chains/introduction) of the Wallet Client.
Used in the [`sendTransaction`](/docs/actions/wallet/sendTransaction) & [`writeContract`](/docs/contract/writeContract) Actions to assert that the chain matches the wallet's active chain.
```ts twoslash
import 'viem/window'
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createWalletClient({
chain: mainnet, // [!code focus]
transport: custom(window.ethereum!)
})
```
### cacheTime (optional)
* **Type:** `number`
* **Default:** `client.pollingInterval`
Time (in ms) that cached data will remain in memory.
```ts twoslash
import 'viem/window'
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createWalletClient({
cacheTime: 10_000, // [!code focus]
chain: mainnet,
transport: custom(window.ethereum!)
})
```
### ccipRead (optional)
* **Type:** `(parameters: CcipRequestParameters) => Promise | false`
* **Default:** `true`
[CCIP Read](https://eips.ethereum.org/EIPS/eip-3668) configuration.
CCIP Read is enabled by default, but if set to `false`, the client will not support offchain CCIP lookups.
```ts twoslash
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// ---cut---
const client = createWalletClient({
ccipRead: false, // [!code focus]
transport: custom(window.ethereum!)
})
```
### ccipRead.request (optional)
* **Type:** `(parameters: CcipRequestParameters) => Promise`
A function that will be called to make the [offchain CCIP lookup request](https://eips.ethereum.org/EIPS/eip-3668#client-lookup-protocol).
```ts twoslash
// @noErrors
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// ---cut---
const client = createWalletClient({
ccipRead: { // [!code focus]
async request({ data, sender, urls }) { // [!code focus]
// ... // [!code focus]
} // [!code focus]
}, // [!code focus]
transport: custom(window.ethereum!)
})
```
### key (optional)
* **Type:** `string`
* **Default:** `"wallet"`
A key for the Client.
```ts twoslash
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// ---cut---
const client = createWalletClient({
key: 'foo', // [!code focus]
transport: custom(window.ethereum!)
})
```
### name (optional)
* **Type:** `string`
* **Default:** `"Wallet Client"`
A name for the Client.
```ts twoslash
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// ---cut---
const client = createWalletClient({
name: 'Foo Wallet Client', // [!code focus]
transport: custom(window.ethereum!)
})
```
### pollingInterval (optional)
* **Type:** `number`
* **Default:** `4_000`
Frequency (in ms) for polling enabled Actions.
```ts twoslash
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// ---cut---
const client = createWalletClient({
pollingInterval: 10_000, // [!code focus]
transport: custom(window.ethereum!)
})
```
### rpcSchema (optional)
* **Type:** `RpcSchema`
* **Default:** `WalletRpcSchema`
Typed JSON-RPC schema for the client.
```ts twoslash
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// @noErrors
// ---cut---
import { rpcSchema } from 'viem'
type CustomRpcSchema = [{ // [!code focus]
Method: 'eth_wagmi', // [!code focus]
Parameters: [string] // [!code focus]
ReturnType: string // [!code focus]
}] // [!code focus]
const client = createWalletClient({
rpcSchema: rpcSchema(), // [!code focus]
transport: custom(window.ethereum!)
})
const result = await client.request({ // [!code focus]
method: 'eth_wa // [!code focus]
// ^|
params: ['hello'], // [!code focus]
}) // [!code focus]
```
### dataSuffix (optional)
* **Type:** `Hex | { value: Hex; required?: boolean }`
Data to append to the end of transaction calldata. Useful for adding [transaction attribution](https://oxlib.sh/ercs/erc8021/Attribution).
When a simple hex string is provided, the suffix is appended on a best-effort basis. When using the object form with `required: true`, transactions will fail if the suffix cannot be appended.
Applies to `sendTransaction`, `sendTransactionSync`, `sendCalls`, `simulateContract`, and `estimateContractGas` actions.
```ts twoslash
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// ---cut---
const client = createWalletClient({
dataSuffix: '0xdeadbeef', // [!code focus]
transport: custom(window.ethereum!)
})
```
# createContractEventFilter \[Creates a Filter to retrieve contract event logs.]
Creates a Filter to retrieve event logs that can be used with [`getFilterChanges`](/docs/actions/public/getFilterChanges) or [`getFilterLogs`](/docs/actions/public/getFilterLogs).
## Usage
By default, an Event Filter with an ABI (`abi`) will retrieve events defined on the ABI.
:::code-group
```ts [example.ts]
import { publicClient } from './client'
import { wagmiAbi } from './abi'
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi
})
/**
* {
* abi: [...],
* id: '0x345a6572337856574a76364e457a4366',
* type: 'event'
* }
*/
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [
{
indexed: true,
name: "from",
type: "address",
},
{ indexed: true, name: "to", type: "address" },
{
indexed: true,
name: "tokenId",
type: "uint256",
},
],
name: "Transfer",
type: "event",
},
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Scoping
You can also scope a Filter to a set of given attributes (listed below).
### Address
A Filter can be scoped to an **address**:
```ts
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi,
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2' // [!code focus]
})
```
### Event
A Filter can be scoped to an **event**:
```ts
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi,
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
eventName: 'Transfer' // [!code focus]
})
```
### Arguments
A Filter can be scoped to given ***indexed* arguments**:
```ts
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi,
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
eventName: 'Transfer',
args: { // [!code focus:4]
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
}
})
```
Only indexed arguments in `event` are candidates for `args`.
A Filter Argument can also be an array to indicate that other values can exist in the position:
```ts
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi,
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
eventName: 'Transfer',
args: { // [!code focus:8]
// '0xd8da...' OR '0xa5cc...' OR '0xa152...'
from: [
'0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
'0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac',
'0xa152f8bb749c55e9943a3a0a3111d18ee2b3f94e',
],
}
})
```
### Block Range
A Filter can be scoped to a **block range**:
```ts
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi,
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
eventName: 'Transfer',
fromBlock: 16330000n, // [!code focus]
toBlock: 16330050n // [!code focus]
})
```
### Strict Mode
By default, `createContractEventFilter` will include logs that [do not conform](/docs/glossary/terms#non-conforming-log) to the indexed & non-indexed arguments on the `event`.
viem will not return a value for arguments that do not conform to the ABI, thus, some arguments on `args` may be undefined.
```ts
const filter = await publicClient.createContractEventFilter({
eventName: 'Transfer',
})
const logs = await publicClient.getFilterLogs({ filter })
logs[0].args // [!code focus]
// ^? { address?: Address, to?: Address, value?: bigint } // [!code focus]
```
You can turn on `strict` mode to only return logs that conform to the indexed & non-indexed arguments on the `event`, meaning that `args` will always be defined. The trade-off is that non-conforming logs will be filtered out.
```ts
const filter = await publicClient.createContractEventFilter({
eventName: 'Transfer',
strict: true
})
const logs = await publicClient.getFilterLogs({ filter })
logs[0].args // [!code focus]
// ^? { address: Address, to: Address, value: bigint } // [!code focus]
```
## Returns
[`Filter`](/docs/glossary/types#filter)
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi, // [!code focus]
})
```
### address (optional)
* **Type:** `Address | Address[]`
The contract address or a list of addresses from which Logs should originate. If no addresses are provided, then it will query all events matching the event signatures on the ABI.
```ts
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi,
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2' // [!code focus]
})
```
### eventName (optional)
* **Type:** `string`
The event name.
```ts
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi,
eventName: 'Transfer' // [!code focus]
})
```
### args (optional)
* **Type:** Inferred.
A list of *indexed* event arguments.
```ts
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi,
eventName: 'Transfer',
args: { // [!code focus:4]
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
}
})
```
### fromBlock (optional)
* **Type:** `bigint`
Block to start querying/listening from.
```ts
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi,
fromBlock: 69420n // [!code focus]
})
```
### toBlock (optional)
* **Type:** `bigint`
Block to query/listen until.
```ts
const filter = await publicClient.createContractEventFilter({
abi: wagmiAbi,
toBlock: 70120n // [!code focus]
})
```
# decodeDeployData
Decodes ABI encoded deploy data (bytecode & arguments).
The opposite of [`encodeDeployData`](/docs/contract/encodeDeployData).
## Install
```ts
import { decodeDeployData } from 'viem'
```
## Usage
:::code-group
```ts [example.ts]
import { decodeDeployData } from 'viem'
import { wagmiAbi } from './abi.ts'
const { args } = decodeDeployData({
abi: wagmiAbi,
bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033',
data: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c634300080700330000000000000000000000000000000000000000000000000000000000010f2c'
})
// { args: [69420n], bytecode: '0x6080604...' }
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [
{
name: 'a',
type: 'uint256',
},
],
stateMutability: 'nonpayable',
type: 'constructor',
},
...
] as const;
```
:::
## Return Value
```ts
{
args: unknown[] | undefined;
bytecode: Hex;
}
```
Decoded deploy data.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const { args } = decodeDeployData({
abi: wagmiAbi, // [!code focus]
bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033',
data: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c634300080700330000000000000000000000000000000000000000000000000000000000010f2c'
})
```
### bytecode
* **Type:** [`Hex`](/docs/glossary/types#hex)
Contract bytecode.
```ts
const { args } = decodeDeployData({
abi: wagmiAbi,
bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033', // [!code focus]
data: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c634300080700330000000000000000000000000000000000000000000000000000000000010f2c'
})
```
### data
* **Type:** [`Hex`](/docs/glossary/types#hex)
The encoded calldata.
```ts
const { args } = decodeDeployData({
abi: wagmiAbi,
bytecode: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c63430008070033',
data: '0x6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfea2646970667358221220116554d4ba29ee08da9e97dc54ff9a2a65d67a648140d616fc225a25ff08c86364736f6c634300080700330000000000000000000000000000000000000000000000000000000000010f2c' // [!code focus]
})
```
# decodeErrorResult
Decodes reverted error from a contract function call.
## Install
```ts
import { decodeErrorResult } from 'viem'
```
## Usage
:::code-group
```ts [example.ts]
import { decodeErrorResult } from 'viem'
import { wagmiAbi } from './abi.ts'
const value = decodeErrorResult({
abi: wagmiAbi,
data: '0xb758934b000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000'
})
// { errorName: 'InvalidTokenError', args: ['sold out'] }
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [
{
name: "reason",
type: "string"
}
],
name: "InvalidTokenError",
type: "error"
},
...
] as const;
```
:::
## Return Value
The decoded error.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const value = decodeErrorResult({
abi: wagmiAbi, // [!code focus]
data: '0xb758934b000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000'
})
```
### data
* **Type:** [`Hex`](/docs/glossary/types#hex)
The calldata.
```ts
const value = decodeErrorResult({
abi: wagmiAbi,
data: '0xb758934b000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000' // [!code focus]
})
```
# decodeEventLog
Decodes ABI encoded event topics & data (from an [Event Log](/docs/glossary/terms#event-log)) into an event name and structured arguments (both indexed & non-indexed).
## Install
```ts
import { decodeEventLog } from 'viem'
```
## Usage
:::code-group
```ts [example.ts]
import { decodeEventLog } from 'viem'
import { wagmiAbi } from './abi.ts'
const topics = decodeEventLog({
abi: wagmiAbi,
data: '0x0000000000000000000000000000000000000000000000000000000000000001',
topics: [
'0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0',
'0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
'0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
]
})
/**
* {
* eventName: 'Transfer',
* args: {
* from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
* value: 1n
* }
* }
*/
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{ indexed: true, name: 'to', type: 'address' },
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Transfer',
type: 'event',
},
...
] as const;
```
:::
### Partial Decode
By default, if the `topics` and `data` does not conform to the ABI (a mismatch between the number of indexed/non-indexed arguments), `decodeEventLog` will throw an error.
For example, the following will throw an error as there is a mismatch in non-`indexed` arguments & `data` length.
```ts
decodeEventLog({
abi: parseAbi(['event Transfer(address indexed, address, uint256)']), // [!code focus]
// `data` should be 64 bytes, but is only 32 bytes. // [!code focus]
data: '0x0000000000000000000000000000000000000000000000000000000000000001', // [!code focus]
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
]
})
// [DecodeLogDataMismatch]: Data size of 32 bytes is too small for non-indexed event parameters.
```
It is possible for `decodeEventLog` to try and partially decode the Log, this can be done by setting the `strict` argument to `false`:
```ts
decodeEventLog({ // [!code focus]
abi: parseAbi(['event Transfer(address indexed, address, uint256)']), // [!code focus]
data: '0x0000000000000000000000000000000000000000000000000000000000000001', // [!code focus]
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
],
strict: false // [!code ++]
})
/**
* {
* eventName: 'Transfer',
* args: ['0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266']
* }
*/
```
## Return Value
```ts
{
eventName: string;
args: Inferred;
}
```
Decoded ABI event topics.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const topics = decodeEventLog({
abi: wagmiAbi, // [!code focus]
data: '0x0000000000000000000000000000000000000000000000000000000000000001',
topics: [
'0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0',
'0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
'0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
]
})
```
### topics
* **Type:** `[Hex, ...(Hex | Hex[] | null)[]]`
A set of topics (encoded indexed args) from the [Event Log](/docs/glossary/terms#event-log).
```ts
const topics = decodeEventLog({
abi: wagmiAbi,
data: '0x0000000000000000000000000000000000000000000000000000000000000001',
topics: [ // [!code focus:5]
'0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0',
'0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
'0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
]
})
```
### data (optional)
* **Type:** `string`
The data (encoded non-indexed args) from the [Event Log](/docs/glossary/terms#event-log).
```ts
const topics = decodeEventLog({
abi: wagmiAbi,
data: '0x0000000000000000000000000000000000000000000000000000000000000001', // [!code focus]
topics: [
'0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0',
'0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
'0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
]
})
```
### eventName (optional)
* **Type:** `string`
An event name from the ABI. Provide an `eventName` to infer the return type of `decodeEventLog`.
```ts
const topics = decodeEventLog({
abi: wagmiAbi,
eventName: 'Transfer', // [!code focus]
topics: [
'0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0',
'0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
'0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
]
})
```
### strict (optional)
* **Type:** `boolean`
* **Default:** `true`
If `true`, `decodeEventLog` will throw an error if the `data` & `topics` lengths to not conform to the event on the ABI.
If `false`, `decodeEventLog` will try and [partially decode](#partial-decode).
```ts
const topics = decodeEventLog({
abi: wagmiAbi,
strict: false, // [!code focus]
topics: [
'0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0',
'0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
'0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
]
})
```
# decodeFunctionData
Decodes ABI encoded data (4 byte selector & arguments) into a function name and arguments.
The opposite of [`encodeFunctionData`](/docs/contract/encodeFunctionData).
## Install
```ts
import { decodeFunctionData } from 'viem'
```
## Usage
Below is a very basic example of how to decode a function to calldata.
:::code-group
```ts [example.ts]
import { decodeFunctionData } from 'viem'
import { wagmiAbi } from './abi.ts'
const { functionName } = decodeFunctionData({
abi: wagmiAbi,
data: '0x18160ddd'
})
// { functionName: 'totalSupply' }
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "totalSupply",
outputs: [{ name: "", type: "uint256" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
:::
### Extracting Arguments
If your calldata includes argument(s) after the 4byte function signature, you can extract them with the `args` return value.
:::code-group
```ts [example.ts]
import { decodeFunctionData } from 'viem'
import { wagmiAbi } from './abi'
// [!code word:args:1]
const { functionName, args } = decodeFunctionData({
abi: wagmiAbi,
data: '0x70a08231000000000000000000000000fba3912ca04dd458c843e2ee08967fc04f3579c2'
})
// { functionName: 'balanceOf', args: ["0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2"] }
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [{ name: "owner", type: "address" }],
name: "balanceOf",
outputs: [{ name: "", type: "uint256" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
:::
## Return Value
```ts
{
functionName: string;
args: unknown[] | undefined;
}
```
Decoded ABI function data.
### functionName
* **Type**: `string`
The decoded function name.
### args
* **Type**: `unknown[] | undefined`
The decoded function arguments.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const { functionName } = decodeFunctionData({
abi: wagmiAbi, // [!code focus]
data: '0x18160ddd'
})
```
### data
* **Type:** [`Hex`](/docs/glossary/types#hex)
The encoded calldata.
```ts
const { functionName } = decodeFunctionData({
abi: wagmiAbi,
data: '0x18160ddd' // [!code focus]
})
```
# decodeFunctionResult
Decodes the result of a function call on a contract.
## Install
```ts
import { decodeFunctionResult } from 'viem'
```
## Usage
Given an ABI (`abi`) and a function (`functionName`), pass through the encoded calldata (`data`) to retrieve the decoded value:
:::code-group
```ts [example.ts]
import { decodeFunctionResult } from 'viem'
import { wagmiAbi } from './abi.ts'
const value = decodeFunctionResult({
abi: wagmiAbi,
functionName: 'ownerOf',
data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac'
})
// '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [{ name: 'tokenId', type: 'uint256' }],
name: 'ownerOf',
outputs: [{ name: '', type: 'address' }],
stateMutability: 'view',
type: 'function',
},
...
] as const;
```
:::
### Without `functionName`
If your `abi` contains only one ABI item, you can omit the `functionName` (it becomes optional):
:::code-group
```ts [example.ts]
import { decodeFunctionResult } from 'viem'
import { abiItem } from './abi.ts'
const value = decodeFunctionResult({
abi: [abiItem],
functionName: 'ownerOf', // [!code --]
data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac'
})
// '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
```
```ts [abi.ts]
const abiItem = {
inputs: [{ name: 'tokenId', type: 'uint256' }],
name: 'ownerOf',
outputs: [{ name: '', type: 'address' }],
stateMutability: 'view',
type: 'function',
}
```
:::
### A more complex example
:::code-group
```ts [example.ts]
import { decodeFunctionResult } from 'viem'
const value = decodeFunctionResult({
abi: wagmiAbi,
functionName: 'getInfo',
data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac0000000000000000000000000000000000000000000000000000000000010f2c0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac0000000000000000000000000000000000000000000000000000000000000045'
})
/**
* {
* foo: {
* sender: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
* x: 69420n,
* y: true
* },
* sender: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
* z: 69
* }
*/
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: 'getInfo',
outputs: [
{
components: [
{
components: [
{
name: 'sender',
type: 'address',
},
{
name: 'x',
type: 'uint256',
},
{
name: 'y',
type: 'bool',
},
],
name: 'foo',
type: 'tuple',
},
{
name: 'sender',
type: 'address',
},
{
name: 'z',
type: 'uint32',
},
],
name: 'res',
type: 'tuple',
},
],
stateMutability: 'pure',
type: 'function',
},
...
] as const;
```
:::
## Return Value
The decoded data. Type is inferred from the ABI.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const value = decodeFunctionResult({
abi: wagmiAbi, // [!code focus]
functionName: 'ownerOf',
data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac'
})
```
### functionName
* **Type:** `string`
The function to encode from the ABI.
```ts
const value = decodeFunctionResult({
abi: wagmiAbi,
functionName: 'ownerOf', // [!code focus]
data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac'
})
```
### data
* **Type:** [`Hex`](/docs/glossary/types#hex)
The calldata.
```ts
const value = decodeFunctionResult({
abi: wagmiAbi,
functionName: 'ownerOf',
data: '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac' // [!code focus]
})
```
# deployContract
Deploys a contract to the network, given bytecode & constructor arguments.
## Usage
:::code-group
```ts [example.ts]
import { wagmiAbi } from './abi'
import { account, walletClient } from './config'
const hash = await walletClient.deployContract({
abi,
account,
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
stateMutability: "nonpayable",
type: "constructor",
},
...
] as const;
```
```ts [client.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Deploying with Constructor Args
:::code-group
```ts [example.ts] {8}
import { deployContract } from 'viem'
import { wagmiAbi } from './abi'
import { account, walletClient } from './config'
const hash = await walletClient.deployContract({
abi,
account,
args: [69420],
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
})
```
```ts [abi.ts] {4}
export const wagmiAbi = [
...
{
inputs: [{ name: "x", type: "uint32" }],
stateMutability: "nonpayable",
type: "constructor",
},
...
] as const;
```
```ts [client.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const hash = await walletClient.deployContract({
abi: wagmiAbi, // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
})
```
### account
* **Type:** `Account | Address`
The Account to deploy the contract from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const hash = await walletClient.deployContract({
abi: wagmiAbi,
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
})
```
### bytecode
* **Type:** [`Hex`](/docs/glossary/types#hex)
The contract's bytecode.
```ts
const hash = await walletClient.deployContract({
abi: wagmiAbi,
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...', // [!code focus]
})
```
### args (if required)
* **Type:** Inferred from ABI.
Constructor arguments to call upon deployment.
```ts
const hash = await walletClient.deployContract({
abi: wagmiAbi,
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
args: [69] // [!code focus]
})
```
## Live Example
Check out the usage of `deployContract` in the live [Deploying Contracts Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/contracts_deploying-contracts) below.
# encodeDeployData
Encodes deploy data (bytecode & constructor args) into an ABI encoded value.
## Install
```ts
import { encodeDeployData } from 'viem'
```
## Usage
Below is a very basic example of how to encode deploy data.
:::code-group
```ts [example.ts]
import { encodeDeployData } from 'viem'
import { wagmiAbi } from './abi.ts'
const data = encodeDeployData({
abi: wagmiAbi,
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...'
})
// 0x608060405260405161083e38038061083e833981016040819052610...
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
stateMutability: 'nonpayable',
type: 'constructor'
},
...
] as const;
```
:::
### Passing Arguments
If your constructor requires argument(s), you can pass them through with the `args` attribute.
TypeScript types for `args` will be inferred from the constructor & ABI, to guard you from inserting the wrong values.
For example, the `constructor` below requires an **address** argument, and it is typed as `["0x${string}"]`.
:::code-group
```ts [example.ts]
import { encodeDeployData } from 'viem'
import { wagmiAbi } from './abi'
const data = encodeDeployData({
abi: wagmiAbi,
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC']
})
// 0x608060405260405161083e38038061083e833981016040819052610...00000000000000000000000000000000a5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [{ name: 'owner', type: 'address' }],
stateMutability: 'nonpayable',
type: 'constructor',
},
...
] as const;
```
:::
## Return Value
[`Hex`](/docs/glossary/types#hex)
ABI encoded data (bytecode & constructor arguments).
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const data = encodeDeployData({
abi: wagmiAbi, // [!code focus]
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC']
})
```
### bytecode
* **Type:** [`Hex`](/docs/glossary/types#hex)
Contract bytecode.
```ts
const data = encodeDeployData({
abi: wagmiAbi,
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...', // [!code focus]
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC']
})
```
### args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
const data = encodeDeployData({
abi: wagmiAbi,
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'] // [!code focus]
})
```
# encodeErrorResult
Encodes a reverted error from a function call. The opposite of [`decodeErrorResult`](/docs/contract/decodeErrorResult).
## Install
```ts
import { encodeErrorResult } from 'viem'
```
## Usage
:::code-group
```ts [example.ts]
import { decodeErrorResult } from 'viem'
import { wagmiAbi } from './abi.ts'
const value = encodeErrorResult({
abi: wagmiAbi,
errorName: 'InvalidTokenError',
args: ['sold out']
})
// 0xb758934b000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [
{
name: "reason",
type: "string"
}
],
name: "InvalidTokenError",
type: "error"
},
...
] as const;
```
:::
### Without `errorName`
If your `abi` contains only one ABI item, you can omit the `errorName` (it becomes optional):
```ts
import { decodeErrorResult } from 'viem'
const abiItem = {
inputs: [{ name: 'reason', type: 'string' }],
name: 'InvalidTokenError',
type: 'error'
}
const value = encodeErrorResult({
abi: [abiItem],
errorName: 'InvalidTokenError', // [!code --]
args: ['sold out']
})
// 0xb758934b000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000
```
## Return Value
[`Hex`](/docs/glossary/types#hex)
The encoded error.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const value = decodeErrorResult({
abi: wagmiAbi, // [!code focus]
errorName: 'InvalidTokenError',
args: ['sold out']
})
```
### errorName
* **Type:** `string`
The error name on the ABI.
```ts
const value = encodeErrorResult({
abi: wagmiAbi,
errorName: 'InvalidTokenError', // [!code focus]
args: ['sold out']
})
```
### args (optional)
* **Type:** Inferred.
Arguments (if required) to pass to the error.
```ts
const value = encodeErrorResult({
abi: wagmiAbi,
errorName: 'InvalidTokenError',
args: ['sold out'] // [!code focus]
})
```
# encodeEventTopics
Encodes an event (with optional arguments) into filter topics.
## Install
```ts
import { encodeEventTopics } from 'viem'
```
## Usage
Below is a very basic example of how to encode event topics without arguments.
:::code-group
```ts [example.ts]
import { encodeEventTopics } from 'viem'
import { wagmiAbi } from './abi.ts'
const topics = encodeEventTopics({
abi: wagmiAbi,
eventName: 'Transfer'
})
// ["0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0"]
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{ indexed: true, name: 'to', type: 'address' },
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Transfer',
type: 'event',
},
...
] as const;
```
:::
### Passing Arguments
If your event has indexed parameters, you can pass their values through with the `args` attribute.
TypeScript types for `args` will be inferred from the event name & ABI, to guard you from inserting the wrong values.
For example, the `Transfer` event below accepts an **address** argument for the `from` and `to` attributes, and it is typed as `"0x${string}"`.
:::code-group
```ts [example.ts]
import { encodeEventTopics } from 'viem'
const topics = encodeEventTopics({
abi: wagmiAbi,
eventName: 'Transfer'
args: {
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
}
})
// ["0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0", "0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266", "0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8"]
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{ indexed: true, name: 'to', type: 'address' },
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Transfer',
type: 'event',
},
...
] as const;
```
:::
### Without `eventName`
If your `abi` contains only one ABI item, you can omit the `eventName` (it becomes optional):
```ts
import { encodeEventTopics } from 'viem'
const abiItem = {
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{ indexed: true, name: 'to', type: 'address' },
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Transfer',
type: 'event',
}
const topics = encodeEventTopics({
abi: [abiItem],
eventName: 'Transfer' // [!code --]
})
// ["0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0"]
```
## Return Value
Encoded topics.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const data = encodeEventTopics({
abi: wagmiAbi, // [!code focus]
functionName: 'Transfer',
})
```
### eventName
* **Type:** `string`
Name of the event.
```ts
const data = encodeEventTopics({
abi: wagmiAbi,
eventName: 'Transfer', // [!code focus]
})
```
### args (optional)
* **Type:** `string`
A list of *indexed* event arguments.
```ts
const data = encodeEventTopics({
abi: wagmiAbi,
eventName: 'Transfer',
args: { // [!code focus:4]
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
}
})
```
# encodeFunctionData
Encodes the function name and parameters into an ABI encoded value (4 byte selector & arguments).
## Install
```ts
import { encodeFunctionData } from 'viem'
```
## Usage
Below is a very basic example of how to encode a function to calldata.
:::code-group
```ts [example.ts]
import { encodeFunctionData } from 'viem'
import { wagmiAbi } from './abi.ts'
const data = encodeFunctionData({
abi: wagmiAbi,
functionName: 'totalSupply'
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "totalSupply",
outputs: [{ name: "", type: "uint256" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
:::
### Passing Arguments
If your function requires argument(s), you can pass them through with the `args` attribute.
TypeScript types for `args` will be inferred from the function name & ABI, to guard you from inserting the wrong values.
For example, the `balanceOf` function name below requires an **address** argument, and it is typed as `["0x${string}"]`.
:::code-group
```ts [example.ts]
import { encodeFunctionData } from 'viem'
import { wagmiAbi } from './abi'
const data = encodeFunctionData({
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC']
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [{ name: "owner", type: "address" }],
name: "balanceOf",
outputs: [{ name: "", type: "uint256" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
:::
### Without `functionName`
If your `abi` contains only one ABI item, you can omit the `functionName` (it becomes optional):
```ts
import { encodeFunctionData } from 'viem'
const abiItem = {
inputs: [{ name: 'owner', type: 'address' }],
name: 'balanceOf',
outputs: [{ name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
}
const data = encodeFunctionData({
abi: [abiItem],
functionName: 'balanceOf', // [!code --]
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC']
})
```
### Preparation (Performance Optimization)
If you are calling the same function multiple times, you can prepare the function selector once and reuse it.
```ts
import { prepareEncodeFunctionData, encodeFunctionData } from 'viem'
const transfer = prepareEncodeFunctionData({
abi: erc20Abi,
functionName: 'transfer',
})
for (const address of addresses) {
const data = encodeFunctionData({
...transfer,
args: [address, 69420n],
})
}
```
## Return Value
[`Hex`](/docs/glossary/types#hex)
ABI encoded data (4byte function selector & arguments).
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const data = encodeFunctionData({
abi: wagmiAbi, // [!code focus]
functionName: 'totalSupply',
})
```
### functionName
* **Type:** `string`
The function to encode from the ABI.
```ts
const data = encodeFunctionData({
abi: wagmiAbi,
functionName: 'totalSupply', // [!code focus]
})
```
### args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
const data = encodeFunctionData({
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'] // [!code focus]
})
```
# encodeFunctionResult
Encodes structured return data into ABI encoded data. It is the opposite of [`decodeFunctionResult`](/docs/contract/decodeFunctionResult).
## Install
```ts
import { encodeFunctionResult } from 'viem';
```
## Usage
Given an ABI (`abi`) and a function (`functionName`), pass through the values (`values`) to encode:
:::code-group
```ts [example.ts]
import { encodeFunctionResult } from 'viem';
import { wagmiAbi } from './abi.ts'
const data = encodeFunctionResult({
abi: wagmiAbi,
functionName: 'ownerOf',
result: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac',
});
// '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac'
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [{ name: 'tokenId', type: 'uint256' }],
name: 'ownerOf',
outputs: [{ name: '', type: 'address' }],
stateMutability: 'view',
type: 'function',
},
...
] as const;
```
:::
### A more complex example
:::code-group
```ts [example.ts]
import { decodeFunctionResult } from 'viem'
const data = decodeFunctionResult({
abi: wagmiAbi,
functionName: 'getInfo',
result: {
foo: {
sender: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
x: 69420n,
y: true
},
sender: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
z: 69
}
})
// 0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac0000000000000000000000000000000000000000000000000000000000010f2c0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac0000000000000000000000000000000000000000000000000000000000000045
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: 'getInfo',
outputs: [
{
components: [
{
components: [
{
name: 'sender',
type: 'address',
},
{
name: 'x',
type: 'uint256',
},
{
name: 'y',
type: 'bool',
},
],
name: 'foo',
type: 'tuple',
},
{
name: 'sender',
type: 'address',
},
{
name: 'z',
type: 'uint32',
},
],
name: 'res',
type: 'tuple',
},
],
stateMutability: 'pure',
type: 'function',
},
...
] as const;
```
:::
### Without `functionName`
If your `abi` contains only one ABI item, you can omit the `functionName` (it becomes optional):
```ts
import { encodeFunctionResult } from 'viem';
const abiItem = {
inputs: [{ name: 'owner', type: 'address' }],
name: 'balanceOf',
outputs: [{ name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
}
const data = encodeFunctionResult({
abi: wagmiAbi,
functionName: 'ownerOf', // [!code --]
result: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac',
});
// '0x000000000000000000000000a5cc3c03994db5b0d9a5eedd10cabab0813678ac'
```
## Return Value
The decoded data. Type is inferred from the ABI.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const data = encodeFunctionResult({
abi: wagmiAbi, // [!code focus]
functionName: 'ownerOf',
result: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac',
});
```
### functionName
* **Type:** `string`
The function to encode from the ABI.
```ts
const data = encodeFunctionResult({
abi: wagmiAbi,
functionName: 'ownerOf', // [!code focus]
result: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac',
});
```
### values
* **Type**: [`Hex`](/docs/glossary/types#hex)
Return values to encode.
```ts
const data = encodeFunctionResult({
abi: wagmiAbi,
functionName: 'ownerOf',
result: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', // [!code focus]
});
```
# estimateContractGas
Estimates the gas required to successfully execute a contract write function call.
Internally, `estimateContractGas` uses a [Public Client](/docs/clients/public) to call the [`estimateGas` action](/docs/actions/public/estimateGas) with [ABI-encoded `data`](/docs/contract/encodeFunctionData).
## Usage
Below is a very basic example of how to estimate gas (with no arguments).
The `mint` function accepts no arguments, and returns a token ID.
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
import { wagmiAbi } from './abi'
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
})
// 69420n
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [{ name: "", type: "uint32" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Passing Arguments
If your function requires argument(s), you can pass them through with the `args` attribute.
TypeScript types for `args` will be inferred from the function name & ABI, to guard you from inserting the wrong values.
For example, the `mint` function name below requires a **tokenId** argument, and it is typed as `[number]`.
:::code-group
```ts [example.ts] {8}
import { account, publicClient } from './config'
import { wagmiAbi } from './abi'
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account,
})
// 69420n
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [{ name: "owner", type: "uint32" }],
name: "mint",
outputs: [{ name: "", type: "uint32" }],
stateMutability: "nonpayable",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Return Value
`bigint`
The gas estimate.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'mint',
account,
})
```
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'mint',
account,
})
```
### functionName
* **Type:** `string`
A function to extract from the ABI.
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint', // [!code focus]
account,
})
```
### account
* **Type:** `Account | Address`
The Account to estimate gas from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' // [!code focus]
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
accessList: [{ // [!code focus:4]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
storageKeys: ['0x1'],
}],
account,
})
```
### args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
const gas = await publicClient.estimateContractGas({
address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'], // [!code focus]
account,
})
```
### dataSuffix (optional)
* **Type:** `Hex`
Data to append to the end of the calldata. Useful for adding a ["domain" tag](https://opensea.notion.site/opensea/Seaport-Order-Attributions-ec2d69bf455041a5baa490941aad307f).
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
dataSuffix: '0xdeadbeef' // [!code focus]
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account,
gasPrice: parseGwei('20'), // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account,
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account,
nonce: 69 // [!code focus]
})
```
### value (optional)
* **Type:** `number`
Value in wei sent with this transaction.
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account,
value: parseEther('1') // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the read against.
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
blockNumber: 15121123n, // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the read against.
```ts
const gas = await publicClient.estimateContractGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
blockTag: 'safe', // [!code focus]
})
```
# getCode
Retrieves the bytecode at an address.
## Usage
:::code-group
```ts [example.ts]
import { publicClient } from './client'
const bytecode = await publicClient.getCode({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
})
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Return Value
[`Hex`](/docs/glossary/types#hex) | `undefined`
The contract's bytecode, or `undefined` if no bytecode is found at the address.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
const bytecode = await publicClient.getCode({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the bytecode read against.
```ts
const bytecode = await publicClient.getCode({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
blockNumber: 15121123n, // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the bytecode read against.
```ts
const bytecode = await publicClient.getCode({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
blockTag: 'safe', // [!code focus]
})
```
## JSON-RPC Method
[`eth_getCode`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getcode)
# Contract Instances
A Contract Instance is a type-safe interface for performing contract-related actions with a specific ABI and address, created by the `getContract` function.
## Import
```ts
import { getContract } from 'viem'
```
## Usage
You can create a Contract Instance with the `getContract` function by passing in a [ABI](/docs/glossary/types#abi), address, and [Public](/docs/clients/public) and/or [Wallet Client](/docs/clients/wallet). Once created, you can call contract methods, fetch for events, listen to events, etc.
:::code-group
```ts [example.ts]
import { getContract } from 'viem'
import { wagmiAbi } from './abi'
import { publicClient, walletClient } from './client'
// 1. Create contract instance
const contract = getContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
// 1a. Insert a single client
client: publicClient,
// 1b. Or public and/or wallet clients
client: { public: publicClient, wallet: walletClient }
})
// 2. Call contract methods, fetch events, listen to events, etc.
const result = await contract.read.totalSupply()
const logs = await contract.getEvents.Transfer()
const unwatch = contract.watchEvent.Transfer(
{ from: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e' },
{ onLogs(logs) { console.log(logs) } }
)
```
```ts [client.ts]
import { createPublicClient, createWalletClient, http, custom } from 'viem'
import { mainnet } from 'viem/chains'
import { EthereumProvider } from '@walletconnect/ethereum-provider'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
})
// eg: Metamask
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
})
// eg: WalletConnect
const provider = await EthereumProvider.init({
projectId: "abcd1234",
showQrModal: true,
chains: [1],
})
export const walletClientWC = createWalletClient({
chain: mainnet,
transport: custom(provider),
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: 'totalSupply',
outputs: [{ type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
{
name: 'Transfer',
type: 'event',
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{ indexed: true, name: 'to', type: 'address' },
{
indexed: true,
name: 'tokenId',
type: 'uint256',
},
],
},
...
] as const;
```
:::
Using Contract Instances can make it easier to work with contracts if you don't want to pass the `abi` and `address` properties every time you perform contract actions, e.g. [`readContract`](/docs/contract/readContract), [`writeContract`](/docs/contract/writeContract), [`estimateContractGas`](/docs/contract/estimateContractGas), etc. Switch between the tabs below to see the difference between standalone Contract Actions and Contract Instance Actions:
:::code-group
```ts [contract-instance.ts]
import { getContract } from 'viem'
import { wagmiAbi } from './abi'
import { publicClient, walletClient } from './client'
const contract = getContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
client: {
public: publicClient,
wallet: walletClient,
}
})
const balance = await contract.read.balanceOf([
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
])
const hash = await contract.write.mint([69420])
const logs = await contract.getEvents.Transfer()
const unwatch = contract.watchEvent.Transfer(
{
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
},
{ onLogs: logs => console.log(logs) }
)
```
```ts [contract-actions.ts]
import { wagmiAbi } from './abi'
import { publicClient, walletClient } from './client'
const balance = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC']
})
const hash = await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420]
})
const unwatch = publicClient.watchContractEvent({
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
abi: wagmiAbi,
eventName: 'Transfer',
args: {
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
},
onLogs: logs => console.log(logs)
})
```
:::
:::tip
While Contract Instances are great for reducing code duplication, they pull in multiple contract actions (e.g. `createContractEventFilter`, `estimateContractGas`, `readContract`, `simulateContract`, `watchContractEvent`, `writeContract`), so they can be a bit heavier than individual calls. If you only need a couple contract methods and you care about minimizing bundle size to the fullest extent, you may want to use individual calls instead.
:::
## Return Value
Contract instance object. Type is inferred.
Depending on if you create a contract instance with a Public Client, Wallet Client, or both, the methods available on the contract instance will vary.
#### With Public Client
If you pass in a [`publicClient`](https://viem.sh/docs/clients/public), the following methods are available:
* [`createEventFilter`](/docs/contract/createContractEventFilter)
* [`estimateGas`](/docs/contract/estimateContractGas)
* [`getEvents`](/docs/contract/getContractEvents)
* [`read`](/docs/contract/readContract)
* [`simulate`](/docs/contract/simulateContract)
* [`watchEvent`](/docs/contract/watchContractEvent)
#### With Wallet Client
If you pass in a [`walletClient`](/docs/clients/wallet), the following methods are available:
* [`estimateGas`](/docs/contract/estimateContractGas)
* [`write`](/docs/contract/writeContract)
#### Calling methods
If you are using [TypeScript](/docs/typescript) with viem, your editor will be able to provide autocomplete suggestions for the methods available on the contract instance, as well as the arguments and other options for each method.
In general, contract instance methods follow the following format:
```ts
// function
contract.(estimateGas|read|simulate|write).(functionName)(args, options)
// event
contract.(createEventFilter|getEvents|watchEvent).(eventName)(args, options)
```
If the contract function/event you are using does not accept arguments (e.g. function has no inputs, event has no indexed inputs), then you can omit the `args` parameter so `options` is the first and only parameter.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
const contract = getContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
client: publicClient
})
```
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const contract = getContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
client: publicClient
})
```
### client
* **Type:** [`Client | { public: Client; wallet: Client }`](/docs/clients/public)
The Client used for performing [contract actions](/docs/contract/getContract#return-value).
```ts
const contract = getContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
client: publicClient, // [!code focus]
})
```
You can also pass in multiple clients (ie. a Wallet Client and a Public Client):
```ts
const contract = getContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
client: { // [!code focus]
public: publicClient, // [!code focus]
wallet: walletClient // [!code focus]
}, // [!code focus]
})
```
# getContractEvents
Returns a list of contract **event logs** matching the provided parameters.
## Usage
By default, `getContractEvents` returns all matched events on the ABI. In practice, you must use scoping to filter for specific events.
:::code-group
```ts [example.ts]
import { publicClient } from './client'
import { erc20Abi } from './abi'
// Fetch event logs for every event on every ERC-20 contract. // [!code focus:99]
const logs = await publicClient.getContractEvents({
abi: erc20Abi
})
// [{ ... }, { ... }, { ... }]
```
```ts [abi.ts]
export const erc20Abi = [
...
{
type: 'event',
name: 'Transfer',
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{
indexed: true,
name: 'to',
type: 'address',
},
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
}
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Scoping
You can also scope to a set of given attributes.
:::code-group
```ts [example.ts]
import { parseAbiItem } from 'viem'
import { publicClient } from './client'
import { erc20Abi } from './abi'
const usdcContractAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' // [!code focus:99]
const logs = await publicClient.getContractEvents({
address: usdcContractAddress,
abi: erc20Abi,
eventName: 'Transfer',
args: {
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
},
fromBlock: 16330000n,
toBlock: 16330050n
})
```
```ts [abi.ts]
export const erc20Abi = [
...
{
type: 'event',
name: 'Transfer',
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{
indexed: true,
name: 'to',
type: 'address',
},
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
}
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Address
Logs can be scoped to an **address**:
:::code-group
```ts [example.ts]
import { publicClient } from './client'
import { erc20Abi } from './abi'
const logs = await publicClient.getContractEvents({
abi: erc20Abi,
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2', // [!code focus]
})
```
```ts [abi.ts]
export const erc20Abi = [
...
{
type: 'event',
name: 'Transfer',
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{
indexed: true,
name: 'to',
type: 'address',
},
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
}
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Event
Logs can be scoped to an **event**.
:::code-group
```ts [example.ts]
import { parseAbiItem } from 'viem' // [!code focus]
import { publicClient } from './client'
import { erc20Abi } from './abi'
const logs = await publicClient.getContractEvents({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
abi: erc20Abi,
eventName: 'Transfer', // [!code focus]
})
```
```ts [abi.ts]
export const erc20Abi = [
...
{
type: 'event',
name: 'Transfer',
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{
indexed: true,
name: 'to',
type: 'address',
},
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
}
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Arguments
Logs can be scoped to given ***indexed* arguments**:
```ts
const logs = await publicClient.getContractEvents({
abi: erc20Abi,
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
eventName: 'Transfer',
args: { // [!code focus:4]
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
}
})
```
Only indexed arguments in `event` are candidates for `args`.
An argument can also be an array to indicate that other values can exist in the position:
```ts
const logs = await publicClient.getContractEvents({
abi: erc20Abi,
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
eventName: 'Transfer',
args: { // [!code focus:8]
// '0xd8da...' OR '0xa5cc...' OR '0xa152...'
from: [
'0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
'0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac',
'0xa152f8bb749c55e9943a3a0a3111d18ee2b3f94e',
],
}
})
```
### Block Range
Logs can be scoped to a **block range**:
```ts
const logs = await publicClient.getContractEvents({
abi: erc20Abi,
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
eventName: 'Transfer',
fromBlock: 16330000n, // [!code focus]
toBlock: 16330050n // [!code focus]
})
```
### Strict Mode
By default, `getContractEvents` will include logs that [do not conform](/docs/glossary/terms#non-conforming-log) to the indexed & non-indexed arguments on the `event`.
viem will not return a value for arguments that do not conform to the ABI, thus, some arguments on `args` may be undefined.
```ts
const logs = await publicClient.getContractEvents({
abi: erc20Abi,
eventName: 'Transfer',
})
logs[0].args // [!code focus]
// ^? { address?: Address, to?: Address, value?: bigint } // [!code focus]
```
You can turn on `strict` mode to only return logs that conform to the indexed & non-indexed arguments on the `event`, meaning that `args` will always be defined. The trade-off is that non-conforming logs will be filtered out.
```ts
const logs = await publicClient.getContractEvents({
abi: erc20Abi,
eventName: 'Transfer',
strict: true
})
logs[0].args // [!code focus]
// ^? { address: Address, to: Address, value: bigint } // [!code focus]
```
## Returns
[`Log[]`](/docs/glossary/types#log)
A list of event logs.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const logs = await publicClient.getContractEvents({
abi: erc20Abi, // [!code focus]
})
```
### address
* **Type:** [`Address | Address[]`](/docs/glossary/types#address)
A contract address or a list of contract addresses. Only logs originating from the contract(s) will be included in the result.
```ts
const logs = await publicClient.getContractEvents({
abi: erc20Abi,
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
})
```
### eventName
* **Type:** `string`
An event name on the `abi`.
```ts
const logs = await publicClient.getContractEvents({
abi: erc20Abi,
eventName: 'Transfer' // [!code focus]
})
```
### args
* **Type:** Inferred.
A list of *indexed* event arguments.
```ts
const logs = await publicClient.getContractEvents({
abi: erc20Abi,
eventName: 'Transfer',
args: { // [!code focus:4]
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
},
})
```
### fromBlock
* **Type:** `bigint | 'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
Block to start including logs from. Mutually exclusive with `blockHash`.
```ts
const filter = await publicClient.getContractEvents({
abi: erc20Abi,
fromBlock: 69420n // [!code focus]
})
```
### toBlock
* **Type:** `bigint | 'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
Block to stop including logs from. Mutually exclusive with `blockHash`.
```ts
const filter = await publicClient.getContractEvents({
abi: erc20Abi,
toBlock: 70120n // [!code focus]
})
```
### blockHash
* **Type:** `'0x${string}'`
Block hash to include logs from. Mutually exclusive with `fromBlock`/`toBlock`.
```ts
const logs = await publicClient.getContractEvents({
abi: erc20Abi,
blockHash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d' // [!code focus]
})
```
## JSON-RPC Method
[`eth_getLogs`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getLogs)
# getStorageAt
Returns the value from a storage slot at a given address.
## Usage
:::code-group
```ts [example.ts]
import { toHex } from 'viem'
import { wagmiAbi } from './abi'
import { publicClient } from './client'
const data = await publicClient.getStorageAt({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
slot: toHex(0)
})
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Return Value
[`Hex`](/docs/glossary/types#hex)
The value of the storage slot.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
const data = await publicClient.getStorageAt({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
slot: toHex(0)
})
```
### slot
* **Type**: [`Hex`](/docs/glossary/types#hex)
The storage position (as a hex encoded value).
```ts
const data = await publicClient.getStorageAt({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
slot: toHex(0) // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the storage slot read against.
```ts
const bytecode = await publicClient.getStorageAt({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
slot: toHex(0),
blockNumber: 15121123n, // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the storage slot read against.
```ts
const bytecode = await publicClient.getStorageAt({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
slot: toHex(0),
blockTag: 'safe', // [!code focus]
})
```
## JSON-RPC Method
[`eth_getStorageAt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getstorageat)
# multicall \[Batches up multiple functions on a contract in a single call.]
Similar to [`readContract`](/docs/contract/readContract), but batches up multiple functions on a contract in a single RPC call via the [`multicall3` contract](https://github.com/mds1/multicall).
## Usage
:::code-group
```ts [example.ts]
import { publicClient } from './client'
import { wagmiAbi } from './abi'
const wagmiContract = {
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi
} as const
const results = await publicClient.multicall({
contracts: [
{
...wagmiContract,
functionName: 'totalSupply',
},
{
...wagmiContract,
functionName: 'ownerOf',
args: [69420n]
},
{
...wagmiContract,
functionName: 'mint'
}
]
})
/**
* [
* { result: 424122n, status: 'success' },
* { result: '0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b', status: 'success' },
* { error: [ContractFunctionExecutionError: ...], status: 'failure' }
* ]
*/
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "totalSupply",
outputs: [{ name: "", type: "uint256" }],
stateMutability: "view",
type: "function",
},
{
inputs: [{ name: "tokenId", type: "uint256" }],
name: "ownerOf",
outputs: [{ name: "", type: "address" }],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "mint",
outputs: [],
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
`({ data: , status: 'success' } | { error: string, status: 'reverted' })[]`
An array of results with accompanying status.
Additionally, when [`allowFailure`](#allowfailure-optional) is set to `false`, it directly returns an array of inferred data:
`()[]`
## Parameters
### contracts.address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
const results = await publicClient.multicall({
contracts: [
{
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'totalSupply',
},
...
]
})
```
### contracts.abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract ABI.
```ts
const results = await publicClient.multicall({
contracts: [
{
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'totalSupply',
},
...
]
})
```
### contracts.functionName
* **Type**: `string`
The function name to call.
```ts
const results = await publicClient.multicall({
contracts: [
{
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply', // [!code focus]
},
...
]
})
```
### contracts.args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
const results = await publicClient.multicall({
contracts: [
{
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b'] // [!code focus]
},
...
]
})
```
### account (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
The account to perform the multicall against.
```ts
const results = await publicClient.multicall({
account: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
contracts: [
...
],
})
```
### allowFailure (optional)
* **Type:** `boolean`
* **Default:** `true`
Whether or not the `multicall` function should throw if a call reverts. If set to `true` (default), and a call reverts, then `multicall` will fail silently and its error will be logged in the `results` array.
```ts
const results = await publicClient.multicall({
contracts: [
{
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
},
...
],
allowFailure: false // [!code focus]
})
```
### batchSize (optional)
* **Type:** `number`
* **Default:** [`client.batch.multicall.batchSize`](/docs/clients/public#batch-multicall-batchsize-optional) (if set) or `1024`
The maximum size (in bytes) for each calldata chunk. Set to `0` to disable the size limit.
> Note: Some RPC Providers limit the amount of calldata (`data`) that can be sent in a single `eth_call` request. It is best to check with your RPC Provider to see if there are any calldata size limits to `eth_call` requests.
```ts
const results = await publicClient.multicall({
contracts: [
{
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
},
...
],
batchSize: 4096 // 4kB // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the read against.
```ts
const results = await publicClient.multicall({
contracts: [
{
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
},
...
],
blockNumber: 15121123n, // [!code focus]
})
```
### deployless (optional)
* **Type:** `boolean`
* **Default:** `false`
Enable deployless multicall.
```ts
const results = await publicClient.multicall({
contracts: [
{
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
},
...
],
deployless: true // [!code focus]
})
```
### multicallAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
* **Default:** `client.chain.contracts.multicall3.address`
Address of Multicall Contract.
```ts
const results = await publicClient.multicall({
contracts: [
{
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
},
...
],
multicallAddress: '0xca11bde05977b3631167028862be2a173976ca11' // [!code focus]
})
```
### stateOverride (optional)
* **Type:** [`StateOverride`](/docs/glossary/types#stateoverride)
The state override set is an optional address-to-state mapping, where each entry specifies some state to be ephemerally overridden prior to executing the call.
```ts
const data = await publicClient.multicall({
contracts: [
{
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
},
...
],
stateOverride: [ // [!code focus]
{ // [!code focus]
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
balance: parseEther('1'), // [!code focus]
stateDiff: [ // [!code focus]
{ // [!code focus]
slot: '0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0', // [!code focus]
value: '0x00000000000000000000000000000000000000000000000000000000000001a4', // [!code focus]
}, // [!code focus]
], // [!code focus]
} // [!code focus]
], // [!code focus]
})
```
## Live Example
Check out the usage of `multicall` in the live [Multicall Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/contracts_multicall) below.
# parseEventLogs
Extracts & decodes logs matching the provided `abi` (and optional `eventName`) from a set of opaque logs.
Useful for decoding logs on Transaction Receipts.
## Install
```ts
import { parseEventLogs } from 'viem'
```
## Usage
:::code-group
```ts [example.ts]
import { parseEventLogs } from 'viem'
import { erc20Abi } from './abi'
import { client } from './client'
const receipt = await getTransactionReceipt(client, {
hash: '0xec23b2ba4bc59ba61554507c1b1bc91649e6586eb2dd00c728e8ed0db8bb37ea',
})
const logs = parseEventLogs({
abi: erc20Abi,
logs: receipt.logs,
})
// [
// { args: { ... }, eventName: 'Transfer', logIndex: 3 ... },
// { args: { ... }, eventName: 'Approval', logIndex: 5 ... },
// ...
// ]
```
```ts [abi.ts]
export const erc20Abi = [
...
{
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{ indexed: true, name: 'to', type: 'address' },
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Transfer',
type: 'event',
},
{
inputs: [
{
indexed: true,
name: 'owner',
type: 'address',
},
{
indexed: true,
name: 'spender',
type: 'address',
},
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Approval',
type: 'event',
}
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Scoping to Event Name(s)
You can scope the logs to a specific event name by providing the `eventName` argument:
:::code-group
```ts [example.ts]
import { parseEventLogs } from 'viem'
import { erc20Abi } from './abi'
import { client } from './client'
const receipt = await getTransactionReceipt(client, {
hash: '0xec23b2ba4bc59ba61554507c1b1bc91649e6586eb2dd00c728e8ed0db8bb37ea',
})
const logs = parseEventLogs({
abi: erc20Abi,
eventName: 'Transfer', // [!code hl]
logs: receipt.logs,
})
// [
// { args: { ... }, eventName: 'Transfer', logIndex: 3, ... },
// { args: { ... }, eventName: 'Transfer', logIndex: 7, ... },
// ...
// ]
```
```ts [abi.ts]
export const erc20Abi = [
...
{
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{ indexed: true, name: 'to', type: 'address' },
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Transfer',
type: 'event',
},
{
inputs: [
{
indexed: true,
name: 'owner',
type: 'address',
},
{
indexed: true,
name: 'spender',
type: 'address',
},
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Approval',
type: 'event',
}
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
You can also pass an array to scope multiple event names:
:::code-group
```ts [example.ts]
import { parseEventLogs } from 'viem'
import { erc20Abi } from './abi'
import { client } from './client'
const receipt = await getTransactionReceipt(client, {
hash: '0xec23b2ba4bc59ba61554507c1b1bc91649e6586eb2dd00c728e8ed0db8bb37ea',
})
const logs = parseEventLogs({
abi: erc20Abi,
eventName: ['Transfer', 'Approval'], // [!code hl]
logs: receipt.logs,
})
// [
// { args: { ... }, eventName: 'Transfer', logIndex: 3, ... },
// { args: { ... }, eventName: 'Approval', logIndex: 5, ... },
// { args: { ... }, eventName: 'Transfer', logIndex: 7, ... },
// ...
// ]
```
```ts [abi.ts]
export const erc20Abi = [
...
{
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{ indexed: true, name: 'to', type: 'address' },
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Transfer',
type: 'event',
},
{
inputs: [
{
indexed: true,
name: 'owner',
type: 'address',
},
{
indexed: true,
name: 'spender',
type: 'address',
},
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Approval',
type: 'event',
}
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Scoping to Arguments
You can scope the logs to arguments by providing the `args` argument:
:::code-group
```ts [example.ts]
import { parseEventLogs } from 'viem'
import { erc20Abi } from './abi'
import { client } from './client'
const receipt = await getTransactionReceipt(client, {
hash: '0xec23b2ba4bc59ba61554507c1b1bc91649e6586eb2dd00c728e8ed0db8bb37ea',
})
const logs = parseEventLogs({
abi: erc20Abi,
args: { // [!code focus]
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
}, // [!code focus]
logs: receipt.logs,
})
// [
// { args: { from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', ... }, eventName: '...', logIndex: 3, ... },
// { args: { from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', ... }, eventName: '...', logIndex: 7, ... },
// ...
// ]
```
```ts [abi.ts]
export const erc20Abi = [
...
{
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{ indexed: true, name: 'to', type: 'address' },
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Transfer',
type: 'event',
},
{
inputs: [
{
indexed: true,
name: 'owner',
type: 'address',
},
{
indexed: true,
name: 'spender',
type: 'address',
},
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Approval',
type: 'event',
}
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
You can also pass an array to scope multiple values of an argument:
:::code-group
```ts [example.ts]
import { parseEventLogs } from 'viem'
import { erc20Abi } from './abi'
import { client } from './client'
const receipt = await getTransactionReceipt(client, {
hash: '0xec23b2ba4bc59ba61554507c1b1bc91649e6586eb2dd00c728e8ed0db8bb37ea',
})
const logs = parseEventLogs({
abi: erc20Abi,
args: { // [!code focus]
from: [ // [!code focus]
'0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
'0xd8da6bf26964af9d7eed9e03e53415d37aa96045', // [!code focus]
], // [!code focus]
}, // [!code focus]
logs: receipt.logs,
})
// [
// { args: { from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', ... }, eventName: '...', logIndex: 3, ... },
// { args: { from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045', ... }, eventName: '...', logIndex: 7, ... },
// ...
// ]
```
```ts [abi.ts]
export const erc20Abi = [
...
{
inputs: [
{
indexed: true,
name: 'from',
type: 'address',
},
{ indexed: true, name: 'to', type: 'address' },
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Transfer',
type: 'event',
},
{
inputs: [
{
indexed: true,
name: 'owner',
type: 'address',
},
{
indexed: true,
name: 'spender',
type: 'address',
},
{
indexed: false,
name: 'value',
type: 'uint256',
},
],
name: 'Approval',
type: 'event',
}
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Partial Decode
By default, if the `topics` and `data` does not conform to the ABI (a mismatch between the number of indexed/non-indexed arguments), `parseEventLogs` will not return return the decoded log.
For example, the following will not return the nonconforming log as there is a mismatch in non-`indexed` arguments & `data` length.
```ts
parseEventLogs({
abi: parseAbi(['event Transfer(address indexed, address, uint256)']),
logs: [{
// `data` should be 64 bytes, but is only 32 bytes. // [!code hl]
data: '0x0000000000000000000000000000000000000000000000000000000000000001', // [!code hl]
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
]
// ...
}]
})
// []
```
It is possible for `parseEventLogs` to try and partially decode the Log, this can be done by setting the `strict` argument to `false`:
```ts
parseEventLogs({
abi: parseAbi(['event Transfer(address indexed, address, uint256)']),
logs: [{
data: '0x0000000000000000000000000000000000000000000000000000000000000001',
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
]
// ...
}]
strict: false // [!code ++]
})
/**
* [
* {
* eventName: 'Transfer',
* args: ['0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'],
* blockNumber: 42069420n,
* logIndex: 69,
* ...
* }
* ]
*/
```
## Return Value
`Log[]`
Decoded logs.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const topics = parseEventLogs({
abi: wagmiAbi, // [!code focus]
logs: [{
blockNumber: 69420n,
data: '0x0000000000000000000000000000000000000000000000000000000000000001',
logIndex: 1,
topics: [
'0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0',
'0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
'0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
]
// ...
}]
})
```
### logs
* **Type:** `Log[]`
An array of logs to parse.
```ts
const topics = parseEventLogs({
abi: wagmiAbi,
logs: [{ // [!code focus]
blockNumber: 69420n, // [!code focus]
data: '0x0000000000000000000000000000000000000000000000000000000000000001', // [!code focus]
logIndex: 1, // [!code focus]
topics: [ // [!code focus]
'0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0', // [!code focus]
'0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
'0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8' // [!code focus]
] // [!code focus]
// ... // [!code focus]
}] // [!code focus]
})
```
### args (optional)
* **Type:** `{ [property: string]: string | string[] | null }`
Arguments to scope the logs to.
```ts
const topics = parseEventLogs({
abi: wagmiAbi,
args: { // [!code focus]
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
}, // [!code focus]
logs: [{
blockNumber: 69420n,
data: '0x0000000000000000000000000000000000000000000000000000000000000001',
logIndex: 1,
topics: [
'0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0',
'0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
'0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
]
// ...
}]
})
```
### eventName (optional)
* **Type:** `string`
An event name from the ABI.
```ts
const topics = parseEventLogs({
abi: wagmiAbi,
eventName: 'Transfer', // [!code focus]
logs: [{
blockNumber: 69420n,
data: '0x0000000000000000000000000000000000000000000000000000000000000001',
logIndex: 1,
topics: [
'0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0',
'0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
'0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
]
// ...
}]
})
```
### strict (optional)
* **Type:** `boolean`
* **Default:** `true`
If `true`, `parseEventLogs` will not return [nonconforming logs](#partial-decode).
If `false`, `parseEventLogs` will try and [partially decode](#partial-decode) nonconforming logs.
```ts
const topics = parseEventLogs({
abi: wagmiAbi,
eventName: 'Transfer',
logs: [{
blockNumber: 69420n,
data: '0x0000000000000000000000000000000000000000000000000000000000000001',
logIndex: 1,
topics: [
'0x406dade31f7ae4b5dbc276258c28dde5ae6d5c2773c5745802c493a2360e55e0',
'0x00000000000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
'0x0000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8'
]
// ...
}],
strict: false // [!code focus]
})
```
# readContract
Calls a read-only function on a contract, and returns the response.
A "read-only" function (constant function) on a Solidity contract is denoted by a `view` or `pure` keyword. They can only read the state of the contract, and cannot make any changes to it. Since read-only methods do not change the state of the contract, they do not require any gas to be executed, and can be called by any user without the need to pay for gas.
Internally, `readContract` uses a [Public Client](/docs/clients/public) to call the [`call` action](/docs/actions/public/call) with [ABI-encoded `data`](/docs/contract/encodeFunctionData).
## Usage
Below is a very basic example of how to call a read-only function on a contract (with no arguments).
:::code-group
```ts [example.ts]
import { publicClient } from './client'
import { wagmiAbi } from './abi'
const data = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
})
// 69420n
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "totalSupply",
outputs: [{ name: "", type: "uint256" }],
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()
})
```
:::
### Passing Arguments
If your function requires argument(s), you can pass them through with the `args` attribute.
TypeScript types for `args` will be inferred from the function name & ABI, to guard you from inserting the wrong values.
For example, the `balanceOf` function name below requires an **address** argument, and it is typed as `["0x${string}"]`.
:::code-group
```ts [example.ts] {8}
import { publicClient } from './client'
import { wagmiAbi } from './abi'
const data = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC']
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [{ name: "owner", type: "address" }],
name: "balanceOf",
outputs: [{ name: "", type: "uint256" }],
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()
})
```
:::
### Deployless Reads
It is possible to call a function on a contract that has not been deployed yet. For instance, we may want
to call a function on an [ERC-4337 Smart Account](https://eips.ethereum.org/EIPS/eip-4337) contract which has not been deployed.
Viem offers two ways of performing a Deployless Call, via:
* [Bytecode](#bytecode)
* a [Deploy Factory](#deploy-factory): "temporarily deploys" a contract with a provided [Deploy Factory](https://docs.alchemy.com/docs/create2-an-alternative-to-deriving-contract-addresses#create2-contract-factory), and calls the function on the deployed contract.
:::tip
The **Deployless Call** pattern is also accessible via the [Contract Instance](/docs/contract/getContract) API.
:::
#### Bytecode
The example below demonstrates how we can utilize a Deployless Call **via Bytecode** to call the `name` function on the [Wagmi Example ERC721 contract](https://etherscan.io/address/0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2#code) which has not been deployed:
:::code-group
```ts twoslash [example.ts]
import { parseAbi } from 'viem'
import { publicClient } from './config'
const data = await publicClient.readContract({
abi: parseAbi(['function name() view returns (string)']),
code: '0x...', // Accessible here: https://etherscan.io/address/0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2#code
functionName: 'name'
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
#### Deploy Factory
The example below demonstrates how we can utilize a Deployless Call **via a [Deploy Factory](https://docs.alchemy.com/docs/create2-an-alternative-to-deriving-contract-addresses#create2-contract-factory)** to call the `entryPoint` function on an [ERC-4337 Smart Account](https://eips.ethereum.org/EIPS/eip-4337) which has not been deployed:
:::code-group
```ts twoslash [example.ts]
import { encodeFunctionData, parseAbi } from 'viem'
import { account, publicClient } from './config'
const data = await publicClient.readContract({
// Address of the Smart Account deployer (factory).
factory: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb',
// Function to execute on the factory to deploy the Smart Account.
factoryData: encodeFunctionData({
abi: parseAbi(['function createAccount(address owner, uint256 salt)']),
functionName: 'createAccount',
args: [account, 0n],
}),
// Function to call on the Smart Account.
abi: account.abi,
address: account.address,
functionName: 'entryPoint',
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http, parseAbi } from 'viem'
import { mainnet } from 'viem/chains'
export const account = {
address: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
abi: parseAbi(['function entryPoint() view returns (address)'])
} as const
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
:::note
This example utilizes the [SimpleAccountFactory](https://github.com/eth-infinitism/account-abstraction/blob/develop/contracts/samples/SimpleAccountFactory.sol).
:::
## Return Value
The response from the contract. Type is inferred.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
const data = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'totalSupply',
})
```
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const data = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'totalSupply',
})
```
### functionName
* **Type:** `string`
A function to extract from the ABI.
```ts
const data = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply', // [!code focus]
})
```
### args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
const data = await publicClient.readContract({
address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'] // [!code focus]
})
```
### account (optional)
* **Type:** `Account | Address`
Optional Account sender override.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const data = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the read against.
```ts
const data = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
blockNumber: 15121123n, // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the read against.
```ts
const data = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
blockTag: 'safe', // [!code focus]
})
```
### factory (optional)
* **Type:**
Contract deployment factory address (ie. Create2 factory, Smart Account factory, etc).
```ts
const data = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
factory: '0x0000000000ffe8b47b3e2130213b802212439497', // [!code focus]
factoryData: '0xdeadbeef',
})
```
### factoryData (optional)
* **Type:**
Calldata to execute on the factory to deploy the contract.
```ts
const data = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
factory: '0x0000000000ffe8b47b3e2130213b802212439497',
factoryData: '0xdeadbeef', // [!code focus]
})
```
### stateOverride (optional)
* **Type:** [`StateOverride`](/docs/glossary/types#stateoverride)
The state override set is an optional address-to-state mapping, where each entry specifies some state to be ephemerally overridden prior to executing the call.
```ts
const data = await publicClient.readContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'totalSupply',
stateOverride: [ // [!code focus]
{ // [!code focus]
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
balance: parseEther('1'), // [!code focus]
stateDiff: [ // [!code focus]
{ // [!code focus]
slot: '0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0', // [!code focus]
value: '0x00000000000000000000000000000000000000000000000000000000000001a4', // [!code focus]
}, // [!code focus]
], // [!code focus]
} // [!code focus]
], // [!code focus]
})
```
## Live Example
Check out the usage of `readContract` in the live [Reading Contracts Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/contracts_reading-contracts) below.
# simulateContract \[Simulates & validates a contract interaction.]
The `simulateContract` function **simulates**/**validates** a contract interaction. This is useful for retrieving **return data** and **revert reasons** of 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/contract/readContract), but also supports contract write functions.
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).
## Usage
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 { account, publicClient } from './config'
import { wagmiAbi } from './abi'
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [{ name: "", type: "uint32" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Passing Arguments
If your function requires argument(s), you can pass them through with the `args` attribute.
TypeScript types for `args` will be inferred from the function name & ABI, to guard you from inserting the wrong values.
For example, the `mint` function name below requires a **tokenId** argument, and it is typed as `[number]`.
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
import { wagmiAbi } from './abi'
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420], // [!code focus]
account,
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [{ name: "owner", type: "uint32" }],
name: "mint",
outputs: [{ name: "", type: "uint32" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### 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 { account, walletClient, publicClient } from './config'
import { wagmiAbi } from './abi'
const { request } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
})
const hash = await walletClient.writeContract(request)
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [{ name: "", type: "uint32" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Handling Custom Errors
In the example below, we are **catching** a [custom error](https://blog.soliditylang.org/2021/04/21/custom-errors/) thrown by the `simulateContract`. It is important to include the custom error item in the contract `abi`.
You can access the custom error through the `data` attribute of the error:
:::code-group
```ts [example.ts] {13-27}
import { BaseError, ContractFunctionRevertedError } from 'viem';
import { account, walletClient, publicClient } from './config'
import { wagmiAbi } from './abi'
try {
await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
})
} catch (err) {
if (err instanceof BaseError) {
const revertError = err.walk(err => err instanceof ContractFunctionRevertedError)
if (revertError instanceof ContractFunctionRevertedError) {
const errorName = revertError.data?.errorName ?? ''
// do something with `errorName`
}
}
}
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [{ name: "", type: "uint32" }],
stateMutability: "view",
type: "function",
},
// Custom solidity error
{
type: 'error',
inputs: [],
name: 'MintIsDisabled'
},
...
] as const;
```
```solidity [WagmiExample.sol]
// ...
error MintIsDisabled();
contract WagmiExample {
// ...
function mint() public {
// ...
revert MintIsDisabled();
// ...
}
// ...
}
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### State Overrides
When using `simulateContract`, there sometimes needs to be an initial state change to make the transaction pass. A common use case would be an approval. For that, there are [state overrides](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-eth#eth-call). In the example below, we are simulating sending a token on behalf of another user. To do this, we need to modify the state of the token contract to have maximum approve from the token owner.
:::code-group
```ts twoslash [example.ts]
import { account, publicClient } from './config'
import { abi, address } from './contract'
// Allowance slot: A 32 bytes hex string representing the allowance slot of the sender.
const allowanceSlot = '0x....'
// Max allowance: A 32 bytes hex string representing the maximum allowance (2^256 - 1)
const maxAllowance = numberToHex(maxUint256)
const { result } = await publicClient.simulateContract({
abi,
address,
account,
functionName: 'transferFrom',
args: [
'0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
account.address,
69420n
],
stateOverride: [ // [!code hl]
{ // [!code hl]
// modifying the state of the token contract // [!code hl]
address, // [!code hl]
stateDiff: [ // [!code hl]
{ // [!code hl]
slot: allowanceSlot, // [!code hl]
value: maxAllowance, // [!code hl]
}, // [!code hl]
], // [!code hl]
}, // [!code hl]
], // [!code hl]
})
console.log(result)
// @log: Output: true
```
```ts twoslash [contract.ts] filename="contract.ts"
export const address = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
export const abi = [
{
type: 'function',
name: 'transferFrom',
stateMutability: 'nonpayable',
inputs: [
{
name: 'sender',
type: 'address',
},
{
name: 'recipient',
type: 'address',
},
{
name: 'amount',
type: 'uint256',
},
],
outputs: [
{
type: 'bool',
},
],
},
] as const
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const account = privateKeyToAccount('0x...')
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Return Value
The simulation result and write request. Type is inferred.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'mint',
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})
```
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'mint',
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})
```
### functionName
* **Type:** `string`
A function to extract from the ABI.
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint', // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})
```
### account
* **Type:** `Account | Address | null`
The Account to simulate the contract method from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc). If set to `null`, it is assumed that the transport will handle the filling the sender of the transaction.
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' // [!code focus]
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
accessList: [{ // [!code focus:4]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
storageKeys: ['0x1'],
}],
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})
```
### authorizationList (optional)
* **Type:** `AuthorizationList`
Signed EIP-7702 Authorization list.
```ts
const authorization = await walletClient.signAuthorization({
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
})
const { result } = await publicClient.simulateContract({
address: account.address,
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
authorizationList: [authorization], // [!code focus]
})
```
:::note
**References**
* [EIP-7702 Overview](/docs/eip7702)
* [`signAuthorization` Docs](/docs/eip7702/signAuthorization)
:::
### args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
const { result } = await publicClient.simulateContract({
address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'], // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the read against.
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
blockNumber: 15121123n, // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the read against.
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
blockTag: 'safe', // [!code focus]
})
```
### dataSuffix (optional)
* **Type:** `Hex`
Data to append to the end of the calldata. Useful for adding a ["domain" tag](https://opensea.notion.site/opensea/Seaport-Order-Attributions-ec2d69bf455041a5baa490941aad307f).
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
dataSuffix: '0xdeadbeef' // [!code focus]
})
```
### gas (optional)
* **Type:** `bigint`
The gas limit for the transaction.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
gas: 69420n, // [!code focus]
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
gasPrice: parseGwei('20'), // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
nonce: 69 // [!code focus]
})
```
### stateOverride (optional)
* **Type:** [`StateOverride`](/docs/glossary/types#stateoverride)
The state override set is an optional address-to-state mapping, where each entry specifies some state to be ephemerally overridden prior to executing the call.
> Note: By using state overrides, you simulate the contract based on a fake state. Using this is useful for testing purposes, but making a transaction based on the returned `request` object might fail regardless of the simulation result.
```ts
const data = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
stateOverride: [ // [!code focus]
{ // [!code focus]
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
balance: parseEther('1'), // [!code focus]
stateDiff: [ // [!code focus]
{ // [!code focus]
slot: '0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0', // [!code focus]
value: '0x00000000000000000000000000000000000000000000000000000000000001a4', // [!code focus]
}, // [!code focus]
], // [!code focus]
} // [!code focus]
], // [!code focus]
})
```
### value (optional)
* **Type:** `number`
Value in wei sent with this transaction.
```ts
const { result } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
value: parseEther('1') // [!code focus]
})
```
## Live Example
Check out the usage of `simulateContract` in the live [Writing to Contracts Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/contracts_writing-to-contracts) below.
# watchContractEvent
Watches and returns emitted contract event logs.
This Action will batch up all the event logs found within the [`pollingInterval`](#pollinginterval-optional), and invoke them via [`onLogs`](#onlogs).
`watchContractEvent` will attempt to create an [Event Filter](/docs/contract/createContractEventFilter) and listen to changes to the Filter per polling interval, however, if the RPC Provider does not support Filters (ie. `eth_newFilter`), then `watchContractEvent` will fall back to using [`getLogs`](/docs/actions/public/getLogs) instead.
## Usage
:::code-group
```ts [example.ts]
import { publicClient } from './client'
import { wagmiAbi } from './abi'
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
onLogs: logs => console.log(logs)
})
// > [{ ... }, { ... }, { ... }]
// > [{ ... }, { ... }]
// > [{ ... }, { ... }, { ... }, { ... }]
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Scoping to an Event Name
You can scope to an event on the given ABI.
:::code-group
```ts [example.ts] {8}
import { publicClient } from './client'
import { wagmiAbi } from './abi'
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
eventName: 'Transfer',
onLogs: logs => console.log(logs)
})
// > [{ ... }, { ... }, { ... }]
// > [{ ... }, { ... }]
// > [{ ... }, { ... }, { ... }, { ... }]
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [
{
indexed: true,
name: "from",
type: "address",
},
{ indexed: true, name: "to", type: "address" },
{
indexed: true,
name: "tokenId",
type: "uint256",
},
],
name: "Transfer",
type: "event",
},
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Scoping to Event Arguments
You can scope to given **indexed event arguments**.
In the example below, we want to filter out `Transfer`s that were sent by the address `"0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b"`.
> Only **`indexed`** arguments on the event ABI are candidates for `args` (see `abi.ts`).
:::code-group
```ts [example.ts] {8-9}
import { publicClient } from './client'
import { wagmiAbi } from './abi'
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
eventName: 'Transfer',
args: { from: '0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b' },
onLogs: logs => console.log(logs)
})
// > [{ ... }, { ... }, { ... }]
// > [{ ... }, { ... }]
// > [{ ... }, { ... }, { ... }, { ... }]
```
```ts [abi.ts] {6-8}
export const wagmiAbi = [
...
{
inputs: [
{
indexed: true,
name: "from",
type: "address",
},
{
indexed: true,
name: "to",
type: "address"
},
{
indexed: false,
name: "tokenId",
type: "uint256",
},
],
name: "Transfer",
type: "event",
},
...
] as const;
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`UnwatchFn`
A function that can be invoked to stop watching for new event logs.
## Arguments
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
onLogs: logs => console.log(logs)
})
```
### onLogs
* **Type:** `(Log[]) => void`
The new event logs.
```ts
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
onLogs: logs => console.log(logs) // [!code focus]
})
```
### address (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address. If no address is provided, then it will emit all events matching the event signatures on the ABI.
```ts
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
onLogs: logs => console.log(logs)
})
```
### args (optional)
* **Type:** Inferred from ABI.
Event arguments to filter logs.
```ts
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
eventName: 'Transfer', // [!code focus]
args: ['0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b'], // [!code focus]
onLogs: logs => console.log(logs)
})
```
### eventName (optional)
* **Type:** `string`
An event name to filter logs.
```ts
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
eventName: 'Transfer', // [!code focus]
onLogs: logs => console.log(logs)
})
```
### batch (optional)
* **Type:** `boolean`
* **Default:** `true`
Whether or not to batch logs between polling intervals.
```ts
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
batch: false, // [!code focus]
onLogs: logs => console.log(logs)
})
```
### onError (optional)
* **Type:** `(error: Error) => void`
Error thrown from listening for new event logs.
```ts
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
onError: error => console.log(error), // [!code focus]
onLogs: logs => console.log(logs)
})
```
### poll (optional)
* **Type:** `boolean`
* **Default:** `false` for WebSocket Clients, `true` for non-WebSocket Clients
Whether or not to use a polling mechanism to check for new logs instead of a WebSocket subscription.
This option is only configurable for Clients with a [WebSocket Transport](/docs/clients/transports/websocket).
```ts
import { createPublicClient, webSocket } from 'viem'
import { mainnet } from 'viem/chains'
const publicClient = createPublicClient({
chain: mainnet,
transport: webSocket()
})
const unwatch = publicClient.watchContractEvent(
{
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
poll: true, // [!code focus]
}
)
```
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to the Client's `pollingInterval` config.
```ts
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
pollingInterval: 1_000, // [!code focus]
onLogs: logs => console.log(logs)
})
```
### fromBlock (optional)
* **Type:** `bigint`
The block number to start listening for logs from.
```ts
const unwatch = publicClient.watchContractEvent({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
onLogs: logs => console.log(logs),
fromBlock: 1n // [!code focus]
})
```
## JSON-RPC Methods
**When poll `true` and RPC Provider supports `eth_newFilter`:**
* Calls [`eth_newFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newfilter) to create a filter (called on initialize).
* On a polling interval, it will call [`eth_getFilterChanges`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterchanges).
**When poll `true` RPC Provider does not support `eth_newFilter`:**
* Calls [`eth_getLogs`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs) for each block between the polling interval.
**When poll `false` and WebSocket Transport:**
* Uses a WebSocket subscription via `eth_subscribe` and the "logs" event.
# writeContract
Executes a write function on a contract.
A "write" function on a Solidity contract modifies the state of the blockchain. These types of functions require gas to be executed, and hence a [Transaction](/docs/glossary/terms) is needed to be broadcast in order to change the state.
Internally, `writeContract` uses a [Wallet Client](/docs/clients/wallet) to call the [`sendTransaction` action](/docs/actions/wallet/sendTransaction) with [ABI-encoded `data`](/docs/contract/encodeFunctionData).
:::warning
The `writeContract` internally sends a transaction – it **does not** validate if the contract write will succeed (the contract may throw an error). It is highly recommended to [simulate the contract write with `simulateContract`](#usage) before you execute it.
:::
## Usage
Below is a very basic example of how to execute a write function on a contract (with no arguments).
While you can use `writeContract` [by itself](#standalone), it is highly recommended to pair it with [`simulateContract`](/docs/contract/simulateContract) to validate that the contract write will execute without errors.
:::code-group
```ts [example.ts]
import { account, publicClient, walletClient } from './config'
import { wagmiAbi } from './abi'
const { request } = await publicClient.simulateContract({
account,
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
})
await walletClient.writeContract(request)
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Passing Arguments
If your function requires argument(s), you can pass them through with the `args` attribute.
TypeScript types for `args` will be inferred from the function name & ABI, to guard you from inserting the wrong values.
For example, the `mint` function name below requires a **tokenId** argument, and it is typed as `[number]`.
:::code-group
```ts [example.ts] {8}
import { account, walletClient } from './client'
import { wagmiAbi } from './abi'
const { request } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account
})
await walletClient.writeContract(request)
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [{ name: "tokenId", type: "uint32" }],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createWalletClient, custom, http} from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount('0x...')
```
:::
### Standalone
If you don't need to perform validation on the contract write, you can also use it by itself:
:::code-group
```ts [example.ts]
import { account, walletClient } from './config'
import { wagmiAbi } from './abi'
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount('0x...')
```
:::
## Return Value
[`Hash`](/docs/glossary/types#hash)
A [Transaction Hash](/docs/glossary/terms#hash).
Unlike [`readContract`](/docs/contract/readContract), `writeContract` only returns a [Transaction Hash](/docs/glossary/terms#hash). If you would like to retrieve the return data of a write function, you can use the [`simulateContract` action](/docs/contract/simulateContract) – this action does not execute a transaction, and does not require gas (it is very similar to `readContract`).
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'mint',
args: [69420]
})
```
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'mint',
args: [69420]
})
```
### functionName
* **Type:** `string`
A function to extract from the ABI.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint', // [!code focus]
args: [69420]
})
```
### account
* **Type:** `Account | Address | null`
The Account to write to the contract from.
Accepts a [JSON-RPC Account (or Address)](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc). If set to `null`, it is assumed that the transport will handle the filling the sender of the transaction.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' // [!code focus]
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
accessList: [{ // [!code focus:4]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
storageKeys: ['0x1'],
}],
})
```
### authorizationList (optional)
* **Type:** `AuthorizationList`
Signed EIP-7702 Authorization list.
```ts
const authorization = await walletClient.signAuthorization({
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
})
await walletClient.writeContract({
address: account.address,
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
authorizationList: [authorization], // [!code focus]
})
```
:::note
**References**
* [EIP-7702 Overview](/docs/eip7702)
* [`signAuthorization` Docs](/docs/eip7702/signAuthorization)
:::
### args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420] // [!code focus]
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
The chain is also used to infer its request type (e.g. the Celo chain has a `gatewayFee` that you can pass through to `sendTransaction`).
```ts
import { optimism } from 'viem/chains' // [!code focus]
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
chain: optimism, // [!code focus]
})
```
### dataSuffix
* **Type:** `Hex`
Data to append to the end of the calldata. Useful for adding a ["domain" tag](https://opensea.notion.site/opensea/Seaport-Order-Attributions-ec2d69bf455041a5baa490941aad307f).
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
dataSuffix: '0xdeadbeef' // [!code focus]
})
```
### gas (optional)
* **Type:** `bigint`
The gas limit for the transaction. Note that passing a gas limit also skips the gas estimation step.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
gas: 69420n, // [!code focus]
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
gasPrice: parseGwei('20'), // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
nonce: 69 // [!code focus]
})
```
### value (optional)
* **Type:** `number`
Value in wei sent with this transaction.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
value: parseEther('1') // [!code focus]
})
```
## Live Example
Check out the usage of `writeContract` in the live [Writing to Contracts Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/contracts_writing-to-contracts) below.
# writeContractSync
Executes a write function on a contract, and waits for the transaction to be included in a block. Returns the transaction receipt.
A "write" function on a Solidity contract modifies the state of the blockchain. These types of functions require gas to be executed, and hence a [Transaction](/docs/glossary/terms) is needed to be broadcast in order to change the state.
Internally, `writeContractSync` uses a [Wallet Client](/docs/clients/wallet) to call the [`sendTransactionSync` action](/docs/actions/wallet/sendTransactionSync) with [ABI-encoded `data`](/docs/contract/encodeFunctionData).
:::warning
This Action is only recommended to be used on chains with low block times and fast finality (most chains apart from `mainnet`).
:::
## Usage
Below is a very basic example of how to execute a write function on a contract (with no arguments).
While you can use `writeContractSync` [by itself](#standalone), it is highly recommended to pair it with [`simulateContract`](/docs/contract/simulateContract) to validate that the contract write will execute without errors.
:::code-group
```ts [example.ts]
import { account, publicClient, walletClient } from './config'
import { wagmiAbi } from './abi'
const { request } = await publicClient.simulateContract({
account,
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
})
const receipt = await walletClient.writeContractSync(request)
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Passing Arguments
If your function requires argument(s), you can pass them through with the `args` attribute.
TypeScript types for `args` will be inferred from the function name & ABI, to guard you from inserting the wrong values.
For example, the `mint` function name below requires a **tokenId** argument, and it is typed as `[number]`.
:::code-group
```ts [example.ts] {8}
import { account, walletClient } from './client'
import { wagmiAbi } from './abi'
const { request } = await publicClient.simulateContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account
})
const receipt = await walletClient.writeContractSync(request)
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [{ name: "tokenId", type: "uint32" }],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createWalletClient, custom, http} from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount('0x...')
```
:::
### Standalone
If you don't need to perform validation on the contract write, you can also use it by itself:
:::code-group
```ts [example.ts]
import { account, walletClient } from './config'
import { wagmiAbi } from './abi'
const receipt = await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
})
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount('0x...')
```
:::
## Return Value
[`TransactionReceipt`](/docs/glossary/types#transaction-receipt)
A [Transaction receipt](/docs/glossary/terms#transaction-receipt).
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'mint',
args: [69420]
})
```
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'mint',
args: [69420]
})
```
### functionName
* **Type:** `string`
A function to extract from the ABI.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint', // [!code focus]
args: [69420]
})
```
### account
* **Type:** `Account | Address | null`
The Account to write to the contract from.
Accepts a [JSON-RPC Account (or Address)](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc). If set to `null`, it is assumed that the transport will handle the filling the sender of the transaction.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' // [!code focus]
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
accessList: [{ // [!code focus:4]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
storageKeys: ['0x1'],
}],
})
```
### authorizationList (optional)
* **Type:** `AuthorizationList`
Signed EIP-7702 Authorization list.
```ts
const authorization = await walletClient.signAuthorization({
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
})
await walletClient.writeContractSync({
address: account.address,
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
authorizationList: [authorization], // [!code focus]
})
```
:::note
**References**
* [EIP-7702 Overview](/docs/eip7702)
* [`signAuthorization` Docs](/docs/eip7702/signAuthorization)
:::
### args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420] // [!code focus]
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
The chain is also used to infer its request type (e.g. the Celo chain has a `gatewayFee` that you can pass through to `sendTransactionSync`).
```ts
import { optimism } from 'viem/chains' // [!code focus]
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
chain: optimism, // [!code focus]
})
```
### dataSuffix
* **Type:** `Hex`
Data to append to the end of the calldata. Useful for adding a ["domain" tag](https://opensea.notion.site/opensea/Seaport-Order-Attributions-ec2d69bf455041a5baa490941aad307f).
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
dataSuffix: '0xdeadbeef' // [!code focus]
})
```
### gas (optional)
* **Type:** `bigint`
The gas limit for the transaction. Note that passing a gas limit also skips the gas estimation step.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
gas: 69420n, // [!code focus]
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
gasPrice: parseGwei('20'), // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
nonce: 69 // [!code focus]
})
```
### pollingInterval (optional)
* **Type:** `number`
* **Default:** `walletClient.pollingInterval`
The polling interval to poll for the transaction receipt.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
pollingInterval: 1_000 // [!code focus]
})
```
### throwOnReceiptRevert (optional)
* **Type:** `boolean`
Whether to throw an error if the transaction was detected as reverted.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
throwOnReceiptRevert: true // [!code focus]
})
```
### timeout (optional)
* **Type:** `number`
* **Default:** `chain.blockTime * 3`
The timeout to wait for the transaction receipt.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
timeout: 20_000 // [!code focus]
})
```
### value (optional)
* **Type:** `number`
Value in wei sent with this transaction.
```ts
await walletClient.writeContractSync({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
value: parseEther('1') // [!code focus]
})
```
# Contract Writes with EIP-7702
The guide below demonstrates how to perform Contract Writes with EIP-7702 to invoke Contract functions on an Externally Owned Account (EOA).
## Overview
Here is an end-to-end overview of how to perform a Contract Write to send a batch of Calls. We will break it down into [Steps](#steps) below.
:::code-group
```ts twoslash [example.ts]
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './config'
import { abi, contractAddress } from './contract'
const eoa = privateKeyToAccount('0x...')
// 1. Authorize designation of the Contract onto the EOA.
const authorization = await walletClient.signAuthorization({
account: eoa,
contractAddress,
})
// 2. Designate the Contract on the EOA, and invoke the
// `initialize` function.
const hash = await walletClient.writeContract({
abi,
address: eoa.address,
authorizationList: [authorization],
// ↑ 3. Pass the Authorization as a parameter.
functionName: 'initialize',
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: sepolia,
transport: http(),
})
```
```ts twoslash [contract.ts] filename="contract.ts"
export const abi = [
{
"type": "function",
"name": "initialize",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
{
"type": "function",
"name": "ping",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
] as const
export const contractAddress = '0x...'
```
```solidity [Delegation.sol]
pragma solidity ^0.8.20;
contract Delegation {
event Log(string message);
function initialize() external payable {
emit Log('Hello, world!');
}
function ping() external pure {
emit Log('Pong!');
}
}
```
:::
## Steps
### 1. Set up Smart Contract
We will need to set up a Smart Contract to designate on the Account. For the purposes of this guide, we will [create](https://book.getfoundry.sh/reference/forge/forge-init) and [deploy](https://book.getfoundry.sh/forge/deploying) a simple demonstration `Delegation.sol` contract, however, you can use any existing deployed contract.
Firstly, [deploy a Contract](https://book.getfoundry.sh/forge/deploying) to the Network with the following source:
```solidity [Delegation.sol]
pragma solidity ^0.8.20;
contract Delegation {
event Log(string message);
function initialize() external payable {
emit Log('Hello, world!');
}
function ping() external pure {
emit Log('Pong!');
}
}
```
### 2. Set up Client & Account
Next, we will need to set up a Client and a "Relay Account" that will be responsible for executing the EIP-7702 Contract Write.
```ts twoslash [config.ts]
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: sepolia,
transport: http(),
})
```
:::info
In this demo, we will be using a "Relay Account" (not the EOA) to execute the Transaction. This is typically how EIP-7702 is used in practice, as the relayer can sponsor the gas fees to perform the Transaction.
However, it is also possible for the EOA to sign and also execute the Transaction. [See more](#note-self-executing-eip-7702).
:::
### 3. Authorize Contract Designation
We will need to sign an Authorization to designate the Contract to the Account.
In the example below, we are instantiating an existing EOA (`account`) and using it to sign the Authorization – this will be the Account that will be used for delegation.
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
import { contractAddress } from './contract'
const eoa = privateKeyToAccount('0x...') // [!code focus]
const authorization = await walletClient.signAuthorization({ // [!code focus]
account: eoa, // [!code focus]
contractAddress, // [!code focus]
}) // [!code focus]
```
```ts twoslash [contract.ts] filename="contract.ts"
export const abi = [
{
"type": "function",
"name": "initialize",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
{
"type": "function",
"name": "ping",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
] as const
export const contractAddress = '0x...'
```
```ts twoslash [config.ts]
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: sepolia,
transport: http(),
})
```
:::
:::info
If the EOA is also executing the Transaction, you will need to pass `executor: 'self'` to `signAuthorization`. [See more](#note-self-executing-eip-7702).
:::
### 4. Execute Contract Write
We can now designate the Contract on the Account (and execute the `initialize` function) by sending an EIP-7702 Contract Write.
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
import { abi, contractAddress } from './contract'
const eoa = privateKeyToAccount('0x...')
const authorization = await walletClient.signAuthorization({
account: eoa,
contractAddress,
})
const hash = await walletClient.writeContract({ // [!code focus]
abi, // [!code focus]
address: eoa.address, // [!code focus]
authorizationList: [authorization], // [!code focus]
functionName: 'initialize', // [!code focus]
}) // [!code focus]
```
```ts twoslash [contract.ts] filename="contract.ts"
export const abi = [
{
"type": "function",
"name": "initialize",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
{
"type": "function",
"name": "ping",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
] as const
export const contractAddress = '0x...'
```
```ts twoslash [config.ts]
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: sepolia,
transport: http(),
})
```
:::
### 5. (Optional) Interact with the Delegated Account
Now that we have designated a Contract onto the Account, we can interact with it by invoking its functions.
Note that we no longer need to use an Authorization!
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
import { abi } from './contract'
const eoa = privateKeyToAccount('0x...')
const hash = await walletClient.writeContract({
abi,
address: eoa.address,
functionName: 'ping', // [!code hl]
})
```
```ts twoslash [contract.ts] filename="contract.ts"
export const abi = [
{
"type": "function",
"name": "initialize",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
{
"type": "function",
"name": "ping",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
] as const
export const contractAddress = '0x...'
```
```ts twoslash [config.ts]
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: sepolia,
transport: http(),
})
```
:::
### Note: Self-executing EIP-7702
If the signer of the Authorization (ie. the EOA) is also executing the Transaction, you will need to pass `executor: 'self'` to `signAuthorization`.
This is because `authorization.nonce` must be incremented by 1 over `transaction.nonce`, so we will need to hint to `signAuthorization` that this is the case.
:::tip
In the example below, we are attaching an EOA to the Wallet Client (see `config.ts`), and using it for signing the Authorization and executing the Transaction.
:::
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
import { abi, contractAddress } from './contract'
const authorization = await walletClient.signAuthorization({
account: eoa, // [!code --]
contractAddress,
executor: 'self', // [!code ++]
})
const hash = await walletClient.writeContract({
abi,
address: eoa.address, // [!code --]
address: walletClient.account.address, // [!code ++]
authorizationList: [authorization],
functionName: 'initialize',
})
```
```ts twoslash [config.ts]
// @noErrors
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...') // [!code --]
export const eoa = privateKeyToAccount('0x...') // [!code ++]
export const walletClient = createWalletClient({
account: relay, // [!code --]
account: eoa, // [!code ++]
chain: sepolia,
transport: http(),
})
```
```ts twoslash [contract.ts] filename="contract.ts"
export const abi = [
{
"type": "function",
"name": "initialize",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
{
"type": "function",
"name": "ping",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
] as const
export const contractAddress = '0x...'
```
:::
# getDelegation
Returns the address that an account has delegated to via [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702).
## Usage
:::code-group
```ts [example.ts]
import { publicClient } from './client'
const delegation = await publicClient.getDelegation({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
})
// '0x1234...5678' or undefined
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Return Value
[`Address`](/docs/glossary/types#address) | `undefined`
The address the account has delegated to, or `undefined` if the account is not delegated.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The address to check for delegation.
```ts
const delegation = await publicClient.getDelegation({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `bigint`
The block number to check the delegation at.
```ts
const delegation = await publicClient.getDelegation({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
blockNumber: 15121123n, // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to check the delegation at.
```ts
const delegation = await publicClient.getDelegation({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
blockTag: 'safe', // [!code focus]
})
```
# hashAuthorization
Calculates an Authorization hash in [EIP-7702 format](https://eips.ethereum.org/EIPS/eip-7702): `keccak256('0x05' || rlp([chain_id, address, nonce]))`.
## Import
```ts twoslash
import { hashAuthorization } from 'viem/utils'
```
## Usage
```ts twoslash
import { hashAuthorization } from 'viem/utils'
hashAuthorization({
contractAddress: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
chainId: 1,
nonce: 0,
})
// 0xd428ed36e6098e46b40a4cb99b83b930b0ca1f054f40b5996589eda33c295663
```
## Returns
[`Hash`](/docs/glossary/types#hash)
The hashed Authorization.
## Parameters
### address
* **Type:** `Address`
Address of the contract to set as code for the Authority.
```ts twoslash
import { hashAuthorization } from 'viem/utils'
hashAuthorization({
contractAddress: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045', // [!code focus]
chainId: 1,
nonce: 0,
})
```
### chainId
* **Type:** `number`
Chain ID to authorize.
```ts twoslash
import { hashAuthorization } from 'viem/utils'
hashAuthorization({
contractAddress: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
chainId: 1, // [!code focus]
nonce: 0,
})
```
### nonce
* **Type:** `number`
Nonce of the Authority to authorize.
```ts twoslash
import { hashAuthorization } from 'viem/utils'
hashAuthorization({
contractAddress: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
chainId: 1,
nonce: 0, // [!code focus]
})
```
### to
* **Type:** `"hex" | "bytes"`
* **Default:** `"hex"`
Output format.
```ts twoslash
import { hashAuthorization } from 'viem/utils'
hashAuthorization({
contractAddress: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
chainId: 1,
nonce: 0,
to: 'bytes', // [!code focus]
})
```
# prepareAuthorization
Prepares an [EIP-7702 Authorization](https://eips.ethereum.org/EIPS/eip-7702) for signing.
This Action will fill the required fields of the Authorization object if they are not provided (e.g. `nonce` and `chainId`).
With the prepared Authorization object, you can use [`signAuthorization`](/docs/eip7702/signAuthorization) to sign over it.
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './client'
const authorization = await walletClient.prepareAuthorization({ // [!code focus]
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
}) // [!code focus]
// @log: {
// @log: chainId: 1,
// @log: contractAddress: "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
// @log: nonce: 1,
// @log: }
const signedAuthorization = await walletClient.signAuthorization(authorization)
```
```ts twoslash [client.ts] filename="client.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: mainnet,
transport: http(),
})
```
:::
### Explicit Scoping
We can explicitly set a `nonce` and/or `chainId` by supplying them as parameters:
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './client'
const authorization = await walletClient.prepareAuthorization({
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
chainId: 10, // [!code focus]
})
// @log: {
// @log: chainId: 10,
// @log: contractAddress: "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
// @log: nonce: 420,
// @log: }
const signedAuthorization = await walletClient.signAuthorization(authorization)
```
```ts twoslash [client.ts] filename="client.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: mainnet,
transport: http(),
})
```
:::
## Returns
`Authorization`
A prepared & unsigned Authorization object.
## Parameters
### account
* **Type:** `Account`
Account to use to prepare the Authorization object.
Accepts a [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './client'
const authorization = await walletClient.prepareAuthorization({
account: privateKeyToAccount('0x...'), // [!code focus]
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2'
})
```
### chainId (optional)
* **Type:** `Address`
* **Default:** `client.chain.id` or Network chain ID
The Chain ID to scope the Authorization to. If set to zero (`0`), then the Authorization will
be valid on all chains.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './client'
const authorization = await walletClient.prepareAuthorization({
account: privateKeyToAccount('0x...'),
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
chainId: 1, // [!code focus]
})
```
### contractAddress
* **Type:** `Address`
The target Contract to designate onto the Account.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './client'
const authorization = await walletClient.prepareAuthorization({
account: privateKeyToAccount('0x...'),
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2' // [!code focus]
})
```
### executor (optional)
* **Type:** `'self' | undefined`
Whether the EIP-7702 Transaction will be executed by the Account that signed the Authorization.
If not specified, it will be assumed that the EIP-7702 Transaction will be executed by another Account (ie. a relayer Account).
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './client'
const authorization = await walletClient.prepareAuthorization({
account: privateKeyToAccount('0x...'),
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
executor: 'self', // [!code focus]
})
```
### nonce (optional)
* **Type:** `Address`
* **Default:** Account's next available nonce.
The nonce to scope the Authorization to.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './client'
const authorization = await walletClient.prepareAuthorization({
account: privateKeyToAccount('0x...'),
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
nonce: 69, // [!code focus]
})
```
# recoverAuthorizationAddress
Recovers the original signing address from a signed Authorization object.
## Import
```ts twoslash
import { recoverAuthorizationAddress } from 'viem/utils'
```
## Usage
:::code-group
```ts twoslash [example.ts]
import { privateKeyToAccount } from 'viem/accounts'
import { recoverAuthorizationAddress } from 'viem/utils' // [!code focus]
import { walletClient } from './client'
const eoa = privateKeyToAccount('0x...')
const authorization = await walletClient.signAuthorization({
account: eoa,
authorization: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2'
})
const address = await recoverAuthorizationAddress({ // [!code focus]
authorization, // [!code focus]
}) // [!code focus]
```
```ts twoslash [client.ts] filename="client.ts"
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: http(),
})
```
:::
## Returns
`Address`
The address that signed the Authorization object.
## Parameters
### authorization
* **Type:** `Authorization | SignedAuthorization`
The Authorization object that was signed.
```ts twoslash
import { recoverAuthorizationAddress } from 'viem/utils'
import { walletClient } from './client'
// ---cut---
const authorization = await walletClient.signAuthorization({
authorization: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2'
})
const address = await recoverAuthorizationAddress({
authorization, // [!code focus]
})
```
### signature
* **Type:** `Hex | ByteArray | Signature | SignedAuthorization`
The signature that was generated by signing the Authorization object with the address's private key.
```ts twoslash
import { recoverAuthorizationAddress } from 'viem/utils'
import { walletClient } from './client'
// ---cut---
const signature = await walletClient.signAuthorization({
contractAddress: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
chainId: 1,
nonce: 0,
})
const address = await recoverAuthorizationAddress({
authorization: {
contractAddress: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
chainId: 1,
nonce: 0,
},
signature, // [!code focus]
})
```
# Sending Transactions with EIP-7702
The guide below demonstrates how to send EIP-7702 Transactions to invoke Contract functions on an Externally Owned Account (EOA).
## Overview
Here is an end-to-end overview of how to execute an EIP-7702 Transaction to emit a simple event on the EOA's designated contract. We will break it down into [Steps](#steps) below.
:::code-group
```ts twoslash [example.ts]
import { encodeFunctionData } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './config'
import { abi, contractAddress } from './contract'
const eoa = privateKeyToAccount('0x...')
// 1. Authorize designation of the Contract onto the EOA.
const authorization = await walletClient.signAuthorization({
account: eoa,
contractAddress,
})
// 2. Designate the Contract on the EOA, and invoke the
// `initialize` function.
const hash = await walletClient.sendTransaction({
authorizationList: [authorization],
// ↑ 3. Pass the Authorization as a parameter.
data: encodeFunctionData({
abi,
functionName: 'initialize',
}),
to: eoa.address,
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: sepolia,
transport: http(),
})
```
```ts twoslash [contract.ts] filename="contract.ts"
export const abi = [
{
"type": "function",
"name": "initialize",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
{
"type": "function",
"name": "ping",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
] as const
export const contractAddress = '0x...'
```
```solidity [Delegation.sol]
pragma solidity ^0.8.20;
contract Delegation {
event Log(string message);
function initialize() external payable {
emit Log('Hello, world!');
}
function ping() external pure {
emit Log('Pong!');
}
}
```
:::
## Steps
### 1. Set up Smart Contract
We will need to set up a Smart Contract to designate on the Account. For the purposes of this guide, we will [create](https://book.getfoundry.sh/reference/forge/forge-init) and [deploy](https://book.getfoundry.sh/forge/deploying) a simple demonstration `Delegation.sol` contract, however, you can use any existing deployed contract.
Firstly, [deploy a Contract](https://book.getfoundry.sh/forge/deploying) to the Network with the following source:
```solidity [Delegation.sol]
pragma solidity ^0.8.20;
contract Delegation {
event Log(string message);
function initialize() external payable {
emit Log('Hello, world!');
}
function ping() external pure {
emit Log('Pong!');
}
}
```
### 2. Set up Client & Account
Next, we will need to set up a Client and a "Relay Account" that will be responsible for executing the EIP-7702 Transaction.
```ts twoslash [config.ts]
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: sepolia,
transport: http(),
})
```
:::info
In this demo, we will be using a "Relay Account" (not the EOA) to execute the Transaction. This is typically how EIP-7702 is used in practice, as the relayer can sponsor the gas fees to perform the Transaction.
However, it is also possible for the EOA to sign and also execute the Transaction. [See more](#note-self-executing-eip-7702).
:::
### 3. Authorize Contract Designation
We will need to sign an Authorization to designate the Contract to the Account.
In the example below, we are instantiating an existing EOA (`account`) and using it to sign the Authorization – this will be the Account that will be used for delegation.
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
import { contractAddress } from './contract'
const eoa = privateKeyToAccount('0x...') // [!code focus]
const authorization = await walletClient.signAuthorization({ // [!code focus]
account: eoa, // [!code focus]
contractAddress, // [!code focus]
}) // [!code focus]
```
```ts twoslash [contract.ts] filename="contract.ts"
export const abi = [
{
"type": "function",
"name": "initialize",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
{
"type": "function",
"name": "ping",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
] as const
export const contractAddress = '0x...'
```
```ts twoslash [config.ts]
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: sepolia,
transport: http(),
})
```
:::
:::info
If the EOA is also executing the Transaction, you will need to pass `executor: 'self'` to `signAuthorization`. [See more](#note-self-executing-eip-7702).
:::
### 4. Execute Transaction
We can now designate the Contract on the Account (and execute the `initialize` function) by sending an EIP-7702 Transaction.
:::code-group
```ts twoslash [example.ts]
import { encodeFunctionData } from 'viem'
import { walletClient } from './config'
import { contractAddress } from './contract'
const eoa = privateKeyToAccount('0x...')
const authorization = await walletClient.signAuthorization({
account: eoa,
contractAddress,
})
const hash = await walletClient.sendTransaction({ // [!code focus]
authorizationList: [authorization], // [!code focus]
data: encodeFunctionData({ // [!code focus]
abi, // [!code focus]
functionName: 'initialize', // [!code focus]
}), // [!code focus]
to: eoa.address, // [!code focus]
}) // [!code focus]
```
```ts twoslash [contract.ts] filename="contract.ts"
export const abi = [
{
"type": "function",
"name": "initialize",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
{
"type": "function",
"name": "ping",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
] as const
export const contractAddress = '0x...'
```
```ts twoslash [config.ts]
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: sepolia,
transport: http(),
})
```
:::
### 5. (Optional) Interact with the Delegated Account
Now that we have designated a Contract onto the Account, we can interact with it by invoking its functions.
Note that we no longer need to use an Authorization!
:::code-group
```ts twoslash [example.ts]
import { encodeFunctionData } from 'viem'
import { walletClient } from './config'
const eoa = privateKeyToAccount('0x...')
const hash = await walletClient.sendTransaction({
data: encodeFunctionData({
abi,
functionName: 'ping',
}),
to: eoa.address,
})
```
```ts twoslash [contract.ts] filename="contract.ts"
export const abi = [
{
"type": "function",
"name": "initialize",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
{
"type": "function",
"name": "ping",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
] as const
export const contractAddress = '0x...'
```
```ts twoslash [config.ts]
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: sepolia,
transport: http(),
})
```
:::
### Note: Self-executing EIP-7702
If the signer of the Authorization (ie. the EOA) is also executing the Transaction, you will need to pass `executor: 'self'` to `signAuthorization`.
This is because `authorization.nonce` must be incremented by 1 over `transaction.nonce`, so we will need to hint to `signAuthorization` that this is the case.
:::tip
In the example below, we are attaching an EOA to the Wallet Client (see `config.ts`), and using it for signing the Authorization and executing the Transaction.
:::
:::code-group
```ts twoslash [example.ts]
import { encodeFunctionData } from 'viem'
import { walletClient } from './config'
import { contractAddress } from './contract'
const authorization = await walletClient.signAuthorization({
account: eoa, // [!code --]
contractAddress,
executor: 'self', // [!code ++]
})
const hash = await walletClient.sendTransaction({
authorizationList: [authorization],
data: encodeFunctionData({
abi,
functionName: 'initialize',
}),
to: eoa.address, // [!code --]
to: walletClient.account.address, // [!code ++]
})
```
```ts twoslash [config.ts]
// @noErrors
import { createWalletClient, http } from 'viem'
import { sepolia } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
export const relay = privateKeyToAccount('0x...') // [!code --]
export const eoa = privateKeyToAccount('0x...') // [!code ++]
export const walletClient = createWalletClient({
account: relay, // [!code --]
account: eoa, // [!code ++]
chain: sepolia,
transport: http(),
})
```
```ts twoslash [contract.ts] filename="contract.ts"
export const abi = [
{
"type": "function",
"name": "initialize",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
{
"type": "function",
"name": "ping",
"inputs": [],
"outputs": [],
"stateMutability": "pure"
},
] as const
export const contractAddress = '0x...'
```
:::
# signAuthorization
Signs an [EIP-7702 Authorization](https://eips.ethereum.org/EIPS/eip-7702). The signed Authorization can be used in Transaction APIs like [`sendTransaction`](/docs/actions/wallet/sendTransaction#authorizationlist-optional) and [`writeContract`](/docs/contract/writeContract#authorizationlist-optional) to delegate an authorized Contract onto an Account.
## Usage
A Contract can be authorized by supplying a `contractAddress`. By default, it will be signed over the Account's next available Nonce and the current Chain ID. You can also [explicitly set the `nonce` and `chainId`](#scoping).
:::code-group
```ts twoslash [example.ts]
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './client'
const eoa = privateKeyToAccount('0x...')
const authorization = await walletClient.signAuthorization({ // [!code focus]
account: eoa, // [!code focus]
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
}) // [!code focus]
// @log: {
// @log: chainId: 1,
// @log: contractAddress: "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
// @log: nonce: 1,
// @log: r: "0xf507fb8fa33ffd05a7f26c980bbb8271aa113affc8f192feba87abe26549bda1",
// @log: s: "0x1b2687608968ecb67230bbf7944199560fa2b3cffe9cc2b1c024e1c8f86a9e08",
// @log: yParity: 0,
// @log: }
const hash = await walletClient.sendTransaction({
authorizationList: [authorization],
data: '0xdeadbeef',
to: eoa.address,
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: mainnet,
transport: http(),
})
```
:::
### Explicit Scoping
We can explicitly sign over a provided `nonce` and/or `chainId` by supplying them as parameters:
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './client'
const eoa = privateKeyToAccount('0x...')
const authorization = await walletClient.signAuthorization({
account: eoa,
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
chainId: 10, // [!code focus]
nonce: 420, // [!code focus]
})
// @log: {
// @log: chainId: 10,
// @log: contractAddress: "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
// @log: nonce: 420,
// @log: r: "0xf507fb8fa33ffd05a7f26c980bbb8271aa113affc8f192feba87abe26549bda1",
// @log: s: "0x1b2687608968ecb67230bbf7944199560fa2b3cffe9cc2b1c024e1c8f86a9e08",
// @log: yParity: 0,
// @log: }
const hash = await walletClient.sendTransaction({
authorizationList: [authorization],
data: '0xdeadbeef',
to: eoa.address,
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const relay = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
account: relay,
chain: mainnet,
transport: http(),
})
```
:::
## Returns
`SignedAuthorization`
A signed Authorization object.
## Parameters
### account
* **Type:** `Account`
Account to use for delegation.
Accepts a [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './client'
const authorization = await walletClient.signAuthorization({
account: privateKeyToAccount('0x...'), // [!code focus]
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2'
})
```
### chainId (optional)
* **Type:** `Address`
* **Default:** `client.chain.id` or Network chain ID
The Chain ID to scope the Authorization to.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './client'
const authorization = await walletClient.signAuthorization({
account: privateKeyToAccount('0x...'),
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
chainId: 1, // [!code focus]
})
```
### contractAddress
* **Type:** `Address`
The target Contract to delegate to the Account.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './client'
const authorization = await walletClient.signAuthorization({
account: privateKeyToAccount('0x...'),
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2' // [!code focus]
})
```
### executor (optional)
* **Type:** `'self' | undefined`
Whether the EIP-7702 Transaction will be executed by the Account that signed the Authorization.
If not specified, it will be assumed that the EIP-7702 Transaction will be executed by another Account (ie. a relayer Account).
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './client'
const authorization = await walletClient.signAuthorization({
account: privateKeyToAccount('0x...'),
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
executor: 'self', // [!code focus]
})
```
### nonce (optional)
* **Type:** `Address`
* **Default:** Account's next available nonce.
The nonce to scope the Authorization to.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
import { walletClient } from './client'
const authorization = await walletClient.signAuthorization({
account: privateKeyToAccount('0x...'),
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
nonce: 69, // [!code focus]
})
```
# verifyAuthorization
Verifies that an Authorization object was signed by the provided address.
## Import
```ts twoslash
import { verifyAuthorization } from 'viem/utils'
```
## Usage
:::code-group
```ts twoslash [example.ts]
import { privateKeyToAccount } from 'viem/accounts'
import { verifyAuthorization } from 'viem/utils' // [!code focus]
import { walletClient } from './client'
const eoa = privateKeyToAccount('0x...')
const authorization = await walletClient.signAuthorization({
account: eoa,
authorization: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2'
})
const valid = await verifyAuthorization({ // [!code focus]
address: eoa.address, // [!code focus]
authorization, // [!code focus]
}) // [!code focus]
```
```ts twoslash [client.ts] filename="client.ts"
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: http(),
})
```
:::
## Returns
`boolean`
Whether the signature is valid for the provided Authorization object.
## Parameters
### address
* **Type:** `Address`
The address that signed the Authorization object.
```ts twoslash
import { verifyAuthorization } from 'viem/utils'
import { walletClient } from './client'
const authorization = await walletClient.signAuthorization({
authorization: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2'
})
// ---cut---
const valid = await verifyAuthorization({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // [!code focus]
authorization,
})
```
### authorization
* **Type:** `Authorization | SignedAuthorization`
The Authorization object to be verified.
```ts twoslash
import { verifyAuthorization } from 'viem/utils'
import { walletClient } from './client'
// ---cut---
const authorization = await walletClient.signAuthorization({
authorization: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2'
})
const valid = await verifyAuthorization({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
authorization, // [!code focus]
})
```
### signature
* **Type:** `Hex | ByteArray | Signature | SignedAuthorization`
The signature that was generated by signing the Authorization object with the address's private key.
```ts twoslash
import { verifyAuthorization } from 'viem/utils'
import { walletClient } from './client'
// ---cut---
const signature = await walletClient.signAuthorization({
authorization: {
address: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
chainId: 1,
nonce: 0,
}
})
const valid = await verifyAuthorization({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
authorization: {
address: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
chainId: 1,
nonce: 0,
},
signature, // [!code focus]
})
```
# Errors \[Glossary of Errors in viem.]
All errors in viem extend the [`BaseError`](https://github.com/wevm/viem/blob/main/src/errors/base.ts).
## ABI
### `AbiConstructorNotFoundError`
### `AbiConstructorParamsNotFoundError`
### `AbiDecodingDataSizeInvalidError`
### `AbiDecodingDataSizeTooSmallError`
### `AbiDecodingZeroDataError`
### `AbiEncodingArrayLengthMismatchError`
### `AbiEncodingBytesSizeMismatchError`
### `AbiEncodingLengthMismatchError`
### `AbiErrorInputsNotFoundError`
### `AbiErrorNotFoundError`
### `AbiErrorSignatureNotFoundError`
### `AbiEventNotFoundError`
### `AbiEventSignatureEmptyTopicsError`
### `AbiEventSignatureNotFoundError`
### `AbiFunctionNotFoundError`
### `AbiFunctionOutputsNotFoundError`
### `AbiFunctionSignatureNotFoundError`
### `BytesSizeMismatchError`
### `DecodeLogTopicsMismatch`
### `InvalidAbiDecodingTypeError`
### `InvalidAbiEncodingTypeError`
### `InvalidArrayError`
### `InvalidDefinitionTypeError`
### `UnsupportedPackedAbiType`
## Account
### `AccountNotFoundError`
When no account is provided to an action that requires an account.
## Address
### `InvalidAddressError`
When address is invalid.
## Block
### `BlockNotFoundError`
## Chain
### `ChainDoesNotSupportContract`
### `ChainMismatchError`
### `ChainNotFoundError`
### `ClientChainNotConfiguredError`
### `InvalidChainIdError`
## Contract
### `CallExecutionError`
### `ContractFunctionExecutionError`
### `ContractFunctionRevertedError`
### `ContractFunctionZeroDataError`
### `RawContractError`
## Data
### `SizeExceedsPaddingSizeError`
## Encoding
### `DataLengthTooLongError`
### `DataLengthTooShortError`
### `IntegerOutOfRangeError`
### `InvalidBytesBooleanError`
### `InvalidHexBooleanError`
### `InvalidHexValueError`
### `OffsetOutOfBoundsError`
### `SizeOverflowError`
## ENS
### `EnsAvatarInvalidMetadataError`
### `EnsAvatarInvalidNftUriError`
### `EnsAvatarUnsupportedNamespaceError`
### `EnsAvatarUriResolutionError`
## Estimate Gas
### `EstimateGasExecutionError`
## Log
### `FilterTypeNotSupportedError`
## Node
### `ExecutionRevertedError`
### `FeeCapTooHighError`
### `FeeCapTooLowError`
### `InsufficientFundsError`
### `IntrinsicGasTooHighError`
### `IntrinsicGasTooLowError`
### `NonceMaxValueError`
### `NonceTooHighError`
### `NonceTooLowError`
### `TipAboveFeeCapError`
### `TransactionTypeNotSupportedError`
### `UnknownNodeError`
## Request
### `HttpRequestError`
### `RpcRequestError`
### `TimeoutError`
### `WebSocketRequestError`
## RPC
### `ChainDisconnectedError`
### `InternalRpcError`
### `InvalidInputRpcError`
### `InvalidParamsRpcError`
### `InvalidRequestRpcError`
### `JsonRpcVersionUnsupportedError`
### `LimitExceededRpcError`
### `MethodNotFoundRpcError`
### `MethodNotSupportedRpcError`
### `ParseRpcError`
### `ProviderDisconnectedError`
### `ProviderRpcError`
### `ResourceNotFoundRpcError`
### `ResourceUnavailableRpcError`
### `RpcError`
### `SwitchChainError`
### `TransactionRejectedRpcError`
### `UnauthorizedProviderError`
### `UnknownRpcError`
### `UnsupportedProviderMethodError`
### `UserRejectedRequestError`
## SIWE
### CreateSiweMessageErrorType
### SiweInvalidMessageFieldErrorType
### VerifySiweMessageErrorType
## Transaction
### `FeeConflictError`
### `InvalidLegacyVError`
### `InvalidSerializableTransactionError`
### `InvalidSerializedTransactionError`
### `InvalidSerializedTransactionTypeError`
### `InvalidStorageKeySizeError`
### `TransactionExecutionError`
### `TransactionNotFoundError`
### `TransactionReceiptNotFoundError`
### `WaitForTransactionReceiptTimeoutError`
## Transport
### `UrlRequiredError`
# Terms \[Glossary of Terms in viem.]
## Block
A block is a bundled unit of information that include an ordered list of transactions and consensus-related information. Blocks are proposed by proof-of-stake validators, at which point they are shared across the entire peer-to-peer network, where they can easily be independently verified by all other nodes. Consensus rules govern what contents of a block are considered valid, and any invalid blocks are disregarded by the network. The ordering of these blocks and the transactions therein create a deterministic chain of events with the end representing the current state of the network.
## Chain
A Chain refers to a specific blockchain network or protocol that maintains a decentralized, distributed ledger of transactions and other data. Each Chain has its own rules, consensus mechanism, and native cryptocurrency (if any).
Examples of Chains include: Ethereum Mainnet, Polygon, Optimism, Avalanche, Binance Smart Chain, etc.
## EIP-1559 Transaction
EIP-1559 is an Ethereum Improvement Proposal that was implemented in August 2021 as part of the London hard fork. It introduced a new transaction format for Ethereum transactions, which is referred to as an EIP-1559 transaction (aka "transaction type 2").
When a user creates an EIP-1559 transaction, they specify the maximum fee they are willing to pay (`maxFeePerGas`) as well as a tip (`maxPriorityFeePerGas`) to incentivize the miner. The actual fee paid by the user is then determined by the network based on the current demand for block space and the priority of the transaction.
## Event Log
An Event Log is a record of an event emitted by a smart contract. Events are a type of function in a smart contract that can be triggered by specific actions or conditions, and they can be used to notify dapps of changes on the network.
[See more](https://ethereum.org/en/developers/docs/smart-contracts/anatomy/#events-and-logs)
## Filter
In Ethereum, a filter is a mechanism used to query the Ethereum blockchain for specific events or information.
There are three types of filters in Ethereum:
1. Block filters - these filters allow users to monitor the blockchain for new blocks that have been added.
2. Pending Transaction filters - these filters allow users to monitor the blockchain for new pending transactions in the mempool.
3. Event filters - these filters allow users to monitor the blockchain for specific events emitted by smart contracts, such as a token transfer.
When a filter is created, it returns a filter ID, which can be used to retrieve the results of the filter at a later time. Users can then periodically poll the filter for new events or changes that match the filter criteria.
## Human-Readable ABI
Human-Readable ABIs compress JSON ABIs into signatures that are nicer to read and less verbose to write. For more info, check out the [ABIType](https://abitype.dev/api/human) docs.
## Legacy Transaction
A Legacy Transaction in Ethereum refers to a transaction that was created using an older version of Ethereum's transaction format, known as "transaction type 0". This transaction format was used prior to the introduction of the EIP-1559 upgrade, which was implemented in August 2021.
## Non-conforming Log
A non-conforming log is a log where its `topics` & `data` do not match the **indexed** & **non-indexed** arguments on the `event`. `topics` correspond to **indexed** arguments, while `data` corresponds to **non-indexed** arguments.
For example, here is an event definition that has 3 indexed arguments & 1 non-indexed arguments:
```solidity
event Transfer(
bool indexed foo,
uint256 baz,
string indexed bar,
boolean indexed barry
)
```
A conforming log for the above signature would be:
```ts
const log = {
...
data: '0x
00...23c346 // ✅ non-indexed argument (baz)
',
topics: [
'0xdd...23b3ef', // event signature
'0x00...000001', // ✅ indexed argument (foo)
'0xae...e1cc58', // ✅ indexed argument (bar)
'0x00...000000', // ✅ indexed argument (barry)
],
...
}
```
A non-conforming log for the above signature would be:
```ts
const log = {
...
data: '0x
00...23c346 // ✅ non-indexed argument (baz)
00...ae0000 // ❌ indexed argument (bar)
00...000001 // ❌ indexed argument (barry)
',
topics: [
'0xdd...23b3ef', // event signature
'0x00...b92266', // ✅ indexed argument (foo)
],
...
}
```
A non-conforming log can arise when another contract could be using the same event signature, but with a different number of indexed & non-indexed arguments. For example, the definition for the above log would be:
```solidity
event Transfer(
bool indexed foo,
uint256 baz,
string bar,
boolean barry
)
```
## Transaction
A transaction is a message sent by an Account requesting to perform an action on the Ethereum blockchain. Transactions can be used to transfer Ether between accounts, execute smart contract code, deploy smart contracts, etc.
## Transaction Receipt
A Transaction Receipt is a record of the result of a specific transaction on the Ethereum blockchain. When a transaction is submitted to the Ethereum network, it is processed by miners and included in a block. Once the block is added to the blockchain, a transaction receipt is generated and stored on the blockchain.
A transaction receipt contains information about the transaction, including:
* The transaction hash: a unique identifier for the transaction.
* The block number and block hash: the block in which the transaction was included.
* The gas used: the amount of gas consumed by the transaction.
* The status of the transaction: "success" if the transaction was executed, otherwise "reverted" if the transaction reverted.
* The logs generated by the transaction: any log events generated by the smart contract during the transaction execution.
## Transport
A Transport is the intermediary layer that is responsible for executing outgoing requests (ie. RPC requests) in viem.
# Types \[Glossary of Types in viem.]
## `Abi`
Type matching the [Contract ABI Specification](https://docs.soliditylang.org/en/latest/abi-spec.html#json)
Re-exported from [ABIType](https://abitype.dev/api/types#abi).
## `AbiError`
ABI [Error](https://docs.soliditylang.org/en/latest/abi-spec#errors) type.
Re-exported from [ABIType](https://abitype.dev/api/types#abierror).
## `AbiEvent`
ABI [Event](https://docs.soliditylang.org/en/latest/abi-spec#events) type.
Re-exported from [ABIType](https://abitype.dev/api/types#abievent).
## `AbiFunction`
ABI [Function](https://docs.soliditylang.org/en/latest/abi-spec#argument-encoding) type.
Re-exported from [ABIType](https://abitype.dev/api/types#abifunction).
## `AbiParameter`
`inputs` and `outputs` item for ABI functions, events, and errors.
Re-exported from [ABIType](https://abitype.dev/api/types#abiparameter).
## `AbiParameterToPrimitiveTypes`
Converts `AbiParameter` to corresponding TypeScript primitive type.
[See more](https://abitype.dev/api/utilities#abiparametertoprimitivetype)
## `AbiParametersToPrimitiveTypes`
Converts array of `AbiParameter` to corresponding TypeScript primitive types.
[See more](https://abitype.dev/api/utilities#abiparameterstoprimitivetypes)
## `AccessList`
An access list.
## `Address`
An address.
Re-exported from [ABIType](https://abitype.dev/api/types#address).
## `Block`
A type for a [Block](/docs/glossary/terms#block).
[See Type](https://github.com/wevm/viem/blob/main/src/types/block.ts)
## `Chain`
A type for a [Chain](/docs/glossary/terms#chain).
[See Type](https://github.com/wevm/viem/blob/main/src/types/chain.ts)
## `CompactSignature`
A type for [EIP-2098](https://eips.ethereum.org/EIPS/eip-2098) compact signatures.
[See Type](https://github.com/wevm/viem/blob/main/src/types/misc.ts)
## `FeeHistory`
A type for fee history.
[See Type](https://github.com/wevm/viem/blob/main/src/types/fee.ts)
## `FeeValues`
A type for fee values.
[See Type](https://github.com/wevm/viem/blob/main/src/types/fee.ts)
## `Filter`
A type for a [Filter](/docs/glossary/terms#filter).
[See Type](https://github.com/wevm/viem/blob/main/src/types/filter.ts)
## `Hash`
Type for a hashed value – a "0x"-prefixed string: `"0x${string}"`
## `Hex`
Type for a hex value – a "0x"-prefixed string: `"0x${string}"`
## `Log`
A type for [Event Logs](/docs/glossary/terms#event-log).
[See Type](https://github.com/wevm/viem/blob/main/src/types/log.ts)
## `Signature`
A type for a structured signature.
[See Type](https://github.com/wevm/viem/blob/main/src/types/misc.ts)
## `Transaction`
A type for [Transactions](/docs/glossary/terms#transaction).
[See Type](https://github.com/wevm/viem/blob/main/src/types/transaction.ts)
## `TransactionReceipt`
A type for [Transaction Receipts](/docs/glossary/terms#transaction-receipt).
[See Type](https://github.com/wevm/viem/blob/main/src/types/transaction.ts)
## `Transport`
A type for [Transports](/docs/glossary/terms#transports).
[See Type](https://github.com/wevm/viem/blob/main/src/clients/transports/createTransport.ts)
## `WalletPermission`
A type for wallet (JSON-RPC Account) permissions.
[See Type](https://github.com/wevm/viem/blob/main/src/types/eip1193.ts)
## `TransactionSerializedEIP1559`
EIP-1559 transaction hex value – a "0x02"-prefixed string: `"0x02${string}"`
## `TransactionSerializedEIP2930`
EIP-2930 transaction hex value – a "0x01"-prefixed string: `"0x01${string}"`
## `TransactionSerializedLegacy`
Legacy transaction hex value – a "0x"-prefixed string: `"0x${string}"`
## `TransactionType`
All types of transactions. `"eip1559" | "eip2930" | "eip4844" | "eip7702" | "legacy"`
## `TransactionRequest`
A type for all transaction requests.
[See Type](https://github.com/wevm/viem/blob/main/src/types/transaction.ts).
## `StateOverride`
A type defining state overrides for `eth_call` method. [See more](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-eth#eth-call)
# Blob Transactions \[Sending your first Blob Transaction with Viem.]
Blob Transactions are a new type of transaction in Ethereum (introduced in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844)) that allows you to broadcast BLObs (Binary Large Objects) to the Ethereum network. Blob Transactions are like any other transaction, but with the added ability to carry a payload of Blobs. Blobs are extremely larger than regular calldata (~128kB), however unlike regular calldata, they are not accessible on the EVM. The EVM can only view the commitments of the blobs. Blobs are also transient, and only last for 4096 epochs (approx. 18 days).
To read more on Blob Transactions and EIP-4844, check out these resources:
* [EIP-4844 Spec](https://eips.ethereum.org/EIPS/eip-4844)
* [EIP-4844 Website](https://www.eip4844.com/#faq)
* [EIP-4844 FAQ](https://notes.ethereum.org/@vbuterin/proto_danksharding_faq#Proto-Danksharding-FAQ)
In this guide, we will walk you through how to send your first Blob Transaction with Viem.
::::steps
## Set up Client
We will first set up our Viem Client.
Let's create a `client.ts` file that holds our Client.
```ts twoslash [client.ts] filename="client.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const account = privateKeyToAccount('0x...')
export const client = createWalletClient({
account,
chain: mainnet,
transport: http()
})
```
## Install KZG bindings
Next, we will need to install some KZG bindings. KZG will be used to compute the commitments of the blobs, and generate proofs from the blobs & commitments. The commitments and proofs are needed to serialize and sign the Blob Transaction before we send it off.
A couple of KZG implementations we recommend are:
* [c-kzg](https://github.com/ethereum/c-kzg-4844): Node.js bindings to c-kzg.
* [kzg-wasm](https://github.com/ethereumjs/kzg-wasm): WebAssembly bindings to c-kzg.
:::code-group
```bash [npm]
npm i c-kzg
# or
npm i kzg-wasm
```
```bash [pnpm]
pnpm i c-kzg
# or
pnpm i kzg-wasm
```
```bash [bun]
bun i c-kzg
# or
bun i kzg-wasm
```
:::
## Set up KZG interface
After that, we will need to hook up the KZG bindings to Viem.
Let's create a `kzg.ts` file that holds our KZG interface.
:::code-group
```ts twoslash [kzg.ts] filename="kzg.ts"
// @noErrors
import * as cKzg from 'c-kzg'
import { setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
export const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
```
```ts twoslash [client.ts]
// [!include client.ts]
```
:::
## Send Blob Transaction
Now that we have our Client and KZG interface set up, we can send our first Blob Transaction.
For demonstration purposes, we will construct a blob with a simple string: `"hello world"`, and send it to the zero address.
:::code-group
```ts twoslash [example.ts]
import { parseGwei, stringToHex, toBlobs } from 'viem'
import { account, client } from './client'
import { kzg } from './kzg'
const blobs = toBlobs({ data: stringToHex('hello world') })
const hash = await client.sendTransaction({
blobs,
kzg,
maxFeePerBlobGas: parseGwei('30'),
to: '0x0000000000000000000000000000000000000000',
})
```
```ts twoslash [kzg.ts]
// [!include kzg.ts]
```
```ts twoslash [client.ts]
// [!include client.ts]
```
:::
::::
## That's it!
You've just sent your first Blob Transaction with Viem.
With the `hash` you received in Step 4, you can now track your Blob Transaction on a blob explorer like [Blobscan](https://blobscan.com/).
# blobsToCommitments
Compute commitments from a list of blobs.
## Import
```ts twoslash
import { blobsToCommitments } from 'viem'
```
## Usage
:::code-group
```ts twoslash [example.ts]
import { blobsToCommitments, toBlobs } from 'viem'
import { kzg } from './kzg'
const blobs = toBlobs({ data: '0x1234' })
const commitments = blobsToCommitments({ blobs, kzg }) // [!code focus]
```
```ts twoslash [kzg.ts] filename="kzg.ts"
// @noErrors
import * as cKzg from 'c-kzg'
import { setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
export const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
```
:::
## Returns
`Hex[] | ByteArray[]`
List of commitments corresponding to the input blobs.
## Parameters
### blobs
* **Type:** `Hex[] | ByteArray[]`
List of blobs to transform into commitments.
```ts twoslash
import { defineKzg } from 'viem'
const kzg = defineKzg({} as any)
// ---cut---
import { blobsToCommitments, toBlobs } from 'viem'
const commitments = blobsToCommitments({
blobs: toBlobs({ data: '0x1234' }), // [!code focus]
kzg,
})
```
### kzg
* **Type:** `KZG`
KZG implementation. See [`setupKzg`](/docs/utilities/setupKzg) for more information.
```ts twoslash
// @noErrors
import * as cKzg from 'c-kzg'
import { blobsToCommitments, setupKzg, toBlobs } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath) // [!code focus]
const commitments = blobsToCommitments({
blobs: toBlobs({ data: '0x1234' }),
kzg, // [!code focus]
})
```
### to
* **Type:** `"bytes" | "hex"`
The output type.
```ts twoslash
import { defineKzg } from 'viem'
const kzg = defineKzg({} as any)
// ---cut---
import { blobsToCommitments, toBlobs } from 'viem'
const commitments = blobsToCommitments({
blobs: toBlobs({ data: '0x1234' }),
kzg,
to: 'bytes', // [!code focus]
})
commitments // [!code focus]
// ^?
```
# blobsToProofs
Compute the proofs for a list of blobs and their commitments.
## Import
```ts twoslash
import { blobsToProofs } from 'viem'
```
## Usage
:::code-group
```ts twoslash [example.ts]
import { blobsToCommitments, blobsToProofs, toBlobs } from 'viem'
import { kzg } from './kzg'
const blobs = toBlobs({ data: '0x...' })
const commitments = blobsToCommitments({ blobs, kzg })
const proofs = blobsToProofs({ blobs, commitments, kzg }) // [!code focus]
```
```ts twoslash [kzg.ts] filename="kzg.ts"
// @noErrors
import * as cKzg from 'c-kzg'
import { setupKzg } from 'viem'
export const kzg = setupKzg('./trusted-setup.json', cKzg)
```
:::
## Returns
`Hex[] | ByteArray[]`
Proofs from the input blobs and commitments.
## Parameters
### blobs
* **Type:** `Hex[] | ByteArray[]`
Blobs to transform into proofs.
```ts twoslash
import { blobsToCommitments, blobsToProofs, toBlobs } from 'viem'
import { kzg } from './kzg'
const blobs = toBlobs({ data: '0x...' }) // [!code focus]
const commitments = blobsToCommitments({ blobs, kzg })
const proofs = blobsToProofs({
blobs, // [!code focus]
commitments,
kzg
})
```
### commitments
* **Type:** `Hex[] | ByteArray[]`
Commitments corresponding to the input blobs.
```ts twoslash
import { blobsToCommitments, blobsToProofs, toBlobs } from 'viem'
import { kzg } from './kzg'
const blobs = toBlobs({ data: '0x...' })
const commitments = blobsToCommitments({ blobs, kzg }) // [!code focus]
const proofs = blobsToProofs({
blobs,
commitments, // [!code focus]
kzg
})
```
### kzg
* **Type:** `KZG`
KZG implementation. See [`setupKzg`](/docs/utilities/setupKzg) for more information.
```ts twoslash
// @noErrors
import * as cKzg from 'c-kzg'
import { blobsToProofs, setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const blobs = toBlobs({ data: '0x...' })
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath) // [!code focus]
const commitments = blobsToCommitments({ blobs, kzg })
const proofs = blobsToProofs({
blobs,
commitments,
kzg, // [!code focus]
})
```
# commitmentsToVersionedHashes
Transform a list of commitments to their versioned hashes.
## Import
```ts twoslash
import { commitmentsToVersionedHashes } from 'viem'
```
## Usage
:::code-group
```ts twoslash [example.ts]
import {
blobsToCommitments,
commitmentsToVersionedHashes,
toBlobs
} from 'viem'
import { kzg } from './kzg'
const blobs = toBlobs({ data: '0x1234' })
const commitments = blobsToCommitments({ blobs, kzg })
const versionedHashes = commitmentsToVersionedHashes({ // [!code focus]
commitments, // [!code focus]
}) // [!code focus]
```
```ts twoslash [kzg.ts] filename="kzg.ts"
// @noErrors
import * as cKzg from 'c-kzg'
import { setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
export const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
```
:::
## Returns
`Hex[] | ByteArray[]`
List of versioned hashes corresponding to the input commitments.
## Parameters
### commitments
* **Type:** `Hex[] | ByteArray[]`
List of commitments to transform into versioned hashes.
```ts twoslash
import {
blobsToCommitments,
commitmentsToVersionedHashes,
toBlobs
} from 'viem'
import { kzg } from './kzg'
// ---cut---
const blobs = toBlobs({ data: '0x1234' })
const commitments = blobsToCommitments({ blobs, kzg })
const versionedHashes = commitmentsToVersionedHashes({
commitments, // [!code focus]
kzg,
})
```
### to
* **Type:** `"bytes" | "hex"`
The output type.
```ts twoslash
import {
blobsToCommitments,
commitmentsToVersionedHashes,
toBlobs
} from 'viem'
import { kzg } from './kzg'
// ---cut---
const blobs = toBlobs({ data: '0x1234' })
const commitments = blobsToCommitments({ blobs, kzg })
const versionedHashes = commitmentsToVersionedHashes({
commitments,
to: 'bytes' // [!code focus]
})
versionedHashes // [!code focus]
// ^?
```
### version
* **Type:** `number`
* **Default:** `1`
Version to tag onto the hashes. Defaults to `1`.
```ts twoslash
import {
blobsToCommitments,
commitmentsToVersionedHashes,
toBlobs
} from 'viem'
import { kzg } from './kzg'
// ---cut---
const blobs = toBlobs({ data: '0x1234' })
const commitments = blobsToCommitments({ blobs, kzg })
const versionedHashes = commitmentsToVersionedHashes({
commitments,
version: 69, // [!code focus]
})
```
# commitmentToVersionedHash
Transform a commitment to it's versioned hash.
## Import
```ts twoslash
import { commitmentToVersionedHash } from 'viem'
```
## Usage
:::code-group
```ts twoslash [example.ts]
import {
blobsToCommitments,
commitmentToVersionedHash,
toBlobs
} from 'viem'
import { kzg } from './kzg'
const blobs = toBlobs({ data: '0x1234' })
const [commitment] = blobsToCommitments({ blobs, kzg })
const versionedHashes = commitmentToVersionedHash({ // [!code focus]
commitment, // [!code focus]
}) // [!code focus]
```
```ts twoslash [kzg.ts] filename="kzg.ts"
// @noErrors
import * as cKzg from 'c-kzg'
import { setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
export const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
```
:::
## Returns
`Hex | ByteArray`
Versioned hash corresponding to the commitment.
## Parameters
### commitment
* **Type:** `Hex | ByteArray`
Commitment to transform into a versioned hash.
```ts twoslash
import {
blobsToCommitments,
commitmentToVersionedHash,
toBlobs
} from 'viem'
import { kzg } from './kzg'
// ---cut---
const blobs = toBlobs({ data: '0x1234' })
const [commitment] = blobsToCommitments({ blobs, kzg })
const versionedHashes = commitmentToVersionedHash({
commitment, // [!code focus]
})
```
### to
* **Type:** `"bytes" | "hex"`
The output type.
```ts twoslash
import {
blobsToCommitments,
commitmentToVersionedHash,
toBlobs
} from 'viem'
import { kzg } from './kzg'
// ---cut---
const blobs = toBlobs({ data: '0x1234' })
const [commitment] = blobsToCommitments({ blobs, kzg })
const versionedHashes = commitmentToVersionedHash({
commitment,
to: 'bytes' // [!code focus]
})
versionedHashes // [!code focus]
// ^?
```
### version
* **Type:** `number`
* **Default:** `1`
Version to tag onto the hash. Defaults to `1`.
```ts twoslash
import {
blobsToCommitments,
commitmentToVersionedHash,
toBlobs
} from 'viem'
import { kzg } from './kzg'
// ---cut---
const blobs = toBlobs({ data: '0x1234' })
const [commitment] = blobsToCommitments({ blobs, kzg })
const versionedHashes = commitmentToVersionedHash({
commitment,
version: 69, // [!code focus]
})
```
# compactSignatureToSignature
Parses a [EIP-2098](https://eips.ethereum.org/EIPS/eip-2098) compact signature into signature format.
## Import
```ts
import { compactSignatureToSignature } from 'viem'
```
## Usage
```ts
import { compactSignatureToSignature } from 'viem'
compactSignatureToSignature({ // [!code focus:10]
r: '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90',
yParityAndS:
'0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064',
})
// {
// r: '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90',
// s: '0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064',
// yParity: 0,
// }
```
## Returns
[`Signature`](/docs/glossary/types#signature)
The signature.
## Parameters
### compactSignature
The compact signature.
* **Type:** [`CompactSignature`](/docs/glossary/types#CompactSignature)
# concat
Concatenates a set of hex values or byte arrays.
## Install
```ts
import { concat } from 'viem'
```
## Usage
```ts
import { concat } from 'viem'
concat(['0x00000069', '0x00000420'])
// 0x0000006900000420
concat([new Uint8Array([69]), new Uint8Array([420])])
// Uint8Array [69, 420]
```
## Returns
`Hex | ByteArray`
The concatenated value.
# defineKzg
Defines a [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) compatible [KZG interface](https://notes.ethereum.org/@vbuterin/proto_danksharding_faq#How-%E2%80%9Ccomplicated%E2%80%9D-and-%E2%80%9Cnew%E2%80%9D-is-KZG). The KZG interface is used in the blob transaction signing process to generate KZG commitments & proofs.
`defineKzg` accepts a KZG interface that implements two functions:
* `blobToKzgCommitment`: A function that takes a blob and returns it's KZG commitment.
* `computeBlobKzgProof`: A function that takes a blob and it's commitment, and returns the KZG proof.
A couple of KZG implementations we recommend are:
* [c-kzg](https://github.com/ethereum/c-kzg-4844): Node.js bindings to c-kzg.
* [kzg-wasm](https://github.com/ethereumjs/kzg-wasm): WebAssembly bindings to c-kzg.
## Import
```ts twoslash
import { defineKzg } from 'viem'
```
## Usage
```ts twoslash
// @noErrors
import * as cKzg from 'c-kzg'
import { defineKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
cKzg.loadTrustedSetup(mainnetTrustedSetupPath)
const kzg = defineKzg(cKzg)
```
## Returns
`Kzg`
The KZG interface.
## Parameters
### blobToKzgCommitment
* **Type:** `(blob: ByteArray) => ByteArray`
Convert a blob to a KZG commitment.
### computeBlobKzgProof
* **Type:** `(blob: ByteArray, commitment: ByteArray) => ByteArray`
Given a blob, return the KZG proof that is used to verify it against the commitment.
# extractChain
Extracts a type-safe chain by ID from a set of chains.
## Usage
```ts
import { extractChain } from 'viem'
import { mainnet, base, optimism, zora } from 'viem/chains'
const optimism = extractChain({
chains: [mainnet, base, optimism, zora],
id: 10,
})
optimism.id
// ^? (property) id: 10
optimism.name
// ^? (property) name: "OP Mainnet"
```
It is also possible to use **all chains** from the `viem/chains` module:
```ts
import { extractChain } from 'viem'
import { mainnet, base, optimism, zora } from 'viem/chains' // [!code --]
import * as chains from 'viem/chains' // [!code ++]
const optimism = extractChain({
chains: [mainnet, base, optimism, zora], // [!code --]
chains: Object.values(chains), // [!code ++]
id: 10,
})
optimism.id
// ^? (property) id: 10
optimism.name
// ^? (property) name: "OP Mainnet"
```
:::warning
By importing all chains from `viem/chains`, this will significantly increase the size of your bundle. It is only recommended to use this method where bundle size is not a concern (ie. server-side, scripts, etc).
:::
## Returns
* **Type:** `Chain` (inferred)
The extracted chain.
## Parameters
### chains
* **Type:** `readonly Chain[]`
The set of chains where the chain will be extracted from.
### id
* **Type:** `number`
The ID of the chain to extract.
# formatEther
Converts numerical wei to a string representation of ether.
## Import
```ts
import { formatEther } from 'viem'
```
## Usage
```ts
import { formatEther } from 'viem'
formatEther(1000000000000000000n) // [!code focus:2]
// '1'
```
## Returns
`string`
## Parameters
### value
* **Type:** `bigint`
The wei value.
# formatGwei
Converts numerical wei to a string representation of gwei.
## Import
```ts
import { formatGwei } from 'viem'
```
## Usage
```ts
import { formatGwei } from 'viem'
formatGwei(1000000000n) // [!code focus:2]
// '1'
```
## Returns
`string`
## Parameters
### value
* **Type:** `bigint`
The wei value.
# formatUnits
Divides a number by a given exponent of base 10 (10exponent), and formats it into a string representation of the number.
## Import
```ts
import { formatUnits } from 'viem'
```
## Usage
```ts
import { formatUnits } from 'viem'
formatUnits(420000000000n, 9) // [!code focus:2]
// '420'
```
## Returns
`string`
## Parameters
### value
* **Type:** `bigint`
The number to divide.
### exponent
* **Type:** `number`
The exponent.
# fromBase58
Coming soon.
# fromBase64
Coming soon.
# fromBlobs
Transforms Viem-shaped blobs into the originating data.
:::warning
This function transforms data from Viem-shaped blobs. It is designed to be used with Viem's `toBlobs` function to convert arbitrary data to blobs.
:::
## Import
```ts twoslash
import { fromBlobs } from 'viem'
```
## Usage
```ts twoslash [example.ts]
import { fromBlobs } from 'viem'
const data = fromBlobs({ blobs: ['0x...'] })
```
## Returns
`Hex | ByteArray`
Data extracted from blobs.
## Parameters
### blobs
* **Type:** `Hex[] | ByteArray[]`
Transforms blobs into the originating data.
```ts twoslash
import { fromBlobs } from 'viem'
const data = fromBlobs({
blobs: ['0x...'] // [!code focus]
})
```
### to
* **Type:** `"bytes" | "hex"`
The output type.
```ts twoslash
import { fromBlobs } from 'viem'
const data = fromBlobs({
blobs: ['0x...'],
to: 'bytes' // [!code focus]
})
data // [!code focus]
// ^?
```
# fromBytes
Decodes a byte array to a string, hex value, boolean or number.
Shortcut Functions:
* [bytesToHex](#bytestohex)
* [bytesToString](#bytestostring)
* [bytesToNumber](#bytestonumber)
* [bytesToBigInt](#bytestobigint)
* [bytesToBool](#bytestobool)
## Import
```ts
import { fromBytes } from 'viem'
```
## Usage
```ts
import { fromBytes } from 'viem'
fromBytes(
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]),
'string'
)
// 'Hello world'
fromBytes(
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]),
'hex'
)
// '0x48656c6c6f20576f726c6421'
fromBytes(new Uint8Array([1, 164]), 'number')
// 420
fromBytes(new Uint8Array([1]), 'boolean')
// true
```
## Returns
`string | Hex | number | bigint | boolean`
The targeted type.
## Parameters
### value
* **Type:** `ByteArray`
The byte array to decode.
### toOrOptions
* **Type:** `"string" | "hex" | "number" | "bigint" | "boolean" | Options`
The output type or options.
```ts
fromBytes(
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]),
'string' // [!code focus]
)
// 'Hello world'
```
```ts
fromBytes(
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
{ // [!code focus]
size: 32, // [!code focus]
to: 'string' // [!code focus]
} // [!code focus]
)
// 'Hello world'
```
## Shortcut Functions
### bytesToHex
* **Type:** `Hex`
Decodes a byte array to a hex value.
```ts
import { bytesToHex } from 'viem'
bytesToHex( // [!code focus:4]
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
)
// '0x48656c6c6f20576f726c6421'
bytesToHex( // [!code focus:5]
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
{ size: 32 }
)
// '0x48656c6c6f20576f726c64210000000000000000000000000000000000000000'
```
### bytesToString
* **Type:** `Hex`
Decodes a byte array to a string.
```ts
import { bytesToString } from 'viem'
bytesToString( // [!code focus:4]
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
)
// 'Hello world'
bytesToString( // [!code focus:5]
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
{ size: 32 }
)
// 'Hello world'
```
### bytesToNumber
* **Type:** `number`
Decodes a byte array to a number.
```ts
import { bytesToNumber } from 'viem'
bytesToNumber(new Uint8Array([1, 164])) // [!code focus:2]
// 420
bytesToNumber( // [!code focus:5]
new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 164]),
{ size: 32 }
)
// 420
```
### bytesToBigInt
* **Type:** `number`
Decodes a byte array to a number.
```ts
import { bytesToBigInt } from 'viem'
bytesToBigInt( // [!code focus:4]
new Uint8Array([12, 92, 243, 146, 17, 135, 111, 181, 229, 136, 67, 39, 250, 86, 252, 11, 117])
)
// 4206942069420694206942069420694206942069n
bytesToBigInt( // [!code focus:5]
new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 92, 243, 146, 17, 135, 111, 181, 229, 136, 67, 39, 250, 86, 252, 11, 117]),
{ size: 32 }
)
// 4206942069420694206942069420694206942069n
```
### bytesToBool
* **Type:** `boolean`
Decodes a byte array to a boolean.
```ts
import { bytesToBool } from 'viem'
bytesToBool(new Uint8Array([1])) // [!code focus:2]
// true
bytesToBool( // [!code focus:5]
new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
{ size: 32 }
)
// true
```
# fromHex
Decodes a hex value to a string, number or byte array.
Shortcut Functions:
* [hexToNumber](#hextonumber)
* [hexToBigInt](#hextobigint)
* [hexToString](#hextostring)
* [hexToBytes](#hextobytes)
* [hexToBool](#hextobool)
## Import
```ts
import { fromHex } from 'viem'
```
## Usage
```ts
import { fromHex } from 'viem'
fromHex('0x1a4', 'number')
// 420
fromHex('0xc5cf39211876fb5e5884327fa56fc0b75', 'bigint')
// 4206942069420694206942069420694206942069n
fromHex('0x48656c6c6f20776f726c642e', 'string')
// "Hello world"
fromHex('0x48656c6c6f20576f726c6421', 'bytes')
// Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
fromHex('0x1', 'boolean')
// true
```
## Returns
`string | bigint | number | ByteArray`
The targeted type.
## Parameters
### hex
* **Type:** `Hex`
The hex value to decode.
### toOrOptions
* **Type:** `"string" | "hex" | "number" | "bigint" | "boolean" | Options`
The output type or options.
```ts
fromHex(
'0x48656c6c6f20776f726c642e',
'string' // [!code focus]
)
// 'Hello world'
```
```ts
fromHex(
'0x48656c6c6f20776f726c642e0000000000000000000000000000000000000000',
{ // [!code focus]
size: 32, // [!code focus]
to: 'string' // [!code focus]
} // [!code focus]
)
// 'Hello world'
```
## Shortcut Functions
### hexToNumber
* **Type:** `Hex`
Decodes a hex value to a number.
```ts
import { hexToNumber } from 'viem'
hexToNumber('0x1a4')
// 420
hexToNumber(
'0x00000000000000000000000000000000000000000000000000000000000001a4',
{ size: 32 }
)
// 420
```
### hexToBigInt
* **Type:** `Hex`
Decodes a hex value to a bigint.
```ts
import { hexToBigInt } from 'viem'
hexToBigInt('0xc5cf39211876fb5e5884327fa56fc0b75')
// 4206942069420694206942069420694206942069n
hexToBigInt(
'0x0000000000000000000000000000000c5cf39211876fb5e5884327fa56fc0b75',
{ size: 32 }
)
// 4206942069420694206942069420694206942069n
```
### hexToString
* **Type:** `Hex`
Decodes a hex value to a string.
```ts
import { hexToString } from 'viem'
hexToString('0x48656c6c6f20576f726c6421')
// "Hello World!"
hexToString(
'0x48656c6c6f20576f726c64210000000000000000000000000000000000000000',
{ size: 32 }
)
// "Hello World!"
```
### hexToBytes
* **Type:** `Hex`
Decodes a hex value to a byte array.
```ts
import { hexToBytes } from 'viem'
hexToBytes('0x48656c6c6f20576f726c6421')
// Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
hexToBytes(
'0x48656c6c6f20576f726c64210000000000000000000000000000000000000000',
{ size: 32 }
)
// Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
```
### hexToBool
* **Type:** `Hex`
Decodes a hex value to a boolean.
```ts
import { hexToBool } from 'viem'
hexToBool('0x1')
// true
hexToBool(
'0x00000000000000000000000000000000000000000000000000000000000001',
{ size: 32 }
)
// true
```
# fromRlp
Decodes a [Recursive-Length Prefix (RLP)](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp) value into a decoded hex value or byte array.
## Import
```ts
import { fromRlp } from 'viem'
```
## Usage
```ts
import { fromRlp } from 'viem'
fromRlp('0x850123456789', 'hex')
// "0x123456789"
fromRlp('0xc67f7f838081e8', 'hex')
// ['0x7f', '0x7f', '0x8081e8']
fromRlp('0x89010203040506070809', 'bytes')
// Uint8Array [1, 2, 3, 4, 5, 6, 7, 8, 9]
fromRlp(new Uint8Array ([133, 1, 35, 69, 103, 137]), 'hex')
// "0x123456789"
```
## Returns
`Hex | ByteArray`
The hex value or byte array.
## Parameters
### value
* **Type:** `Hex | ByteArray`
The RLP value to decode.
### to
* **Type:** `"bytes" | "hex"`
The output type.
# getAddress
Converts an address into an address that is [checksum encoded](https://eips.ethereum.org/EIPS/eip-55). Supports [EIP-1191](https://eips.ethereum.org/EIPS/eip-1191).
## Import
```ts
import { getAddress } from 'viem'
```
## Usage
```ts
import { getAddress } from 'viem'
getAddress('0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac') // [!code focus:2]
// '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'
```
## Returns
[`Address`](/docs/glossary/types#address)
The checksummed address.
## Parameters
### address
* **Type:** `string`
An Ethereum address.
### chainId (optional)
* **Type:** `number`
The chain ID of the network the address is on. Complies to [EIP-1191](https://eips.ethereum.org/EIPS/eip-1191).
:::warning\[Warning]
EIP-1191 checksum addresses are generally not backwards compatible with
the wider Ethereum ecosystem, meaning it will break when validated against
an application/tool that relies on EIP-55 checksum encoding (checksum without chainId).
It is highly recommended to not use this feature unless you know what you are doing.
See more: https://github.com/ethereum/EIPs/issues/1121
:::
# getContractAddress
Retrieves the contract address generated by the [`CREATE`](https://ethereum.stackexchange.com/a/68945) or [`CREATE2`](https://eips.ethereum.org/EIPS/eip-1014) opcode – invoked after deploying a contract to the network.
## Import
```ts
import { getContractAddress } from 'viem'
```
## Usage
```ts
import { getContractAddress } from 'viem'
getContractAddress({ // [!code focus:99]
from: '0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b',
nonce: 69420n
})
// '0xDf2e056f7062790dF95A472f691670717Ae7b1B6'
```
## Returns
[`Address`](/docs/glossary/types#address)
The contract address.
## Parameters
### from (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
The address the contract was deployed from.
```ts
getContractAddress({
from: '0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b', // [!code focus:1]
nonce: 69420n
})
```
### nonce (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
The nonce of the transaction which deployed the contract.
```ts
getContractAddress({
from: '0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b',
nonce: 69420n // [!code focus:1]
})
```
### opcode (optional)
* **Type:** `"CREATE" | "CREATE2"`
* **Default:** `"CREATE"`
The opcode to invoke the contract deployment. Defaults to `"CREATE"`.
[Learn more about `CREATE2`](https://eips.ethereum.org/EIPS/eip-1014).
```ts
getContractAddress({
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
from: '0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b',
opcode: 'CREATE2', // [!code focus:1]
salt: toBytes('wagmi'),
})
```
### bytecode (optional)
* **Type:** `ByteArray` | [`Hex`](/docs/glossary/types#hex)
* **Only applicable for `opcode: 'CREATE2'` deployments**
The to-be-deployed contract’s bytecode
```ts
getContractAddress({
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...', // [!code focus:1]
from: '0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b',
opcode: 'CREATE2',
salt: toBytes('wagmi'),
})
```
### bytecodeHash (optional)
* **Type:** `ByteArray` | [`Hex`](/docs/glossary/types#hex)
* **Only applicable for `opcode: 'CREATE2'` deployments**
A hash of the to-be-deployed contract’s bytecode
```ts
getContractAddress({
bytecodeHash: '0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54', // [!code focus:1]
from: '0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b',
opcode: 'CREATE2',
salt: toBytes('wagmi'),
})
```
### salt (optional)
* **Type:** `ByteArray` | [`Hex`](/docs/glossary/types#hex)
* **Only applicable for `opcode: 'CREATE2'` deployments**
An arbitrary value provided by the sender.
```ts
getContractAddress({
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
from: '0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b',
opcode: 'CREATE2',
salt: toBytes('wagmi'), // [!code focus:1]
})
```
# hashMessage
Calculates an Ethereum-specific hash in [EIP-191 format](https://eips.ethereum.org/EIPS/eip-191): `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`.
## Import
```ts
import { hashMessage } from 'viem'
```
## Usage
```ts
import { hashMessage } from 'viem'
hashMessage('hello world') // [!code focus:2]
// 0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68
// Hash a hex data value. // [!code focus:3]
hashMessage({ raw: '0x68656c6c6f20776f726c64' })
// 0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68
// Hash a bytes data value. // [!code focus:6]
hashMessage({
raw: Uint8Array.from([
104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100,
])})
// 0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The hashed message.
## Parameters
### message
Message to hash.
* **Type:** `string | { raw: Hex | ByteArray }`
# hashTypedData \[Hashes EIP-712 typed data.]
Calculates an Ethereum-specific hash in [EIP-712 format](https://eips.ethereum.org/EIPS/eip-712): `keccak256("\x19\x01" ‖ domainSeparator ‖ hashStruct(message))`.
## Import
```ts
import { hashTypedData } from 'viem'
```
## Usage
```ts
import { hashTypedData } from 'viem'
hashTypedData({
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The hashed message.
## Parameters
### domain
**Type:** `TypedDataDomain`
The typed data domain.
```ts
const hash = hashTypedData({
domain: { // [!code focus:6]
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### types
The type definitions for the typed data.
```ts
const hash = hashTypedData({
domain,
types: { // [!code focus:11]
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### primaryType
**Type:** Inferred `string`.
The primary type to extract from `types` and use in `value`.
```ts
const hash = hashTypedData({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [ // [!code focus:5]
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail', // [!code focus]
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### message
**Type:** Inferred from `types` & `primaryType`.
```ts
const hash = hashTypedData({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: { // [!code focus:11]
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
# isAddress
Checks if the address is valid. By default, it also verifies whether the address is in checksum format.
## Import
```ts
import { isAddress } from 'viem'
```
## Usage
```ts
import { isAddress } from 'viem'
isAddress('0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC') // [!code focus:2]
// true
```
## Returns
`boolean`
Whether or not the address is valid.
## Parameters
### address
* **Type:** `string`
An Ethereum address.
### options.strict (optional)
* **Type:** `boolean`
* **Default:** `true`
Enables strict mode. If enabled, it also verifies whether the address is in checksum format.
```ts
isAddress('0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', { strict: false })
// true
isAddress('0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac', { strict: true })
// false
isAddress('lol', { strict: false })
// false
```
# isAddressEqual
Checks if the given addresses (checksummed) are equal.
## Import
```ts
import { isAddressEqual } from 'viem'
```
## Usage
```ts
import { isAddressEqual } from 'viem'
isAddressEqual('0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac', '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC') // [!code focus:2]
// true
```
## Returns
`boolean`
Whether or not the addresses are equal.
# isBytes
Checks whether the value is a byte array or not.
## Install
```ts
import { isBytes } from 'viem'
```
## Usage
```ts
import { isBytes } from 'viem'
isBytes(new Uint8Array([1, 69, 420]))
// true
isBytes([1, 69, 420])
// false
```
## Returns
`boolean`
Returns truthy is the value is a byte array.
# isErc6492Signature
Checks whether the signature is in [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492) format.
## Import
```ts
import { isErc6492Signature } from 'viem/utils'
```
## Usage
```ts twoslash
import { isErc6492Signature } from 'viem/utils'
const result = isErc6492Signature('0x000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000004deadbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041a461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b000000000000000000000000000000000000000000000000000000000000006492649264926492649264926492649264926492649264926492649264926492')
```
## Returns
`boolean`
Whether the signature is in ERC-6492 format.
## Parameters
### signature
* **Type:** [`Hex`](/docs/glossary/types#hex)
The signature to check.
# isHash
Checks if a string is a valid 32-byte hex hash.
## Import
```ts
import { isHash } from 'viem'
```
## Usage
```ts
import { isHash } from 'viem'
isHash('0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68') // [!code focus:3]
// true
isHash('0xa5cc3c03994db5b0d9a5eEdD10Cabab0813678ac') // [!code focus:4]
// false
```
## Returns
`boolean`
Whether the string is a valid 32-byte hex hash.
## Parameters
### hash
The string to check.
* **Type:** `string`
# isHex
Checks whether the value is a hex value or not.
## Install
```ts
import { isHex } from 'viem'
```
## Usage
```ts
import { isHex } from 'viem'
isHex('0x1a4')
// true
isHex('0x1a4z')
isHex('foo')
// false
```
## Returns
`boolean`
Returns truthy is the value is a hex value.
## Parameters
### value
* **Type:** `unknown`
The value to check.
```ts
isHex(
'0x1a4' // [!code focus]
)
// true
```
### options.strict
* **Type:** `boolean`
* **Default:** `true`
When enabled, checks if the value strictly consists of only hex characters (`"0x[0-9a-fA-F]*"`).
When disabled, checks if the value loosely matches hex format (`value.startsWith('0x')`).
```ts
isHex('0xlol', { strict: false })
// true
isHex('0xlol', { strict: true })
// false
isHex('lol', { strict: false })
// false
```
# keccak256
Calculates the [Keccak256](https://en.wikipedia.org/wiki/SHA-3) hash of a byte array or hex value.
This function is a re-export of `keccak_256` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes) – an audited & minimal JS hashing library.
## Install
```ts
import { keccak256 } from 'viem'
```
## Usage
```ts
import { keccak256 } from 'viem'
keccak256(new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
// 0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0
keccak256('0xdeadbeef')
// 0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1
// hash utf-8 string
keccak256(toHex('hello world'))
// 0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0
```
## Returns
`Hex | ByteArray`
The hashed value.
## Parameters
### value
* **Type:** `Hex | ByteArray`
The hex value or byte array to hash.
### to
* **Type:** `"bytes" | "hex"`
* **Default:** `"hex"`
The output type.
```ts
import { keccak256 } from 'viem'
keccak256(
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33],
'bytes' // [!code focus]
)
// Uint8Array [62, 162, 241, 208, 171, 243, 252, 102, 207, 41, 238, 187, 112, 203, 212, 231, 254, 118, 46, 248, 160, 155, 204, 6, 200, 237, 246, 65, 35, 10, 254, 192] // [!code focus]
```
# pad
Pads a hex value or byte array with leading or trailing zeros.
## Install
```ts
import { pad } from 'viem'
```
## Usage
By default, `pad` will pad a value with leading zeros up to 32 bytes (64 hex chars).
```ts
import { pad } from 'viem'
pad('0xa4e12a45')
// 0x00000000000000000000000000000000000000000000000000000000a4e12a45
pad(new Uint8Array([1, 122, 51, 123]))
// Uint8Array [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,122,51,123]
```
## Returns
`Hex | ByteArray`
The value with padded zeros.
## Parameters
### dir
* **Type:** `"left" | "right"`
* **Default:** `"left"`
The direction in which to pad the zeros – either leading (left), or trailing (right).
```ts
pad('0xa4e12a45', {
dir: 'right'
})
// 0xa4e12a4500000000000000000000000000000000000000000000000000000000
```
### size
* **Type:** `number`
* **Default:** `32`
Size (in bytes) of the targeted value.
```ts
pad('0xa4e12a45', {
size: 16
})
// 0x000000000000000000000000a4e12a45
```
# parseCompactSignature
Parses a hex formatted compact signature into a structured ("split") compact signature.
## Import
```ts
import { parseCompactSignature } from 'viem'
```
## Usage
```ts
import { parseCompactSignature } from 'viem'
parseCompactSignature('0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76939c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793') // [!code focus:7]
/**
* {
* r: '0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76',
* yParityAndS: '0x939c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793'
* }
*/
```
## Returns
[`CompactSignature`](/docs/glossary/types#compactsignature)
The structured ("split") compact signature.
## Parameters
### signatureHex
The compact signature in hex format.
* **Type:** [`Hex`](/docs/glossary/types#hex)
# parseErc6492Signature
Parses a hex-formatted [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492) flavoured signature.
If the signature is not in ERC-6492 format, then the underlying (original) signature is returned.
## Import
```ts
import { parseErc6492Signature } from 'viem/utils'
```
## Usage
```ts twoslash
import { parseErc6492Signature } from 'viem/utils'
const { // [!code focus:99]
address,
data,
signature,
} = parseErc6492Signature('0x000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000004deadbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041a461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b000000000000000000000000000000000000000000000000000000000000006492649264926492649264926492649264926492649264926492649264926492')
/**
* {
* address: '0xCafEBAbECAFEbAbEcaFEbabECAfebAbEcAFEBaBe',
* data: '0xdeadbeef',
* signature: '0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b'
* }
*/
```
## Returns
`ParseErc6492SignatureReturnType`
The ERC-6492 signature components.
## Parameters
### signature
* **Type:** [`Hex`](/docs/glossary/types#hex)
The ERC-6492 signature in hex format.
# parseEther
Converts a string representation of ether to numerical wei.
## Import
```ts
import { parseEther } from 'viem'
```
## Usage
```ts
import { parseEther } from 'viem'
parseEther('420') // [!code focus:2]
// 420000000000000000000n
```
## Returns
`bigint`
## Parameters
### value
* **Type:** `string`
The string representation of ether.
# parseGwei
Converts a string representation of gwei to numerical wei.
## Import
```ts
import { parseGwei } from 'viem'
```
## Usage
```ts
import { parseGwei } from 'viem'
parseGwei('420') // [!code focus:2]
// 420000000000n
```
## Returns
`bigint`
## Parameters
### value
* **Type:** `string`
The string representation of gwei.
# parseSignature
Parses a hex formatted signature into a structured ("split") signature.
## Import
```ts
import { parseSignature } from 'viem'
```
## Usage
```ts
import { parseSignature } from 'viem'
parseSignature('0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db81c') // [!code focus:8]
/**
* {
* r: '0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf',
* s: '0x4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db8',
* yParity: 1
* }
*/
```
## Returns
[`Signature`](/docs/glossary/types#signature)
The structured ("split") signature.
## Parameters
### signatureHex
The signature in hex format.
* **Type:** [`Hex`](/docs/glossary/types#hex)
# parseTransaction
Parses a serialized RLP-encoded transaction. Supports signed & unsigned EIP-1559, EIP-2930 and Legacy Transactions.
## Import
```ts
import { parseTransaction } from 'viem'
```
## Usage
```ts
import { parseTransaction } from 'viem'
const transaction = parseTransaction('0x02ef0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0')
```
## Returns
`TransactionSerializable`
The parsed transaction object.
## Parameters
### serializedTransaction
* **Type:** `Hex`
The serialized transaction.
# parseUnits
Multiplies a string representation of a number by a given exponent of base 10 (10exponent).
## Import
```ts
import { parseUnits } from 'viem'
```
## Usage
```ts
import { parseUnits } from 'viem'
parseUnits('420', 9) // [!code focus:2]
// 420000000000n
```
## Returns
`bigint`
## Parameters
### value
* **Type:** `string`
The string representation of the number to multiply.
### exponent
* **Type:** `number`
The exponent.
# recoverAddress
Recovers the original signing address from a hash & signature.
## Usage
```ts [example.ts]
import { recoverAddress } from 'viem'
const address = await recoverAddress({
hash: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68',
signature: '0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c'
})
// 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
```
## Returns
[`Address`](/docs/glossary/types#address)
The signing address.
## Parameters
### hash
* **Type:** `string`
The hash that was signed.
```ts
const address = await recoverAddress({
hash: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', // [!code focus]
signature: '0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c'
})
```
### signature
* **Type:** `Hex | ByteArray | Signature`
The signature of the hash.
```ts
const address = await recoverAddress({
hash: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68',
signature: '0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c' // [!code focus]
})
```
# recoverMessageAddress
Recovers the original signing address from a message & signature.
Useful for obtaining the address of a message that was signed with [`signMessage`](/docs/actions/wallet/signMessage).
## Usage
:::code-group
```ts [example.ts]
import { recoverMessageAddress } from 'viem';
import { account, walletClient } from './config'
const signature = await walletClient.signMessage({
account,
message: 'hello world',
})
const address = await recoverMessageAddress({ // [!code focus:99]
message: 'hello world',
signature,
})
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
export const walletClient = createWalletClient({
transport: custom(window.ethereum)
})
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount('0x...')
```
:::
## Returns
[`Address`](/docs/glossary/types#address)
The signing address.
## Parameters
### message
* **Type:** `string | { raw: Hex | ByteArray }`
The message that was signed.
By default, viem verifies the UTF-8 representation of the message.
```ts
const address = await recoverMessageAddress({
message: 'hello world', // [!code focus]
signature: '0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c'
})
```
To verify the data representation of the message, you can use the `raw` attribute.
```ts
const address = await recoverMessageAddress({
message: { raw: '0x68656c6c6f20776f726c64' }, // [!code focus:1]
signature: '0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c'
})
```
### signature
* **Type:** `Hex | ByteArray | Signature`
The signature of the message.
```ts
const address = await recoverMessageAddress({
message: 'hello world',
signature: '0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c' // [!code focus]
})
```
# recoverPublicKey
Recovers the original signing 64-byte public key from a hash & signature.
## Usage
```ts [example.ts]
import { recoverPublicKey } from 'viem'
const publicKey = await recoverPublicKey({
hash: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68',
signature: '0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c'
})
// 0x048318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed753547f11ca8696646f2f3acb08e31016afac23e630c5d11f59f61fef57b0d2aa5
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The signing public key.
## Parameters
### hash
* **Type:** `string`
The hash that was signed.
```ts
const publicKey = await recoverPublicKey({
hash: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68', // [!code focus]
signature: '0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c'
})
```
### signature
* **Type:** `Hex | ByteArray | Signature`
The signature of the hash.
```ts
const publicKey = await recoverPublicKey({
hash: '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68',
signature: '0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c' // [!code focus]
})
```
# recoverTransactionAddress
Recovers the original signing address from a transaction & signature.
## Usage
:::code-group
```ts twoslash [example.ts]
import { recoverTransactionAddress } from 'viem'
import { walletClient } from './client'
const request = await walletClient.prepareTransactionRequest({
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
const serializedTransaction = await walletClient.signTransaction(request)
const address = await recoverTransactionAddress({ // [!code focus:99]
serializedTransaction,
})
```
```ts [client.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
```ts twoslash [config.ts (Local Account)] filename="client.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
transport: http()
})
```
:::
## Returns
[`Address`](/docs/glossary/types#address)
The signing address.
## Parameters
### serializedTransaction
* **Type:** `TransactionSerialized`
The RLP serialized transaction.
### signature (optional)
* **Type:** `Signature | Hex | ByteArray`
* **Default:** Signature inferred on `serializedTransaction` (if exists)
The signature.
# recoverTypedDataAddress
Recovers the original signing address from EIP-712 typed data & signature.
Useful for obtaining the address of a message that was signed with [`signTypedData`](/docs/actions/wallet/signTypedData).
## Usage
:::code-group
```ts [example.ts]
import { recoverTypedDataAddress } from 'viem'
import { account, walletClient } from './client'
const message = {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
} as const
const signature = await walletClient.signTypedData({
account,
domain,
types,
primaryType: 'Mail',
message,
})
const address = await recoverTypedDataAddress({ // [!code focus:99]
domain,
types,
primaryType: 'Mail',
message,
signature,
})
```
```ts [data.ts]
// All properties on a domain are optional
export const domain = {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
} as const
// The named list of all type definitions
export const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
} as const
```
```ts [client.ts]
import { createWalletClient, custom, getAccount } from 'viem'
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
export const walletClient = createWalletClient({
transport: custom(window.ethereum)
})
```
:::
## Returns
[`Address`](/docs/glossary/types#address)
The signing address.
## Parameters
### domain
**Type:** `TypedDataDomain`
The typed data domain.
```ts
const address = await recoverTypedDataAddress({
domain: { // [!code focus:6]
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...'
})
```
### types
The type definitions for the typed data.
```ts
const address = await recoverTypedDataAddress({
domain,
types: { // [!code focus:11]
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...'
})
```
### primaryType
**Type:** Inferred `string`.
The primary type to extract from `types` and use in `value`.
```ts
const address = await recoverTypedDataAddress({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [ // [!code focus:5]
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail', // [!code focus]
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...'
})
```
### message
**Type:** Inferred from `types` & `primaryType`.
```ts
const address = await recoverTypedDataAddress({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: { // [!code focus:11]
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...'
})
```
### signature
* **Type:** `Hex | ByteArray`
The signature of the typed data.
```ts
const address = await recoverTypedDataAddress({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...' // [!code focus]
})
```
# ripemd160
Calculates the [Ripemd160](https://en.wikipedia.org/wiki/RIPEMD) hash of a byte array or hex value.
This function is a re-export of `ripemd160` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes) – an audited & minimal JS hashing library.
## Install
```ts
import { ripemd160 } from 'viem'
```
## Usage
```ts
import { ripemd160 } from 'viem'
ripemd160(new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
// 0x8476ee4631b9b30ac2754b0ee0c47e161d3f724c
ripemd160('0xdeadbeef')
// 0x226821c2f5423e11fe9af68bd285c249db2e4b5a
```
## Returns
`Hex | ByteArray`
The hashed value.
## Parameters
### value
* **Type:** `Hex | ByteArray`
The hex value or byte array to hash.
### to
* **Type:** `"bytes" | "hex"`
* **Default:** `"hex"`
The output type.
```ts
import { ripemd160 } from 'viem'
ripemd160(
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33],
'bytes' // [!code focus]
)
// Uint8Array [132, 118, 238, 70, 49, 185, 179, 10, 194, 117, 75, 14, 224, 196, 126, 22, 29, 63, 114, 76] // [!code focus]
```
# serializeCompactSignature
Serializes a [EIP-2098](https://eips.ethereum.org/EIPS/eip-2098) compact signature into hex format.
## Import
```ts
import { serializeCompactSignature } from 'viem'
```
## Usage
```ts
import { serializeCompactSignature } from 'viem'
serializeCompactSignature({ // [!code focus:8]
r: '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90',
yParityAndS:
'0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064',
})
// "0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b907e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064"
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The hex formatted signature.
## Parameters
### compactSignature
The compact signature.
* **Type:** [`CompactSignature`](/docs/glossary/types#CompactSignature)
# serializeErc6492Signature
Serializes a [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492) flavoured signature into hex format.
## Import
```ts
import { serializeErc6492Signature } from 'viem/utils'
```
## Usage
```ts twoslash
import { serializeErc6492Signature } from 'viem/utils'
serializeErc6492Signature({ // [!code focus:99]
address: '0xcafebabecafebabecafebabecafebabecafebabe',
data: '0xdeadbeef',
signature: '0x41a461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b',
})
// "0x000000000000000000000000cafebabecafebabecafebabecafebabecafebabe000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000004deadbeef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041a461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b000000000000000000000000000000000000000000000000000000000000006492649264926492649264926492649264926492649264926492649264926492"
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The hex formatted signature.
## Parameters
### address
* **Type:** `Address`
The ERC-4337 Account Factory or preparation address to use for counterfactual verification.
### data
* **Type:** `Hex`
Calldata to pass to deploy the ERC-4337 Account (if not deployed) for counterfactual verification.
### signature
* **Type:** `Hex`
The original signature.
# serializeSignature
Serializes a structured signature into hex format.
## Import
```ts
import { serializeSignature } from 'viem'
```
## Usage
```ts
import { serializeSignature } from 'viem'
serializeSignature({
r: '0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf',
s: '0x4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db8',
yParity: 1
}) // [!code focus:8]
// "0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db81c"
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The hex formatted signature.
## Parameters
### signature
The signature.
* **Type:** [`Signature`](/docs/glossary/types#signature)
# serializeTransaction
Serializes a transaction object. Supports EIP-1559, EIP-2930, and Legacy transactions.
## Import
```ts
import { serializeTransaction } from 'viem'
```
## Usage
```ts
import { serializeTransaction } from 'viem'
const serialized = serializeTransaction({
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69,
to: "0x1234512345123451234512345123451234512345",
value: parseEther('0.01'),
})
```
## Returns
Returns a template `Hex` value based on transaction type:
* `eip1559`: [TransactionSerializedEIP1559](/docs/glossary/types#TransactionSerializedEIP1559)
* `eip2930`: [TransactionSerializedEIP2930](/docs/glossary/types#TransactionSerializedEIP2930)
* `eip4844`: [TransactionSerializedEIP4844](/docs/glossary/types#TransactionSerializedEIP4844)
* `eip7702`: [TransactionSerializedEIP7702](/docs/glossary/types#TransactionSerializedEIP7702)
* `legacy`: [TransactionSerializedLegacy](/docs/glossary/types#TransactionSerializedLegacy)
## Parameters
### transaction
* **Type:** `TransactionSerializable`
The transaction object to serialize.
```ts
const serialized = serializeTransaction({
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69,
to: '0x1234512345123451234512345123451234512345',
value: parseEther('0.01'),
})
```
### signature
* **Type:** `Hex`
Optional signature to include.
```ts
const serialized = serializeTransaction({
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69,
to: '0x1234512345123451234512345123451234512345',
value: parseEther('0.01'),
}, { // [!code focus:5]
r: '0x123451234512345123451234512345123451234512345123451234512345',
s: '0x123451234512345123451234512345123451234512345123451234512345',
yParity: 1
})
```
# setupKzg
Sets up and defines a [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) compatible [KZG interface](https://notes.ethereum.org/@vbuterin/proto_danksharding_faq#How-%E2%80%9Ccomplicated%E2%80%9D-and-%E2%80%9Cnew%E2%80%9D-is-KZG). The KZG interface is used in the blob transaction signing process to generate KZG commitments & proofs.
`setupKzg` accepts a KZG interface that implements three functions:
* `loadTrustedSetup`: A function to initialize the KZG trusted setup.
* `blobToKzgCommitment`: A function that takes a blob and returns it's KZG commitment.
* `computeBlobKzgProof`: A function that takes a blob and it's commitment, and returns the KZG proof.
A couple of KZG implementations we recommend are:
* [c-kzg](https://github.com/ethereum/c-kzg-4844): Node.js bindings to c-kzg.
* [kzg-wasm](https://github.com/ethereumjs/kzg-wasm): WebAssembly bindings to c-kzg.
## Import
```ts twoslash
import { setupKzg } from 'viem'
```
## Usage
```ts twoslash
// @noErrors
import * as cKzg from 'c-kzg'
import { setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
```
### Trusted Setups
As seen above, when you set up your KZG interface, you will need to provide a trusted setup file. You can either import a trusted setup via the [`viem/node` entrypoint](#viemnode-entrypoint) (if you're using an engine that supports Node.js' `node:fs` module), or you can directly import the trusted setup `.json` via the [`viem/trusted-setups` entrypoint](#viemtrusted-setups-entrypoint).
Viem exports the following trusted setups:
* `mainnet.json`: For Ethereum Mainnet & it's Testnets (Sepolia, Goerli, etc).
* `minimal.json`: For low-resource local dev testnets, and spec-testing.
The trusted setup files are retrieved from the Ethereum [consensus-specs repository](https://github.com/ethereum/consensus-specs/tree/dev/presets).
#### `viem/node` Entrypoint
Viem exports **paths to the trusted setup** via the `viem/node` entrypoint, designed to be used with `setupKzg`.
```ts
import {
mainnetTrustedSetupPath,
minimalTrustedSetupPath,
} from 'viem/node'
```
#### `viem/trusted-setups` Entrypoint
Alternatively, you can directly import the **contents of the trusted setup** file from the `viem/trusted-setups` entrypoint.
```ts
import mainnetTrustedSetup from 'viem/trusted-setups/mainnet.json'
import minimalTrustedSetup from 'viem/trusted-setups/minimal.json'
```
## Returns
`Kzg`
The KZG interface.
## Parameters
### kzg
* **Type:** `Kzg & { loadTrustedSetup(path: string): void }`
The [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) compatible [KZG interface](https://notes.ethereum.org/@vbuterin/proto_danksharding_faq#How-%E2%80%9Ccomplicated%E2%80%9D-and-%E2%80%9Cnew%E2%80%9D-is-KZG).
```ts twoslash
// @noErrors
import * as cKzg from 'c-kzg' // [!code focus]
import { setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(
cKzg, // [!code focus]
mainnetTrustedSetupPath
)
```
### path
* **Type:** `string`
The path to the trusted setup file.
```ts twoslash
// @noErrors
import * as cKzg from 'c-kzg'
import { setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node' // [!code focus]
const kzg = setupKzg(
cKzg,
mainnetTrustedSetupPath // [!code focus]
)
```
# sha256
Calculates the [Sha256](https://en.wikipedia.org/wiki/SHA-256) hash of a byte array or hex value.
This function is a re-export of `sha256` from [`@noble/hashes`](https://github.com/paulmillr/noble-hashes) – an audited & minimal JS hashing library.
## Install
```ts
import { sha256 } from 'viem'
```
## Usage
```ts
import { sha256 } from 'viem'
sha256(new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
// 0x7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069
sha256('0xdeadbeef')
// 0x5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953
```
## Returns
`Hex | ByteArray`
The hashed value.
## Parameters
### value
* **Type:** `Hex | ByteArray`
The hex value or byte array to hash.
### to
* **Type:** `"bytes" | "hex"`
* **Default:** `"hex"`
The output type.
```ts
import { sha256 } from 'viem'
sha256(
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33],
'bytes' // [!code focus]
)
// Uint8Array [95, 120, 195, 50, 116, 228, 63, 169, 222, 86, 89, 38, 92, 29, 145, 126, 37, 192, 55, 34, 220, 176, 184, 210, 125, 184, 213, 254, 170, 129, 57, 83] // [!code focus]
```
# sidecarsToVersionedHashes
Transforms a list of sidecars to their versioned hashes.
## Import
```ts twoslash
import { sidecarsToVersionedHashes } from 'viem'
```
## Usage
:::code-group
```ts twoslash [example.ts]
import { toBlobSidecars, sidecarsToVersionedHashes } from 'viem'
import { kzg } from './kzg'
const sidecars = toBlobSidecars({ data: '0x...', kzg })
const versionedHashes = sidecarsToVersionedHashes({ sidecars }) // [!code focus]
```
```ts twoslash [kzg.ts] filename="kzg.ts"
// @noErrors
import * as cKzg from 'c-kzg'
import { setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
export const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
```
:::
## Returns
`Hex[] | ByteArray[]`
Versioned hashes from the input sidecars.
## Parameters
### sidecars
* **Type:** `BlobSidecars`
Sidecars to transform to versioned hashes.
```ts twoslash
import { toBlobSidecars, sidecarsToVersionedHashes } from 'viem'
import { kzg } from './kzg'
const sidecars = toBlobSidecars({ data: '0x...', kzg })
const versionedHashes = sidecarsToVersionedHashes({
sidecars, // [!code focus]
})
```
### to
* **Type:** `"bytes" | "hex"`
Commitments corresponding to the input blobs.
```ts twoslash
import { toBlobSidecars, sidecarsToVersionedHashes } from 'viem'
import { kzg } from './kzg'
const sidecars = toBlobSidecars({ data: '0x...', kzg })
const versionedHashes = sidecarsToVersionedHashes({
sidecars,
to: 'bytes', // [!code focus]
})
versionedHashes // [!code focus]
// ^?
```
### version
* **Type:** `number`
* **Default:** `1`
Version to tag onto the hashes. Defaults to `1`.
```ts twoslash
import { toBlobSidecars, sidecarsToVersionedHashes } from 'viem'
import { kzg } from './kzg'
const sidecars = toBlobSidecars({ data: '0x...', kzg })
const versionedHashes = sidecarsToVersionedHashes({
sidecars,
version: 69, // [!code focus]
})
```
# signatureToCompactSignature
Parses a signature into a [EIP-2098](https://eips.ethereum.org/EIPS/eip-2098) compact signature.
## Import
```ts
import { signatureToCompactSignature } from 'viem'
```
## Usage
```ts
import { signatureToCompactSignature, Signature } from 'viem'
signatureToCompactSignature({ // [!code focus:9]
r: '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90',
s: '0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064'
yParity: 0
})
// {
// r: '0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90',
// yParityAndS: '0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064',
// }
```
## Returns
[`CompactSignature`](/docs/glossary/types#compactsignature)
The compact signature.
## Parameters
### signature
The signature.
* **Type:** [`Signature`](/docs/glossary/types#signature)
# size
Retrieves the size of the value (in bytes).
## Install
```ts
import { size } from 'viem'
```
## Usage
```ts
import { size } from 'viem'
size('0xa4') // 1
size('0xa4e12a45') // 4
size(new Uint8Array([1, 122, 51, 123])) // 4
```
## Returns
`number`
The size of the value (in bytes).
## Parameters
### value
* **Type:** [`Hex`](/docs/glossary/types#hex) | `ByteArray`
The value (hex or byte array) to retrieve the size of.
# slice
Returns a section of the hex or byte array given a start/end bytes offset.
## Install
```ts
import { slice } from 'viem'
```
## Usage
```ts
import { slice } from 'viem'
slice('0x0123456789', 1, 4)
// 0x234567
slice(new Uint8Array([1, 122, 51, 123]), 1, 3)
// Uint8Array [122, 51]
```
## Returns
`Hex | ByteArray`
The section of the sliced value.
## Parameters
### value
* **Type:** `Hex | ByteArray`
The hex or byte array to slice.
```ts
slice(
'0x0123456789', // [!code focus]
1,
4
)
```
### start (optional)
* **Type:** `number`
The start offset (in bytes).
```ts
slice(
'0x0123456789',
1 // [!code focus]
)
```
### end (optional)
* **Type:** `number`
The end offset (in bytes).
```ts
slice(
'0x0123456789',
1,
4 // [!code focus]
)
```
#### options.strict (optional)
* **Type:** `boolean`
* **Default:** `false`
Whether or not the end offset should be inclusive of the bounds of the data.
```ts
slice('0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678', 0, 20, { strict: true })
// [SliceOffsetOutOfBoundsError] Slice ending at offset "20" is out-of-bounds (size: 19).
slice('0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', 0, 20, { strict: true })
// 0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC
```
# toBase58
Coming soon.
# toBase64
Coming soon.
# toBlobs
Transforms arbitrary data into Viem-shaped blobs.
:::warning
This function transforms data into Viem-shaped blobs. It is designed to be used with Viem's `fromBlobs` function to convert back to the data.
:::
## Import
```ts twoslash
import { toBlobs } from 'viem'
```
## Usage
```ts twoslash [example.ts]
import { toBlobs } from 'viem'
const blobs = toBlobs({ data: '0x...' })
```
## Returns
`Hex[] | ByteArray[]`
Blobs from the input data.
## Parameters
### data
* **Type:** `Hex | ByteArray`
Data to transform into blobs.
```ts twoslash
import { toBlobs } from 'viem'
const blobs = toBlobs({
data: '0x...' // [!code focus]
})
```
### to
* **Type:** `"bytes" | "hex"`
The output type.
```ts twoslash
import { toBlobs } from 'viem'
const blobs = toBlobs({
data: '0x...',
to: 'bytes' // [!code focus]
})
blobs // [!code focus]
// ^?
```
# toBlobSidecars
Transforms arbitrary data (or blobs, commitments, & proofs) into a blob sidecar array.
## Import
```ts twoslash
import { toBlobSidecars } from 'viem'
```
## Usage
### With Arbitrary Data
You can generate blob sidecars from arbitrary data without having to compute the blobs, commitments, and proofs first (that's done internally).
:::code-group
```ts twoslash [example.ts]
import { toBlobSidecars } from 'viem'
import { kzg } from './kzg'
const sidecars = toBlobSidecars({ data: '0x...', kzg }) // [!code focus]
```
```ts twoslash [kzg.ts] filename="kzg.ts"
// @noErrors
import * as cKzg from 'c-kzg'
import { setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
export const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
```
:::
### With Blobs, Commitments, and Proofs
Alternatively, you can reach for the lower-level API and insert the blobs, commitments, and proofs directly.
:::code-group
```ts twoslash [example.ts]
import {
blobsToCommitments,
blobsToProofs,
toBlobSidecars,
toBlobs
} from 'viem'
import { kzg } from './kzg'
const blobs = toBlobs({ data: '0x...' })
const commitments = blobsToCommitments({ blobs, kzg })
const proofs = blobsToProofs({ blobs, commitments, kzg })
const sidecars = toBlobSidecars({ blobs, commitments, proofs }) // [!code focus]
```
```ts twoslash [kzg.ts] filename="kzg.ts"
// @noErrors
import * as cKzg from 'c-kzg'
import { setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
export const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
```
:::
## Returns
`BlobSidecars`
Blob sidecars from the input data.
## Parameters
### blobs
* **Type:** `Hex[] | ByteArray[]`
Blobs to transform into blob sidecars.
```ts twoslash
import {
blobsToCommitments,
blobsToProofs,
toBlobSidecars,
toBlobs
} from 'viem'
import { kzg } from './kzg'
const blobs = toBlobs({ data: '0x...' }) // [!code focus]
const commitments = blobsToCommitments({ blobs, kzg })
const proofs = blobsToProofs({ blobs, commitments, kzg })
const sidecars = toBlobSidecars({
blobs, // [!code focus]
commitments,
proofs,
})
```
### commitments
* **Type:** `Hex[] | ByteArray[]`
Commitments corresponding to the input blobs.
```ts twoslash
import {
blobsToCommitments,
blobsToProofs,
toBlobSidecars,
toBlobs
} from 'viem'
import { kzg } from './kzg'
const blobs = toBlobs({ data: '0x...' })
const commitments = blobsToCommitments({ blobs, kzg }) // [!code focus]
const proofs = blobsToProofs({ blobs, commitments, kzg })
const sidecars = toBlobSidecars({
blobs,
commitments, // [!code focus]
proofs,
})
```
### data
* **Type:** `Hex | ByteArray`
Data to transform into blob sidecars.
```ts twoslash
import { toBlobSidecars } from 'viem'
import { kzg } from './kzg'
const sidecars = toBlobSidecars({
data: '0x...', // [!code focus]
kzg,
})
```
### kzg
* **Type:** `KZG`
KZG implementation. See [`setupKzg`](/docs/utilities/setupKzg) for more information.
```ts twoslash
// @noErrors
import * as cKzg from 'c-kzg'
import { toBlobSidecars, setupKzg } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath) // [!code focus]
const sidecars = toBlobSidecars({
data: '0x...',
kzg, // [!code focus]
})
```
### proofs
* **Type:** `Hex[] | ByteArray[]`
Proofs corresponding to the input blobs.
```ts twoslash
import {
blobsToCommitments,
blobsToProofs,
toBlobSidecars,
toBlobs
} from 'viem'
import { kzg } from './kzg'
const blobs = toBlobs({ data: '0x...' })
const commitments = blobsToCommitments({ blobs, kzg })
const proofs = blobsToProofs({ blobs, commitments, kzg }) // [!code focus]
const sidecars = toBlobSidecars({
blobs,
commitments,
proofs, // [!code focus]
})
```
### to
* **Type:** `"bytes" | "hex"`
The output type.
```ts twoslash
import { defineKzg } from 'viem'
const kzg = defineKzg({} as any)
// ---cut---
import { toBlobSidecars, toBlobs } from 'viem'
const sidecars = toBlobSidecars({
data: '0x1234',
kzg,
to: 'bytes', // [!code focus]
})
sidecars // [!code focus]
// ^?
```
# toBytes
Encodes a string, hex value, number or boolean to a byte array.
Shortcut Functions:
* [hexToBytes](#hextobytes)
* [stringToBytes](#stringtobytes)
* [numberToBytes](#numbertobytes)
* [boolToBytes](#booltobytes)
## Import
```ts
import { toBytes } from 'viem'
```
## Usage
```ts
import { toBytes } from 'viem'
toBytes('Hello world')
// Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
toBytes('0x48656c6c6f20576f726c6421')
// Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
toBytes(420)
// Uint8Array([1, 164])
toBytes(true)
// Uint8Array([1])
```
## Returns
`ByteArray`
The byte array represented as a `Uint8Array`.
## Parameters
### value
* **Type:** `string | Hex`
The value to encode as bytes.
```ts
toBytes(
'Hello world' // [!code focus]
)
// Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
```
### options
```ts
toBytes(
'Hello world',
{ size: 32 } // [!code focus]
)
// Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
```
## Shortcut Functions
### hexToBytes
* **Type:** `Hex`
Encodes a hex value to a byte array.
```ts
import { hexToBytes } from 'viem'
hexToBytes('0x48656c6c6f20576f726c6421') // [!code focus:2]
// Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
hexToBytes('0x48656c6c6f20576f726c6421', { size: 32 }) // [!code focus:2]
// Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
```
### stringToBytes
* **Type:** `Hex`
Encodes a string to a byte array.
```ts
import { stringToBytes } from 'viem'
stringToBytes('Hello world') // [!code focus:2]
// Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
stringToBytes('Hello world', { size: 32 }) // [!code focus:2]
// Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
```
### numberToBytes
* **Type:** `number | bigint`
Encodes a number to a byte array.
```ts
import { numberToBytes } from 'viem'
numberToBytes(420) // [!code focus:2]
// Uint8Array([1, 164])
numberToBytes(420, { size: 32 }) // [!code focus:2]
// Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 164])
```
### boolToBytes
* **Type:** `boolean`
Encodes a boolean to a byte array.
```ts
import { boolToBytes } from 'viem'
boolToBytes(true) // [!code focus:2]
// Uint8Array([1])
boolToBytes(true, { size: 32 }) // [!code focus:2]
// Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
```
# toEventHash
Returns the hash (of the event signature) for a given event definition.
## Install
```ts
import { toEventHash } from 'viem'
```
## Usage
```ts twoslash
import { toEventHash } from 'viem'
const hash_1 = toEventHash('event Transfer(address,address,uint256)')
// @log: Output: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
const hash_2 = toEventHash({
name: 'Transfer',
type: 'event',
inputs: [
{ name: 'from', type: 'address', indexed: true },
{ name: 'to', type: 'address', indexed: true },
{ name: 'amount', type: 'uint256', indexed: false },
],
})
// @log: Output: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The hash of the event signature.
## Parameters
### event
* **Type:** `string` | [`AbiEvent`](https://abitype.dev/api/types#abievent)
The event to generate a hash for.
# toEventSelector
Returns the event selector for a given event definition.
## Install
```ts
import { toEventSelector } from 'viem'
```
## Usage
```ts twoslash
import { toEventSelector } from 'viem'
const selector_1 = toEventSelector('Transfer(address,address,uint256)')
// @log: Output: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
const selector_2 = toEventSelector('Transfer(address indexed from, address indexed to, uint256 amount)')
// @log: Output: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
// or from an `AbiEvent` on your contract ABI
const selector_3 = toEventSelector({
name: 'Transfer',
type: 'event',
inputs: [
{ name: 'from', type: 'address', indexed: true },
{ name: 'to', type: 'address', indexed: true },
{ name: 'amount', type: 'uint256', indexed: false },
],
})
// @log: Output: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The selector as a hex value.
## Parameters
### event
* **Type:** `string |`[`AbiEvent`](https://abitype.dev/api/types#abievent)
The event to generate a selector for.
# toEventSignature
Returns the signature for a given event definition.
:::tip
This only returns the **event signature**. If you need the **full human-readable definition**, check out ABIType's [`formatAbiItem`](https://abitype.dev/api/human#formatabiitem-1).
:::
## Install
```ts
import { toEventSignature } from 'viem'
```
## Usage
```ts twoslash
import { toEventSignature } from 'viem'
// from event definition
const signature_1 = toEventSignature('event Transfer(address indexed from, address indexed to, uint256 amount)')
// @log: Output: Transfer(address,address,uint256)
// from an `AbiEvent` on your contract ABI
const signature_2 = toEventSignature({
name: 'Transfer',
type: 'event',
inputs: [
{ name: 'address', type: 'address', indexed: true },
{ name: 'address', type: 'address', indexed: true },
{ name: 'uint256', type: 'uint256', indexed: false },
],
})
// @log: Output: Transfer(address,address,uint256)
```
## Returns
`string`
The signature as a string value.
## Parameters
### definition
* **Type:** `string | AbiEvent`
The event definition to generate a signature for.
# toFunctionHash
Returns the hash (of the function signature) for a given function definition.
## Install
```ts
import { toFunctionHash } from 'viem'
```
## Usage
```ts twoslash
import { toFunctionHash } from 'viem'
const hash_1 = toFunctionHash('function ownerOf(uint256)')
// @log: Output: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
// or from an `AbiEvent` on your contract ABI
const hash_2 = toFunctionHash({
name: 'ownerOf',
type: 'function',
inputs: [{ name: 'tokenId', type: 'uint256' }],
outputs: [],
stateMutability: 'view',
})
// @log: Output: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The hash of the function signature.
## Parameters
### function
* **Type:** `string` | [`AbiFunction`](https://abitype.dev/api/types#abifunction)
The function to generate a hash for.
# toFunctionSelector
Returns the function selector (4 byte encoding) for a given function definition.
## Install
```ts
import { toFunctionSelector } from 'viem'
```
## Usage
```ts twoslash
import { toFunctionSelector } from 'viem'
const selector_1 = toFunctionSelector('function ownerOf(uint256 tokenId)')
// @log: Output: 0x6352211e
const selector_2 = toFunctionSelector('ownerOf(uint256)')
// @log: Output: 0x6352211e
// or from an `AbiFunction` on your contract ABI
const selector_3 = toFunctionSelector({
name: 'ownerOf',
type: 'function',
inputs: [{ name: 'tokenId', type: 'uint256' }],
outputs: [],
stateMutability: 'view',
})
// @log: Output: 0x6352211e
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The selector as a hex value.
## Parameters
### function
* **Type:** `string |`[`AbiFunction`](https://abitype.dev/api/types#abifunction)
The function to generate a selector for.
# toFunctionSignature
Returns the signature for a given function definition.
:::tip
This only returns the **function signature**. If you need the **full human-readable definition**, check out ABIType's [`formatAbiItem`](https://abitype.dev/api/human#formatabiitem-1).
:::
## Install
```ts
import { toFunctionSignature } from 'viem'
```
## Usage
```ts twoslash
import { toFunctionSignature } from 'viem'
// from function definition
const signature_1 = toFunctionSignature('function ownerOf(uint256 tokenId)')
// @log: Output: ownerOf(uint256)
// from an `AbiFunction` on your contract ABI
const signature_2 = toFunctionSignature({
name: 'ownerOf',
type: 'function',
inputs: [{ name: 'tokenId', type: 'uint256' }],
outputs: [],
stateMutability: 'view',
})
// @log: Output: ownerOf(uint256)
```
## Returns
`string`
The signature as a string value.
## Parameters
### definition
* **Type:** `string | AbiFunction`
The function definition to generate a signature for.
# toHex
Encodes a string, number, boolean or byte array to a hex value value.
Shortcut Functions:
* [numberToHex](#numbertohex)
* [stringToHex](#stringtohex)
* [bytesToHex](#bytestohex)
* [boolToHex](#booltohex)
## Import
```ts
import { toHex } from 'viem'
```
## Usage
```ts
import { toHex } from 'viem'
toHex(420)
// "0x1a4"
toHex('Hello world')
// "0x48656c6c6f20776f726c642e"
toHex(
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
)
// "0x48656c6c6f20576f726c6421"
toHex(true)
// "0x1"
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The hex value.
## Parameters
### value
* **Type:** `string | number | bigint | ByteArray`
The value to hex encode.
```ts
toHex(
'Hello world' // [!code focus]
)
// '0x48656c6c6f20776f726c642e'
```
### options
```ts
toHex(
'Hello world',
{ size: 32 } // [!code focus]
)
// '0x48656c6c6f20776f726c642e0000000000000000000000000000000000000000'
```
## Shortcut Functions
### numberToHex
* **Type:** `number | bigint`
Encodes a number value to a hex value.
```ts
import { numberToHex } from 'viem'
numberToHex(420)
// "0x1a4"
numberToHex(4206942069420694206942069420694206942069n)
// "0xc5cf39211876fb5e5884327fa56fc0b75"
numberToHex(420, { size: 32 })
// "0x00000000000000000000000000000000000000000000000000000000000001a4"
numberToHex(4206942069420694206942069420694206942069n, { size: 32 })
// "0x0000000000000000000000000000000c5cf39211876fb5e5884327fa56fc0b75"
```
### stringToHex
* **Type:** `string`
Encodes a UTF-8 string value to a hex value.
```ts
import { stringToHex } from 'viem'
stringToHex('Hello World!')
// "0x48656c6c6f20576f726c6421"
stringToHex('Hello World!', { size: 32 })
// "0x48656c6c6f20576f726c64210000000000000000000000000000000000000000"
```
### bytesToHex
* **Type:** `ByteArray`
Encodes a byte array to a hex value.
```ts
import { bytesToHex } from 'viem'
bytesToHex(
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]),
)
// "0x48656c6c6f20576f726c6421"
bytesToHex(
new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]),
{ size: 32 }
)
// "0x48656c6c6f20576f726c64210000000000000000000000000000000000000000"
```
### boolToHex
* **Type:** `boolean`
Encodes a boolean to a hex value.
```ts
import { boolToHex } from 'viem'
boolToHex(true)
// "0x1"
boolToHex(true, { size: 32 })
// "0x0000000000000000000000000000000000000000000000000000000000000001"
```
# toRlp
Encodes a hex value or byte array into a [Recursive-Length Prefix (RLP)](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/) encoded value.
## Import
```ts
import { toRlp } from 'viem'
```
## Usage
```ts
import { toRlp } from 'viem'
toRlp('0x123456789')
// "0x850123456789"
toRlp(['0x7f', '0x7f', '0x8081e8'])
// "0xc67f7f838081e8"
toRlp(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]))
// "0x89010203040506070809"
toRlp('0x123456789', 'bytes')
// Uint8Array [133, 1, 35, 69, 103, 137]
```
## Returns
`Hex | ByteArray`
The hex value or byte array.
## Parameters
### value
* **Type:** `Hex | ByteArray`
The value to RLP encode.
### to
* **Type:** `"bytes" | "hex"`
* **Default:** `"hex"`
The output type.
```ts
toRlp('0x123456789', 'bytes')
// Uint8Array [133, 1, 35, 69, 103, 137]
```
# trim
Trims the leading or trailing zero byte data from a hex value or byte array.
## Install
```ts
import { trim } from 'viem'
```
## Usage
By default, `trim` will trim the leading zero byte data from a hex value or byte array.
```ts
import { trim } from 'viem'
trim('0x00000000000000000000000000000000000000000000000000000001a4e12a45')
// 0x01a4e12a45
trim(new Uint8Array([0, 0, 0, 0, 0, 0, 1, 122, 51, 123]))
// Uint8Array [1,122,51,123]
```
## Returns
`Hex | ByteArray`
The trimmed value.
## Parameters
### dir
* **Type:** `"left" | "right"`
* **Default:** `"left"`
The direction in which to trim the zero byte data – either leading (left), or trailing (right).
```ts
trim('0xa4e12a4510000000000000000000000000000000000000000000000000000000', {
dir: 'right'
})
// 0xa4e12a4510
```
# verifyMessage
Verify that a message was signed by the provided address.
:::warning\[Warning]
This utility can only verify a message that was signed by an Externally Owned Account (EOA).
To verify messages from Contract Accounts (& EOA), use the [`publicClient.verifyMessage` Action](/docs/actions/public/verifyMessage) instead.
:::
## Usage
:::code-group
```ts [example.ts]
import { verifyMessage } from 'viem'
import { account, walletClient } from './client'
const signature = await walletClient.signMessage({
account,
message: 'hello world',
})
const valid = await verifyMessage({ // [!code focus:99]
address: account.address,
message: 'hello world',
signature,
})
// true
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
export const walletClient = createWalletClient({
transport: custom(window.ethereum)
})
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
## Returns
`boolean`
Whether the provided `address` generated the `signature`.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The Ethereum address that signed the original message.
```ts
const valid = await verifyMessage({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
message: 'hello world',
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### message
* **Type:** `string`
The message to be verified.
By default, viem signs the UTF-8 representation of the message.
```ts
const valid = await verifyMessage({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: 'hello world', // [!code focus:1]
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
To sign the data representation of the message, you can use the `raw` attribute.
```ts
const valid = await verifyMessage({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: { raw: '0x68656c6c6f20776f726c64' }, // [!code focus:1]
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### signature
* **Type:** `Hex | ByteArray | Signature`
The signature that was generated by signing the message with the address's private key.
```ts
const valid = await verifyMessage({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: 'hello world',
signature: // [!code focus:2]
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
# verifyTypedData
Verify that typed data was signed by the provided address.
:::warning\[Warning]
This utility can only verify typed data that was signed by an Externally Owned Account (EOA).
To verify messages from Contract Accounts (& EOA), use the [`publicClient.verifyTypedData` Action](/docs/actions/public/verifyTypedData) instead.
:::
## Usage
:::code-group
```ts [example.ts]
import { verifyTypedData } from 'viem'
import { account, walletClient } from './client'
const message = {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
} as const
const signature = await walletClient.signTypedData({
account,
domain,
types,
primaryType: 'Mail',
message,
})
// [!code focus:99]
const valid = await verifyTypedData({
address: account.address,
domain,
types,
primaryType: 'Mail',
message,
signature,
})
// true
```
```ts [data.ts]
// All properties on a domain are optional
export const domain = {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
} as const
// The named list of all type definitions
export const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
} as const
```
```ts [client.ts]
import { createWalletClient, custom } from 'viem'
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
export const walletClient = createWalletClient({
transport: custom(window.ethereum),
})
```
:::
## Returns
`boolean`
Whether the provided `address` generated the `signature`.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The Ethereum address that signed the original message.
```ts
const valid = await verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### domain
**Type:** `TypedDataDomain`
The typed data domain.
```ts
const valid = await verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: { // [!code focus:6]
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### types
The type definitions for the typed data.
```ts
const valid = await verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain,
types: { // [!code focus:11]
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### primaryType
**Type:** Inferred `string`.
The primary type to extract from `types` and use in `value`.
```ts
const valid = await verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [ // [!code focus:5]
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail', // [!code focus]
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### message
**Type:** Inferred from `types` & `primaryType`.
```ts
const valid = await verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: { // [!code focus:11]
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### signature
* **Type:** `Hex | ByteArray | Signature`
The signature of the typed data.
```ts
const valid = await verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...', // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `bigint`
Only used when verifying a typed data that was signed by a Smart Contract Account. The block number to check if the contract was already deployed.
```ts
const valid = await verifyTypedData({
blockNumber: 42069n, // [!code focus]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
Only used when verifying a typed data that was signed by a Smart Contract Account. The block tag to check if the contract was already deployed.
```ts
const valid = await verifyTypedData({
blockNumber: 42069n, // [!code focus]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
## JSON-RPC Method
[`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call) to a deployless [universal signature validator contract](https://eips.ethereum.org/EIPS/eip-6492).
# Extending Client with ERC-7715 \[Setting up your Viem Client]
To use the experimental functionality of ERC-7715, you can extend your existing (or new) Viem Client with experimental ERC-7715 Actions.
```ts
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7715Actions } from 'viem/experimental' // [!code focus]
const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
}).extend(erc7715Actions()) // [!code focus]
const id = await walletClient.grantPermissions({/* ... */})
```
# grantPermissions
Request permissions from a wallet to perform actions on behalf of a user.
[Read more.](https://eips.ethereum.org/EIPS/eip-7715)
:::warning\[Warning]
This is an experimental action that is not supported in most wallets. It is recommended to have a fallback mechanism if using this in production.
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, walletClient } from './config'
const result = await walletClient.grantPermissions({ // [!code focus:99]
account,
expiry: 1716846083638,
permissions: [
{
type: 'native-token-transfer',
data: {
ticker: 'ETH',
},
policies: [
{
type: 'token-allowance',
data: {
allowance: parseEther('1'),
},
},
],
},
],
})
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7715Actions } from 'viem/experimental'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
}).extend(erc7715Actions())
export const [account] = await walletClient.getAddresses()
```
:::
## Returns
`GrantPermissionsReturnType`
Response from the wallet after issuing permissions.
## Parameters
### account
* **Type:** `Account | Address | undefined`
The Account to scope the permissions to.
```ts twoslash
import { parseEther } from 'viem'
import { account, walletClient } from './config'
const result = await walletClient.grantPermissions({
account, // [!code focus]
expiry: 1716846083638,
permissions: [
{
type: 'native-token-transfer',
data: {
ticker: 'ETH',
},
policies: [
{
type: 'token-allowance',
data: {
allowance: parseEther('1'),
},
},
],
},
],
})
```
### expiry
* **Type:** `number`
The timestamp (in seconds) when the permissions will expire.
```ts twoslash
import { parseEther } from 'viem'
import { account, walletClient } from './config'
const result = await walletClient.grantPermissions({
account,
expiry: 1716846083638, // [!code focus]
permissions: [
{
type: 'native-token-transfer',
data: {
ticker: 'ETH',
},
policies: [
{
type: 'token-allowance',
data: {
allowance: parseEther('1'),
},
},
],
},
],
})
```
### permissions
* **Type:** `Permission[]`
Set of Permissions & Policies to grant to the user.
```ts twoslash
// @noErrors
import { parseEther } from 'viem'
import { account, walletClient } from './config'
const result = await walletClient.grantPermissions({
account,
expiry: 1716846083638,
permissions: [ // [!code focus:19]
{
type: 'native-token-transfer',
data: {
ticker: 'ETH',
},
policies: [
{
type: 'token-allowance',
data: {
allowance: parseEther('1'),
},
},
],
},
{
type: '
// ^|
}
],
})
```
:::tip
The `type` property is constrained to the canonical set of [Permission & Policy types as
defined in ERC-7715](https://github.com/pedrouid/ERCs/blob/19c16341c57f6ac8770cb778d60845dcf30f6a40/ERCS/erc-7715.md#permissions), however, consumers can utilize a `custom` property on `type` as an escape hatch to use custom Permission or Policy types:
```ts twoslash
// @noErrors
import { parseEther } from 'viem'
import { account, walletClient } from './config'
const result = await walletClient.grantPermissions({
account,
expiry: 1716846083638,
permissions: [
{
type: { custom: 'example' }, // [!code focus]
data: {
value: '0xdeadbeef',
}
}
],
})
```
:::
### signer
* **Type:** `Signer | undefined`
Custom signer type to scope the permissions to.
```ts twoslash
import { parseEther } from 'viem'
import { account, walletClient } from './config'
const result = await walletClient.grantPermissions({
expiry: 1716846083638,
permissions: [
{
type: 'native-token-limit',
data: {
amount: parseEther('0.5'),
},
required: true,
},
],
signer: { // [!code focus]
type: 'key', // [!code focus]
data: { // [!code focus]
id: '...' // [!code focus]
} // [!code focus]
} // [!code focus]
})
```
# Extending Client with ERC-7739 Actions \[Setting up your Viem Client]
To use the experimental functionality of ERC-7739, you can extend your existing (or new) Viem Client with experimental ERC-7739 Actions.
```ts
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7739Actions } from 'viem/experimental' // [!code focus]
const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
}).extend(erc7739Actions()) // [!code focus]
const id = await walletClient.signMessage({/* ... */})
```
# hashMessage
Calculates a [EIP-191](https://eips.ethereum.org/EIPS/eip-191) personal sign hash via [ERC-7739 `PersonalSign` format](https://eips.ethereum.org/EIPS/eip-7739).
## Import
```ts
import { hashMessage } from 'viem/experimental/erc7739'
```
## Usage
```ts
import { hashMessage } from 'viem/experimental/erc7739'
// Hash a UTF-8 value.
hashMessage({
message: 'hello world',
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
// Hash a hex data value.
hashMessage({
message: { raw: '0x68656c6c6f20776f726c64' },
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
// Hash a bytes data value.
hashMessage({
message: {
raw: Uint8Array.from([
104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100,
])
},
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
```
## Returns
[`Hex`](/docs/glossary/types#hex)
A signable message hash.
## Parameters
### message
* **Type:** `string | { raw: Hex | ByteArray }`
Message to hash.
### verifierDomain
* **Type:** `TypedDataDomain`
The EIP-712 domain of the verifying contract.
# hashTypedData
Hashes [EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed data via [ERC-7739 `TypedDataSign` format](https://eips.ethereum.org/EIPS/eip-7739).
## Import
```ts
import { hashTypedData } from 'viem/experimental/erc7739'
```
## Usage
```ts
import { hashTypedData } from 'viem/experimental/erc7739'
hashTypedData({
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
extensions: [],
fields: '0x0f',
verifierDomain: {
chainId: 1,
name: 'Smart Account',
salt: '0x0000000000000000000000000000000000000000000000000000000000000000',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
},
})
```
## Returns
[`Hex`](/docs/glossary/types#hex)
A signable typed data hash.
## Parameters
### domain
**Type:** `TypedDataDomain`
The typed data domain.
```ts
const hash = hashTypedData({
domain: { // [!code focus:6]
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
extensions: [],
fields: '0x0f',
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
```
### types
The type definitions for the typed data.
```ts
const hash = hashTypedData({
domain,
types: { // [!code focus:11]
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
extensions: [],
fields: '0x0f',
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
```
### primaryType
**Type:** Inferred `string`.
The primary type to extract from `types` and use in `value`.
```ts
const hash = hashTypedData({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [ // [!code focus:5]
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail', // [!code focus]
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
extensions: [],
fields: '0x0f',
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
```
### message
**Type:** Inferred from `types` & `primaryType`.
```ts
const hash = hashTypedData({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: { // [!code focus:11]
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
extensions: [],
fields: '0x0f',
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
```
### extensions
**Type:** `readonly bigint[]`
Extensions for the typed data.
```ts
const hash = hashTypedData({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
extensions: [], // [!code focus]
fields: '0x0f',
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
```
### fields
**Type:** `Hex`
Typed data fields.
```ts
const hash = hashTypedData({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
extensions: [],
fields: '0x0f', // [!code focus]
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
```
### verifierDomain
**Type:** `TypedDataDomain`
Domain of the verifying contract.
```ts
const hash = hashTypedData({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
extensions: [],
fields: '0x0f',
verifierDomain: { // [!code focus]
name: 'Smart Account', // [!code focus]
version: '1', // [!code focus]
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678', // [!code focus]
chainId: 1, // [!code focus]
}, // [!code focus]
})
```
# signMessage
Signs an [EIP-191](https://eips.ethereum.org/EIPS/eip-191) personal sign message via [ERC-7739 `PersonalSign` format](https://eips.ethereum.org/EIPS/eip-7739).
This Action is suitable to sign messages for contracts (e.g. ERC-4337 Smart Accounts) that implement (or conform to) [ERC-7739](https://eips.ethereum.org/EIPS/eip-7739) (e.g. Solady's [ERC1271.sol](https://github.com/Vectorized/solady/blob/main/src/accounts/ERC1271.sol)).
With the calculated signature, you can use [`verifyMessage`](/docs/actions/public/verifyMessage) to verify the signature
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient } from './config'
const signature_1 = await walletClient.signMessage({ // [!code focus:99]
// Account used for signing.
account,
message: 'hello world',
// Verifying contract address (e.g. ERC-4337 Smart Account).
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})
const signature_2 = await walletClient.signMessage({
// Account used for signing.
account,
// Hex data representation of message.
message: { raw: '0x68656c6c6f20776f726c64' },
// Verifying contract address (e.g. ERC-4337 Smart Account)
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7739Actions } from 'viem/experimental'
export const walletClient = createWalletClient({
chain: mainnet,
transport: http(),
}).extend(erc7739Actions())
export const [account] = await walletClient.getAddresses()
// @log: ↑ JSON-RPC Account
// export const account = privateKeyToAccount(...)
// @log: ↑ Local Account
```
:::
## Account and/or Verifier Hoisting
If you do not wish to pass an `account` and/or `verifier` to every `signMessage`, you can also hoist the Account and/or Verifier on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#withaccount).
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const signature = await walletClient.signMessage({ // [!code focus:99]
message: 'hello world',
})
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
import { erc7739Actions } from 'viem/experimental'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
}).extend(erc7739Actions({
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
}))
```
```ts twoslash [config.ts (Local Account)] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { erc7739Actions } from 'viem/experimental'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
transport: http()
}).extend(erc7739Actions({
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
}))
```
:::
## Returns
[`Hex`](/docs/glossary/types#hex)
The signed message.
## Parameters
### account
* **Type:** `Account | Address`
Account to used to sign the message.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signMessage({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
message: 'hello world',
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})
```
### message
* **Type:** `string | { raw: Hex | ByteArray }`
Message to sign.
By default, viem signs the UTF-8 representation of the message.
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signMessage({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: 'hello world', // [!code focus:1]
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2',
})
```
To sign the data representation of the message, you can use the `raw` attribute.
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signMessage({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: { raw: '0x68656c6c6f20776f726c64' }, // [!code focus:1]
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2',
})
```
### verifier
* **Type:** `Address`
The address of the verifying contract (e.g. a ERC-4337 Smart Account). Required if `verifierDomain` is not passed.
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signMessage({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: 'hello world',
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2', // [!code focus:1]
})
```
### verifierDomain
* **Type:** `TypedDataDomain`
Account domain separator. Required if `verifier` is not passed.
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signMessage({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: 'hello world',
verifierDomain: { // [!code focus]
name: 'SoladyAccount', // [!code focus]
version: '1', // [!code focus]
chainId: 1, // [!code focus]
verifyingContract: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2' // [!code focus]
}, // [!code focus]
})
```
# signTypedData
Signs [EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed data via [ERC-7739 `TypedDataSign` format](https://eips.ethereum.org/EIPS/eip-7739).
This Action is suitable to sign messages for contracts (e.g. ERC-4337 Smart Accounts) that implement (or conform to) [ERC-7739](https://eips.ethereum.org/EIPS/eip-7739) (e.g. Solady's [ERC1271.sol](https://github.com/Vectorized/solady/blob/main/src/accounts/ERC1271.sol)).
With the calculated signature, you can use [`verifyTypedData`](/docs/actions/public/verifyTypedData) to verify the signature
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient } from './config'
import { domain, types } from './data'
const signature = await walletClient.signTypedData({ // [!code focus:99]
// Account used for signing.
account,
domain,
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
// Verifying contract address (e.g. ERC-4337 Smart Account).
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})
```
```ts twoslash [data.ts]
// All properties on a domain are optional
export const domain = {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
} as const
// The named list of all type definitions
export const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
} as const
```
```ts twoslash [config.ts] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7739Actions } from 'viem/experimental'
export const walletClient = createWalletClient({
chain: mainnet,
transport: http(),
}).extend(erc7739Actions())
export const [account] = await walletClient.getAddresses()
// @log: ↑ JSON-RPC Account
// export const account = privateKeyToAccount(...)
// @log: ↑ Local Account
```
:::
## Account and/or Verifier Hoisting
If you do not wish to pass an `account` and/or `verifier` to every `signTypedData`, you can also hoist the Account and/or Verifier on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#withaccount).
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
import { domain, types } from './data'
const signature = await walletClient.signTypedData({ // [!code focus:99]
domain,
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
```ts twoslash [data.ts]
// All properties on a domain are optional
export const domain = {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
} as const
// The named list of all type definitions
export const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
} as const
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
import { erc7739Actions } from 'viem/experimental'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
}).extend(erc7739Actions({
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
}))
```
```ts twoslash [config.ts (Local Account)] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { erc7739Actions } from 'viem/experimental'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
transport: http()
}).extend(erc7739Actions({
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
}))
```
:::
## Returns
[`Hex`](/docs/glossary/types#hex)
The signed data.
## Parameters
### account
* **Type:** `Account | Address`
Account to used to sign the typed data.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})
```
### domain
**Type:** `TypedDataDomain`
The typed data domain.
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: { // [!code focus:6]
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})
```
### types
The type definitions for the typed data.
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: { // [!code focus:11]
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### primaryType
**Type:** Inferred `string`.
The primary type to extract from `types` and use in `value`.
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [ // [!code focus:5]
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail', // [!code focus]
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### message
**Type:** Inferred from `types` & `primaryType`.
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: { // [!code focus:11]
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2'
})
```
### verifier
* **Type:** `Address`
The address of the verifying contract (e.g. a ERC-4337 Smart Account). Required if `verifierDomain` is not passed.
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
verifier: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2' // [!code focus]
})
```
### verifierDomain
* **Type:** `TypedDataDomain`
Account domain separator. Required if `verifier` is not passed.
```ts twoslash
import { walletClient } from './config'
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
verifierDomain: { // [!code focus]
name: 'SoladyAccount', // [!code focus]
version: '1', // [!code focus]
chainId: 1, // [!code focus]
verifyingContract: '0xCB9fA1eA9b8A3bf422a8639f23Df77ea66020eC2' // [!code focus]
}, // [!code focus]
})
```
# wrapTypedDataSignature
Wraps a EIP-712 typed data signature into via [ERC-7739](https://eips.ethereum.org/EIPS/eip-7739) format for verification.
## Import
```ts
import { wrapTypedDataSignature } from 'viem/experimental/erc7739'
```
## Usage
```ts
import { wrapTypedDataSignature } from 'viem/experimental/erc7739'
wrapTypedDataSignature({
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The wrapped signature.
## Parameters
### domain
**Type:** `TypedDataDomain`
The typed data domain.
```ts
const signature = wrapTypedDataSignature({
domain: { // [!code focus:6]
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
```
### types
The type definitions for the typed data.
```ts
const signature = wrapTypedDataSignature({
domain,
types: { // [!code focus:11]
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
```
### primaryType
**Type:** Inferred `string`.
The primary type to extract from `types` and use in `value`.
```ts
const signature = wrapTypedDataSignature({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [ // [!code focus:5]
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail', // [!code focus]
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
```
### message
**Type:** Inferred from `types` & `primaryType`.
```ts
const signature = wrapTypedDataSignature({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: { // [!code focus:11]
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
verifierDomain: {
name: 'Smart Account',
version: '1',
verifyingContract: '0x1234567890abcdef1234567890abcdef12345678',
chainId: 1,
},
})
```
### signature
**Type:** `Hex`
The signature of the signed typed data.
```ts
const signature = wrapTypedDataSignature({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...', // [!code focus]
})
```
# Extending Client with ERC-7811 Actions \[Setting up your Viem Client]
To use the experimental functionality of [ERC-7811](https://github.com/ethereum/ERCs/blob/master/ERCS/erc-7811.md), you can extend your existing (or new) Viem Client with experimental [ERC-7811](https://github.com/ethereum/ERCs/blob/master/ERCS/erc-7811.md) Actions.
```ts
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7811Actions } from 'viem/experimental' // [!code focus]
const client = createClient({
chain: mainnet,
transport: http(),
}).extend(erc7811Actions()) // [!code focus]
const assets = await client.getAssets({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
})
```
# getAssets
Requests to get assets for an account from a Wallet.
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const assets = await walletClient.getAssets({ // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
}) // [!code focus]
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { erc7811Actions } from 'viem/experimental'
export const walletClient = createWalletClient({
transport: custom(window.ethereum!),
}).extend(erc7811Actions())
```
:::
## Returns
List of assets for the given account.
The `0` key represents the aggregated assets across the returned chains.
```ts
type ReturnType = {
/** Aggregated assets across returned chains. */
0: readonly {
address: Address | 'native'
balance: Hex
chainIds: readonly number[]
metadata?: unknown | undefined
type: 'native' | 'erc20' | 'erc721' | (string & {})
}[]
/** Assets for each chain. */
[chainId: number]: readonly {
address: Address | 'native'
balance: Hex
metadata?: unknown | undefined
type: 'native' | 'erc20' | 'erc721' | (string & {})
}[]
}
```
## Parameters
### `account`
* **Type:** `Account | Address`
The account to get assets for.
```ts
import { walletClient } from './config'
const assets = await walletClient.getAssets({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
})
```
### `assets`
* **Type:** `{ [chainId: number]: readonly { address: Address | 'native', type: 'native' | 'erc20' | 'erc721' | (string & {}) }[] }`
Filter by assets.
```ts
import { walletClient } from './config'
const assets = await walletClient.getAssets({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
assets: { // [!code focus]
8453: [{ address: '0x1234567890abcdef1234567890abcdef12345678', type: 'erc20' }], // [!code focus]
}, // [!code focus]
})
```
### `assetTypes`
* **Type:** `readonly ('native' | 'erc20' | 'erc721' | (string & {}))[]`
Filter by asset types.
```ts
import { walletClient } from './config'
const assets = await walletClient.getAssets({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
assetTypes: ['erc20'], // [!code focus]
})
```
### `chainIds`
* **Type:** `readonly number[]`
Filter by chain IDs.
```ts
import { walletClient } from './config'
const assets = await walletClient.getAssets({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
chainIds: [8453], // [!code focus]
})
```
## JSON-RPC Methods
* [`wallet_getAssets`](https://github.com/ethereum/ERCs/blob/master/ERCS/erc-7811.md)
# Extending Client with ERC-7821 Actions \[Setting up your Viem Client]
To use the experimental functionality of [ERC-7821](https://eips.ethereum.org/EIPS/eip-7821), you can extend your existing (or new) Viem Client with experimental [ERC-7821](https://eips.ethereum.org/EIPS/eip-7821) Actions.
```ts
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7821Actions } from 'viem/experimental' // [!code focus]
const client = createClient({
chain: mainnet,
transport: http(),
}).extend(erc7821Actions()) // [!code focus]
const hash = await client.execute({/* ... */})
```
# execute
Executes call(s) using the `execute` function on an [ERC-7821-compatible contract](https://eips.ethereum.org/EIPS/eip-7821).
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, client } from './config'
const hash = await client.execute({ // [!code focus:99]
account,
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { erc7821Actions } from 'viem/experimental'
export const account = privateKeyToAccount('0x...')
export const client = createClient({
chain: mainnet,
transport: http(),
}).extend(erc7821Actions())
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `sendCalls`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, client } from './config'
const hash = await client.execute({ // [!code focus:99]
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { erc7821Actions } from 'viem/experimental'
export const account = privateKeyToAccount('0x...')
export const client = createClient({
account,
chain: mainnet,
transport: http(),
}).extend(erc7821Actions())
```
:::
### Contract Calls
The `calls` property also accepts **Contract Calls**, and can be used via the `abi`, `functionName`, and `args` properties.
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, client } from './config'
const abi = parseAbi([
'function approve(address, uint256) returns (bool)',
'function transferFrom(address, address, uint256) returns (bool)',
])
const hash = await client.execute({ // [!code focus:99]
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'approve',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'transferFrom',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
'0x0000000000000000000000000000000000000000',
100n
],
},
],
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { erc7821Actions } from 'viem/experimental'
export const account = privateKeyToAccount('0x...')
export const client = createClient({
account,
chain: mainnet,
transport: http(),
}).extend(erc7821Actions())
```
:::
## Return Value
[`Hash`](/docs/glossary/types#hash)
A [Transaction Hash](/docs/glossary/terms#hash).
## Parameters
### account
* **Type:** `Account | Address | null`
Account to invoke the execution of the calls.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc). If set to `null`, it is assumed that the transport will handle filling the sender of the transaction.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
### address
* **Type:** `0x${string}`
Address of the contract to execute the calls on.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D', // [!code focus]
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
### calls
* **Type:** `Call[]`
Set of calls to execute.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [ // [!code focus]
{ // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1') // [!code focus]
}, // [!code focus]
{ // [!code focus]
data: '0xdeadbeef', // [!code focus]
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
}, // [!code focus]
], // [!code focus]
})
```
#### calls.data
* **Type:** `Hex`
Calldata to broadcast (typically a contract function selector with encoded arguments, or contract deployment bytecode).
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef', // [!code focus]
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
#### calls.to
* **Type:** `Address`
Recipient address of the call.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
},
],
})
```
#### calls.value
* **Type:** `Address`
Value to send with the call.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
### authorizationList (optional)
* **Type:** `AuthorizationList`
Signed EIP-7702 Authorization list.
```ts twoslash
// @noErrors
import { createWalletClient, http, parseEther } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { erc7821Actions } from 'viem/experimental'
const account = privateKeyToAccount('0x...')
export const client = createWalletClient({
account,
chain: mainnet,
transport: http(),
})
.extend(erc7821Actions())
// ---cut---
const authorization = await client.signAuthorization({
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
})
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
authorizationList: [authorization], // [!code focus]
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
:::note
**References**
* [EIP-7702 Overview](/docs/eip7702)
* [`signAuthorization` Docs](/docs/eip7702/signAuthorization)
:::
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `client.chain`
Chain to execute the calls on.
```ts twoslash
import { client } from './config'
// ---cut---
import { optimism } from 'viem/chains' // [!code focus]
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
chain: optimism, // [!code focus]
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
gasPrice: parseGwei('20'), // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei).
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### opData (optional)
* **Type:** `Hex`
Additional data to pass to execution.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
opData: '0xdeadbeef', // [!code focus]
})
```
# executeBatches
Executes batches of call(s) using the ["batch of batches" mode](https://eips.ethereum.org/EIPS/eip-7821#optional-batch-of-batches-mode) on an [ERC-7821-compatible contract](https://eips.ethereum.org/EIPS/eip-7821).
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, client } from './config'
const hash = await client.executeBatches({ // [!code focus:99]
account,
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
batches: [
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
]
},
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('2')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
},
],
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { erc7821Actions } from 'viem/experimental'
export const account = privateKeyToAccount('0x...')
export const client = createClient({
chain: mainnet,
transport: http(),
}).extend(erc7821Actions())
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `sendCalls`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, client } from './config'
const hash = await client.execute({ // [!code focus:99]
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
batches: [
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
]
},
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('2')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
},
],
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { erc7821Actions } from 'viem/experimental'
export const account = privateKeyToAccount('0x...')
export const client = createClient({
account,
chain: mainnet,
transport: http(),
}).extend(erc7821Actions())
```
:::
### Contract Calls
The `calls` property also accepts **Contract Calls**, and can be used via the `abi`, `functionName`, and `args` properties.
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, client } from './config'
const abi = parseAbi([
'function approve(address, uint256) returns (bool)',
'function transferFrom(address, address, uint256) returns (bool)',
])
const hash = await client.execute({ // [!code focus:99]
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
batches: [
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
]
},
{
calls: [
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'approve',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'transferFrom',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
'0x0000000000000000000000000000000000000000',
100n
],
},
],
},
],
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { erc7821Actions } from 'viem/experimental'
export const account = privateKeyToAccount('0x...')
export const client = createClient({
account,
chain: mainnet,
transport: http(),
}).extend(erc7821Actions())
```
:::
## Return Value
[`Hash`](/docs/glossary/types#hash)
A [Transaction Hash](/docs/glossary/terms#hash).
## Parameters
### account
* **Type:** `Account | Address | null`
Account to invoke the execution of the calls.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc). If set to `null`, it is assumed that the transport will handle filling the sender of the transaction.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
batches: [
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
]
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
},
],
})
```
### address
* **Type:** `0x${string}`
Address of the contract to execute the calls on.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D', // [!code focus]
batches: [
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
]
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
},
],
})
```
### batches
* **Type:** `{ calls: Call[], opData?: Hex }[]`
Set of call batches to execute.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
batches: [ // [!code focus]
{ // [!code focus]
calls: [ // [!code focus]
{ // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1') // [!code focus]
}, // [!code focus]
] // [!code focus]
}, // [!code focus]
{ // [!code focus]
calls: [ // [!code focus]
{ // [!code focus]
data: '0xdeadbeef', // [!code focus]
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
}, // [!code focus]
], // [!code focus]
}, // [!code focus]
], // [!code focus]
})
```
### batches.calls
* **Type:** `Call[]`
Set of calls in a batch to execute.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
batches: [
{
calls: [ // [!code focus]
{ // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1') // [!code focus]
}, // [!code focus]
] // [!code focus]
},
{
calls: [ // [!code focus]
{ // [!code focus]
data: '0xdeadbeef', // [!code focus]
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
}, // [!code focus]
], // [!code focus]
},
],
})
```
### batches.opData (optional)
* **Type:** `Hex`
Additional data to pass to execution.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
batches: [
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
],
opData: '0xdeadbeef', // [!code focus]
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
},
],
})
```
### authorizationList (optional)
* **Type:** `AuthorizationList`
Signed EIP-7702 Authorization list.
```ts twoslash
// @noErrors
import { createWalletClient, http, parseEther } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { erc7821Actions } from 'viem/experimental'
const account = privateKeyToAccount('0x...')
export const client = createWalletClient({
account,
chain: mainnet,
transport: http(),
})
.extend(erc7821Actions())
// ---cut---
const authorization = await client.signAuthorization({
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
})
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
authorizationList: [authorization], // [!code focus]
batches: [
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
]
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
},
],
})
```
:::note
**References**
* [EIP-7702 Overview](/docs/eip7702)
* [`signAuthorization` Docs](/docs/eip7702/signAuthorization)
:::
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `client.chain`
Chain to execute the calls on.
```ts twoslash
import { client } from './config'
// ---cut---
import { optimism } from 'viem/chains' // [!code focus]
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
batches: [
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
]
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
},
],
chain: optimism, // [!code focus]
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
batches: [
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
]
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
},
],
gasPrice: parseGwei('20'), // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
batches: [
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
]
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
},
],
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei).
```ts twoslash
import { client } from './config'
// ---cut---
const hash = await client.execute({
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
batches: [
{
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
]
},
{
calls: [
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
},
],
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
# supportsExecutionMode
Checks if the contract supports the [ERC-7821](https://eips.ethereum.org/EIPS/eip-7821) execution mode.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './config'
const supported = await client.supportsExecutionMode({ // [!code focus:99]
address: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7821Actions } from 'viem/experimental'
export const client = createClient({
chain: mainnet,
transport: http(),
}).extend(erc7821Actions())
```
:::
## Returns
`boolean`
If the contract supports the ERC-7821 execution mode.
## Parameters
### address
* **Type:** `Address`
The address of the contract to check.
### opData
* **Type:** `Hex`
Additional data to pass to execution.
# Extending Client with ERC-7846 Actions \[Setting up your Viem Client]
To use the experimental functionality of [ERC-7846](https://eips.ethereum.org/EIPS/eip-7846), you can extend your existing (or new) Viem Client with experimental [ERC-7846](https://eips.ethereum.org/EIPS/eip-7846) Actions.
```ts
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7846Actions } from 'viem/experimental' // [!code focus]
const client = createClient({
chain: mainnet,
transport: http(),
}).extend(erc7846Actions()) // [!code focus]
const hash = await client.connect()
```
# connect
Requests to connect Account(s) with optional [capabilities](#capabilities).
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const { accounts } = await walletClient.connect() // [!code focus]
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7846Actions } from 'viem/experimental'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
}).extend(erc7846Actions())
```
:::
## Returns
List of connected accounts.
```ts
type ReturnType = {
accounts: readonly {
address: Address
capabilities: Record
}[]
}
```
## Parameters
### `capabilities`
* **Type:** `Record`
Key-value pairs of [capabilities](#capabilities).
```ts twoslash
import { walletClient } from './config'
const { accounts } = await walletClient.connect({
capabilities: { // [!code focus]
unstable_signInWithEthereum: { // [!code focus]
chainId: 1, // [!code focus]
nonce: 'abcd1234', // [!code focus]
} // [!code focus]
} // [!code focus]
})
```
## Capabilities
### `unstable_addSubAccount`
Adds a Sub Account to the connected Account. [See more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md)
```ts twoslash
import { walletClient } from './config'
const { accounts } = await walletClient.connect({
capabilities: {
unstable_addSubAccount: { // [!code focus]
account: { // [!code focus]
keys: [{ // [!code focus]
key: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
type: 'address', // [!code focus]
}], // [!code focus]
type: 'create', // [!code focus]
} // [!code focus]
} // [!code focus]
}
})
// @log: [{
// @log: address: '0x90F79bf6EB2c4f870365E785982E1f101E93b906',
// @log: capabilities: {
// @log: unstable_subAccounts: [{
// @log: address: '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',
// @log: }],
// @log: },
// @log: }]
```
### `unstable_subAccounts`
Returns all Sub Accounts of the connected Account. [See more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md)
```ts twoslash
import { walletClient } from './config'
const { accounts } = await walletClient.connect()
// @log: [{
// @log: address: '0x90F79bf6EB2c4f870365E785982E1f101E93b906',
// @log: capabilities: {
// @log: unstable_subAccounts: [{
// @log: address: '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',
// @log: }],
// @log: },
// @log: }]
```
### `unstable_signInWithEthereum`
Authenticate offchain using Sign-In with Ethereum. [See more](https://github.com/ethereum/ERCs/blob/abd1c9f4eda2d6ad06ade0e3af314637a27d1ee7/ERCS/erc-7846.md#signinwithethereum)
```ts twoslash
import { walletClient } from './config'
const { accounts } = await walletClient.connect({
capabilities: {
unstable_signInWithEthereum: {
chainId: 1,
nonce: 'abcd1234',
}
}
})
// @log: [{
// @log: address: '0x90F79bf6EB2c4f870365E785982E1f101E93b906',
// @log: capabilities: {
// @log: unstable_signInWithEthereum: {
// @log: message: 'example.com wants you to sign in with your Ethereum account...',
// @log: signature: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
// @log: },
// @log: },
// @log: }]
```
## JSON-RPC Methods
* [`wallet_connect`](https://github.com/ethereum/ERCs/blob/abd1c9f4eda2d6ad06ade0e3af314637a27d1ee7/ERCS/erc-7846.md)
* Falls back to [`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102)
# disconnect
Requests to disconnect account(s).
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const { accounts } = await walletClient.disconnect() // [!code focus]
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7846Actions } from 'viem/experimental'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
}).extend(erc7846Actions())
```
:::
# addSubAccount
Requests to add a Sub Account. [See more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md)
[What is a Sub Account?](https://blog.base.dev/subaccounts)
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const subAccount = await walletClient.addSubAccount({
type: 'create',
})
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7895Actions } from 'viem/experimental'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
}).extend(erc7895Actions())
```
:::
## Returns
The created Sub Account.
```ts
type ReturnType = {
address: Address
factory?: Address | undefined
factoryData?: Hex | undefined
}
```
## Parameters
### New Accounts
Allows the wallet to create a Sub Account with a set of known signing keys. [Learn more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md#createaccount)
#### `keys`
Set of signing keys that will belong to the Sub Account.
```ts twoslash
import { walletClient } from './config'
const subAccount = await walletClient.addSubAccount({
keys: [{ // [!code focus]
publicKey: '0xefd5fb29a274ea6682673d8b3caa9263e936d48d486e5df68893003e01241522', // [!code focus]
type: 'p256' // [!code focus]
}], // [!code focus]
type: 'create',
})
```
#### `keys.publicKey`
* **Type:** `Hex`
The public key of the signing key.
* This is a 32-byte hexadecimal string.
* For `type: "address"`, this is a 20-byte address.
```ts twoslash
import { walletClient } from './config'
const subAccount = await walletClient.addSubAccount({
keys: [{
publicKey: '0xefd5fb29a274ea6682673d8b3caa9263e936d48d486e5df68893003e01241522', // [!code focus]
type: 'p256'
}],
type: 'create',
})
```
#### `keys.type`
* **Type:** `'address' | 'p256' | 'webcrypto-p256' | 'webauthn-p256'`
The type of signing key.
```ts twoslash
import { walletClient } from './config'
const subAccount = await walletClient.addSubAccount({
keys: [{
publicKey: '0xefd5fb29a274ea6682673d8b3caa9263e936d48d486e5df68893003e01241522',
type: 'p256' // [!code focus]
}],
type: 'create',
})
```
### Deployed Accounts
An existing account that the user wants to link to their global account. [Learn more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md#deployedaccount)
#### `address`
Address of the deployed account.
```ts twoslash
import { walletClient } from './config'
const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000', // [!code focus]
type: 'deployed',
})
```
#### `chainId`
The chain ID of the deployed account.
```ts twoslash
import { walletClient } from './config'
const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000',
chainId: 1, // [!code focus]
type: 'deployed',
})
```
### Undeployed Accounts
An account that has been created, but is not yet deployed. The wallet will decide whether or not to deploy it. [Learn more](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md#undeployedaccount)
#### `address`
Address of the undeployed account.
```ts twoslash
import { walletClient } from './config'
const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000', // [!code focus]
factory: '0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce',
factoryData: '0xdeadbeef',
type: 'undeployed',
})
```
#### `chainId`
The chain ID the account will be deployed on.
```ts twoslash
import { walletClient } from './config'
const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000',
chainId: 1, // [!code focus]
factory: '0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce',
factoryData: '0xdeadbeef',
type: 'undeployed',
})
```
#### `factory`
The address of the factory contract.
```ts twoslash
import { walletClient } from './config'
const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000',
factory: '0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce', // [!code focus]
factoryData: '0xdeadbeef',
type: 'undeployed',
})
```
#### `factoryData`
The data to be passed to the factory contract.
```ts twoslash
import { walletClient } from './config'
const subAccount = await walletClient.addSubAccount({
address: '0x0000000000000000000000000000000000000000',
factory: '0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce',
factoryData: '0xdeadbeef', // [!code focus]
type: 'undeployed',
})
```
# Extending Client with ERC-7895 Actions \[Setting up your Viem Client]
To use the experimental functionality of [ERC-7895](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md), you can extend your existing (or new) Viem Client with experimental [ERC-7895](https://github.com/ethereum/ERCs/blob/4d3d641ee3c84750baf461b8dd71d27c424417a9/ERCS/erc-7895.md) Actions.
```ts
import { createClient, http } from 'viem'
import { mainnet } from 'viem/chains'
import { erc7895Actions } from 'viem/experimental' // [!code focus]
const client = createClient({
chain: mainnet,
transport: http(),
}).extend(erc7895Actions()) // [!code focus]
const subAccount = await client.addSubAccount({
keys: [{ key: '0x0000000000000000000000000000000000000000', type: 'address' }],
type: 'create',
})
```
# buildDepositTransaction
Builds & prepares parameters for a [deposit transaction](https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md) to be initiated on an L1 and executed on the L2.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClientL2, walletClientL1 } from './config'
const args = await publicClientL2.buildDepositTransaction({ // [!code hl]
account, // [!code hl]
mint: parseEther('1'), // [!code hl]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code hl]
}) // [!code hl]
const hash = await walletClientL1.depositTransaction(args)
```
```ts [config.ts]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, base } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const walletClientL1 = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
// JSON-RPC Account
export const [account] = await walletClientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `buildDepositTransaction`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts [example.ts]
import { publicClientL2, walletClientL1 } from './config'
const args = await publicClientL2.buildDepositTransaction({
mint: parseEther('1')
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
const hash = await walletClientL1.depositTransaction(args)
```
```ts [config.ts (JSON-RPC Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, base } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider. // [!code hl]
const [account] = await window.ethereum.request({ // [!code hl]
method: 'eth_requestAccounts' // [!code hl]
}) // [!code hl]
export const walletClientL1 = createWalletClient({
account, // [!code hl]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, base } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const walletClientL1 = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code hl]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
`DepositTransactionParameters`
The parameters required to execute a [deposit transaction](/op-stack/actions/depositTransaction).
## Parameters
### account (optional)
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const args = await client.buildDepositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### data (optional)
* **Type:** `Hex`
Contract deployment bytecode or encoded contract method & arguments.
```ts
const args = await client.buildDepositTransaction({
data: '0x...', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### gas (optional)
* **Type:** `bigint`
Gas limit for transaction execution on the L2.
```ts
const args = await client.buildDepositTransaction({
gas: 21_000n, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### isCreation (optional)
* **Type:** `boolean`
Whether or not this is a contract deployment transaction.
```ts
const args = await client.buildDepositTransaction({
data: '0x...',
isCreation: true // [!code focus]
})
```
### mint (optional)
* **Type:** `bigint`
Value in wei to mint (deposit) on the L2. Debited from the caller's L1 balance.
```ts
const args = await client.buildDepositTransaction({
mint: parseEther('1') // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### to (optional)
* **Type:** `Address`
L2 Transaction recipient.
```ts
const args = await client.buildDepositTransaction({
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
})
```
### value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction on the L2. Debited from the caller's L2 balance.
```ts
const args = await client.buildDepositTransaction({
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
})
```
# buildInitiateWithdrawal
Builds & prepares parameters for a [withdrawal](https://community.optimism.io/docs/protocol/withdrawal-flow/#withdrawal-initiating-transaction) to be initiated on an L2.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClientL1, walletClientL2 } from './config'
const args = await publicClientL1.buildInitiateWithdrawal({ // [!code hl]
account, // [!code hl]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code hl]
value: parseEther('1'), // [!code hl]
}) // [!code hl]
const hash = await walletClientL2.initiateWithdrawal(args)
```
```ts [config.ts]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL2 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
chain: optimism,
transport: custom(window.ethereum)
}).extend(walletActionsL2())
// JSON-RPC Account
export const [account] = await walletClientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `buildInitiateWithdrawal`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts [example.ts]
import { publicClientL1, walletClientL2 } from './config'
const args = await publicClientL1.buildInitiateWithdrawal({
mint: parseEther('1')
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
const hash = await walletClientL2.initiateWithdrawal(args)
```
```ts [config.ts (JSON-RPC Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL2 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider. // [!code hl]
const [account] = await window.ethereum.request({ // [!code hl]
method: 'eth_requestAccounts' // [!code hl]
}) // [!code hl]
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL2 = createWalletClient({
chain: optimism,
account, // [!code hl]
transport: custom(window.ethereum)
}).extend(walletActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL2 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL2 = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code hl]
chain: optimism,
transport: custom(window.ethereum)
}).extend(walletActionsL2())
```
:::
## Returns
`InitiateWithdrawalParameters`
The parameters required to initiate a [withdrawal](/op-stack/actions/initiateWithdrawal).
## Parameters
### account (optional)
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const args = await client.buildInitiateWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### data (optional)
* **Type:** `Hex`
Encoded contract method & arguments.
```ts
const args = await client.buildInitiateWithdrawal({
data: '0x...', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### gas (optional)
* **Type:** `bigint`
Gas limit for transaction execution on the L1.
```ts
const args = await client.buildInitiateWithdrawal({
gas: 21_000n, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### to (optional)
* **Type:** `Address`
L1 recipient.
```ts
const args = await client.buildInitiateWithdrawal({
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
})
```
### value (optional)
* **Type:** `bigint`
Value in wei to withdrawal from the L2 to the L1. Debited from the caller's L2 balance.
```ts
const args = await client.buildInitiateWithdrawal({
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
})
```
# buildProveWithdrawal
Builds the transaction that proves a withdrawal was initiated on an L2. Used in the Withdrawal flow.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClientL2, walletClientL1 } from './config'
const receipt = await getTransactionReceipt(publicClientL2, {
hash: '0xbbdd0957a82a057a76b5f093de251635ac4ddc6e2d0c4aa7fbf82d73e4e11039',
})
const [withdrawal] = getWithdrawals(receipt)
const output = await walletClientL1.getL2Output({
l2BlockNumber: receipt.blockNumber,
targetChain: publicClientL2.chain,
})
const args = await publicClientL2.buildProveWithdrawal({ // [!code hl]
account, // [!code hl]
output, // [!code hl]
withdrawal, // [!code hl]
}) // [!code hl]
const hash = await walletClientL1.proveWithdrawal(args)
```
```ts [config.ts]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, base } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const walletClientL1 = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
// JSON-RPC Account
export const [account] = await walletClientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `buildProveWithdrawal`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts [example.ts]
import { publicClientL2, walletClientL1 } from './config'
const args = await publicClientL2.buildProveWithdrawal({
output,
withdrawal,
})
const hash = await walletClientL1.proveWithdrawal(args)
```
```ts [config.ts (JSON-RPC Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, base } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider. // [!code hl]
const [account] = await window.ethereum.request({ // [!code hl]
method: 'eth_requestAccounts' // [!code hl]
}) // [!code hl]
export const walletClientL1 = createWalletClient({
account, // [!code hl]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, base } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const walletClientL1 = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code hl]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
`BuildProveWithdrawalReturnType`
The parameters required to execute a [prove withdrawal transaction](/op-stack/actions/proveWithdrawal).
## Parameters
### account (optional)
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const args = await client.buildProveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
output,
withdrawal,
})
```
### output
* **Type:** `GetL2OutputReturnType`
The L2 output. Typically provided by [`getL2Output` Action](/op-stack/actions/getL2Output).
```ts
const args = await client.buildProveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
output: { /* ... */ }, // [!code focus]
withdrawal,
})
```
### withdrawal
* **Type:** `Withdrawal`
The withdrawal message. Typically provided by [`getWithdrawals` Action](/op-stack/utilities/getWithdrawals).
```ts
const args = await client.buildProveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
output,
withdrawal: { /* ... */ }, // [!code focus]
})
```
# depositTransaction
Initiates a [deposit transaction](https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md) on an L1, which executes a transaction on an L2.
Internally performs a contract write to the [`depositTransaction` function](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol#L378) on the [Optimism Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol).
## Usage
:::code-group
```ts [example.ts]
import { base } from 'viem/chains'
import { account, walletClientL1 } from './config'
const hash = await walletClientL1.depositTransaction({
account,
request: {
gas: 21_000n,
mint: parseEther('1')
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
},
targetChain: base,
})
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { walletActionsL1 } from 'viem/op-stack'
export const walletClientL1 = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
// JSON-RPC Account
export const [account] = await walletClientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
:::warning
You must [build the parameters](#building-parameters) on the L2 before calling this function. If the gas is too low, transaction execution will fail on the L2.
:::
### Building Parameters
The [`buildDepositTransaction` Action](/op-stack/actions/buildDepositTransaction) builds & prepares the deposit transaction parameters (ie. `gas`, `targetChain`, etc).
We can use the resulting `args` to initiate the deposit transaction on the L1.
:::code-group
```ts [example.ts]
import { account, publicClientL2, walletClientL1 } from './config'
// Build parameters for the transaction on the L2.
const args = await publicClientL2.buildDepositTransaction({
account,
mint: parseEther('1')
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
// Execute the deposit transaction on the L1.
const hash = await walletClientL1.depositTransaction(args)
```
```ts [config.ts]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, base } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const walletClientL1 = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
// JSON-RPC Account
export const [account] = await clientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
[See more on the `buildDepositTransaction` Action.](/op-stack/actions/buildDepositTransaction)
### Account Hoisting
If you do not wish to pass an `account` to every `depositTransaction`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more.](/docs/clients/wallet#account)
:::code-group
```ts [example.ts]
import { publicClientL2, walletClientL1 } from './config'
// Prepare parameters for the deposit transaction on the L2.
const args = await publicClientL2.buildDepositTransaction({
mint: parseEther('1')
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
// Initiate the deposit transaction on the L1.
const hash = await walletClientL1.depositTransaction(args)
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, createPublicClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, base } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider. // [!code hl]
const [account] = await window.ethereum.request({ // [!code hl]
method: 'eth_requestAccounts' // [!code hl]
}) // [!code hl]
export const walletClientL1 = createWalletClient({
account, // [!code hl]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, base } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const walletClientL1 = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code hl]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [L1 Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
targetChain: base,
})
```
### args.data (optional)
* **Type:** `Hex`
Contract deployment bytecode or encoded contract method & arguments.
```ts
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
data: '0x...', // [!code focus]
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
targetChain: base,
})
```
### args.gas
* **Type:** `bigint`
Gas limit for transaction execution on the L2.
```ts
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
targetChain: base,
})
```
### args.isCreation (optional)
* **Type:** `boolean`
Whether or not this is a contract deployment transaction.
```ts
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
data: '0x...',
gas: 69_420n,
isCreation: true // [!code focus]
},
targetChain: base,
})
```
### args.mint (optional)
* **Type:** `bigint`
Value in wei to mint (deposit) on the L2. Debited from the caller's L1 balance.
```ts
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
mint: parseEther('1') // [!code focus]
},
targetChain: base,
})
```
### args.to (optional)
* **Type:** `Address`
L2 Transaction recipient.
```ts
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
},
targetChain: base,
})
```
### args.value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction on the L2. Debited from the caller's L2 balance.
```ts
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
},
targetChain: base,
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain to execute the transaction on.
```ts
import { mainnet } from 'viem/chains'
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
chain: mainnet,
targetChain: base, // [!code focus]
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `client.chain`
The L1 chain. If there is a mismatch between the wallet's current chain & this chain, an error will be thrown.
```ts
import { mainnet } from 'viem/chains'
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
chain: mainnet, // [!code focus]
targetChain: base,
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
maxFeePerGas: parseGwei('20'), // [!code focus]
targetChain: base,
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
targetChain: base,
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
nonce: 69, // [!code focus]
targetChain: base,
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [Optimism Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol). Defaults to the Optimism Portal contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const hash = await client.depositTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# estimateContractL1Fee
Estimates the [L1 data fee](https://docs.optimism.io/stack/transactions/fees#l1-data-fee) to execute an L2 contract write.
Invokes the `getL1Fee` method on the [Gas Price Oracle](https://github.com/ethereum-optimism/optimism/blob/233ede59d16cb01bdd8e7ff662a153a4c3178bdd/packages/contracts/contracts/L2/predeploys/OVM_GasPriceOracle.sol) predeploy contract.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
import { wagmiAbi } from './abi'
const l1Fee = await publicClient.estimateContractL1Fee({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [{ name: "", type: "uint32" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
`bigint`
The L1 data fee estimate (in wei).
## Parameters
### account
* **Type:** `Account | Address`
The Account to estimate fee from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const fee = await publicClient.estimateContractL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
})
```
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const fee = await publicClient.estimateContractL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'mint',
})
```
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
const fee = await publicClient.estimateContractL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'mint',
})
```
### functionName
* **Type:** `string`
A function to extract from the ABI.
```ts
const fee = await publicClient.estimateContractL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint', // [!code focus]
})
```
### args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
const fee = await publicClient.estimateContractL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'], // [!code focus]
})
```
### gasPriceOracleAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Address of the Gas Price Oracle predeploy contract.
```ts
const fee = await publicClient.estimateContractL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
gasPriceOracleAddress: '0x420000000000000000000000000000000000000F', // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const fee = await publicClient.estimateContractL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei).
```ts
const fee = await publicClient.estimateContractL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const fee = await publicClient.estimateContractL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
nonce: 69, // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts
const fee = await publicClient.estimateContractL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
value: parseEther('1') // [!code focus]
})
```
# estimateContractL1Gas
Estimates the [L1 data gas](https://docs.optimism.io/stack/transactions/fees#l1-data-fee) to execute an L2 contract write.
Invokes the `getL1GasUsed` method on the [Gas Price Oracle](https://github.com/ethereum-optimism/optimism/blob/233ede59d16cb01bdd8e7ff662a153a4c3178bdd/packages/contracts/contracts/L2/predeploys/OVM_GasPriceOracle.sol) predeploy contract.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
import { wagmiAbi } from './abi'
const l1Fee = await publicClient.estimateContractL1Gas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [{ name: "", type: "uint32" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
`bigint`
The L1 data gas estimate.
## Parameters
### account
* **Type:** `Account | Address`
The Account to estimate gas from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const gas = await publicClient.estimateContractL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
})
```
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const gas = await publicClient.estimateContractL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'mint',
})
```
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
const gas = await publicClient.estimateContractL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'mint',
})
```
### functionName
* **Type:** `string`
A function to extract from the ABI.
```ts
const gas = await publicClient.estimateContractL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint', // [!code focus]
})
```
### args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
const gas = await publicClient.estimateContractL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'], // [!code focus]
})
```
### gasPriceOracleAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Address of the Gas Price Oracle predeploy contract.
```ts
const gas = await publicClient.estimateContractL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
gasPriceOracleAddress: '0x420000000000000000000000000000000000000F', // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const gas = await publicClient.estimateContractL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei).
```ts
const gas = await publicClient.estimateContractL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const { result } = await publicClient.estimateContractL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
nonce: 69, // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts
const gas = await publicClient.estimateContractL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
value: parseEther('1') // [!code focus]
})
```
# estimateContractTotalFee
Estimates the total ([L1 data](https://docs.optimism.io/stack/transactions/fees#l1-data-fee) + L2) fee to execute an L2 contract write.
Invokes the `getL1Fee` method on the [Gas Price Oracle](https://github.com/ethereum-optimism/optimism/blob/233ede59d16cb01bdd8e7ff662a153a4c3178bdd/packages/contracts/contracts/L2/predeploys/OVM_GasPriceOracle.sol) predeploy contract.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
import { wagmiAbi } from './abi'
const fee = await publicClient.estimateContractTotalFee({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [{ name: "", type: "uint32" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
`bigint`
The total (L1 + L2) fee estimate (in wei).
## Parameters
### account
* **Type:** `Account | Address`
The Account to estimate fee from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const fee = await publicClient.estimateContractTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
})
```
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const fee = await publicClient.estimateContractTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'mint',
})
```
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
const fee = await publicClient.estimateContractTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'mint',
})
```
### functionName
* **Type:** `string`
A function to extract from the ABI.
```ts
const fee = await publicClient.estimateContractTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint', // [!code focus]
})
```
### args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
const fee = await publicClient.estimateContractTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'], // [!code focus]
})
```
### gasPriceOracleAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Address of the Gas Price Oracle predeploy contract.
```ts
const fee = await publicClient.estimateContractTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
gasPriceOracleAddress: '0x420000000000000000000000000000000000000F', // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const fee = await publicClient.estimateContractTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei).
```ts
const fee = await publicClient.estimateContractTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const fee = await publicClient.estimateContractTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
nonce: 69, // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts
const fee = await publicClient.estimateContractTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
value: parseEther('1') // [!code focus]
})
```
# estimateContractTotalGas
Estimates the total ([L1 data](https://docs.optimism.io/stack/transactions/fees#l1-data-fee) + L2) gas to execute an L2 contract write.
Invokes the `getL1GasUsed` method on the [Gas Price Oracle](https://github.com/ethereum-optimism/optimism/blob/233ede59d16cb01bdd8e7ff662a153a4c3178bdd/packages/contracts/contracts/L2/predeploys/OVM_GasPriceOracle.sol) predeploy contract.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
import { wagmiAbi } from './abi'
const gas = await publicClient.estimateContractTotalGas({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
account,
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
name: "mint",
outputs: [{ name: "", type: "uint32" }],
stateMutability: "view",
type: "function",
},
...
] as const;
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
`bigint`
The total (L1 data + L2) gas estimate.
## Parameters
### account
* **Type:** `Account | Address`
The Account to estimate gas from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const gas = await publicClient.estimateContractTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
})
```
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const gas = await publicClient.estimateContractTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'mint',
})
```
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
const gas = await publicClient.estimateContractTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'mint',
})
```
### functionName
* **Type:** `string`
A function to extract from the ABI.
```ts
const gas = await publicClient.estimateContractTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint', // [!code focus]
})
```
### args (optional)
* **Type:** Inferred from ABI.
Arguments to pass to function call.
```ts
const gas = await publicClient.estimateContractTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0x1dfe7ca09e99d10835bf73044a23b73fc20623df',
abi: wagmiAbi,
functionName: 'balanceOf',
args: ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'], // [!code focus]
})
```
### gasPriceOracleAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Address of the Gas Price Oracle predeploy contract.
```ts
const gas = await publicClient.estimateContractTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
gasPriceOracleAddress: '0x420000000000000000000000000000000000000F', // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const gas = await publicClient.estimateContractTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei).
```ts
const gas = await publicClient.estimateContractTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const { result } = await publicClient.estimateContractTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
nonce: 69, // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts
const gas = await publicClient.estimateContractTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
value: parseEther('1') // [!code focus]
})
```
# estimateDepositTransactionGas
Estimates gas to initiate a [deposit transaction](https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md) on an L1, which executes a transaction on an L2.
## Usage
:::code-group
```ts [example.ts]
import { base } from 'viem/chains'
import { account, publicClientL1 } from './config'
const gas = await publicClientL1.estimateDepositTransactionGas({
account,
request: {
gas: 21_000n,
mint: parseEther('1')
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
},
targetChain: base,
})
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
// JSON-RPC Account
export const [account] = await publicClientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
## Returns
`bigint`
Gas required to execute the transaction on the L1.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
targetChain: base,
})
```
### args.data (optional)
* **Type:** `Hex`
Contract deployment bytecode or encoded contract method & arguments.
```ts
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
data: '0x...', // [!code focus]
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
targetChain: base,
})
```
### args.gas
* **Type:** `bigint`
Gas limit for transaction execution on the L2.
```ts
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
targetChain: base,
})
```
### args.isCreation (optional)
* **Type:** `boolean`
Whether or not this is a contract deployment transaction.
```ts
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
data: '0x...',
gas: 69_420n,
isCreation: true // [!code focus]
},
targetChain: base,
})
```
### args.mint (optional)
* **Type:** `bigint`
Value in wei to mint (deposit) on the L2. Debited from the caller's L1 balance.
```ts
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
mint: parseEther('1') // [!code focus]
},
targetChain: base,
})
```
### args.to (optional)
* **Type:** `Address`
L2 Transaction recipient.
```ts
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
},
targetChain: base,
})
```
### args.value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction on the L2. Debited from the caller's L2 balance.
```ts
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
},
targetChain: base,
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain to execute the transaction on.
```ts
import { mainnet } from 'viem/chains'
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
chain: mainnet,
targetChain: base, // [!code focus]
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `client.chain`
The L1 chain. If there is a mismatch between the wallet's current chain & this chain, an error will be thrown.
```ts
import { mainnet } from 'viem/chains'
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
chain: mainnet, // [!code focus]
targetChain: base,
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
maxFeePerGas: parseGwei('20'), // [!code focus]
targetChain: base,
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
targetChain: base,
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
nonce: 69, // [!code focus]
targetChain: base,
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [Optimism Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol). Defaults to the Optimism Portal contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const gas = await client.estimateDepositTransactionGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# estimateFinalizeWithdrawalGas
Estimates gas required to finalize a withdrawal that occurred on an L2.
## Usage
:::code-group
```ts [example.ts]
import { optimism } from 'viem/chains'
import { account, publicClientL1 } from './config'
const gas = await publicClientL1.estimateFinalizeWithdrawalGas({ // [!code hl]
account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', // [!code hl]
targetChain: optimism, // [!code hl]
withdrawal: { ... }, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
// JSON-RPC Account
export const [account] = await walletClientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
## Returns
`bigint`
The estimated gas.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const hash = await client.estimateFinalizeWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `client.chain`
The L1 chain. If there is a mismatch between the wallet's current chain & this chain, an error will be thrown.
```ts
import { mainnet } from 'viem/chains'
const hash = await client.estimateFinalizeWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
chain: mainnet, // [!code focus]
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### gas (optional)
* **Type:** `bigint`
Gas limit for transaction execution on the L1.
```ts
const hash = await client.estimateFinalizeWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
gas: 420_000n, // [!code focus]
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### proofSubmitter (optional)
* **Type:** `Address`
The address of the proof submitter to use when finalizing the withdrawal. No-op when the OptimismPortal contract version is less than v3.
If unspecified, the sending account is the proof submitter.
```ts
const hash = await client.finalizeWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
proofSubmitter: '0xD15F47c16BD277ff2dee6a0bD4e418165231CB69', // [!code focus]
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const hash = await client.estimateFinalizeWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
maxFeePerGas: parseGwei('20'), // [!code focus]
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const hash = await client.estimateFinalizeWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const hash = await client.estimateFinalizeWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
withdrawal: { /* ... */ },
nonce: 69, // [!code focus]
targetChain: optimism,
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [Optimism Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol). Defaults to the Optimism Portal contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const hash = await client.estimateFinalizeWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
outputRootProof: { /* ... */ },
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
targetChain: optimism,
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain to execute the transaction on.
```ts
import { mainnet } from 'viem/chains'
const hash = await client.estimateFinalizeWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
withdrawal: { /* ... */ },
targetChain: optimism, // [!code focus]
})
```
### withdrawal
* **Type:** `bigint`
The withdrawal.
```ts
const hash = await client.estimateFinalizeWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
gas: 420_000n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ }, // [!code focus]
targetChain: optimism,
})
```
# estimateInitiateWithdrawalGas
Estimates gas required to initiate a [withdrawal](https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md) on an L2 to the L1.
## Usage
:::code-group
```ts [example.ts]
import { base } from 'viem/chains'
import { account, publicClientL2 } from './config'
const gas = await publicClientL2.estimateInitiateWithdrawalGas({
account,
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
})
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack'
export const publicClientL2 = createPublicClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
// JSON-RPC Account
export const [account] = await walletClientL2.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
## Returns
`bigint`
Estimated gas required to initiate the withdrawal.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const gas = await client.estimateInitiateWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
targetChain: base,
})
```
### args.data (optional)
* **Type:** `Hex`
Encoded contract method & arguments.
```ts
const gas = await client.estimateInitiateWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
data: '0x...', // [!code focus]
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
})
```
### args.gas
* **Type:** `bigint`
Gas limit for transaction execution on the L1.
```ts
const gas = await client.estimateInitiateWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
})
```
### args.to
* **Type:** `Address`
L1 Transaction recipient.
```ts
const gas = await client.estimateInitiateWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
},
})
```
### args.value (optional)
* **Type:** `bigint`
Value in wei to withdrawal from the L2 to the L1. Debited from the caller's L2 balance.
```ts
const gas = await client.estimateInitiateWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
},
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `client.chain`
The L2 chain. If there is a mismatch between the wallet's current chain & this chain, an error will be thrown.
```ts
import { optimism } from 'viem/chains'
const gas = await client.estimateInitiateWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
chain: optimism, // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const gas = await client.estimateInitiateWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const gas = await client.estimateInitiateWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const gas = await client.estimateInitiateWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
nonce: 69, // [!code focus]
})
```
# estimateL1Fee
Estimates the [L1 data fee](https://docs.optimism.io/stack/transactions/fees#l1-data-fee) to execute an L2 transaction.
Invokes the `getL1Fee` method on the [Gas Price Oracle](https://github.com/ethereum-optimism/optimism/blob/233ede59d16cb01bdd8e7ff662a153a4c3178bdd/packages/contracts/contracts/L2/predeploys/OVM_GasPriceOracle.sol) predeploy contract.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
const fee = await publicClient.estimateL1Fee({ // [!code focus:7]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
`bigint`
The L1 data fee (in wei).
## Parameters
### account
* **Type:** `Account | Address`
The Account to estimate fee from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const fee = await publicClient.estimateL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### data (optional)
* **Type:** `0x${string}`
Contract code or a hashed method call with encoded args.
```ts
const fee = await publicClient.estimateL1Fee({
data: '0x...', // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### gasPriceOracleAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Address of the Gas Price Oracle predeploy contract.
```ts
const fee = await publicClient.estimateL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
gasPriceOracleAddress: '0x420000000000000000000000000000000000000F', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const fee = await publicClient.estimateL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei).
```ts
const fee = await publicClient.estimateL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const fee = await publicClient.estimateL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### to (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Transaction recipient.
```ts
const fee = await publicClient.estimateL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts
const fee = await publicClient.estimateL1Fee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
})
```
# estimateL1Gas
Estimates the amount of [L1 data gas](https://docs.optimism.io/stack/transactions/fees#l1-data-fee) required to execute an L2 transaction.
Invokes the `getL1GasUsed` method on the [Gas Price Oracle](https://github.com/ethereum-optimism/optimism/blob/233ede59d16cb01bdd8e7ff662a153a4c3178bdd/packages/contracts/contracts/L2/predeploys/OVM_GasPriceOracle.sol) predeploy contract.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
const gas = await publicClient.estimateL1Gas({ // [!code focus:7]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
`bigint`
The L1 data gas estimate.
## Parameters
### account
* **Type:** `Account | Address`
The Account to estimate gas from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const gas = await publicClient.estimateL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### data (optional)
* **Type:** `0x${string}`
Contract code or a hashed method call with encoded args.
```ts
const gas = await publicClient.estimateL1Gas({
data: '0x...', // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### gasPriceOracleAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Address of the Gas Price Oracle predeploy contract.
```ts
const gas = await publicClient.estimateL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
gasPriceOracleAddress: '0x420000000000000000000000000000000000000F', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const gas = await publicClient.estimateL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei).
```ts
const gas = await publicClient.estimateL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const fee = await publicClient.estimateL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### to (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Transaction recipient.
```ts
const gas = await publicClient.estimateL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts
const gas = await publicClient.estimateL1Gas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
})
```
# estimateOperatorFee
Estimates the [operator fee](https://docs.optimism.io/stack/transactions/fees#operator-fee) to execute an L2 transaction.
The operator fee is part of the Isthmus upgrade and allows OP Stack operators to recover costs related to Alt-DA, ZK proving, or custom gas tokens. Returns 0 for pre-Isthmus chains or when operator fee functions don't exist.
The fee is calculated using the formula: `operatorFee = operatorFeeConstant + operatorFeeScalar * gasUsed / 1e6`
## Usage
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
const fee = await publicClient.estimateOperatorFee({ // [!code focus:7]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
`bigint`
The operator fee (in wei).
## Parameters
### account
* **Type:** `Account | Address`
The Account to estimate fee from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const fee = await publicClient.estimateOperatorFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### data (optional)
* **Type:** `0x${string}`
Contract code or a hashed method call with encoded args.
```ts
const fee = await publicClient.estimateOperatorFee({
data: '0x...', // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### l1BlockAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Address of the L1Block predeploy contract.
```ts
const fee = await publicClient.estimateOperatorFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l1BlockAddress: '0x4200000000000000000000000000000000000015', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const fee = await publicClient.estimateOperatorFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei).
```ts
const fee = await publicClient.estimateOperatorFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const fee = await publicClient.estimateOperatorFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### to (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Transaction recipient.
```ts
const fee = await publicClient.estimateOperatorFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts
const fee = await publicClient.estimateOperatorFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
})
```
# estimateProveWithdrawalGas
Estimates gas required to prove a withdrawal that occurred on an L2.
## Usage
:::code-group
```ts [example.ts]
import { optimism } from 'viem/chains'
import { account, publicClientL1 } from './config'
const gas = await publicClientL1.estimateProveWithdrawalGas({ // [!code hl]
account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', // [!code hl]
l2OutputIndex: 4529n, // [!code hl]
outputRootProof: { ... }, // [!code hl]
targetChain: optimism, // [!code hl]
withdrawalProof: [ ... ], // [!code hl]
withdrawal: { ... }, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
// JSON-RPC Account
export const [account] = await walletClientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
## Returns
`bigint`
The estimated gas.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
l2OutputIndex: 4529n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `client.chain`
The L1 chain. If there is a mismatch between the wallet's current chain & this chain, an error will be thrown.
```ts
import { mainnet } from 'viem/chains'
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
chain: mainnet, // [!code focus]
l2OutputIndex: 4529n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### gas (optional)
* **Type:** `bigint`
Gas limit for transaction execution on the L1.
```ts
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
gas: 420_000n, // [!code focus]
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### l2OutputIndex
* **Type:** `bigint`
The index of the L2 output. Typically derived from the [`buildProveWithdrawal` Action](/op-stack/actions/buildProveWithdrawal).
```ts
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n, // [!code focus]
gas: 420_000n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
maxFeePerGas: parseGwei('20'), // [!code focus]
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
nonce: 69, // [!code focus]
targetChain: optimism,
})
```
### outputRootProof (optional)
* **Type:** `bigint`
The proof of the L2 output. Typically derived from the [`buildProveWithdrawal` Action](/op-stack/actions/buildProveWithdrawal).
```ts
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
gas: 420_000n,
outputRootProof: { /* ... */ }, // [!code focus]
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [Optimism Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol). Defaults to the Optimism Portal contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
outputRootProof: { /* ... */ },
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
targetChain: optimism,
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain to execute the transaction on.
```ts
import { mainnet } from 'viem/chains'
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism, // [!code focus]
})
```
### withdrawalProof
* **Type:** `bigint`
The proof of the L2 withdrawal. Typically derived from the [`buildProveWithdrawal` Action](/op-stack/actions/buildProveWithdrawal).
```ts
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
gas: 420_000n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ], // [!code focus]
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### withdrawal
* **Type:** `bigint`
The withdrawal. Typically derived from the [`buildProveWithdrawal` Action](/op-stack/actions/buildProveWithdrawal).
```ts
const hash = await client.estimateProveWithdrawalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
gas: 420_000n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ }, // [!code focus]
targetChain: optimism,
})
```
# estimateTotalFee
Estimates the [L1 data fee](https://docs.optimism.io/stack/transactions/fees#l1-data-fee) + L2 fee + [operator fee](https://docs.optimism.io/stack/transactions/fees#operator-fee) to execute an L2 transaction.
It is the sum of [`estimateL1Fee`](/op-stack/actions/estimateL1Fee) (L1 Gas), [`estimateOperatorFee`](/op-stack/actions/estimateOperatorFee) (Operator Fee), and [`estimateGas`](/docs/actions/public/estimateGas.md) \* [`getGasPrice`](/docs/actions/public/getGasPrice.md) (L2 Gas \* L2 Gas Price).
## Usage
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
const fee = await publicClient.estimateTotalFee({ // [!code focus:7]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
`bigint`
The total fee (L1 + L2 + operator fee, in wei).
## Parameters
### account
* **Type:** `Account | Address`
The Account to estimate fee from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const fee = await publicClient.estimateTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### data (optional)
* **Type:** `0x${string}`
Contract code or a hashed method call with encoded args.
```ts
const fee = await publicClient.estimateTotalFee({
data: '0x...', // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### gasPriceOracleAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Address of the Gas Price Oracle predeploy contract.
```ts
const fee = await publicClient.estimateTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
gasPriceOracleAddress: '0x420000000000000000000000000000000000000F', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### l1BlockAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Address of the L1Block predeploy contract.
```ts
const fee = await publicClient.estimateTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l1BlockAddress: '0x4200000000000000000000000000000000000015', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const fee = await publicClient.estimateTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei).
```ts
const fee = await publicClient.estimateTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const fee = await publicClient.estimateTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### to (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Transaction recipient.
```ts
const fee = await publicClient.estimateTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts
const fee = await publicClient.estimateTotalFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
})
```
# estimateTotalGas
Estimates the amount of [L1 data gas](https://docs.optimism.io/stack/transactions/fees#l1-data-fee) + L2 gas required to execute an L2 transaction.
It is the sum of [`estimateL1Gas`](/op-stack/actions/estimateL1Gas) (L1 Gas) and [`estimateGas`](/docs/actions/public/estimateGas.md) (L2 Gas).
## Usage
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
const gas = await publicClient.estimateTotalGas({ // [!code focus:7]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'
import { publicActionsL2 } from 'viem/op-stack'
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: base,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
`bigint`
The total (L1 + L2) gas estimate.
## Parameters
### account
* **Type:** `Account | Address`
The Account to estimate gas from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const gas = await publicClient.estimateTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### data (optional)
* **Type:** `0x${string}`
Contract code or a hashed method call with encoded args.
```ts
const gas = await publicClient.estimateTotalGas({
data: '0x...', // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### gasPriceOracleAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Address of the Gas Price Oracle predeploy contract.
```ts
const gas = await publicClient.estimateTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
gasPriceOracleAddress: '0x420000000000000000000000000000000000000F', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const gas = await publicClient.estimateTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei).
```ts
const gas = await publicClient.estimateTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const fee = await publicClient.estimateTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### to (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Transaction recipient.
```ts
const gas = await publicClient.estimateTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts
const gas = await publicClient.estimateTotalGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
})
```
# finalizeWithdrawal
Finalizes a withdrawal that occurred on an L2. Used in the Withdrawal flow.
Internally performs a contract write to the [`finalizeWithdrawalTransaction` function](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L383) on the [Optimism Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol).
If the proof submitter is specified and the OptimismPortal contract version is v3 or greater, the [`finalizeWithdrawalTransactionExternalProof` function](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L390) function will be used to finalize the withdrawal with the provided address as the proof submitter.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClientL2, walletClientL1 } from './config'
const receipt = await getTransactionReceipt(publicClientL2, {
hash: '0xbbdd0957a82a057a76b5f093de251635ac4ddc6e2d0c4aa7fbf82d73e4e11039',
})
const [withdrawal] = getWithdrawals(receipt)
const hash = await walletClientL1.finalizeWithdrawal({ // [!code hl]
account, // [!code hl]
targetChain: publicClientL2.chain, // [!code hl]
withdrawal, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const walletClientL1 = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
// JSON-RPC Account
export const [account] = await walletClientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `finalizeWithdrawal`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more.](/docs/clients/wallet#account)
:::code-group
```ts [example.ts]
import { account, publicClientL2, walletClientL1 } from './config'
const receipt = await getTransactionReceipt(publicClientL2, {
hash: '0xbbdd0957a82a057a76b5f093de251635ac4ddc6e2d0c4aa7fbf82d73e4e11039',
})
const [withdrawal] = getWithdrawals(receipt)
const hash = await walletClientL1.finalizeWithdrawal({
account, // [!code --]
targetChain: publicClientL2.chain,
withdrawal,
})
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, createPublicClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider. // [!code ++]
const [account] = await window.ethereum.request({ // [!code ++]
method: 'eth_requestAccounts' // [!code ++]
}) // [!code ++]
export const walletClientL1 = createWalletClient({
account, // [!code ++]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const walletClientL1 = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code ++]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The finalize withdrawal [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const hash = await client.finalizeWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `client.chain`
The L1 chain. If there is a mismatch between the wallet's current chain & this chain, an error will be thrown.
```ts
import { mainnet } from 'viem/chains'
const hash = await client.finalizeWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
chain: mainnet, // [!code focus]
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### gas (optional)
* **Type:** `bigint`
Gas limit for transaction execution on the L1.
`null` to skip gas estimation & defer calculation to signer.
```ts
const hash = await client.finalizeWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
gas: 420_000n, // [!code focus]
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### proofSubmitter (optional)
* **Type:** `Address`
The address of the proof submitter to use when finalizing the withdrawal. No-op when the OptimismPortal contract version is less than v3.
If unspecified, the sending account is the proof submitter.
```ts
const hash = await client.finalizeWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
proofSubmitter: '0xD15F47c16BD277ff2dee6a0bD4e418165231CB69', // [!code focus]
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const hash = await client.finalizeWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'), // [!code focus]
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const hash = await client.finalizeWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const hash = await client.finalizeWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
withdrawal: { /* ... */ },
nonce: 69, // [!code focus]
targetChain: optimism,
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [Optimism Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol). Defaults to the Optimism Portal contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const hash = await client.finalizeWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
targetChain: optimism,
withdrawal: { /* ... */ },
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain to execute the transaction on.
```ts
import { mainnet } from 'viem/chains'
const hash = await client.finalizeWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
withdrawal: { /* ... */ },
targetChain: optimism, // [!code focus]
})
```
### withdrawal
* **Type:** `bigint`
The withdrawal.
```ts
const hash = await client.finalizeWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
gas: 420_000n,
withdrawal: { /* ... */ }, // [!code focus]
targetChain: optimism,
})
```
# getGame
Retrieves a valid dispute game on an L2 that occurred after a provided L2 block number. Used for the [Withdrawal](/op-stack/guides/withdrawals) flow.
:::info
This Action is only compatible with OP Stack chains that have upgraded to [Fault Proofs](https://docs.optimism.io/stack/protocol/fault-proofs/overview) and have a deployed [DisputeGameFactoryProxy contract](https://github.com/ethereum-optimism/superchain-registry/blob/main/superchain/extra/addresses/addresses.json).
:::
## Usage
:::code-group
```ts [example.ts]
import { optimism } from 'viem/chains'
import { account, publicClientL1 } from './config'
const game = await publicClientL1.getGame({ // [!code hl]
l2BlockNumber: 69420n, // [!code hl]
targetChain: optimism, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
```
:::
## Returns
`GetGameReturnType`
A valid dispute game.
## Parameters
### l2BlockNumber
* **Type:** `bigint`
The L2 block number.
```ts
const game = await publicClientL1.getGame({
l2BlockNumber: 69420n, // [!code focus]
targetChain: optimism,
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const game = await publicClientL1.getGame({
l2BlockNumber,
targetChain: optimism, // [!code focus]
})
```
### disputeGameFactoryAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.disputeGameFactory[chainId].address`
The address of the [`DisputeGameFactory` contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/dispute/DisputeGameFactory.sol). Defaults to the `DisputeGameFactory` contract specified on the `targetChain`.
If a `disputeGameFactoryAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const game = await publicClientL1.getGame({
l2BlockNumber,
disputeGameFactoryAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# getGames
Retrieves dispute games for an L2. Used for the [Withdrawal](/op-stack/guides/withdrawals) flow.
:::info
This Action is only compatible with OP Stack chains that have upgraded to [Fault Proofs](https://docs.optimism.io/stack/protocol/fault-proofs/overview) and have a deployed [DisputeGameFactoryProxy contract](https://github.com/ethereum-optimism/superchain-registry/blob/main/superchain/extra/addresses/addresses.json).
:::
## Usage
:::code-group
```ts [example.ts]
import { optimism } from 'viem/chains'
import { account, publicClientL1 } from './config'
const games = await publicClientL1.getGames({ // [!code hl]
targetChain: optimism, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
```
:::
## Returns
`GetGamesReturnType`
Dispute games.
## Parameters
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const games = await publicClientL1.getGames({
l2BlockNumber,
targetChain: optimism, // [!code focus]
})
```
### disputeGameFactoryAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.disputeGameFactory[chainId].address`
The address of the [`DisputeGameFactory` contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/dispute/DisputeGameFactory.sol). Defaults to the `DisputeGameFactory` contract specified on the `targetChain`.
If a `disputeGameFactoryAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const games = await publicClientL1.getGames({
l2BlockNumber,
disputeGameFactoryAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
### l2BlockNumber (optional)
* **Type:** `bigint`
The L2 block number.
```ts
const games = await publicClientL1.getGames({
l2BlockNumber: 69420n, // [!code focus]
targetChain: optimism,
})
```
### limit (optional)
* **Type:** `number`
* **Default:** `100`
Limit of games to extract.
```ts
const games = await publicClientL1.getGames({
limit: 10, // [!code focus]
targetChain: optimism,
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [`Portal` contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol). Defaults to the `Portal` contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const games = await publicClientL1.getGames({
l2BlockNumber,
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# getL2Output
Retrieves the first L2 output proposal that occurred after a provided block number. Used for the [Withdrawal](/op-stack/guides/withdrawals) flow.
:::warning
**This Action will be deprecated in the future.**
Use [`getGame`](/op-stack/actions/getGame) for OP Stack chains that have upgraded to [Fault Proofs](https://docs.optimism.io/stack/protocol/fault-proofs/overview) and have a deployed [DisputeGameFactoryProxy contract](https://github.com/ethereum-optimism/superchain-registry/blob/main/superchain/extra/addresses/addresses.json).
:::
## Usage
:::code-group
```ts [example.ts]
import { optimism } from 'viem/chains'
import { account, publicClientL1 } from './config'
const output = await publicClientL1.getL2Output({ // [!code hl]
l2BlockNumber: 69420n, // [!code hl]
targetChain: optimism, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
```
:::
## Returns
`GetL2OutputReturnType`
The L2 output proposal.
## Parameters
### l2BlockNumber
* **Type:** `bigint`
The L2 block number.
```ts
const output = await publicClientL1.getL2Output({
l2BlockNumber: 69420n, // [!code focus]
targetChain: optimism,
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const output = await publicClientL1.getL2Output({
l2BlockNumber,
targetChain: optimism, // [!code focus]
})
```
### l2OutputOracleAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.l2OutputOracle[chainId].address`
The address of the [L2 Output Oracle contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L2OutputOracle.sol). Defaults to the L2 Output Oracle contract specified on the `targetChain`.
If a `l2OutputOracleAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const output = await publicClientL1.getL2Output({
l2BlockNumber,
l2OutputOracleAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# getTimeToFinalize
Returns the time until the withdrawal transaction can be finalized. Used for the [Withdrawal](/op-stack/guides/withdrawals) flow.
## Usage
:::code-group
```ts [example.ts]
import { optimism } from 'viem/chains'
import { account, publicClientL1, publicClientL2 } from './config'
const receipt = await publicClientL2.getTransactionReceipt({
hash: '0x9a2f4283636ddeb9ac32382961b22c177c9e86dd3b283735c154f897b1a7ff4a',
})
const [message] = getWithdrawals(receipt)
const { // [!code hl]
period, // [!code hl]
seconds, // [!code hl]
timestamp, // [!code hl]
} = await publicClientL1.getTimeToFinalize({ // [!code hl]
withdrawalHash: message.withdrawalHash, // [!code hl]
targetChain: optimism // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: custom(window.ethereum)
})
```
:::
## Returns
`{ period: number, seconds: number, timestamp: number }`
* `period` in seconds of the finalization stage (max wait time).
* `seconds` until the transaction can be finalized.
* `timestamp` of when the transaction can be finalized.
## Parameters
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const { seconds } = await publicClientL1.getTimeToFinalize({
withdrawalHash: '0x...', // [!code focus]
targetChain: optimism, // [!code focus]
})
```
### withdrawalHash
* **Type:** `Hash`
The withdrawal hash.
```ts
const { seconds, timestamp } = await publicClientL1.getTimeToFinalize({
withdrawalHash: '0x...', // [!code focus]
targetChain: optimism,
})
```
### l2OutputOracleAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.l2OutputOracle[chainId].address`
The address of the [L2 Output Oracle contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol). Defaults to the L2 Output Oracle contract specified on the `targetChain`.
If a `l2OutputOracleAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const { seconds } = await publicClientL1.getTimeToFinalize({
withdrawalHash: '0x...',
l2OutputOracleAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed'
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol). Defaults to the L2 Output Oracle contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const { seconds } = await publicClientL1.getTimeToFinalize({
withdrawalHash: '0x...',
l2OutputOracleAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed',
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# getTimeToNextGame
Returns the time until the next L2 dispute game (after the provided block number) is submitted. Used for the [Withdrawal](/op-stack/guides/withdrawals) flow.
:::info
This Action is only compatible with OP Stack chains that have upgraded to [Fault Proofs](https://docs.optimism.io/stack/protocol/fault-proofs/overview) and have a deployed [DisputeGameFactoryProxy contract](https://github.com/ethereum-optimism/superchain-registry/blob/main/superchain/extra/addresses/addresses.json).
:::
## Usage
:::code-group
```ts [example.ts]
import { optimism } from 'viem/chains'
import { account, publicClientL1, publicClientL2 } from './config'
const l2BlockNumber = publicClientL2.getBlockNumber()
const { // [!code hl]
interval, // [!code hl]
seconds, // [!code hl]
timestamp // [!code hl]
} = await publicClientL1.getTimeToNextGame({ // [!code hl]
l2BlockNumber, // [!code hl]
targetChain: publicClientL2.chain, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: custom(window.ethereum)
})
```
:::
## Returns
`{ interval: number, seconds: number, timestamp: number }`
* Estimated `interval` between dispute games – the max time to wait for transaction to be proved.
* Estimated `seconds` until the next dispute game is submitted.
* Estimated `timestamp` of the next dispute game.
## Parameters
### l2BlockNumber
* **Type:** `bigint`
The latest L2 block number.
```ts
const l2BlockNumber = publicClientL2.getBlockNumber() // [!code focus]
const { seconds } = await publicClientL1.getTimeToNextGame({
l2BlockNumber, // [!code focus]
targetChain: optimism,
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const { seconds } = await publicClientL1.getTimeToNextGame({
l2BlockNumber,
targetChain: optimism, // [!code focus]
})
```
### disputeGameFactoryAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.disputeGameFactory[chainId].address`
The address of the [`DisputeGameFactory` contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/dispute/DisputeGameFactory.sol). Defaults to the `DisputeGameFactory` contract specified on the `targetChain`.
If a `disputeGameFactoryAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const { seconds } = await publicClientL1.getTimeToNextGame({
l2BlockNumber,
disputeGameFactoryAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
### intervalBuffer (optional)
* **Type:** `number`
* **Default:** `1.1`
The buffer to account for discrepancies between non-deterministic time intervals.
```ts
const { seconds } = await publicClientL1.getTimeToNextGame({
intervalBuffer: 1.2, // [!code focus]
l2BlockNumber,
targetChain: optimism,
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [`Portal` contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol). Defaults to the `Portal` contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const { seconds } = await publicClientL1.getTimeToNextGame({
l2BlockNumber,
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# getTimeToNextL2Output
Returns the time until the next L2 output (after a provided block number) is submitted. Used for the [Withdrawal](/op-stack/guides/withdrawals) flow.
:::warning
**This Action will be deprecated in the future.**
Use [`getTimeToNextGame`](/op-stack/actions/getTimeToNextGame) for OP Stack chains that have upgraded to [Fault Proofs](https://docs.optimism.io/stack/fault-proofs/explainer) and have a deployed [DisputeGameFactoryProxy contract](https://github.com/ethereum-optimism/superchain-registry/blob/main/superchain/extra/addresses/addresses.json).
:::
## Usage
:::code-group
```ts [example.ts]
import { optimism } from 'viem/chains'
import { account, publicClientL1, publicClientL2 } from './config'
const l2BlockNumber = publicClientL2.getBlockNumber()
const { // [!code hl]
interval, // [!code hl]
seconds, // [!code hl]
timestamp // [!code hl]
} = await publicClientL1.getTimeToNextL2Output({ // [!code hl]
l2BlockNumber, // [!code hl]
targetChain: publicClientL2.chain, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: custom(window.ethereum)
})
```
:::
## Returns
`{ interval: number, seconds: number, timestamp: number }`
* `interval` between L2 outputs – the max time to wait for transaction to be proved.
* Estimated `seconds` until the next L2 Output is submitted.
* Estimated `timestamp` of the next L2 Output.
## Parameters
### l2BlockNumber
* **Type:** `bigint`
The latest L2 block number.
```ts
const l2BlockNumber = publicClientL2.getBlockNumber() // [!code focus]
const { seconds } = await publicClientL1.getTimeToNextL2Output({
l2BlockNumber, // [!code focus]
targetChain: optimism,
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const { seconds } = await publicClientL1.getTimeToNextL2Output({
l2BlockNumber,
targetChain: optimism, // [!code focus]
})
```
### intervalBuffer (optional)
* **Type:** `number`
* **Default:** `1.1`
The buffer to account for discrepancies between non-deterministic time intervals.
```ts
const { seconds } = await publicClientL1.getTimeToNextL2Output({
intervalBuffer: 1.2, // [!code focus]
l2BlockNumber,
targetChain: optimism,
})
```
### l2OutputOracleAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.l2OutputOracle[chainId].address`
The address of the [L2 Output Oracle contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L2OutputOracle.sol). Defaults to the L2 Output Oracle contract specified on the `targetChain`.
If a `l2OutputOracleAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const { seconds } = await publicClientL1.getTimeToNextL2Output({
l2BlockNumber,
l2OutputOracleAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# getTimeToProve
Gets time until the L2 withdrawal transaction is ready to be proved. Used for the [Withdrawal](/op-stack/guides/withdrawals) flow.
Internally calls [`getTimeToNextL2Output`](/op-stack/actions/getTimeToNextL2Output).
## Usage
:::code-group
```ts [example.ts]
import { account, publicClientL1, publicClientL2 } from './config'
const receipt = await publicClientL2.getTransactionReceipt({
hash: '0x7b5cedccfaf9abe6ce3d07982f57bcb9176313b019ff0fc602a0b70342fe3147'
})
const { // [!code hl]
interval, // [!code hl]
seconds, // [!code hl]
timestamp // [!code hl]
} = await publicClientL1.getTimeToProve({ // [!code hl]
receipt, // [!code hl]
targetChain: publicClientL2.chain, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
})
```
:::
## Returns
`{ interval: number, seconds: number, timestamp: number }`
* `interval` between L2 outputs – the max time to wait for transaction to be proved.
* Estimated `seconds` until the transaction can be proved.
* Estimated `timestamp` of when the transaction can be proved.
## Parameters
### receipt
* **Type:** `TransactionReceipt`
The transaction receipt.
```ts
const time = await publicClientL1.getTimeToProve({
receipt, // [!code focus]
targetChain: optimism,
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const time = await publicClientL1.getTimeToProve({
l2BlockNumber,
targetChain: optimism, // [!code focus]
})
```
### intervalBuffer (optional)
* **Type:** `number`
* **Default:** `1.1`
The buffer to account for discrepancies between non-deterministic time intervals.
```ts
const time = await publicClientL1.getTimeToProve({
intervalBuffer: 1.2, // [!code focus]
l2BlockNumber,
targetChain: optimism,
})
```
### l2OutputOracleAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.l2OutputOracle[chainId].address`
The address of the [L2 Output Oracle contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol). Defaults to the L2 Output Oracle contract specified on the `targetChain`.
If a `l2OutputOracleAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const time = await publicClientL1.getTimeToProve({
l2BlockNumber,
l2OutputOracleAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# getWithdrawalStatus
Returns the current status of a withdrawal. Used for the [Withdrawal](/op-stack/guides/withdrawals) flow.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClientL1, publicClientL2 } from './config'
const receipt = await publicClientL2.getTransactionReceipt({
hash: '0x7b5cedccfaf9abe6ce3d07982f57bcb9176313b019ff0fc602a0b70342fe3147'
})
const status = await publicClientL1.getWithdrawalStatus({ // [!code hl]
receipt, // [!code hl]
targetChain: publicClientL2.chain, // [!code hl]
}) // [!code hl]
// "ready-to-prove" // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
})
```
:::
## Returns
`"waiting-to-prove" | "ready-to-prove" | "waiting-to-finalize" | "ready-to-finalize" | "finalized"`
## Parameters
### receipt
* **Type:** `TransactionReceipt`
The transaction receipt.
```ts
const status = await publicClientL1.getWithdrawalStatus({
receipt, // [!code focus]
targetChain: optimism,
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const status = await publicClientL1.getWithdrawalStatus({
receipt,
targetChain: optimism, // [!code focus]
})
```
### l2OutputOracleAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.l2OutputOracle[chainId].address`
The address of the [L2 Output Oracle contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol). Defaults to the L2 Output Oracle contract specified on the `targetChain`.
If a `l2OutputOracleAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const status = await publicClientL1.getWithdrawalStatus({
receipt,
l2OutputOracleAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed'
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol). Defaults to the L2 Output Oracle contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const status = await publicClientL1.getWithdrawalStatus({
receipt,
l2OutputOracleAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed',
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# initiateWithdrawal
Initiates a [withdrawal](https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md) on an L2 to the L1.
Internally performs a contract write to the [`initiateWithdrawal` function](https://github.com/ethereum-optimism/optimism/blob/283f0aa2e3358ced30ff7cbd4028c0c0c3faa140/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol#L73) on the [Optimism L2ToL1MessagePasser predeploy contract](https://github.com/ethereum-optimism/optimism/blob/283f0aa2e3358ced30ff7cbd4028c0c0c3faa140/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol).
## Usage
:::code-group
```ts [example.ts]
import { base } from 'viem/chains'
import { account, walletClientL2 } from './config'
const hash = await walletClientL2.initiateWithdrawal({
account,
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
})
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { optimism } from 'viem/chains'
import { walletActionsL2 } from 'viem/op-stack'
export const walletClientL2 = createWalletClient({
chain: optimism,
transport: custom(window.ethereum)
}).extend(walletActionsL2())
// JSON-RPC Account
export const [account] = await walletClientL2.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
:::warning
You must [build the parameters](#building-parameters) on the L1 before calling this function. If the gas is too low, transaction execution will fail on the L1.
:::
### Building Parameters
The [`buildInitiateWithdrawal` Action](/op-stack/actions/buildInitiateWithdrawal) builds & prepares the initiate withdrawal transaction parameters.
We can use the resulting `args` to initiate the withdrawal transaction on the L2.
:::code-group
```ts [example.ts]
import { account, publicClientL1, walletClientL2 } from './config'
const args = await publicClientL1.buildInitiateWithdrawal({ // [!code hl]
account, // [!code hl]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code hl]
value: parseEther('1'), // [!code hl]
}) // [!code hl]
const hash = await walletClientL2.initiateWithdrawal(args)
```
```ts [config.ts]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL2 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL2 = createWalletClient({
chain: optimism,
transport: custom(window.ethereum)
}).extend(walletActionsL2())
// JSON-RPC Account
export const [account] = await walletClientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
[See more on the `buildInitiateWithdrawal` Action.](/op-stack/actions/buildInitiateWithdrawal)
### Account Hoisting
If you do not wish to pass an `account` to every `proveWithdrawal`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more.](/docs/clients/wallet#account)
:::code-group
```ts [example.ts]
import { account, publicClientL1, walletClientL2 } from './config'
const args = await publicClientL1.buildInitiateWithdrawal({
account, // [!code --]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'),
})
const hash = await walletClientL2.initiateWithdrawal(args)
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, createPublicClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL2 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider. // [!code hl]
const [account] = await window.ethereum.request({ // [!code hl]
method: 'eth_requestAccounts' // [!code hl]
}) // [!code hl]
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL2 = createWalletClient({
account, // [!code hl]
chain: optimism,
transport: custom(window.ethereum)
}).extend(walletActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL2 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL2 = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code hl]
chain: optimism,
transport: custom(window.ethereum)
}).extend(walletActionsL2())
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [L2 Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const hash = await client.initiateWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
targetChain: base,
})
```
### args.data (optional)
* **Type:** `Hex`
Encoded contract method & arguments.
```ts
const hash = await client.initiateWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
data: '0x...', // [!code focus]
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
})
```
### args.gas
* **Type:** `bigint`
Gas limit for transaction execution on the L1.
```ts
const hash = await client.initiateWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
})
```
### args.to
* **Type:** `Address`
L1 Transaction recipient.
```ts
const hash = await client.initiateWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
},
})
```
### args.value (optional)
* **Type:** `bigint`
Value in wei to withdrawal from the L2 to the L1. Debited from the caller's L2 balance.
```ts
const hash = await client.initiateWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
},
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `client.chain`
The L2 chain. If there is a mismatch between the wallet's current chain & this chain, an error will be thrown.
```ts
import { optimism } from 'viem/chains'
const hash = await client.initiateWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
chain: optimism, // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const hash = await client.initiateWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const hash = await client.initiateWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const hash = await client.initiateWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
request: {
gas: 21_000n,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
nonce: 69, // [!code focus]
})
```
# proveWithdrawal
Proves a withdrawal that occurred on an L2. Used in the Withdrawal flow.
Internally performs a contract write to the [`proveWithdrawalTransaction` function](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol#L197) on the [Optimism Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol).
## Usage
:::code-group
```ts [example.ts]
import { account, publicClientL1, publicClientL2, walletClientL1 } from './config'
const receipt = await getTransactionReceipt(publicClientL2, {
hash: '0xbbdd0957a82a057a76b5f093de251635ac4ddc6e2d0c4aa7fbf82d73e4e11039',
})
const [withdrawal] = getWithdrawals(receipt)
const output = await publicClientL1.getL2Output({
l2BlockNumber: receipt.blockNumber,
targetChain: publicClientL2.chain,
})
const args = await publicClientL2.buildProveWithdrawal({
account,
output,
withdrawal,
})
const hash = await walletClientL1.proveWithdrawal(args) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
// JSON-RPC Account
export const [account] = await walletClientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
:::warning
You must [build the parameters](#building-parameters) on the L2 before calling this function. If the gas is too low, transaction execution will fail on the L2.
:::
### Building Parameters
The [`buildProveWithdrawal` Action](/op-stack/actions/buildProveWithdrawal) builds & prepares the prove withdrawal transaction parameters.
We can use the resulting `args` to prove the withdrawal transaction on the L1.
:::code-group
```ts [example.ts]
import { account, publicClientL2, walletClientL1 } from './config'
const receipt = await getTransactionReceipt(publicClientL2, {
hash: '0xbbdd0957a82a057a76b5f093de251635ac4ddc6e2d0c4aa7fbf82d73e4e11039',
})
const [withdrawal] = getWithdrawals(receipt)
const output = await walletClientL1.getL2Output({
l2BlockNumber: receipt.blockNumber,
targetChain: publicClientL2.chain,
})
const args = await publicClientL2.buildProveWithdrawal({ // [!code hl]
account, // [!code hl]
output, // [!code hl]
withdrawal, // [!code hl]
}) // [!code hl]
const hash = await walletClientL1.proveWithdrawal(args)
```
```ts [config.ts]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const walletClientL1 = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
// JSON-RPC Account
export const [account] = await walletClientL1.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
[See more on the `buildProveWithdrawal` Action.](/op-stack/actions/buildProveWithdrawal)
### Account Hoisting
If you do not wish to pass an `account` to every `proveWithdrawal`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more.](/docs/clients/wallet#account)
:::code-group
```ts [example.ts]
import { account, publicClientL2, walletClientL1 } from './config'
const receipt = await getTransactionReceipt(publicClientL2, {
hash: '0xbbdd0957a82a057a76b5f093de251635ac4ddc6e2d0c4aa7fbf82d73e4e11039',
})
const [withdrawal] = getWithdrawals(receipt)
const output = await walletClientL1.getL2Output({
l2BlockNumber: receipt.blockNumber,
targetChain: publicClientL2.chain,
})
const args = await publicClientL2.buildProveWithdrawal({
output,
withdrawal,
})
const hash = await walletClientL1.proveWithdrawal(args)
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, createPublicClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider. // [!code hl]
const [account] = await window.ethereum.request({ // [!code hl]
method: 'eth_requestAccounts' // [!code hl]
}) // [!code hl]
export const walletClientL1 = createWalletClient({
account, // [!code hl]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const walletClientL1 = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code hl]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The prove withdrawal [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
l2OutputIndex: 4529n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `client.chain`
The L1 chain. If there is a mismatch between the wallet's current chain & this chain, an error will be thrown.
```ts
import { mainnet } from 'viem/chains'
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
chain: mainnet, // [!code focus]
l2OutputIndex: 4529n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### gas (optional)
* **Type:** `bigint`
Gas limit for transaction execution on the L1.
`null` to skip gas estimation & defer calculation to signer.
```ts
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
gas: 420_000n, // [!code focus]
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### l2OutputIndex
* **Type:** `bigint`
The index of the L2 output. Typically derived from the [`buildProveWithdrawal` Action](/op-stack/actions/buildProveWithdrawal).
```ts
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n, // [!code focus]
gas: 420_000n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`.
```ts
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
maxFeePerGas: parseGwei('20'), // [!code focus]
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
nonce: 69, // [!code focus]
targetChain: optimism,
})
```
### outputRootProof (optional)
* **Type:** `bigint`
The proof of the L2 output. Typically derived from the [`buildProveWithdrawal` Action](/op-stack/actions/buildProveWithdrawal).
```ts
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
gas: 420_000n,
outputRootProof: { /* ... */ }, // [!code focus]
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [Optimism Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol). Defaults to the Optimism Portal contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
outputRootProof: { /* ... */ },
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
targetChain: optimism,
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain to execute the transaction on.
```ts
import { mainnet } from 'viem/chains'
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ },
targetChain: optimism, // [!code focus]
})
```
### withdrawalProof
* **Type:** `bigint`
The proof of the L2 withdrawal. Typically derived from the [`buildProveWithdrawal` Action](/op-stack/actions/buildProveWithdrawal).
```ts
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
gas: 420_000n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ], // [!code focus]
withdrawal: { /* ... */ },
targetChain: optimism,
})
```
### withdrawal
* **Type:** `bigint`
The withdrawal. Typically derived from the [`buildProveWithdrawal` Action](/op-stack/actions/buildProveWithdrawal).
```ts
const hash = await client.proveWithdrawal({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2OutputIndex: 4529n,
gas: 420_000n,
outputRootProof: { /* ... */ },
withdrawalProof: [ /* ... */ ],
withdrawal: { /* ... */ }, // [!code focus]
targetChain: optimism,
})
```
# waitForNextGame
Waits for the next dispute game (after the provided block number) to be submitted. Used within the [waitToProve](/op-stack/actions/waitToProve) Action.
Internally calls [`getTimeToNextGame`](/op-stack/actions/getTimeToNextGame) and waits the returned `seconds`.
:::info
This Action is only compatible with OP Stack chains that have upgraded to [Fault Proofs](https://docs.optimism.io/stack/protocol/fault-proofs/overview) and have a deployed [DisputeGameFactoryProxy contract](https://github.com/ethereum-optimism/superchain-registry/blob/main/superchain/extra/addresses/addresses.json).
:::
## Usage
:::code-group
```ts [example.ts]
import { account, publicClientL1, publicClientL2 } from './config'
const l2BlockNumber = await publicClientL2.getBlockNumber()
const game = await publicClientL1.waitForNextGame({ // [!code hl]
l2BlockNumber, // [!code hl]
targetChain: publicClientL2.chain, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
})
```
:::
## Returns
`waitForNextGameReturnType`
The dispute game.
## Parameters
### l2BlockNumber
* **Type:** `bigint`
The L2 block number.
```ts
const game = await publicClientL1.waitForNextGame({
l2BlockNumber: 69420n, // [!code focus]
targetChain: optimism,
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const game = await publicClientL1.waitForNextGame({
l2BlockNumber,
targetChain: optimism, // [!code focus]
})
```
### disputeGameFactoryAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.disputeGameFactory[chainId].address`
The address of the [`DisputeGameFactory` contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/dispute/DisputeGameFactory.sol). Defaults to the `DisputeGameFactory` contract specified on the `targetChain`.
If a `disputeGameFactoryAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const game = await publicClientL1.waitForNextGame({
l2BlockNumber,
disputeGameFactoryAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
### intervalBuffer (optional)
* **Type:** `number`
* **Default:** `1.1`
The buffer to account for discrepancies between non-deterministic time intervals.
```ts
const game = await publicClientL1.waitForNextGame({
intervalBuffer: 1.2, // [!code focus]
l2BlockNumber,
targetChain: optimism,
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [`Portal` contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal2.sol). Defaults to the `Portal` contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const game = await publicClientL1.waitForNextGame({
l2BlockNumber,
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# waitForNextL2Output
Waits for the next L2 output (after the provided block number) to be submitted. Used within the [waitToProve](/op-stack/actions/waitToProve) Action.
Internally calls [`getTimeToNextL2Output`](/op-stack/actions/getTimeToNextL2Output) and waits the returned `seconds`.
:::warning
**This Action will be deprecated in the future.**
Use [`waitForNextGame`](/op-stack/actions/waitForNextGame) for OP Stack chains that have upgraded to [Fault Proofs](https://docs.optimism.io/stack/protocol/fault-proofs/overview) and have a deployed [DisputeGameFactoryProxy contract](https://github.com/ethereum-optimism/superchain-registry/blob/main/superchain/extra/addresses/addresses.json).
:::
## Usage
:::code-group
```ts [example.ts]
import { account, publicClientL1, publicClientL2 } from './config'
const l2BlockNumber = await publicClientL2.getBlockNumber()
const output = await publicClientL1.waitForNextL2Output({ // [!code hl]
l2BlockNumber, // [!code hl]
targetChain: publicClientL2.chain, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
})
```
:::
## Returns
`WaitForNextL2OutputReturnType`
The L2 output proposal.
## Parameters
### l2BlockNumber
* **Type:** `bigint`
The L2 block number.
```ts
const output = await publicClientL1.waitForNextL2Output({
l2BlockNumber: 69420n, // [!code focus]
targetChain: optimism,
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const output = await publicClientL1.waitForNextL2Output({
l2BlockNumber,
targetChain: optimism, // [!code focus]
})
```
### intervalBuffer (optional)
* **Type:** `number`
* **Default:** `1.1`
The buffer to account for discrepancies between non-deterministic time intervals.
```ts
const output = await publicClientL1.waitForNextL2Output({
intervalBuffer: 1.2, // [!code focus]
l2BlockNumber,
targetChain: optimism,
})
```
### l2OutputOracleAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.l2OutputOracle[chainId].address`
The address of the [L2 Output Oracle contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L2OutputOracle.sol). Defaults to the L2 Output Oracle contract specified on the `targetChain`.
If a `l2OutputOracleAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const output = await publicClientL1.waitForNextL2Output({
l2BlockNumber,
l2OutputOracleAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# waitToFinalize
Waits until the withdrawal transaction can be finalized. Used for the [Withdrawal](/op-stack/guides/withdrawals) flow.
Internally calls [`getTimeToFinalize`](/op-stack/actions/getTimeToFinalize) and waits the returned `seconds`.
## Usage
:::code-group
```ts [example.ts]
import { optimism } from 'viem/chains'
import { account, publicClientL1, publicClientL2 } from './config'
const receipt = await publicClientL2.getTransactionReceipt({
hash: '0x9a2f4283636ddeb9ac32382961b22c177c9e86dd3b283735c154f897b1a7ff4a',
})
const [message] = getWithdrawals(receipt)
await publicClientL1.waitToFinalize({ // [!code hl]
withdrawalHash: message.withdrawalHash, // [!code hl]
targetChain: optimism // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: custom(window.ethereum)
})
```
:::
## Parameters
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const { seconds } = await publicClientL1.waitToFinalize({
withdrawalHash: '0x...', // [!code focus]
targetChain: optimism, // [!code focus]
})
```
### withdrawalHash
* **Type:** `Hash`
The withdrawal hash.
```ts
const { seconds, timestamp } = await publicClientL1.waitToFinalize({
withdrawalHash: '0x...', // [!code focus]
targetChain: optimism,
})
```
### l2OutputOracleAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.l2OutputOracle[chainId].address`
The address of the [L2 Output Oracle contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L2OutputOracle.sol). Defaults to the L2 Output Oracle contract specified on the `targetChain`.
If a `l2OutputOracleAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const { seconds } = await publicClientL1.waitToFinalize({
withdrawalHash: '0x...',
l2OutputOracleAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed'
})
```
### portalAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.portal[chainId].address`
The address of the [Portal contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OptimismPortal.sol). Defaults to the L2 Output Oracle contract specified on the `targetChain`.
If a `portalAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const { seconds } = await publicClientL1.waitToFinalize({
withdrawalHash: '0x...',
l2OutputOracleAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed',
portalAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# waitToProve
Waits until the L2 withdrawal transaction is ready to be proved. Used for the [Withdrawal](/op-stack/guides/withdrawals) flow.
Internally calls [`getTimeToNextL2Output`](/op-stack/actions/getTimeToNextL2Output) and waits the returned `seconds`.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClientL1, publicClientL2 } from './config'
const receipt = await publicClientL2.getTransactionReceipt({
hash: '0x7b5cedccfaf9abe6ce3d07982f57bcb9176313b019ff0fc602a0b70342fe3147'
})
const output = await publicClientL1.waitToProve({ // [!code hl]
receipt, // [!code hl]
targetChain: publicClientL2.chain, // [!code hl]
}) // [!code hl]
```
```ts [config.ts]
import { createPublicClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1 } from 'viem/op-stack'
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
})
```
:::
## Returns
`WaitToProveReturnType`
The L2 output and the withdrawal message.
## Parameters
### receipt
* **Type:** `TransactionReceipt`
The transaction receipt.
```ts
const output = await publicClientL1.waitToProve({
receipt, // [!code focus]
targetChain: optimism,
})
```
### targetChain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The L2 chain.
```ts
const output = await publicClientL1.waitToProve({
l2BlockNumber,
targetChain: optimism, // [!code focus]
})
```
### l2OutputOracleAddress (optional)
* **Type:** `Address`
* **Default:** `targetChain.contracts.l2OutputOracle[chainId].address`
The address of the [L2 Output Oracle contract](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/L2OutputOracle.sol). Defaults to the L2 Output Oracle contract specified on the `targetChain`.
If a `l2OutputOracleAddress` is provided, the `targetChain` parameter becomes optional.
```ts
const output = await publicClientL1.waitToProve({
l2BlockNumber,
l2OutputOracleAddress: '0xbEb5Fc579115071764c7423A4f12eDde41f106Ed' // [!code focus]
})
```
# Deposits
This guide will demonstrate how to deposit (bridge) **1 Ether** from **Mainnet** to **[Optimism (OP Mainnet)](https://www.optimism.io/)**.
## Overview
Here is an end-to-end overview of how to execute a deposit transaction. We will break it down into [Steps](#steps) below.
:::code-group
```ts [deposit.ts]
import { getL2TransactionHashes } from 'viem/op-stack'
import { account, publicClientL1, publicClientL2, walletClientL1 } from './config'
// Build parameters for the transaction on the L2.
const args = await publicClientL2.buildDepositTransaction({
mint: parseEther('1'),
to: account.address,
})
// Execute the deposit transaction on the L1.
const hash = await walletClientL1.depositTransaction(args)
// Wait for the L1 transaction to be processed.
const receipt = await publicClientL1.waitForTransactionReceipt({ hash })
// Get the L2 transaction hash from the L1 transaction receipt.
const [l2Hash] = getL2TransactionHashes(receipt)
// Wait for the L2 transaction to be processed.
const l2Receipt = await publicClientL2.waitForTransactionReceipt({
hash: l2Hash
})
```
```ts [config.ts (JSON-RPC Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: http()
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
:::
## Steps
### 1. Set up Viem Clients
First, we will set up our Viem Clients for the Mainnet and Optimism chains, including the necessary extensions for the OP Stack.
We will place these in a `config.ts` file.
:::info
The example belows how to set up a Client for either a **JSON-RPC Account (Browser Extension, WalletConnect, etc)** or **Local Account (Private Key)**
:::
:::code-group
```ts [config.ts (JSON-RPC Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: http()
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
:::
### 2. Build the Deposit Transaction
Next, we will build the deposit transaction on the Optimism (L2) chain using the Clients that we created in the previous step.
In the example below, we want to deposit **1 Ether** (via `mint`) onto the Optimism chain, to ourselves (`account.address`).
:::info
The `mint` value is the value to deposit (mint) on the Optimism (L2) chain. It is debited from the account's Mainnet (L1) balance.
You can also use someone else's address as the `to` value if you wanted to.
:::
:::code-group
```ts [deposit.ts]
// Import Viem Clients.
import { publicClientL2 } from './config'
// Build parameters for the transaction on the L2.
const args = await publicClientL2.buildDepositTransaction({
mint: parseEther('1'),
to: account.address,
})
```
```ts [config.ts (JSON-RPC Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: http()
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
:::
### 3. Execute the Deposit Transaction
After that, we will execute the deposit transaction on the Mainnet (L1) chain.
:::code-group
```ts [deposit.ts]
// Import Viem Clients.
import { account, publicClientL2, walletClientL1 } from './config'
// Build parameters for the transaction on the L2.
const args = await publicClientL2.buildDepositTransaction({
mint: parseEther('1'),
to: account.address,
})
// Execute the deposit transaction on the L1. // [!code focus]
const hash = await walletClientL1.depositTransaction(args) // [!code focus]
```
```ts [config.ts (JSON-RPC Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const clientL1 = createClient({
account,
chain: mainnet,
transport: fallback([custom(window.ethereum), http()])
})
.extend(publicActions)
.extend(walletActionsL1())
export const clientL2 = createClient({
chain: optimism,
transport: http()
})
.extend(publicActions)
.extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: http()
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
:::
### 4. Wait for Transaction to be Processed
Once we have broadcast the transaction to the Mainnet (L1) chain, we need to wait for it to be processed on a block so we can extract the transaction receipt. We will need the transaction receipt to extract the transaction on the Optimism (L2) chain.
:::info
When the transaction has been processed, the `mint` value (1 Ether) will be debited from the account's Mainnet (L1) balance.
:::
:::code-group
```ts [deposit.ts]
// Import Viem Clients.
import {
account,
publicClientL1,
publicClientL2,
walletClientL1
} from './config'
// Build parameters for the transaction on the L2.
const args = await publicClientL2.buildDepositTransaction({
mint: parseEther('1'),
to: account.address,
})
// Execute the deposit transaction on the L1.
const hash = await walletClientL1.depositTransaction(args)
// Wait for the L1 transaction to be processed. // [!code focus]
const receipt = await publicClientL1.waitForTransactionReceipt({ hash }) // [!code focus]
```
```ts [config.ts (JSON-RPC Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const clientL1 = createClient({
account,
chain: mainnet,
transport: fallback([custom(window.ethereum), http()])
})
.extend(publicActions)
.extend(walletActionsL1())
export const clientL2 = createClient({
chain: optimism,
transport: http()
})
.extend(publicActions)
.extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: http()
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
:::
### 5. Compute the L2 Transaction Hash
Once we have the transaction receipt from the Mainnet (L1) chain, we can extract the Optimism (L2) transaction hash from the logs in the transaction receipt.
:::code-group
```ts [deposit.ts]
// Import Viem Clients.
import {
account,
publicClientL1,
publicClientL2,
walletClientL1
} from './config'
// Build parameters for the transaction on the L2.
const args = await publicClientL2.buildDepositTransaction({
mint: parseEther('1'),
to: account.address,
})
// Execute the deposit transaction on the L1.
const hash = await walletClientL1.depositTransaction(args)
// Wait for the L1 transaction to be processed.
const receipt = await publicClientL1.waitForTransactionReceipt({ hash })
// Get the L2 transaction hash from the L1 transaction receipt. // [!code focus]
const [l2Hash] = getL2TransactionHashes(receipt) // [!code focus]
```
```ts [config.ts (JSON-RPC Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const clientL1 = createClient({
account,
chain: mainnet,
transport: fallback([custom(window.ethereum), http()])
})
.extend(publicActions)
.extend(walletActionsL1())
export const clientL2 = createClient({
chain: optimism,
transport: http()
})
.extend(publicActions)
.extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: http()
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
:::
### 6. Wait for Transaction to be Processed
Now that we have the Optimism (L2) transaction hash, we can wait for the transaction to be processed on the Optimism (L2) chain.
Once the `waitForTransactionReceipt` call resolves, the transaction has been processed and you should now be credited with 1 Ether on the Optimism (L2) chain 🥳.
:::code-group
```ts [deposit.ts]
// Import Viem Clients.
import {
account,
publicClientL1,
publicClientL2,
walletClientL1
} from './config'
// Build parameters for the transaction on the L2.
const args = await publicClientL2.buildDepositTransaction({
mint: parseEther('1'),
to: account.address,
})
// Execute the deposit transaction on the L1.
const hash = await walletClientL1.depositTransaction(args)
// Wait for the L1 transaction to be processed.
const receipt = await publicClientL1.waitForTransactionReceipt({ hash })
// Get the L2 transaction hash from the L1 transaction receipt.
const [l2Hash] = getL2TransactionHashes(receipt)
// Wait for the L2 transaction to be processed. // [!code focus]
const l2Receipt = await publicClientL2.waitForTransactionReceipt({ // [!code focus]
hash: l2Hash // [!code focus]
}) // [!code focus]
```
```ts [config.ts (JSON-RPC Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const clientL1 = createClient({
account,
chain: mainnet,
transport: fallback([custom(window.ethereum), http()])
})
.extend(publicActions)
.extend(walletActionsL1())
export const clientL2 = createClient({
chain: optimism,
transport: http()
})
.extend(publicActions)
.extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: http()
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
```
:::
## Example
# Withdrawals
This guide will demonstrate how to withdraw **1 Ether** from **[Optimism (OP Mainnet)](https://www.optimism.io/)** to **Mainnet**.
## Overview
Withdrawals on the OP Stack are a [two-step (plus one) process](https://blog.oplabs.co/two-step-withdrawals/). The process involves:
0. **Initiating** the Withdrawal Transaction on the L2,
> *Wait one hour (max) for the L2 Output containing the transaction to be proposed.*
1. **Proving** the Withdrawal Transaction on the L1,
> *Wait the 7 day finalization period*
2. **Finalizing** the Withdrawal Transaction on the L1.
> *Withdrawal complete!*
Here is a complete end-to-end overview of how to execute a withdrawal. Don't worry, we will break it down into [Steps](#steps) below.
:::code-group
```ts [withdrawal.ts]
import { getWithdrawals } from 'viem/op-stack'
import {
account,
publicClientL1,
walletClientL1,
publicClientL2,
walletClientL2
} from './config'
// Build parameters to initiate the withdrawal transaction on the L1.
const args = await publicClientL1.buildInitiateWithdrawal({
to: account.address,
value: parseEther('1')
})
// Execute the initiate withdrawal transaction on the L2.
const hash = await walletClientL2.initiateWithdrawal(args)
// Wait for the initiate withdrawal transaction receipt.
const receipt = await publicClientL2.waitForTransactionReceipt({ hash })
// Wait until the withdrawal is ready to prove.
const { output, withdrawal } = await publicClientL1.waitToProve({
receipt,
targetChain: walletClientL2.chain
})
// Build parameters to prove the withdrawal on the L2.
const proveArgs = await publicClientL2.buildProveWithdrawal({
output,
withdrawal,
})
// Prove the withdrawal on the L1.
const proveHash = await walletClientL1.proveWithdrawal(proveArgs)
// Wait until the prove withdrawal is processed.
const proveReceipt = await publicClientL1.waitForTransactionReceipt({
hash: proveHash
})
// Wait until the withdrawal is ready to finalize.
await publicClientL1.waitToFinalize({
targetChain: walletClientL2.chain,
withdrawalHash: withdrawal.withdrawalHash,
})
// Finalize the withdrawal.
const finalizeHash = await walletClientL1.finalizeWithdrawal({
targetChain: walletClientL2.chain,
withdrawal,
})
// Wait until the withdrawal is finalized.
const finalizeReceipt = await publicClientL1.waitForTransactionReceipt({
hash: finalizeHash
})
```
```ts [config.ts (JSON-RPC Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL1, walletActionsL2 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
export const walletClientL2 = createWalletClient({
account,
chain: optimism,
transport: custom(window.ethereum)
}).extend(walletActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL1, walletActionsL2 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
export const walletClientL2 = createWalletClient({
account,
chain: optimism,
transport: http()
}).extend(walletActionsL2())
```
:::
## Steps
### 1. Set up Viem Clients
First, we will set up our Viem Clients for the Mainnet and Optimism chains, including the necessary extensions for the OP Stack.
We will need the following clients:
* `publicClientL1`/`walletClientL1`: Public & Wallet Client for **Mainnet**
* `publicClientL2`/`walletClientL2`: Public & Wallet Client for **OP Mainnet**
We will place these in a `config.ts` file.
:::info
The example belows how to set up a Client for either a **JSON-RPC Account (Browser Extension, WalletConnect, etc)** or **Local Account (Private Key)**
:::
:::code-group
```ts [config.ts (JSON-RPC Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL1, walletActionsL2 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
export const walletClientL2 = createWalletClient({
account,
chain: optimism,
transport: custom(window.ethereum)
}).extend(walletActionsL2())
```
```ts [config.ts (Local Account)]
// Import Viem modules.
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL1, walletActionsL2 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
export const walletClientL2 = createWalletClient({
account,
chain: optimism,
transport: http()
}).extend(walletActionsL2())
```
:::
### 2. Initiate Withdrawal
Next, we will initiate the withdrawal transaction on the L2 by building the parameters on the L1 (1), and then executing the transaction on the L2 (2). We also want to wait for the L2 transaction to be processed on a block (3) before we continue.
In the example below, we are initiating a withdrawal for **1 Ether** from the L2 (OP Mainnet) to the L1 (Mainnet).
:::code-group
```ts [withdrawal.ts]
import {
account,
publicClientL1,
publicClientL2,
walletClientL2
} from './config'
// 1. Build parameters to initiate the withdrawal transaction on the L1.
const args = await publicClientL1.buildInitiateWithdrawal({
to: account.address,
value: parseEther('1')
})
// 2. Execute the initiate withdrawal transaction on the L2.
const hash = await walletClientL2.initiateWithdrawal(args)
// 3. Wait for the initiate withdrawal transaction receipt.
const receipt = await publicClientL2.waitForTransactionReceipt({ hash })
```
```ts [config.ts (JSON-RPC Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL1, walletActionsL2 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
export const walletClientL2 = createWalletClient({
account,
chain: optimism,
transport: custom(window.ethereum)
}).extend(walletActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL1, walletActionsL2 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
export const walletClientL2 = createWalletClient({
account,
chain: optimism,
transport: http()
}).extend(walletActionsL2())
```
:::
### 3. Prove Withdrawal
After the initiate withdrawal transaction has been processed on a block on the L2, we will then need to prove that withdrawal on the L1.
Before a withdrawal transaction can be proved, the transaction needs to be included in an L2 Output proposal. Until then, we will need to wait for the withdrawal transaction to be ready to be proved (1). This usually takes a maximum of **one hour**.
Once the L2 output has been proposed, we will need to build the parameters for the prove withdrawal transaction on the L2 (2), and then execute the transaction on the L1 (3). We also want to wait for the L1 transaction to be processed on a block (4) before we continue.
:::code-group
```ts [withdrawal.ts]
import {
account,
publicClientL1,
publicClientL2,
walletClientL1,
walletClientL2
} from './config'
// (Shortcut) Get receipt from transaction created in Step 1.
const receipt =
await publicClientL2.getTransactionReceipt({ hash: '0x...' })
// 1. Wait until the withdrawal is ready to prove. // [!code hl]
const { output, withdrawal } = await publicClientL1.waitToProve({ // [!code hl]
receipt, // [!code hl]
targetChain: walletClientL2.chain // [!code hl]
}) // [!code hl]
// 2. Build parameters to prove the withdrawal on the L2. // [!code hl]
const args = await publicClientL2.buildProveWithdrawal({ // [!code hl]
output, // [!code hl]
withdrawal, // [!code hl]
}) // [!code hl]
// 3. Prove the withdrawal on the L1. // [!code hl]
const hash = await walletClientL1.proveWithdrawal(args) // [!code hl]
// 4. Wait until the prove withdrawal is processed. // [!code hl]
const receipt = await publicClientL1.waitForTransactionReceipt({ // [!code hl]
hash // [!code hl]
}) // [!code hl]
```
```ts [config.ts (JSON-RPC Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL1, walletActionsL2 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
export const walletClientL2 = createWalletClient({
account,
chain: optimism,
transport: custom(window.ethereum)
}).extend(walletActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL1, walletActionsL2 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
export const walletClientL2 = createWalletClient({
account,
chain: optimism,
transport: http()
}).extend(walletActionsL2())
```
:::
:::tip
You can utilize the [`getTimeToProve`](/op-stack/actions/getTimeToProve) Action if you want to extract the estimated time left to prove the withdrawal from the `waitToProve` method and display it to the user or store in a database.
```ts
const { seconds, timestamp } = await publicClientL1.getTimeToProve({
receipt,
targetChain: walletClientL2.chain
})
```
:::
:::warning
If you aren't using the `waitToProve` Action, it is highly recommended to check if the withdrawal is ready to be proved by using the [`getWithdrawalStatus`](/op-stack/actions/getWithdrawalStatus) Action. This will prevent you from proving a withdrawal that isn't ready yet.
```ts
const status = await publicClientL1.getWithdrawalStatus({
receipt,
targetChain: walletClientL2.chain
})
if (status === 'ready-to-prove') {
// ...
}
```
:::
### 4. Finalize Withdrawal
When the withdrawal transaction has been proved, we will then need to finalize that withdrawal on the L1.
Before a withdrawal transaction can be finalized, we will need to wait the **finalization period** of **7 days** (1).
After the finalization period has elapsed, we can finalize the withdrawal (2).
Once the withdrawal has been successfully finalized (3), then the withdrawal is complete! 🥳
:::code-group
```ts [withdrawal.ts]
import { getWithdrawals } from 'viem/op-stack'
import {
account,
publicClientL1,
publicClientL2,
walletClientL1,
walletClientL2
} from './config'
// (Shortcut) Get receipt from transaction created in Step 1.
const receipt =
await publicClientL2.getTransactionReceipt({ hash: '0x...' })
// (Shortcut) Get withdrawals from receipt in Step 3.
const [withdrawal] = getWithdrawals(receipt)
// 1. Wait until the withdrawal is ready to finalize. // [!code hl]
await publicClientL1.waitToFinalize({ // [!code hl]
targetChain: walletClientL2.chain, // [!code hl]
withdrawalHash: withdrawal.withdrawalHash, // [!code hl]
}) // [!code hl]
// 2. Finalize the withdrawal. // [!code hl]
const hash = await walletClientL1.finalizeWithdrawal({ // [!code hl]
targetChain: walletClientL2.chain, // [!code hl]
withdrawal, // [!code hl]
}) // [!code hl]
// 3. Wait until the withdrawal is finalized. // [!code hl]
const receipt = await publicClientL1.waitForTransactionReceipt({ // [!code hl]
hash // [!code hl]
}) // [!code hl]
```
```ts [config.ts (JSON-RPC Account)]
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL1, walletActionsL2 } from 'viem/op-stack'
// Retrieve Account from an EIP-1193 Provider.
export const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
export const walletClientL2 = createWalletClient({
account,
chain: optimism,
transport: custom(window.ethereum)
}).extend(walletActionsL2())
```
```ts [config.ts (Local Account)]
import { createPublicClient, createWalletClient, http } from 'viem'
import { mainnet, optimism } from 'viem/chains'
import { publicActionsL1, walletActionsL1, walletActionsL2 } from 'viem/op-stack'
export const account = privateKeyToAccount('0x...')
export const publicClientL1 = createPublicClient({
chain: mainnet,
transport: http()
}).extend(publicActionsL1())
export const walletClientL1 = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
export const publicClientL2 = createPublicClient({
chain: optimism,
transport: http()
}).extend(publicActionsL2())
export const walletClientL2 = createWalletClient({
account,
chain: optimism,
transport: http()
}).extend(walletActionsL2())
```
:::
:::tip
You can utilize the [`getTimeToFinalize`](/op-stack/actions/getTimeToFinalize) Action if you want to extract the estimated time left to finalize the withdrawal from the `waitToFinalize` method and display it to the user or store in a database.
```ts
const { seconds, timestamp } = await publicClientL1.getTimeToFinalize({
receipt,
targetChain: walletClientL2.chain
})
```
:::
:::warning
If you aren't using the `waitToFinalize` Action, it is highly recommended to check if the withdrawal is ready to be finalized by using the [`getWithdrawalStatus`](/op-stack/actions/getWithdrawalStatus) Action. This will prevent you from finalizing a withdrawal that isn't ready yet.
```ts
const status = await publicClientL1.getWithdrawalStatus({
receipt,
targetChain: walletClientL2.chain
})
if (status === 'ready-to-finalize') {
// ...
}
```
:::
# extractTransactionDepositedLogs
Extracts `TransactionDeposited` logs from an opaque array of logs.
## Import
```ts
import { extractTransactionDepositedLogs } from 'viem'
```
## Usage
```ts
import { extractTransactionDepositedLogs } from 'viem'
const receipt = await client.getTransactionReceipt({
hash: '0xc9c0361bc3da9cd3560e48b469d0d6aac0e633e4897895edfd26a287f7c578ec',
})
const logs = extractTransactionDepositedLogs(receipt)
// [
// { args: { ... }, blockHash: '0x...', eventName: 'TransactionDeposited' },
// { args: { ... }, blockHash: '0x...', eventName: 'TransactionDeposited' },
// { args: { ... }, blockHash: '0x...', eventName: 'TransactionDeposited' },
// ]
```
## Returns
`Log[]`
The `TransactionDeposited` logs.
## Parameters
### logs
* **Type:** `Log[]`
An array of opaque logs.
```ts
const logs = extractTransactionDepositedLogs({
logs: receipt.logs // [!code focus]
})
```
# extractWithdrawalMessageLogs
Extracts [`MessagePassed` logs](https://github.com/ethereum-optimism/optimism/blob/9f73402cb4341f7cfa83bf79769c8dddd9b014c0/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol#L29-L45) from a withdrawal initialization from an opaque array of logs.
## Import
```ts
import { extractWithdrawalMessageLogs } from 'viem'
```
## Usage
```ts
import { extractWithdrawalMessageLogs } from 'viem'
const receipt = await client.getTransactionReceipt({
hash: '0xc9c0361bc3da9cd3560e48b469d0d6aac0e633e4897895edfd26a287f7c578ec',
})
const logs = extractWithdrawalMessageLogs(receipt)
// [
// { args: { ... }, blockHash: '0x...', eventName: 'MessagePassed' },
// { args: { ... }, blockHash: '0x...', eventName: 'MessagePassed' },
// { args: { ... }, blockHash: '0x...', eventName: 'MessagePassed' },
// ]
```
## Returns
`Log[]`
The `MessagePassed` logs.
## Parameters
### logs
* **Type:** `Log[]`
An array of opaque logs.
```ts
const logs = extractWithdrawalMessageLogs({
logs: receipt.logs // [!code focus]
})
```
# opaqueDataToDepositData
Decodes opaque deposit data found in the `TransactionDeposited` event log data.
## Import
```ts
import { opaqueDataToDepositData } from 'viem'
```
## Usage
```ts
import { opaqueDataToDepositData } from 'viem'
const data = opaqueDataToDepositData('0x00000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000045000000000000526c01deadbeef')
```
## Returns
```
{
mint: bigint
value: bigint
gas: bigint
isCreation: boolean
data: Hex
}
```
The decoded opaque data.
## Parameters
### opaqueData
* **Type:** `Hex`
The ABI (packed) encoded opaque data.
# getL2TransactionHash
Computes the L2 transaction hash from an L1 `TransactionDeposited` log.
:::warning
For the general case of retrieving an L2 transaction hash from an L1 transaction receipt, you probably want to use [getL2TransactionHashes](/op-stack/utilities/getL2TransactionHashes).
:::
## Import
```ts
import { getL2TransactionHash } from 'viem'
```
## Usage
```ts
import { extractTransactionDepositedLogs, getL2TransactionHash } from 'viem'
const receipt = await client.getTransactionReceipt({
hash: '0xa08acae48f12243bccd7153c88d892673d5578cce4ee9988c0332e8bba47436b',
})
const [log] = extractTransactionDepositedLogs(receipt)
const l2Hash = getL2TransactionHash({ log }) // [!code hl]
```
## Returns
`Hex`
The L2 transaction hash.
## Parameters
### log
* **Type:** `Log`
An L1 `TransactionDeposited` log.
```ts
const l2Hash = getL2TransactionHash({
log: { // [!code focus]
args: { // [!code focus]
from: '0x1a1E021A302C237453D3D45c7B82B19cEEB7E2e6', // [!code focus]
opaqueData: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045000000000000520800', // [!code focus]
to: '0x1a1E021A302C237453D3D45c7B82B19cEEB7E2e6', // [!code focus]
version: 0n, // [!code focus]
}, // [!code focus]
blockHash: '0x634c52556471c589f42db9131467e0c9484f5c73049e32d1a74e2a4ce0f91d57', // [!code focus]
eventName: 'TransactionDeposited', // [!code focus]
logIndex: 109, // [!code focus]
} // [!code focus]
})
```
# getL2TransactionHashes
Computes the L2 transaction hashes from an array of L1 `TransactionDeposited` logs.
Useful for extracting L2 hashes from an **L1 Transaction Receipt**.
## Import
```ts
import { getL2TransactionHashes } from 'viem'
```
## Usage
```ts
import { extractTransactionDepositedLogs, getL2TransactionHashes } from 'viem'
const receipt = await client.getTransactionReceipt({
hash: '0xa08acae48f12243bccd7153c88d892673d5578cce4ee9988c0332e8bba47436b',
})
const l2Hashes = getL2TransactionHashes(receipt) // [!code hl]
```
## Returns
`Hex`
The L2 transaction hash.
## Parameters
### logs
* **Type:** `Log[]`
An array of L1 logs.
```ts
const l2Hashes = getL2TransactionHash({
logs: receipt.logs // [!code focus]
})
```
# getSourceHash
Computes the [source hash](https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md#source-hash-computation) of a deposit transaction.
## Import
```ts
import { getSourceHash } from 'viem'
```
## Usage
```ts
import { getSourceHash } from 'viem'
// User Deposit
const sourceHash = getSourceHash({
domain: 'userDeposit',
l1BlockHash:
'0x9ba3933dc6ce43c145349770a39c30f9b647f17668f004bd2e05c80a2e7262f7',
l1LogIndex: 196,
})
// L1 attributes deposited
const sourceHash = getSourceHash({
domain: 'l1InfoDeposit',
l1BlockHash:
'0x9ba3933dc6ce43c145349770a39c30f9b647f17668f004bd2e05c80a2e7262f7',
sequenceNumber: 1,
})
```
## Returns
`Hex`
The source hash of the deposit transaction.
## Parameters
### domain
* **Type:** `"userDeposit" | "l1InfoDeposit"`
The domain of the deposit transaction.
```ts
const sourceHash = getSourceHash({
domain: 'userDeposit', // [!code focus]
l1BlockHash:
'0x9ba3933dc6ce43c145349770a39c30f9b647f17668f004bd2e05c80a2e7262f7',
l1LogIndex: 196,
})
```
### l1BlockHash
* **Type:** `Hex`
The hash of the L1 block the deposit transaction was included in.
```ts
const sourceHash = getSourceHash({
domain: 'userDeposit',
l1BlockHash:
'0x9ba3933dc6ce43c145349770a39c30f9b647f17668f004bd2e05c80a2e7262f7', // [!code focus]
l1LogIndex: 196,
})
```
### l1LogIndex
* **Type:** `number`
The index of the L1 log. **Only required for `"userDeposit"` domain.**
```ts
const sourceHash = getSourceHash({
domain: 'userDeposit',
l1BlockHash:
'0x9ba3933dc6ce43c145349770a39c30f9b647f17668f004bd2e05c80a2e7262f7',
l1LogIndex: 196, // [!code focus]
})
```
### sequenceNumber
* **Type:** `number`
The sequence number (difference between L2 block number and first L2 epoch block number). **Only required for `"l1InfoDeposit"` domain.**
```ts
const sourceHash = getSourceHash({
domain: 'l1InfoDeposit',
l1BlockHash:
'0x9ba3933dc6ce43c145349770a39c30f9b647f17668f004bd2e05c80a2e7262f7',
sequenceNumber: 1, // [!code focus]
})
```
# getWithdrawalHashStorageSlot
Computes the withdrawal hash storage slot to be used when proving a withdrawal.
## Import
```ts
import { getWithdrawalHashStorageSlot } from 'viem'
```
## Usage
```ts
import { getWithdrawalHashStorageSlot } from 'viem'
const slot = getWithdrawalHashStorageSlot({ // [!code hl]
withdrawalHash: '0xB1C3824DEF40047847145E069BF467AA67E906611B9F5EF31515338DB0AABFA2' // [!code hl]
}) // [!code hl]
```
## Returns
`Hex`
The storage slot.
## Parameters
### withdrawalHash
* **Type:** `Hash`
Hash emitted from the L2 withdrawal `MessagePassed` event.
```ts
const slot = getWithdrawalHashStorageSlot({
withdrawalHash: '0xB1C3824DEF40047847145E069BF467AA67E906611B9F5EF31515338DB0AABFA2' // [!code focus]
})
```
# getWithdrawals
Gets withdrawal messages emitted from the [`MessagePassed` log](https://github.com/ethereum-optimism/optimism/blob/9f73402cb4341f7cfa83bf79769c8dddd9b014c0/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol#L29-L45) from a withdrawal initialization.
## Import
```ts
import { getWithdrawals } from 'viem'
```
## Usage
```ts
import { extractTransactionDepositedLogs, getWithdrawals } from 'viem'
const receipt = await client.getTransactionReceipt({
hash: '0xa08acae48f12243bccd7153c88d892673d5578cce4ee9988c0332e8bba47436b',
})
const withdrawals = getWithdrawals(receipt) // [!code hl]
```
## Returns
`Hex`
The L2 transaction hash.
## Parameters
### logs
* **Type:** `Log[]`
An array of L2 logs.
```ts
const withdrawals = getWithdrawals({
logs: receipt.logs // [!code focus]
})
```
# opaqueDataToDepositData
Converts an opaque data into a structured deposit data object. This includes extracting and converting the `mint`, `value`, `gas`, `isCreation` flag, and `data` from a hex string.
## Import
```ts
import { opaqueDataToDepositData } from "viem";
```
## Usage
```ts
import { opaqueDataToDepositData } from "viem";
const opaqueData =
"0x00000000000000000000000000000000000000000000000000470DE4DF82000000000000000000000000000000000000000000000000000000470DE4DF82000000000000000186A00001";
const depositData = opaqueDataToDepositData(opaqueData);
// {
// mint: 20000000000000000n,
// value: 20000000000000000n,
// gas: 100000n,
// isCreation: false,
// data: '0x01',
// }
```
## Returns
`OpaqueDataToDepositDataReturnType`
An object containing the parsed deposit data.
## Parameters
### opaqueData
* **Type:** `Hex`
The opaque hex-encoded data.
## Errors
`OpaqueDataToDepositDataErrorType`
An error type that includes potential slice, size, and generic errors encountered during the parsing process.
# parseTransaction (OP Stack)
Parses a serialized RLP-encoded transaction. Supports signed & unsigned Deposit, EIP-1559, EIP-2930 and Legacy Transactions.
## Import
```ts
import { parseTransaction } from 'viem'
```
## Usage
```ts
import { parseTransaction } from 'viem'
const transaction = parseTransaction('0x02ef0182031184773594008477359400809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0')
```
### Deposit Transactions
The `parseTransaction` module from `viem/op-stack` also supports parsing deposit transactions (`0x7e`-prefixed):
```ts
import { parseTransaction } from 'viem'
const transaction = parseTransaction('0x7ef83ca018040f35752170c3339ddcd850f185c9cc46bdef4d6e1f2ab323f4d3d710431994977f82a600a1414e583f7f13623f1ac5d58b1c0b808080808080')
```
## Returns
`TransactionSerializable`
The parsed transaction object.
## Parameters
### serializedTransaction
* **Type:** `Hex`
The serialized transaction.
# serializeTransaction (OP Stack)
Serializes a transaction object, with support for OP Stack transactions. Supports Deposit, EIP-1559, EIP-2930, and Legacy transactions.
## Import
```ts
import { serializeTransaction } from 'viem/op-stack'
```
## Usage
```ts
import { serializeTransaction } from 'viem/op-stack'
const serialized = serializeTransaction({
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69,
to: "0x1234512345123451234512345123451234512345",
value: parseEther('0.01'),
})
```
### Deposit Transactions
The `serializeTransaction` module from `viem/op-stack` also supports serializing deposit transactions:
```ts
import { parseEther } from 'viem'
import { serializeTransaction } from 'viem/op-stack'
const serialized = serializeTransaction({
from: '0x977f82a600a1414e583f7f13623f1ac5d58b1c0b',
gas: 21000n,
mint: parseEther('1'),
sourceHash: '0x18040f35752170c3339ddcd850f185c9cc46bdef4d6e1f2ab323f4d3d7104319',
value: parseEther('1'),
type: 'deposit'
})
```
## Returns
Returns a template `Hex` value based on transaction type:
* `deposit`: [TransactionSerializedDeposit](/docs/glossary/types#TransactionSerializedDeposit)
* `eip1559`: [TransactionSerializedEIP1559](/docs/glossary/types#TransactionSerializedEIP1559)
* `eip2930`: [TransactionSerializedEIP2930](/docs/glossary/types#TransactionSerializedEIP2930)
* `legacy`: [TransactionSerializedLegacy](/docs/glossary/types#TransactionSerializedLegacy)
## Parameters
### transaction
* **Type:** `TransactionSerializable`
The transaction object to serialize.
```ts
const serialized = serializeTransaction({
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69,
to: '0x1234512345123451234512345123451234512345',
value: parseEther('0.01'),
})
```
### signature
* **Type:** `Hex`
Optional signature to include. **Ignored for deposit transactions.**
```ts
const serialized = serializeTransaction({
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69,
to: '0x1234512345123451234512345123451234512345',
value: parseEther('0.01'),
}, { // [!code focus:5]
r: '0x123451234512345123451234512345123451234512345123451234512345',
s: '0x123451234512345123451234512345123451234512345123451234512345',
yParity: 1
})
```
# `Account.fromP256`
Instantiates an Account from a P256 private key.
## Usage
```ts twoslash
import { Account } from 'viem/tempo'
const account = Account.fromP256(
'0x...'
)
console.log('Address:', account.address)
// @log: Address: 0x...
```
### Access Keys
Create an account that acts as an access key for a parent account:
:::code-group
```ts twoslash [example.ts]
import { Account, P256 } from 'viem/tempo'
import { client } from './viem.config'
// Create root account
const account = Account.fromSecp256k1(
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
)
// Create access key
const accessKey = Account.fromP256(
P256.randomPrivateKey(),
{ access: account }
)
// Sign a key authorization
const keyAuthorization = await account.signKeyAuthorization(accessKey, {
expiry: Math.floor(Date.now() / 1000) + 86400, // 24 hour expiry
})
// Attach to next transaction
const receipt = await client.sendTransactionSync({
account: accessKey,
keyAuthorization,
to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
})
// Now any subsequent transaction can be used with `accessKey`
// WITHOUT the `keyAuthorization` parameter!
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
The return type of `Account.fromP256` is backwards compatible with Viem's `Account` type.
```ts
type ReturnType = Account
type Account = {
/** Account address */
address: Address
/** Key type */
keyType: string
/** Public key (hex) */
publicKey: Hex
/** Account source */
source: string
/** Account type */
type: 'local'
/** Assigns a key authorization to the next transaction */
assignKeyAuthorization: (keyAuthorization: KeyAuthorization) => Promise
/** Signs a raw digest */
sign: (parameters: { hash: Hex }) => Promise
/** Signs an EIP-7702 authorization */
signAuthorization: (parameters: SignAuthorizationParameters) => Promise
/** Signs a key authorization */
signKeyAuthorization: (
key: { accessKeyAddress: Address; keyType: string },
parameters?: { expiry?: bigint; limits?: Limits }
) => Promise
/** Signs a EIP-191 `personal_sign` message */
signMessage: (parameters: { message: string | { raw: Hex } }) => Promise
/** Signs a transaction */
signTransaction: (transaction: TransactionRequest) => Promise
/** Signs a EIP-712 typed data */
signTypedData: (typedData: TypedData) => Promise
}
```
## Parameters
### privateKey
* **Type:** `Hex`
The P256 private key as a hex string.
### options (optional)
#### options.access
* **Type:** `Address | Account`
Parent account to access.
# `Account.fromSecp256k1`
Instantiates an Account from a secp256k1 private key (standard Ethereum signature scheme).
## Usage
```ts twoslash
import { Account } from 'viem/tempo'
const account = Account.fromSecp256k1(
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
)
console.log('Address:', account.address)
// @log: Address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
```
### Access Keys
Create an account that acts as an access key for a parent account:
:::code-group
```ts twoslash [example.ts]
import { Account, Secp256k1 } from 'viem/tempo'
import { client } from './viem.config'
// Create root account
const account = Account.fromSecp256k1(
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
)
// Create access key
const accessKey = Account.fromSecp256k1(
Secp256k1.randomPrivateKey(),
{ access: account }
)
// Sign a key authorization
const keyAuthorization = await account.signKeyAuthorization(accessKey, {
expiry: Math.floor(Date.now() / 1000) + 86400, // 24 hour expiry
})
// Attach to next transaction
const receipt = await client.sendTransactionSync({
account: accessKey,
keyAuthorization,
to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
})
// Now any subsequent transaction can be used with `accessKey`
// WITHOUT the `keyAuthorization` parameter!
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
The return type of `Account.fromSecp256k1` is backwards compatible with Viem's `Account` type.
```ts
type ReturnType = Account
type Account = {
/** Account address */
address: Address
/** Key type */
keyType: string
/** Public key (hex) */
publicKey: Hex
/** Account source */
source: string
/** Account type */
type: 'local'
/** Assigns a key authorization to the next transaction */
assignKeyAuthorization: (keyAuthorization: KeyAuthorization) => Promise
/** Signs a raw digest */
sign: (parameters: { hash: Hex }) => Promise
/** Signs an EIP-7702 authorization */
signAuthorization: (parameters: SignAuthorizationParameters) => Promise
/** Signs a key authorization */
signKeyAuthorization: (
key: { accessKeyAddress: Address; keyType: string },
parameters?: { expiry?: bigint; limits?: Limits }
) => Promise
/** Signs a EIP-191 `personal_sign` message */
signMessage: (parameters: { message: string | { raw: Hex } }) => Promise
/** Signs a transaction */
signTransaction: (transaction: TransactionRequest) => Promise
/** Signs a EIP-712 typed data */
signTypedData: (typedData: TypedData) => Promise
}
```
## Parameters
### privateKey
* **Type:** `Hex`
The secp256k1 private key as a hex string.
### options (optional)
#### options.access
* **Type:** `Address | Account`
Parent account to access.
# `Account.fromWebAuthnP256`
Instantiates an Account from a WebAuthn credential (passkey).
## Usage
### Creating Credentials
Create a credential with `WebAuthnP256.createCredential` and then instantiate a Viem Account with `Account.fromWebAuthnP256`.
:::warning
It is highly recommended to store the credential's public key in an external store for future use (ie. for future calls to `WebAuthnP256.getCredential`).
:::
```ts twoslash
// @noErrors
import { Account, WebAuthnP256 } from 'viem/tempo'
import { store } from './store'
// 1. Create credential
const credential = await WebAuthnP256.createCredential({ name: 'Example' })
// 2. Instantiate account
const account = Account.fromWebAuthnP256(credential)
// 3. Store public key
await store.set(credential.id, credential.publicKey)
console.log('Address:', account.address)
// @log: Address: 0x...
```
### Loading Credentials
Get a credential from `WebAuthnP256.getCredential` and then instantiate an account with `Account.fromWebAuthnP256`.
:::warning
The `getPublicKey` function is required to fetch the public key paired with the credential from an external store.
The public key is required to derive the account's address.
:::
```ts twoslash
// @noErrors
import { Account, WebAuthnP256 } from 'viem/tempo'
import { store } from './store'
// 1. Get credential
const credential = await WebAuthnP256.getCredential({
async getPublicKey(credential) {
// 2. Get public key from external store.
return await store.get(credential.id)
}
})
// 3. Instantiate account
const account = Account.fromWebAuthnP256(credential)
console.log('Address:', account.address)
// @log: Address: 0x...
```
## Return Type
The return type of `Account.fromWebAuthnP256` is backwards compatible with Viem's `Account` type.
```ts
type ReturnType = Account
type Account = {
/** Account address */
address: Address
/** Key type */
keyType: string
/** Public key (hex) */
publicKey: Hex
/** Account source */
source: string
/** Account type */
type: 'local'
/** Signs a raw digest */
sign: (parameters: { hash: Hex }) => Promise
/** Signs an EIP-7702 authorization */
signAuthorization: (parameters: SignAuthorizationParameters) => Promise
/** Signs a EIP-191 `personal_sign` message */
signMessage: (parameters: { message: string | { raw: Hex } }) => Promise
/** Signs a transaction */
signTransaction: (transaction: TransactionRequest) => Promise
/** Signs a EIP-712 typed data */
signTypedData: (typedData: TypedData) => Promise
}
```
## Parameters
### credential
* **Type:** `{ id: string; publicKey: Hex }`
The WebAuthn credential object containing:
* `id` - The credential ID
* `publicKey` - The public key as a hex string
### options (optional)
#### options.getFn
* **Type:** `(options: CredentialRequestOptions) => Promise`
Custom function to get the WebAuthn credential. Use this to override the default `navigator.credentials.get` behavior.
#### options.rpId
* **Type:** `string`
The relying party ID. This should match the domain of your application.
# `Account.fromWebCryptoP256`
Instantiates an Account from a WebCrypto P256 key pair.
## Usage
```ts twoslash
import { Account } from 'viem/tempo'
import { WebCryptoP256 } from 'ox'
const keyPair = await WebCryptoP256.createKeyPair()
const account = Account.fromWebCryptoP256(keyPair)
console.log('Address:', account.address)
// @log: Address: 0x...
```
### Access Keys
Create an account that acts as an access key for a parent account:
:::code-group
```ts twoslash [example.ts]
import { Account, WebCryptoP256 } from 'viem/tempo'
import { client } from './viem.config'
// Create root account
const account = Account.fromSecp256k1(
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
)
// Create access key
const keyPair = await WebCryptoP256.createKeyPair()
const accessKey = Account.fromWebCryptoP256(keyPair, { access: account })
// Sign a key authorization
const keyAuthorization = await account.signKeyAuthorization(accessKey, {
expiry: Math.floor(Date.now() / 1000) + 86400, // 24 hour expiry
})
// Attach to next transaction
const receipt = await client.sendTransactionSync({
account: accessKey,
keyAuthorization,
to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
})
// Now any subsequent transaction can be used with `accessKey`
// WITHOUT the `keyAuthorization` parameter!
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
The return type of `Account.fromWebCryptoP256` is backwards compatible with Viem's `Account` type.
```ts
type ReturnType = Account
type Account = {
/** Account address */
address: Address
/** Key type */
keyType: string
/** Public key (hex) */
publicKey: Hex
/** Account source */
source: string
/** Account type */
type: 'local'
/** Assigns a key authorization to the next transaction */
assignKeyAuthorization: (keyAuthorization: KeyAuthorization) => Promise
/** Signs a raw digest */
sign: (parameters: { hash: Hex }) => Promise
/** Signs an EIP-7702 authorization */
signAuthorization: (parameters: SignAuthorizationParameters) => Promise
/** Signs a key authorization */
signKeyAuthorization: (
key: { accessKeyAddress: Address; keyType: string },
parameters?: { expiry?: bigint; limits?: Limits }
) => Promise
/** Signs a EIP-191 `personal_sign` message */
signMessage: (parameters: { message: string | { raw: Hex } }) => Promise
/** Signs a transaction */
signTransaction: (transaction: TransactionRequest) => Promise
/** Signs a EIP-712 typed data */
signTypedData: (typedData: TypedData) => Promise
}
```
## Parameters
### keyPair
* **Type:** `{ publicKey: PublicKey; privateKey: CryptoKey }`
The WebCrypto P256 key pair from `WebCryptoP256.createKeyPair()`.
### options (optional)
#### options.access
* **Type:** `Address | Account`
Parent account to access.
# `accessKey.authorize`
Authorizes an access key by signing a key authorization and sending a transaction.
## Usage
:::code-group
```ts twoslash [example.ts]
import { generatePrivateKey } from 'viem/accounts'
import { Account } from 'viem/tempo'
import { client } from './viem.config'
// 1. Define root account
const account = Account.from({ privateKey: '0x...' })
// 2. Define access key attached to the root account
const accessKey = Account.fromP256(generatePrivateKey(), {
access: account,
})
// 3. Authorize the access key
const { receipt } = await client.accessKey.authorizeSync({
accessKey,
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
:::tip
By deferring a key authorization to a later transaction, you can bundle it with another operation,
which enables an end-user to not pay for the authorization upfront.
```ts twoslash
import { Account, Actions } from 'viem/tempo'
import { generatePrivateKey } from 'viem/accounts'
import { client } from './viem.config'
const account = Account.from({ privateKey: '0x...' })
const accessKey = Account.fromP256(generatePrivateKey(), {
access: account,
})
// [!code focus:start]
// 1. Sign the key authorization (offline, no transaction sent)
const keyAuthorization = await Actions.accessKey.signAuthorization(
account,
{
accessKey,
expiry: Math.floor((Date.now() + 30_000) / 1000),
},
)
// 2. Attach keyAuthorization to any write action (can be sent with the access key)
const { receipt } = await client.token.transferSync({
account: accessKey,
token: '0x20c0000000000000000000000000000000000001',
to: '0xcafebabecafebabecafebabecafebabecafebabe',
amount: 100n,
keyAuthorization,
})
// [!code focus:end]
```
:::
### With Expiry and Spending Limits
You can set an expiry and per-token spending limits when authorizing an access key:
```ts twoslash
import { generatePrivateKey } from 'viem/accounts'
import { Account } from 'viem/tempo'
import { client } from './viem.config'
const account = Account.from({ privateKey: '0x...' })
const accessKey = Account.fromP256(generatePrivateKey(), {
access: account,
})
const { receipt } = await client.accessKey.authorizeSync({
accessKey,
expiry: Math.floor((Date.now() + 30_000) / 1000), // [!code focus]
limits: [ // [!code focus]
{ token: '0x20c0000000000000000000000000000000000001', limit: 1000000n }, // [!code focus]
], // [!code focus]
})
```
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `accessKey.authorize` action and wait for inclusion manually:
```ts twoslash
import { Actions, Account } from 'viem/tempo'
import { generatePrivateKey } from 'viem/accounts'
import { client } from './viem.config'
const account = Account.from({ privateKey: '0x...' })
const accessKey = Account.fromP256(generatePrivateKey(), {
access: account,
})
const hash = await client.accessKey.authorize({
accessKey,
expiry: Math.floor((Date.now() + 30_000) / 1000),
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.accessKey.authorize.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** The account that authorized the key. */
account: Address
/** The public key that was authorized. */
publicKey: Address
/** The signature type. */
signatureType: number
/** The expiry timestamp. */
expiry: bigint
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### accessKey
* **Type:** `Pick`
The access key to authorize.
### expiry (optional)
* **Type:** `number`
Unix timestamp when the key expires.
### limits (optional)
* **Type:** `{ token: Address; limit: bigint }[]`
Spending limits per token.
# `accessKey.getMetadata`
Gets access key information.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const key = await client.accessKey.getMetadata({
account: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
accessKey: '0x1234567890abcdef1234567890abcdef12345678',
})
console.log('Key type:', key.keyType)
// @log: Key type: p256
console.log('Spend policy:', key.spendPolicy)
// @log: Spend policy: unlimited
console.log('Revoked:', key.isRevoked)
// @log: Revoked: false
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = {
/** The access key address. */
address: Address
/** The key type. */
keyType: 'secp256k1' | 'p256' | 'webAuthn'
/** The expiry timestamp. */
expiry: bigint
/** The spending policy. */
spendPolicy: 'limited' | 'unlimited'
/** Whether the key is revoked. */
isRevoked: boolean
}
```
## Parameters
### accessKey
* **Type:** `Address | AccessKeyAccount`
The access key address or account.
### account
* **Type:** `Address | Account`
Account address.
# `accessKey.getRemainingLimit`
Gets the remaining spending limit for a key-token pair.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const remaining = await client.accessKey.getRemainingLimit({
account: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
accessKey: '0x1234567890abcdef1234567890abcdef12345678',
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Remaining limit:', remaining)
// @log: Remaining limit: 1000000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = bigint
```
The remaining spending amount.
## Parameters
### accessKey
* **Type:** `Address | AccessKeyAccount`
The access key address or account.
### account
* **Type:** `Address | Account`
Account address.
### token
* **Type:** `Address`
The token address.
# `accessKey.revoke`
Revokes an authorized access key.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.accessKey.revokeSync({
accessKey: '0x1234567890abcdef1234567890abcdef12345678',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `accessKey.revoke` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.accessKey.revoke({
accessKey: '0x1234567890abcdef1234567890abcdef12345678',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.accessKey.revoke.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** The account that owned the key. */
account: Address
/** The public key that was revoked. */
publicKey: Address
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### accessKey
* **Type:** `Address | AccessKeyAccount`
The access key to revoke.
# `accessKey.signAuthorization`
Signs a key authorization for an access key. This is a local signing operation — no transaction is sent.
:::info
If you want to authorize a key and send the transaction in one step, use [`accessKey.authorize`](/tempo/actions/accessKey.authorize) instead.
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { generatePrivateKey } from 'viem/accounts'
import { Account, Actions } from 'viem/tempo'
// 1. Define root account
const account = Account.from({ privateKey: '0x...' })
// 2. Define access key attached to the root account
const accessKey = Account.fromP256(generatePrivateKey(), {
access: account,
})
// 3. Sign the key authorization
const keyAuthorization = await Actions.accessKey.signAuthorization(
account,
{
accessKey,
expiry: Math.floor((Date.now() + 30_000) / 1000),
},
)
```
:::
### Submitting the Authorization
The signed `keyAuthorization` can be attached to any write action.
```ts
// Authorize the key alongside a transfer, sent with the access key
const { receipt } = await client.token.transferSync({
account: accessKey,
token: '0x20c0000000000000000000000000000000000001',
to: '0xcafebabecafebabecafebabecafebabecafebabe',
amount: 100n,
keyAuthorization,
})
```
## Return Type
```ts
type ReturnType = KeyAuthorization.Signed
```
A signed key authorization object that can be passed as `keyAuthorization` to any write action.
## Parameters
### account
* **Type:** `RootAccount`
The root account signing the authorization. Must be a local account with signing capabilities (e.g. created via `Account.from`).
### accessKey
* **Type:** `Pick`
The access key to authorize.
### expiry (optional)
* **Type:** `number`
Unix timestamp when the key expires.
### limits (optional)
* **Type:** `{ token: Address; limit: bigint }[]`
Spending limits per token.
# `accessKey.updateLimit`
Updates the spending limit for a specific token on an authorized access key.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { receipt } = await client.accessKey.updateLimitSync({
accessKey: '0x1234567890abcdef1234567890abcdef12345678',
token: '0x20c0000000000000000000000000000000000000',
limit: parseUnits('100', 6),
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `accessKey.updateLimit` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.accessKey.updateLimit({
accessKey: '0x1234567890abcdef1234567890abcdef12345678',
token: '0x20c0000000000000000000000000000000000000',
limit: parseUnits('100', 6),
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.accessKey.updateLimit.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** The account that owned the key. */
account: Address
/** The public key. */
publicKey: Address
/** The token address. */
token: Address
/** The new spending limit. */
limit: bigint
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### accessKey
* **Type:** `Address | AccessKeyAccount`
The access key to update.
### token
* **Type:** `Address`
The token address.
### limit
* **Type:** `bigint`
The new spending limit.
# `amm.burn`
Burns liquidity tokens and receives the underlying token pair. [Learn more about the Fee AMM](https://docs.tempo.xyz/protocol/fees/spec-fee-amm)
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { amountUserToken, amountValidatorToken, receipt } =
await client.amm.burnSync({
liquidity: parseUnits('10.5', 18),
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
userToken: '0x20c0000000000000000000000000000000000000',
validatorToken: '0x20c0000000000000000000000000000000000001',
})
console.log('Received user tokens:', amountUserToken)
// @log: Received user tokens: 5250000000000000000n
console.log('Received validator tokens:', amountValidatorToken)
// @log: Received validator tokens: 5250000000000000000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `amm.burn` action and wait for inclusion manually:
```ts twoslash
import { parseUnits } from 'viem'
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.amm.burn({
liquidity: parseUnits('10.5', 18),
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
userToken: '0x20c0000000000000000000000000000000000000',
validatorToken: '0x20c0000000000000000000000000000000000001',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { amountUserToken, amountValidatorToken } }
= Actions.amm.burn.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Amount of user tokens received */
amountUserToken: bigint
/** Amount of validator tokens received */
amountValidatorToken: bigint
/** Amount of liquidity tokens burned */
liquidity: bigint
/** Transaction receipt */
receipt: TransactionReceipt
/** Address that initiated the burn */
sender: Address
/** Address that received the underlying tokens */
to: Address
/** Address of the user token */
userToken: Address
/** Address of the validator token */
validatorToken: Address
}
```
## Parameters
### liquidity
* **Type:** `bigint`
Amount of LP tokens to burn.
### to
* **Type:** `Address`
Address to send tokens to.
### userToken
* **Type:** `Address | bigint`
Address or ID of the user token.
### validatorToken
* **Type:** `Address | bigint`
Address or ID of the validator token.
# `amm.getLiquidityBalance`
Gets the liquidity balance for an address in a specific pool.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const balance = await client.amm.getLiquidityBalance({
address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
userToken: '0x20c0000000000000000000000000000000000000',
validatorToken: '0x20c0000000000000000000000000000000000001',
})
console.log('Liquidity balance:', balance)
// @log: Liquidity balance: 10500000000000000000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = bigint // Liquidity balance
```
## Parameters
### address
* **Type:** `Address`
Address to check balance for.
### poolId (optional)
* **Type:** `Hex`
Pool ID.
### userToken (optional)
* **Type:** `Address | bigint`
User token.
### validatorToken (optional)
* **Type:** `Address | bigint`
Validator token.
# `amm.getPool`
Gets the reserves for a liquidity pool.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const pool = await client.amm.getPool({
userToken: '0x20c0000000000000000000000000000000000000',
validatorToken: '0x20c0000000000000000000000000000000000001',
})
console.log('User token reserve:', pool.reserveUserToken)
// @log: User token reserve: 1000000000000000000000n
console.log('Validator token reserve:', pool.reserveValidatorToken)
// @log: Validator token reserve: 1000000000000000000000n
console.log('Total supply:', pool.totalSupply)
// @log: Total supply: 1000000000000000000000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = {
/** Reserve of user token */
reserveUserToken: bigint
/** Reserve of validator token */
reserveValidatorToken: bigint
/** Total supply of LP tokens */
totalSupply: bigint
}
```
## Parameters
### userToken
* **Type:** `Address | bigint`
Address or ID of the user token.
### validatorToken
* **Type:** `Address | bigint`
Address or ID of the validator token.
# `amm.mint`
Mints liquidity tokens by providing a token pair. [Learn more about the Fee AMM](https://docs.tempo.xyz/protocol/fees/spec-fee-amm)
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { liquidity, receipt } = await client.amm.mintSync({
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
userTokenAddress: '0x20c0000000000000000000000000000000000000',
validatorTokenAddress: '0x20c0000000000000000000000000000000000001',
validatorTokenAmount: parseUnits('100', 6),
})
console.log('Liquidity minted:', liquidity)
// @log: Liquidity minted: 100000000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `amm.mint` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.amm.mint({
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
userTokenAddress: '0x20c0000000000000000000000000000000000000',
validatorTokenAddress: '0x20c0000000000000000000000000000000000001',
validatorTokenAmount: parseUnits('100', 6),
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { liquidity } }
= Actions.amm.mint.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Amount of user tokens provided */
amountUserToken: bigint
/** Amount of validator tokens provided */
amountValidatorToken: bigint
/** Amount of liquidity tokens minted */
liquidity: bigint
/** Transaction receipt */
receipt: TransactionReceipt
/** Address that initiated the mint */
sender: Address
/** Address of the user token */
userToken: Address
/** Address of the validator token */
validatorToken: Address
}
```
## Parameters
### to
* **Type:** `Address`
Address to mint the liquidity tokens to.
### userTokenAddress
* **Type:** `Address | bigint`
User token address.
### validatorTokenAddress
* **Type:** `Address | bigint`
Validator token address.
### validatorTokenAmount
* **Type:** `bigint`
Amount of validator tokens to provide.
# `amm.rebalanceSwap`
Performs a rebalance swap between user and validator tokens. [Learn more about the Fee AMM](https://docs.tempo.xyz/protocol/fees/spec-fee-amm)
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { amountIn, receipt } = await client.amm.rebalanceSwapSync({
amountOut: parseUnits('10.5', 6),
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
userToken: '0x20c0000000000000000000000000000000000000',
validatorToken: '0x20c0000000000000000000000000000000000001',
})
console.log('Amount in:', amountIn)
// @log: 10605000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `amm.rebalanceSwap` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.amm.rebalanceSwap({
amountOut: parseUnits('10.5', 6),
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
userToken: '0x20c0000000000000000000000000000000000000',
validatorToken: '0x20c0000000000000000000000000000000000001',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { amountIn } }
= Actions.amm.rebalanceSwap.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Amount of tokens required for the swap */
amountIn: bigint
/** Amount of output tokens received */
amountOut: bigint
/** Transaction receipt */
receipt: TransactionReceipt
/** Address that initiated the swap */
swapper: Address
/** Address of the user token */
userToken: Address
/** Address of the validator token */
validatorToken: Address
}
```
## Parameters
### amountOut
* **Type:** `bigint`
Amount of user token to receive.
### to
* **Type:** `Address`
Address to send the user token to.
### userToken
* **Type:** `Address | bigint`
Address or ID of the user token.
### validatorToken
* **Type:** `Address | bigint`
Address or ID of the validator token.
# `amm.watchBurn`
Watches for liquidity burn events on the Fee AMM.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.amm.watchBurn({
onBurn: (args, log) => {
console.log('User token amount:', args.amountUserToken)
console.log('Validator token amount:', args.amountValidatorToken)
console.log('Liquidity burned:', args.liquidity)
console.log('Sender:', args.sender)
console.log('Recipient:', args.to)
console.log('User token:', args.userToken)
console.log('Validator token:', args.validatorToken)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onBurn
* **Type:** `function`
```ts
declare function onBurn(args: Args, log: Log): void
type Args = {
/** Amount of user token received */
amountUserToken: bigint
/** Amount of validator token received */
amountValidatorToken: bigint
/** Amount of LP tokens burned */
liquidity: bigint
/** Address that removed liquidity */
sender: Address
/** Address that received the tokens */
to: Address
/** Address of the user token */
userToken: Address
/** Address of the validator token */
validatorToken: Address
}
```
Callback to invoke when liquidity is removed.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by sender address */
sender?: Address | Address[] | null
/** Filter by user token address */
userToken?: Address | Address[] | null
/** Filter by validator token address */
validatorToken?: Address | Address[] | null
}
```
Filter events by indexed parameters.
### userToken (optional)
* **Type:** `Address | bigint`
Address or ID of the user token to filter events.
### validatorToken (optional)
* **Type:** `Address | bigint`
Address or ID of the validator token to filter events.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Enable polling mode.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `amm.watchMint`
Watches for liquidity mint events on the Fee AMM.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.amm.watchMint({
onMint: (args, log) => {
console.log('Liquidity minted:', args.liquidity)
console.log('Sender:', args.sender)
console.log('User token amount:', args.amountValidatorToken)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onMint
* **Type:**
```ts
declare function onMint(args: Args, log: Log): void
type Args = {
/** Amount of LP tokens minted */
liquidity: bigint
/** Address that added liquidity */
sender: Address
/** User token details */
userToken: {
/** Address of the user token */
address: Address
/** Amount of user token added */
amount: bigint
}
/** Validator token details */
validatorToken: {
/** Address of the validator token */
address: Address
/** Amount of validator token added */
amount: bigint
}
}
```
Callback to invoke when liquidity is added.
### sender (optional)
* **Type:** `Address | bigint`
Address or ID of the sender to filter events.
### userToken (optional)
* **Type:** `Address | bigint`
Address or ID of the user token to filter events.
### validatorToken (optional)
* **Type:** `Address | bigint`
Address or ID of the validator token to filter events.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `(error: Error) => void`
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Enable polling mode for watching events.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `amm.watchRebalanceSwap`
Watches for rebalance swap events on the Fee AMM.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.amm.watchRebalanceSwap({
onRebalanceSwap: (args, log) => {
console.log('Amount in:', args.amountIn)
console.log('Amount out:', args.amountOut)
console.log('Swapper:', args.swapper)
console.log('User token:', args.userToken)
console.log('Validator token:', args.validatorToken)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onRebalanceSwap
* **Type:** `function`
```ts
declare function onRebalanceSwap(args: Args, log: Log): void
type Args = {
/** Address of the user token */
userToken: Address
/** Address of the validator token */
validatorToken: Address
/** Address of the swapper */
swapper: Address
/** Amount of validator token swapped in */
amountIn: bigint
/** Amount of user token received */
amountOut: bigint
}
```
Callback to invoke when a rebalance swap occurs.
### userToken (optional)
* **Type:** `Address | bigint`
Address or ID of the user token to filter events.
### validatorToken (optional)
* **Type:** `Address | bigint`
Address or ID of the validator token to filter events.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by user token address */
userToken?: Address | Address[] | null
/** Filter by validator token address */
validatorToken?: Address | Address[] | null
/** Filter by swapper address */
swapper?: Address | Address[] | null
}
```
Filter parameters for the event.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `dex.buy`
Buys a specific amount of tokens from the Stablecoin DEX orderbook.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { receipt } = await client.dex.buySync({
amountOut: parseUnits('100', 6),
maxAmountIn: parseUnits('105', 6),
tokenIn: '0x20c0000000000000000000000000000000000001',
tokenOut: '0x20c0000000000000000000000000000000000002',
})
console.log('Transaction hash:', receipt.transactionHash)
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `dex.buy` action and wait for inclusion manually:
```ts twoslash
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.dex.buy({
amountOut: parseUnits('100', 6),
maxAmountIn: parseUnits('105', 6),
tokenIn: '0x20c0000000000000000000000000000000000001',
tokenOut: '0x20c0000000000000000000000000000000000002',
})
const receipt = await client.waitForTransactionReceipt({ hash })
```
## Return Type
```ts
type ReturnType = {
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### amountOut
* **Type:** `bigint`
Amount of tokenOut to buy.
### maxAmountIn
* **Type:** `bigint`
Maximum amount of tokenIn to spend.
### tokenIn
* **Type:** `Address`
Address of the token to spend.
### tokenOut
* **Type:** `Address`
Address of the token to buy.
# `dex.cancel`
Cancels an order from the Stablecoin DEX orderbook.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { orderId, receipt } = await client.dex.cancelSync({
orderId: 123n,
})
console.log('Cancelled order ID:', orderId)
// @log: Cancelled order ID: 123n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `dex.cancel` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.dex.cancel({
orderId: 123n,
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { orderId } }
= Actions.dex.cancel.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** ID of the cancelled order */
orderId: bigint
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### orderId
* **Type:** `bigint`
ID of the order to cancel.
# `dex.cancelStale`
Cancels a stale order from the Stablecoin DEX orderbook.
A stale order is one where the maker has been blacklisted by a TIP-403 policy. Anyone can cancel stale orders.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { orderId, receipt } = await client.dex.cancelStaleSync({
orderId: 123n,
})
console.log('Cancelled stale order ID:', orderId)
// @log: Cancelled stale order ID: 123n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `dex.cancelStale` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.dex.cancelStale({
orderId: 123n,
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { orderId } }
= Actions.dex.cancelStale.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** ID of the cancelled order */
orderId: bigint
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### orderId
* **Type:** `bigint`
ID of the stale order to cancel.
# `dex.createPair`
Creates a new trading pair on the Stablecoin DEX.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { key, base, quote, receipt } = await client.dex.createPairSync({
base: '0x20c0000000000000000000000000000000000001',
})
console.log('Pair key:', key)
console.log('Base token:', base)
console.log('Quote token:', quote)
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `dex.createPair` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.dex.createPair({
base: '0x20c0000000000000000000000000000000000001',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { base, quote } }
= Actions.dex.createPair.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Key of the trading pair */
key: Hex
/** Address of the base token */
base: Address
/** Address of the quote token */
quote: Address
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### base
* **Type:** `Address`
Address of the base token for the pair. The quote token is determined by the base token's quote token.
# `dex.getBalance`
Gets a user's token balance on the Stablecoin DEX.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const balance = await client.dex.getBalance({
account: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000001',
})
console.log('DEX balance:', balance)
// @log: DEX balance: 1000000000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = bigint
```
## Parameters
### account
* **Type:** `Address`
Address of the account.
### token
* **Type:** `Address`
Address of the token.
# `dex.getBuyQuote`
Gets the quote for buying a specific amount of tokens.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const amountIn = await client.dex.getBuyQuote({
amountOut: parseUnits('100', 6),
tokenIn: '0x20c0000000000000000000000000000000000001',
tokenOut: '0x20c0000000000000000000000000000000000002',
})
console.log('Amount needed:', amountIn)
// @log: Amount needed: 100300000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = bigint
```
Returns the amount of `tokenIn` needed to buy the specified `amountOut` of `tokenOut`.
## Parameters
### amountOut
* **Type:** `bigint`
Amount of tokenOut to buy.
### tokenIn
* **Type:** `Address`
Address of the token to spend.
### tokenOut
* **Type:** `Address`
Address of the token to buy.
# `dex.getOrder`
Gets an order's details from the Stablecoin DEX orderbook.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const order = await client.dex.getOrder({
orderId: 123n,
})
console.log('Order details:', order)
// @log: Order details: { amount: 100000000n, maker: '0x...', isBid: true, ... }
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = {
/** Original order amount */
amount: bigint
/** Orderbook key (identifies the trading pair) */
bookKey: Hex
/** Tick to flip to when fully filled (for flip orders). For bid flips: must be > tick. For ask flips: must be < tick */
flipTick: number
/** Whether this is a bid (true) or ask (false) order */
isBid: boolean
/** Whether this is a flip order */
isFlip: boolean
/** Address of the user who placed this order */
maker: Address
/** Next order ID in the doubly linked list (0 if tail) */
next: bigint
/** The order ID */
orderId: bigint
/** Previous order ID in the doubly linked list (0 if head) */
prev: bigint
/** Remaining amount to be filled */
remaining: bigint
/** Price tick */
tick: number
}
```
Returns the complete order details including the maker's address, order amounts, price tick, linked list pointers, and flip order information.
## Parameters
### orderId
* **Type:** `bigint`
Order ID to query.
# `dex.getSellQuote`
Gets the quote for selling a specific amount of tokens.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const amountOut = await client.dex.getSellQuote({
amountIn: parseUnits('100', 6),
tokenIn: '0x20c0000000000000000000000000000000000001',
tokenOut: '0x20c0000000000000000000000000000000000002',
})
console.log('Amount received:', amountOut)
// @log: Amount received: 99700000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = bigint
```
Returns the amount of `tokenOut` received for selling the specified `amountIn` of `tokenIn`.
## Parameters
### amountIn
* **Type:** `bigint`
Amount of tokenIn to sell.
### tokenIn
* **Type:** `Address`
Address of the token to sell.
### tokenOut
* **Type:** `Address`
Address of the token to receive.
# `dex.getTickLevel`
Gets the tick level information at a specific tick on the Stablecoin DEX orderbook.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
import { Tick } from 'viem/tempo'
const level = await client.dex.getTickLevel({
base: '0x20c0000000000000000000000000000000000001',
tick: Tick.fromPrice('1.001'),
isBid: true,
})
console.log('Tick level:', level)
// @log: Tick level: { head: 1n, tail: 5n, totalLiquidity: 1000000000n }
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = {
/** Order ID of the first order at this tick (0 if empty) */
head: bigint
/** Order ID of the last order at this tick (0 if empty) */
tail: bigint
/** Total liquidity available at this tick level */
totalLiquidity: bigint
}
```
Returns the price level information including the order IDs for the head and tail of the FIFO queue at this price level, and the total liquidity available.
## Parameters
### base
* **Type:** `Address`
Address of the base token.
### isBid
* **Type:** `boolean`
Whether to query the bid side (`true`) or ask side (`false`).
### tick
* **Type:** `number`
Price tick to query. Can be created using `Tick.fromPrice()`.
# `dex.place`
Places a limit order on the Stablecoin DEX orderbook.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { Tick } from 'viem/tempo'
import { client } from './viem.config'
const { orderId, receipt } = await client.dex.placeSync({
amount: parseUnits('100', 6),
tick: Tick.fromPrice('0.99'),
token: '0x20c0000000000000000000000000000000000001',
type: 'buy',
})
console.log('Order ID:', orderId)
// @log: Order ID: 123n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `dex.place` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseUnits } from 'viem'
import { Tick } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.dex.place({
amount: parseUnits('100', 6),
tick: Tick.fromPrice('0.99'),
token: '0x20c0000000000000000000000000000000000001',
type: 'buy',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { orderId } }
= Actions.dex.place.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** ID of the placed order */
orderId: bigint
/** Address of the order maker */
maker: Address
/** Address of the base token */
token: Address
/** Amount of tokens in the order */
amount: bigint
/** Whether this is a buy order */
isBid: boolean
/** Price tick for the order */
tick: number
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### amount
* **Type:** `bigint`
Amount of tokens to place in the order.
### tick
* **Type:** `number`
Price tick for the order. Use `Tick.fromPrice()` to convert from a price string.
### token
* **Type:** `Address`
Address of the base token.
### type
* **Type:** `OrderType`
Order type - `'buy'` to buy the token, `'sell'` to sell it.
# `dex.placeFlip`
Places a flip order that automatically flips to the opposite side when filled.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { Tick } from 'viem/tempo'
import { client } from './viem.config'
const { orderId, receipt } = await client.dex.placeFlipSync({
amount: parseUnits('100', 6),
flipTick: Tick.fromPrice('1.01'),
tick: Tick.fromPrice('0.99'),
token: '0x20c0000000000000000000000000000000000001',
type: 'buy',
})
console.log('Flip order ID:', orderId)
// @log: Flip order ID: 456n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `dex.placeFlip` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseUnits } from 'viem'
import { Tick } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.dex.placeFlip({
amount: parseUnits('100', 6),
flipTick: Tick.fromPrice('1.01'),
tick: Tick.fromPrice('0.99'),
token: '0x20c0000000000000000000000000000000000001',
type: 'buy',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { orderId } }
= Actions.dex.placeFlip.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** ID of the placed flip order */
orderId: bigint
/** Address of the order maker */
maker: Address
/** Address of the base token */
token: Address
/** Amount of tokens in the order */
amount: bigint
/** Whether this is a buy order */
isBid: boolean
/** Price tick for the order */
tick: number
/** Target tick to flip to when order is filled */
flipTick: number
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### amount
* **Type:** `bigint`
Amount of tokens to place in the order.
### flipTick
* **Type:** `number`
Target tick to flip to when order is filled. Must be greater than `tick` for buy orders, less than `tick` for sell orders.
### tick
* **Type:** `number`
Price tick for the order. Use `Tick.fromPrice()` to convert from a price string.
### token
* **Type:** `Address`
Address of the base token.
### type
* **Type:** `'buy' | 'sell'`
Order type - `'buy'` to buy the token, `'sell'` to sell it.
# `dex.sell`
Sells a specific amount of tokens on the Stablecoin DEX orderbook.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { receipt } = await client.dex.sellSync({
amountIn: parseUnits('100', 6),
minAmountOut: parseUnits('95', 6),
tokenIn: '0x20c0000000000000000000000000000000000001',
tokenOut: '0x20c0000000000000000000000000000000000002',
})
console.log('Transaction hash:', receipt.transactionHash)
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `dex.sell` action and wait for inclusion manually:
```ts twoslash
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.dex.sell({
amountIn: parseUnits('100', 6),
minAmountOut: parseUnits('95', 6),
tokenIn: '0x20c0000000000000000000000000000000000001',
tokenOut: '0x20c0000000000000000000000000000000000002',
})
const receipt = await client.waitForTransactionReceipt({ hash })
```
## Return Type
```ts
type ReturnType = {
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### amountIn
* **Type:** `bigint`
Amount of tokenIn to sell.
### minAmountOut
* **Type:** `bigint`
Minimum amount of tokenOut to receive.
### tokenIn
* **Type:** `Address`
Address of the token to sell.
### tokenOut
* **Type:** `Address`
Address of the token to receive.
# `dex.watchFlipOrderPlaced`
Watches for flip order placed events on the Stablecoin DEX.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.dex.watchFlipOrderPlaced({
onFlipOrderPlaced: (args, log) => {
console.log('Flip order placed:', args.orderId)
console.log('Maker:', args.maker)
console.log('Amount:', args.amount)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onFlipOrderPlaced
* **Type:** `function`
```ts
declare function onFlipOrderPlaced(args: Args, log: Log): void
type Args = {
/** ID of the placed order */
orderId: bigint
/** Address that placed the order */
maker: Address
/** Address of the base token */
token: Address
/** Amount of tokens in the order */
amount: bigint
/** Whether this is a buy order */
isBid: boolean
/** Price tick for the order */
tick: number
/** Target tick to flip to when filled */
flipTick: number
}
```
Callback to invoke when a flip order is placed.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by order ID */
orderId?: bigint | bigint[] | null
/** Filter by maker address */
maker?: Address | Address[] | null
/** Filter by token address */
token?: Address | Address[] | null
}
```
Filter parameters for the event subscription.
### maker (optional)
* **Type:** `Address`
Address of the maker to filter events.
### token (optional)
* **Type:** `Address`
Address of the token to filter events.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `(error: Error) => void`
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `dex.watchOrderCancelled`
Watches for order cancelled events on the Stablecoin DEX.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.dex.watchOrderCancelled({
onOrderCancelled: (args, log) => {
console.log('Order cancelled:', args.orderId)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onOrderCancelled
* **Type:** `function`
```ts
declare function onOrderCancelled(args: Args, log: Log): void
type Args = {
/** ID of the cancelled order */
orderId: bigint
}
```
Callback to invoke when an order is cancelled.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Order ID to filter events */
orderId?: bigint | bigint[] | null
}
```
Filter options for the event.
### orderId (optional)
* **Type:** `bigint`
Order ID to filter events.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Enable polling mode.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `dex.watchOrderFilled`
Watches for order filled events on the Stablecoin DEX.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.dex.watchOrderFilled({
onOrderFilled: (args, log) => {
console.log('Order filled:', args.orderId)
console.log('Maker:', args.maker)
console.log('Amount filled:', args.amountFilled)
console.log('Partial fill:', args.partialFill)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onOrderFilled
* **Type:** `function`
```ts
declare function onOrderFilled(args: Args, log: Log): void
type Args = {
/** ID of the filled order */
orderId: bigint
/** Address that placed the order */
maker: Address
/** Amount of tokens filled */
amountFilled: bigint
/** Whether the order was partially filled */
partialFill: boolean
}
```
Callback to invoke when an order is filled.
### maker (optional)
* **Type:** `Address`
Address of the maker to filter events.
### orderId (optional)
* **Type:** `bigint`
Order ID to filter events.
### taker (optional)
* **Type:** `Address`
Address of the taker to filter events.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `dex.watchOrderPlaced`
Watches for order placed events on the Stablecoin DEX.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.dex.watchOrderPlaced({
onOrderPlaced: (args, log) => {
console.log('Order placed:', args.orderId)
console.log('Maker:', args.maker)
console.log('Token:', args.token)
console.log('Amount:', args.amount)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onOrderPlaced
* **Type:** `function`
```ts
declare function onOrderPlaced(args: Args, log: Log): void
type Args = {
/** ID of the placed order */
orderId: bigint
/** Address that placed the order */
maker: Address
/** Address of the base token */
token: Address
/** Amount of tokens in the order */
amount: bigint
/** Whether this is a buy order */
isBid: boolean
/** Price tick for the order */
tick: number
}
```
Callback to invoke when an order is placed.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by order ID */
orderId?: bigint | bigint[] | null
/** Filter by maker address */
maker?: Address | Address[] | null
/** Filter by token address */
token?: Address | Address[] | null
}
```
Filter parameters for the watch subscription.
### maker (optional)
* **Type:** `Address`
Address of the maker to filter events.
### token (optional)
* **Type:** `Address`
Address of the token to filter events.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `(error: Error) => void`
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Enable polling mode.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `dex.withdraw`
Withdraws tokens from the Stablecoin DEX to your wallet.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { receipt } = await client.dex.withdrawSync({
amount: parseUnits('100', 6),
token: '0x20c0000000000000000000000000000000000001',
})
console.log('Transaction hash:', receipt.transactionHash)
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `dex.withdraw` action and wait for inclusion manually:
```ts twoslash
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.dex.withdraw({
amount: parseUnits('100', 6),
token: '0x20c0000000000000000000000000000000000001',
})
const receipt = await client.waitForTransactionReceipt({ hash })
```
## Return Type
```ts
type ReturnType = {
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### amount
* **Type:** `bigint`
Amount of tokens to withdraw.
### token
* **Type:** `Address`
Address of the token to withdraw.
# `faucet.fund`
Funds an account with an initial amount of tokens on Tempo's testnet.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const hashes = await client.faucet.fund({
account: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
})
console.log('Transaction hashes:', hashes)
// @log: Transaction hashes: ['0x...', '0x...']
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Synchronous Usage
Use `fundSync` to wait for the transactions to be included on a block before returning:
```ts twoslash
import { client } from './viem.config'
const receipts = await client.faucet.fundSync({
account: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
})
console.log('Receipts:', receipts)
// @log: Receipts: [{ blockNumber: 123n, ... }, { blockNumber: 123n, ... }]
```
## Return Type
### fund
```ts
type ReturnType = readonly Hash[]
```
Returns an array of transaction hashes for the funding transactions.
### fundSync
```ts
type ReturnType = readonly TransactionReceipt[]
```
Returns an array of transaction receipts after the transactions are confirmed.
## Parameters
### account
* **Type:** `Account | Address`
Account to fund with testnet tokens.
### timeout (fundSync only)
* **Type:** `number`
* **Default:** `10000`
Timeout in milliseconds to wait for transaction confirmation.
# `fee.getUserToken`
Gets the user's default fee token preference. [Learn more about fees](https://docs.tempo.xyz/protocol/fees)
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const result = await client.fee.getUserToken({
account: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
})
console.log('Fee token address:', result?.address)
// @log: Fee token address: 0x20c0000000000000000000000000000000000000
console.log('Fee token ID:', result?.id)
// @log: Fee token ID: 0n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = {
/** Address of the fee token */
address: Address
/** ID of the fee token */
id: bigint
} | null
```
Returns `null` if the user has not set a default fee token.
## Parameters
### account
* **Type:** `Address`
Account address.
# `fee.setUserToken`
Sets the user's default fee token preference. [Learn more about fees](https://docs.tempo.xyz/protocol/fees)
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.fee.setUserTokenSync({
token: '0x20c0000000000000000000000000000000000001',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `fee.setUserToken` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.fee.setUserToken({
token: '0x20c0000000000000000000000000000000000001',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.fee.setUserToken.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Address of the user */
user: Address
/** Address of the token set */
token: Address
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token to use for fees.
# `fee.watchSetUserToken`
Watches for user token set events on the Fee Manager.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.fee.watchSetUserToken({
onUserTokenSet: (args, log) => {
console.log('User:', args.user)
console.log('New fee token:', args.token)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onUserTokenSet
* **Type:** `function`
```ts
declare function onUserTokenSet(args: Args, log: Log): void
type Args = {
/** Address of the user */
user: Address
/** Address of the new fee token */
token: Address
}
```
Callback to invoke when a user token is set.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Address of the user to filter by */
user?: Address | Address[] | null
/** Address of the token to filter by */
token?: Address | Address[] | null
}
```
Optional filters for the event.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `nonce.getNonce`
Gets the nonce for an account and nonce key. This is useful for managing multiple nonce lanes for parallel transaction submission.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const nonce = await client.nonce.getNonce({
account: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
nonceKey: 1n,
})
console.log('Nonce:', nonce)
// @log: Nonce: 42n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = bigint
```
The current nonce value for the given account and nonce key.
## Parameters
### account
* **Type:** `Address`
Account address to get the nonce for.
### nonceKey
* **Type:** `bigint`
Nonce key (must be > 0, key 0 is reserved for protocol nonces).
# `nonce.watchNonceIncremented`
Watches for nonce incremented events. This event is emitted whenever a transaction is executed using a specific nonce key.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.nonce.watchNonceIncremented({
onNonceIncremented: (args, log) => {
console.log('Account:', args.account)
console.log('Nonce key:', args.nonceKey)
console.log('New nonce:', args.newNonce)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onNonceIncremented
* **Type:** `function`
```ts
declare function onNonceIncremented(args: Args, log: Log): void
type Args = {
/** Address of the account */
account: Address
/** Nonce key that was incremented */
nonceKey: bigint
/** New nonce value after increment */
newNonce: bigint
}
```
Callback to invoke when a nonce is incremented.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Address of the account to filter by */
account?: Address | Address[] | null
/** Nonce key to filter by */
nonceKey?: bigint | bigint[] | null
}
```
Optional filters for the event.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `policy.create`
Creates a new transfer policy for token access control. [Learn more about transfer policies](https://docs.tempo.xyz/protocol/tip403/spec)
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { policyId, policyType, receipt } = await client.policy.createSync({
admin: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
addresses: [
'0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
],
type: 'whitelist',
})
console.log('Policy ID:', policyId)
// @log: Policy ID: 1n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `policy.create` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.policy.create({
admin: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
addresses: [
'0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
],
type: 'whitelist',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { policyId } }
= Actions.policy.create.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** ID of the created policy */
policyId: bigint
/** Type of the policy (0 = whitelist, 1 = blacklist) */
policyType: number
/** Transaction receipt */
receipt: TransactionReceipt
/** Address that created the policy */
updater: Address
}
```
## Parameters
### type
* **Type:** `'whitelist' | 'blacklist'`
Type of policy to create. A `whitelist` policy only allows listed addresses, while a `blacklist` policy allows all except listed addresses.
### addresses (optional)
* **Type:** `Address[]`
Optional array of addresses to initialize the policy with.
### admin
* **Type:** `Address`
Address of the policy admin.
# `policy.getData`
Gets the data for a transfer policy, including its type and admin address.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { admin, type } = await client.policy.getData({
policyId: 1n,
})
console.log('Policy admin:', admin)
// @log: Policy admin: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb
console.log('Policy type:', type)
// @log: Policy type: whitelist
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = {
/** Address of the policy admin */
admin: Address
/** Type of policy */
type: PolicyType
}
```
## Parameters
### policyId
* **Type:** `bigint`
ID of the policy to query.
# `policy.isAuthorized`
Checks if an address is authorized by a transfer policy.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const isAuthorized = await client.policy.isAuthorized({
user: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
policyId: 1n,
})
console.log('Is authorized:', isAuthorized)
// @log: Is authorized: true
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = boolean
```
## Parameters
### policyId
* **Type:** `bigint`
Policy ID.
### user
* **Type:** `Address`
User address to check.
# `policy.modifyBlacklist`
Modifies the blacklist for a blacklist-type transfer policy. Requires policy admin role.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.policy.modifyBlacklistSync({
address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
policyId: 1n,
restricted: true,
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `policy.modifyBlacklist` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.policy.modifyBlacklist({
address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
policyId: 1n,
restricted: true,
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.policy.modifyBlacklist.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Address that was added/removed from blacklist */
account: Address
/** ID of the policy */
policyId: bigint
/** Transaction receipt */
receipt: TransactionReceipt
/** Whether the address is restricted */
restricted: boolean
/** Address that modified the blacklist */
updater: Address
}
```
## Parameters
### address
* **Type:** `Address`
Target account address to add or remove from the blacklist.
### policyId
* **Type:** `bigint`
ID of the blacklist policy to modify.
### restricted
* **Type:** `boolean`
Whether the address should be restricted (`true`) or unrestricted (`false`).
# `policy.modifyWhitelist`
Modifies the whitelist for a whitelist-type transfer policy. Requires policy admin role.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.policy.modifyWhitelistSync({
address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
allowed: true,
policyId: 1n,
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `policy.modifyWhitelist` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.policy.modifyWhitelist({
address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
allowed: true,
policyId: 1n,
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.policy.modifyWhitelist.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Address that was added/removed from whitelist */
account: Address
/** Whether the address is allowed */
allowed: boolean
/** ID of the policy */
policyId: bigint
/** Transaction receipt */
receipt: TransactionReceipt
/** Address that modified the whitelist */
updater: Address
}
```
## Parameters
### address
* **Type:** `Address`
Target account address to add or remove from the whitelist.
### allowed
* **Type:** `boolean`
Whether the address should be allowed (`true`) or disallowed (`false`).
### policyId
* **Type:** `bigint`
ID of the whitelist policy to modify.
# `policy.setAdmin`
Sets the admin for a transfer policy. Requires current policy admin role.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.policy.setAdminSync({
admin: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
policyId: 1n,
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `policy.setAdmin` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.policy.setAdmin({
admin: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
policyId: 1n,
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.policy.setAdmin.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Address of the new admin */
admin: Address
/** ID of the policy */
policyId: bigint
/** Transaction receipt */
receipt: TransactionReceipt
/** Address that updated the admin */
updater: Address
}
```
## Parameters
### admin
* **Type:** `Address`
Address to set as the new policy admin.
### policyId
* **Type:** `bigint`
ID of the policy to update.
# `policy.watchAdminUpdated`
Watches for policy admin update events on the TIP403 Registry.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.policy.watchAdminUpdated({
onAdminUpdated: (args, log) => {
console.log('Admin:', args.admin)
console.log('Policy ID:', args.policyId)
console.log('Updater:', args.updater)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onAdminUpdated
* **Type:** `function`
```ts
declare function onAdminUpdated(args: Args, log: Log): void
type Args = {
/** ID of the policy */
policyId: bigint
/** Address that updated the admin */
updater: Address
/** Address of the admin */
admin: Address
}
```
Callback to invoke when a policy admin is updated.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by policy ID */
policyId?: bigint | bigint[] | null
/** Filter by updater address */
updater?: Address | Address[] | null
/** Filter by admin address */
admin?: Address | Address[] | null
}
```
Optional filter arguments for the event.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `policy.watchBlacklistUpdated`
Watches for blacklist update events on the TIP403 Registry.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.policy.watchBlacklistUpdated({
onBlacklistUpdated: (args, log) => {
console.log('Account:', args.account)
console.log('Policy ID:', args.policyId)
console.log('Restricted:', args.restricted)
console.log('Updater:', args.updater)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onBlacklistUpdated
* **Type:** `function`
```ts
declare function onBlacklistUpdated(args: Args, log: Log): void
type Args = {
/** Address of the account */
account: Address
/** ID of the policy */
policyId: bigint
/** Whether the account is restricted */
restricted: boolean
/** Address that updated the blacklist */
updater: Address
}
```
Callback to invoke when a blacklist is updated.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by policy ID */
policyId?: bigint | bigint[] | null
/** Filter by updater address */
updater?: Address | Address[] | null
/** Filter by account address */
account?: Address | Address[] | null
}
```
Optional filter arguments to narrow the events being watched.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `policy.watchCreate`
Watches for policy creation events on the TIP403 Registry.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.policy.watchCreate({
onPolicyCreated: (args, log) => {
console.log('Policy ID:', args.policyId)
console.log('Type:', args.type)
console.log('Updater:', args.updater)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onPolicyCreated
* **Type:** `function`
```ts
declare function onPolicyCreated(args: Args, log: Log): void
type Args = {
/** ID of the created policy */
policyId: bigint
/** Type of policy */
type: PolicyType
/** Address that created the policy */
updater: Address
}
```
Callback to invoke when a policy is created.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by policy ID */
policyId?: bigint | bigint[] | null
/** Filter by updater address */
updater?: Address | Address[] | null
}
```
Optional filter arguments to narrow which events to watch.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `policy.watchWhitelistUpdated`
Watches for whitelist update events on the TIP403 Registry.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.policy.watchWhitelistUpdated({
onWhitelistUpdated: (args, log) => {
console.log('Account:', args.account)
console.log('Allowed:', args.allowed)
console.log('Policy ID:', args.policyId)
console.log('Updater:', args.updater)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onWhitelistUpdated
* **Type:** `function`
```ts
declare function onWhitelistUpdated(args: Args, log: Log): void
type Args = {
/** Address of the account */
account: Address
/** Whether the account is allowed */
allowed: boolean
/** ID of the policy */
policyId: bigint
/** Address that updated the whitelist */
updater: Address
}
```
Callback to invoke when a whitelist is updated.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by policy ID */
policyId?: bigint | bigint[] | null
/** Filter by updater address */
updater?: Address | Address[] | null
/** Filter by account address */
account?: Address | Address[] | null
}
```
Optional filter arguments for the watch.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `reward.claim`
Claims accumulated rewards for the caller.
## Usage
Use the `reward.claim` action on the Viem `client` to claim rewards that have accumulated for your address.
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.reward.claimSync({
token: '0x20c0000000000000000000000000000000000001',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `reward.claim` action and wait for inclusion manually:
```ts twoslash
import { client, token } from './viem.config'
const hash = await client.reward.claim({
token,
})
const receipt = await client.waitForTransactionReceipt({ hash })
```
## Return Type
```ts
type ReturnType = {
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### token
* **Type:** `Address`
Address of the TIP-20 token.
# `reward.distribute`
Distributes rewards to opted-in token holders.
## Usage
Use the `reward.distribute` action on the Viem `client` to distribute rewards to token holders.
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { client } from './viem.config'
const { amount, funder, receipt } =
await client.reward.distributeSync({
amount: parseEther('1000'),
token: '0x20c0000000000000000000000000000000000001',
})
console.log('Amount:', amount)
// @log: Amount: 1000000000000000000000n
console.log('Funder:', funder)
// @log: Funder: 0x...
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `reward.distribute` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseEther } from 'viem'
import { client } from './viem.config'
const hash = await client.reward.distribute({
amount: parseEther('1000'),
token: '0x20c0000000000000000000000000000000000001',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { amount, funder } }
= Actions.reward.distribute.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Amount distributed */
amount: bigint
/** Address that funded the distribution */
funder: Address
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### amount
* **Type:** `bigint`
The amount of tokens to distribute. Must be greater than 0.
### token
* **Type:** `Address`
Address of the TIP-20 token.
# `reward.getGlobalRewardPerToken`
Gets the global reward per token value.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const rewardPerToken = await client.reward.getGlobalRewardPerToken({
token: '0x20c0000000000000000000000000000000000001',
})
console.log('Global reward per token:', rewardPerToken)
// @log: Global reward per token: 385802469135802469135n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnValue = bigint
```
Returns the current global reward per token value scaled by `ACC_PRECISION` (1e18). This value increases each time rewards are distributed.
## Parameters
### token
* **Type:** `Address`
Address of the TIP-20 token.
# `reward.getPendingRewards`
Calculates the pending claimable rewards for an account without modifying state.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const pending = await client.reward.getPendingRewards({
token: '0x20c0000000000000000000000000000000000001',
account: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
})
console.log('Pending rewards:', pending)
// @log: Pending rewards: 1000000000000000000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnValue = bigint
```
Returns the total pending claimable reward amount, including stored balance and newly accrued rewards.
## Parameters
### account
* **Type:** `Address`
The account address to query pending rewards for.
### token
* **Type:** `Address`
Address of the TIP-20 token.
# `reward.getUserRewardInfo`
Gets reward information for a specific account.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { rewardBalance, rewardPerToken, rewardRecipient } =
await client.reward.getUserRewardInfo({
account: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000001',
})
console.log('Reward recipient:', rewardRecipient)
// @log: Reward recipient: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb
console.log('Reward balance:', rewardBalance)
// @log: Reward balance: 1000000000000000000n
console.log('Reward per token:', rewardPerToken)
// @log: Reward per token: 385802469135802469135n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = {
/** Accumulated reward balance claimable by the account */
rewardBalance: bigint
/** Reward per token checkpoint for the account */
rewardPerToken: bigint
/** Current reward recipient address (zero address if opted out) */
rewardRecipient: Address
}
```
## Parameters
### account
* **Type:** `Address`
Address of the account to get reward info for.
### token
* **Type:** `Address`
Address of the TIP-20 token.
# `reward.setRecipient`
Sets or changes the reward recipient for a token holder.
## Usage
Use the `reward.setRecipient` action on the Viem `client` to opt in to rewards or change your reward recipient.
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { holder, receipt, recipient } = await client.reward.setRecipientSync({
recipient: client.account.address, // receive rewards directly
token: '0x20c0000000000000000000000000000000000001',
})
console.log('Holder:', holder)
// @log: Holder: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
console.log('Recipient:', recipient)
// @log: Recipient: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Opt Out of Rewards
Set `recipient` to the zero address to opt out from rewards distribution:
```ts twoslash
import { client, token } from './viem.config'
await client.reward.setRecipientSync({
recipient: '0x0000000000000000000000000000000000000000',
token: '0x20c0000000000000000000000000000000000001',
})
```
### Delegate Rewards
Set `recipient` to another address to delegate your rewards to them:
```ts twoslash
import { client } from './viem.config'
await client.reward.setRecipientSync({
recipient: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
token: '0x20c0000000000000000000000000000000000001',
})
```
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `reward.setRecipient` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client, token } from './viem.config'
const hash = await client.reward.setRecipient({
recipient: client.account.address,
token,
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { holder, recipient } }
= Actions.reward.setRecipient.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Token holder address who set their reward recipient */
holder: Address
/** Transaction receipt */
receipt: TransactionReceipt
/** Reward recipient address (zero address indicates opt-out) */
recipient: Address
}
```
:::tip
Rewards are automatically distributed to the current recipient before changing. This happens during any balance-changing operation (transfers, mints, burns).
:::
## Parameters
### recipient
* **Type:** `Address`
The reward recipient address. Use zero address to opt out of rewards.
### token
* **Type:** `Address`
The TIP20 token address.
# `reward.watchRewardDistributed`
Watches for reward distributed events when rewards are distributed to token holders.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.reward.watchRewardDistributed({
onRewardDistributed: (args, log) => {
console.log('Funder:', args.funder)
console.log('Amount:', args.amount)
},
token: '0x20c0000000000000000000000000000000000001',
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onRewardDistributed
* **Type:** `function`
```ts
declare function onRewardDistributed(args: Args, log: Log): void
type Args = {
/** Amount distributed */
amount: bigint
/** Address that funded the distribution */
funder: Address
}
```
Callback to invoke when rewards are distributed.
### token
* **Type:** `Address`
Address of the TIP-20 token to watch.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by funder address */
funder?: Address | Address[]
}
```
Optional filters to narrow down events by funder address.
# `reward.watchRewardRecipientSet`
Watches for reward recipient set events when token holders change their reward recipient.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.reward.watchRewardRecipientSet({
onRewardRecipientSet: (args, log) => {
console.log('Holder:', args.holder)
console.log('Recipient:', args.recipient)
},
token: '0x20c0000000000000000000000000000000000001',
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onRewardRecipientSet
* **Type:**
```ts
declare function onRewardRecipientSet(args: Args, log: Log): void
type Args = {
/** Token holder address who set their reward recipient */
holder: Address
/** New reward recipient address (zero address indicates opt-out) */
recipient: Address
}
```
Callback to invoke when a reward recipient is set.
### token
* **Type:** `Address`
Address of the TIP-20 token to watch.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter events by holder address */
holder?: Address
/** Filter events by recipient address */
recipient?: Address
}
```
Optional filters for the event.
# Setup
Setup the Tempo extension for Viem by following the steps below.
::::steps
## Install
To install the Tempo extension, you will need to install [Viem](https://viem.sh) and Tempo:
:::code-group
```bash [npm]
npm i tempo.ts viem
```
```bash [pnpm]
pnpm i tempo.ts viem
```
:::
## Configure
Next, we will configure a [Viem Client](/docs/clients/custom).
```ts twoslash [viem.config.ts]
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
## Use Viem Actions
Once we have configured our Viem client with Tempo, we can then use regular Viem actions (e.g. `sendTransactionSync`)
that are decorated with [Tempo properties](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction)
like `calls` (batch transactions), `feePayer` (fee sponsorship), `nonceKey` (concurrent transactions) and more!
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const receipt = await client.sendTransactionSync({
calls: [
{
data: '0xcafebabe00000000000000000000000000000001',
to: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'
},
{
data: '0xdeadbeef00000000000000000000000000000002',
to: '0xfeedfacefeedfacefeedfacefeedfacefeedface'
},
{
data: '0xfeedface00000000000000000000000000000003',
to: '0xfeedfacefeedfacefeedfacefeedfacefeedface'
},
],
feePayer: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
nonceKey: 1337n,
})
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
:::tip
[See all Viem Actions](https://viem.sh/docs/actions/public/introduction)
:::
## Use Tempo Actions
You can also use [Tempo-specific Actions](/tempo/actions):
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const alphaUsd = '0x20c0000000000000000000000000000000000001'
const metadata = await client.token.getMetadata({
token: alphaUsd
})
console.log(
'Alpha USD Metadata:',
metadata.name,
metadata.symbol,
metadata.decimals,
metadata.totalSupply
)
// @log: Alpha USD Metadata: Alpha USD, AlphaUSD, 6, 1000000000000000000000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
:::tip
[See all Tempo Actions](/tempo/actions)
:::
## Next Steps
After you have set up Tempo with Viem, you can now:
* Follow a guide on how to [use accounts](https://docs.tempo.xyz/guide/use-accounts), [make payments](https://docs.tempo.xyz/guide/payments), [issue stablecoins](https://docs.tempo.xyz/guide/issuance), [exchange stablecoins](https://docs.tempo.xyz/guide/stablecoin-exchange), and [more](/).
* Use the [suite of Tempo Actions](/tempo/actions)
::::
# `token.approve`
Approves a spender to transfer TIP-20 tokens on behalf of the caller.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { receipt } = await client.token.approveSync({
amount: parseUnits('10.5', 6),
spender: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.approve` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.token.approve({
amount: parseUnits('10.5', 6),
spender: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.token.approve.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Address of the token owner */
owner: Address
/** Address of the spender */
spender: Address
/** Amount of tokens approved */
amount: bigint
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### amount
* **Type:** `bigint`
Amount of tokens to approve.
### spender
* **Type:** `Address`
Address of the spender.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.burn`
Burns TIP-20 tokens from the caller's balance.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { receipt } = await client.token.burnSync({
amount: parseUnits('10.5', 6),
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.burn` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.token.burn({
amount: parseUnits('10.5', 6),
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.token.burn.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Amount of tokens burned */
amount: bigint
/** Address tokens were burned from */
from: Address
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### amount
* **Type:** `bigint`
Amount of tokens to burn.
### memo (optional)
* **Type:** `Hex`
Memo to include in the transfer.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.burnBlocked`
Burns TIP-20 tokens from a blocked address. Requires the `BURN_BLOCKED` role. [Learn more about token roles](https://docs.tempo.xyz/protocol/tip403/spec)
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { receipt } = await client.token.burnBlockedSync({
amount: parseUnits('10.5', 6),
from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.burnBlocked` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.token.burnBlocked({
amount: parseUnits('10.5', 6),
from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.token.burnBlocked.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Amount of tokens burned */
amount: bigint
/** Address tokens were burned from */
from: Address
/** Transaction receipt */
receipt: TransactionReceipt
}
```
## Parameters
### amount
* **Type:** `bigint`
Amount of tokens to burn.
### from
* **Type:** `Address`
Address to burn tokens from.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.changeTransferPolicy`
Changes the transfer policy for a TIP-20 token. Requires the default admin role. [Learn more about transfer policies](https://docs.tempo.xyz/protocol/tip403/spec)
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.token.changeTransferPolicySync({
policyId: 1n,
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.changeTransferPolicy` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.token.changeTransferPolicy({
policyId: 1n,
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.token.changeTransferPolicy.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** ID of the new transfer policy */
newPolicyId: bigint
/** Transaction receipt */
receipt: TransactionReceipt
/** Address that updated the policy */
updater: Address
}
```
## Parameters
### policyId
* **Type:** `bigint`
New transfer policy ID.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.create`
Creates a new TIP-20 token, and assigns the admin role to the calling account. [Learn more](https://docs.tempo.xyz/protocol/tip20/overview)
## Usage
Use the `token.create` action on the Viem `client` to create and deploy a new TIP-20 token.
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { admin, receipt, token, tokenId } = await client.token.createSync({
admin: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
currency: 'USD',
name: 'My Company USD',
symbol: 'CUSD',
})
console.log('Address:', token)
// @log: Address: 0x20c0000000000000000000000000000000000004
console.log('Admin:', admin)
// @log: Admin: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb
console.log('ID:', tokenId)
// @log: ID: 4n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.create` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.token.create({
admin: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
currency: 'USD',
name: 'My Company USD',
symbol: 'CUSD',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args: { token, tokenId } }
= Actions.token.create.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Address of the admin that was granted the admin role */
admin: Address
/** Currency code of the token */
currency: string
/** Name of the token */
name: string
/** Address of the quote token */
quoteToken: Address
/** Transaction receipt */
receipt: TransactionReceipt
/** Symbol of the token */
symbol: string
/** Address of the deployed TIP-20 token */
token: Address
/** ID of the deployed TIP-20 token */
tokenId: bigint
}
```
## Parameters
### admin
* **Type:** `Address`
Admin address for the token.
### currency
* **Type:** `string`
Currency code for the token.
### name
* **Type:** `string`
Name of the token.
### quoteToken (optional)
* **Type:** `Address | bigint`
Quote token address or ID.
### salt (optional)
* **Type:** `Hex`
* **Default:** `Hex.random(32)`
Unique salt for deterministic token address generation.
### symbol
* **Type:** `string`
Symbol of the token.
# `token.getAllowance`
Gets the amount of tokens that a spender is approved to transfer on behalf of an owner.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const allowance = await client.token.getAllowance({
account: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
spender: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Allowance:', allowance)
// @log: Allowance: 10500000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = bigint // Allowance amount
```
## Parameters
### account
* **Type:** `Address`
Account address.
### spender
* **Type:** `Address`
Address of the spender.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP20 token.
# `token.getBalance`
Gets the token balance of an address.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const balance = await client.token.getBalance({
account: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Balance:', balance)
// @log: Balance: 10500000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = bigint // Balance amount
```
## Parameters
### account
* **Type:** `Address`
Account address.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP20 token.
# `token.getMetadata`
Gets the metadata for a TIP-20 token, including name, symbol, decimals, currency, and total supply.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const metadata = await client.token.getMetadata({
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Currency:', metadata.currency)
// @log: Currency: USD
console.log('Decimals:', metadata.decimals)
// @log: Decimals: 18
console.log('Name:', metadata.name)
// @log: Name: United States Dollar
console.log('Symbol:', metadata.symbol)
// @log: Symbol: USD
console.log('Total Supply:', metadata.totalSupply)
// @log: Total Supply: 1000000000000000000000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = {
currency: string
decimals: number
name: string
paused?: boolean
quoteToken?: Address
supplyCap?: bigint
symbol: string
totalSupply: bigint
transferPolicyId?: bigint
}
```
## Parameters
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.grantRoles`
Grants a role to an address. Requires the admin role for the role being granted. [Learn more about token roles](https://docs.tempo.xyz/protocol/tip403/spec)
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt, value } = await client.token.grantRolesSync({
roles: ['issuer'],
token: '0x20c0000000000000000000000000000000000000',
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
})
console.log('Role granted:', value[0].hasRole)
// @log: Role granted: true
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.grantRoles` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.token.grantRoles({
roles: ['issuer'],
token: '0x20c0000000000000000000000000000000000000',
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const events = Actions.token.grantRoles.extractEvents(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Transaction receipt */
receipt: TransactionReceipt
/** Array of role membership update events */
value: readonly {
/** Role identifier */
role: Hex
/** Address that received the role */
account: Address
/** Address that granted the role */
sender: Address
/** Whether the role was granted (true) or revoked (false) */
hasRole: boolean
}[]
}
```
## Parameters
### role
* **Type:** `"defaultAdmin" | "pause" | "unpause" | "issuer" | "burnBlocked"`
Role to grant.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP20 token.
### to
* **Type:** `Address`
Address to grant the role to.
# `token.hasRole`
Checks if an address has a specific role for a TIP-20 token. [Learn more about token roles](https://docs.tempo.xyz/protocol/tip403/spec)
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const hasRole = await client.token.hasRole({
account: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
role: 'issuer',
token: '0x20c0000000000000000000000000000000000011',
})
console.log('Has issuer role:', hasRole)
// @log: Has issuer role: true
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = boolean // Whether the account has the role
```
## Parameters
### account
* **Type:** `Address`
Address to check for the role.
### role
* **Type:** `"defaultAdmin" | "pause" | "unpause" | "issuer" | "burnBlocked"`
Role to check.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.mint`
Mints new TIP-20 tokens to a recipient. Requires the `ISSUER` role. [Learn more about roles](https://docs.tempo.xyz/protocol/tip20/spec#role-based-access-control)
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { receipt } = await client.token.mintSync({
amount: parseUnits('10.5', 6),
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.mint` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.token.mint({
amount: parseUnits('10.5', 6),
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.token.mint.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Amount of tokens minted */
amount: bigint
/** Transaction receipt */
receipt: TransactionReceipt
/** Address tokens were minted to */
to: Address
}
```
## Parameters
### amount
* **Type:** `bigint`
Amount of tokens to mint.
### memo (optional)
* **Type:** `Hex`
Memo to include in the mint.
### to
* **Type:** `Address`
Address to mint tokens to.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.pause`
Pauses a TIP-20 token, preventing all transfers. Requires the `PAUSE` role. [Learn more about token roles](https://docs.tempo.xyz/protocol/tip403/spec)
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { isPaused, receipt } = await client.token.pauseSync({
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Is paused:', isPaused)
// @log: Is paused: true
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.pause` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.token.pause({
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.token.pause.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Whether the token is paused */
isPaused: boolean
/** Transaction receipt */
receipt: TransactionReceipt
/** Address that paused the token */
updater: Address
}
```
## Parameters
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.renounceRoles`
Renounces one or more roles from the caller's address. [Learn more about token roles](https://docs.tempo.xyz/protocol/tip403/spec)
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt, value } = await client.token.renounceRolesSync({
roles: ['issuer'],
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Roles renounced:', value.length)
// @log: Roles renounced: 1
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.renounceRoles` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.token.renounceRoles({
roles: ['issuer'],
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const events = Actions.token.renounceRoles.extractEvents(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Transaction receipt */
receipt: TransactionReceipt
/** Array of role membership update events */
value: readonly {
/** Address that renounced the role */
account: Address
/** Whether the role was granted (true) or revoked (false) */
hasRole: boolean
/** Role identifier */
role: Hex
/** Address that initiated the change */
sender: Address
}[]
}
```
## Parameters
### role
* **Type:** `"defaultAdmin" | "pause" | "unpause" | "issuer" | "burnBlocked"`
Role to renounce.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.revokeRoles`
Revokes one or more roles from an address. Requires the admin role for each role being revoked. [Learn more about token roles](https://docs.tempo.xyz/protocol/tip403/spec)
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt, value } = await client.token.revokeRolesSync({
from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
roles: ['issuer'],
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Roles revoked:', value.length)
// @log: Roles revoked: 1
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.revokeRoles` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.token.revokeRoles({
from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
roles: ['issuer'],
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const events = Actions.token.revokeRoles.extractEvents(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Transaction receipt */
receipt: TransactionReceipt
/** Array of role membership update events */
value: readonly {
/** Role identifier */
role: Hex
/** Address that had role revoked */
account: Address
/** Address that revoked the role */
sender: Address
/** Whether the role was granted (true) or revoked (false) */
hasRole: boolean
}[]
}
```
## Parameters
### from
* **Type:** `Address`
Address to revoke the role from.
### role
* **Type:** `"defaultAdmin" | "pause" | "unpause" | "issuer" | "burnBlocked"`
Role to revoke.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.setRoleAdmin`
Sets the admin role for another role. Requires the current admin role for the target role. [Learn more about token roles](https://docs.tempo.xyz/protocol/tip403/spec)
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.token.setRoleAdminSync({
adminRole: 'defaultAdmin',
role: 'issuer',
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.setRoleAdmin` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.token.setRoleAdmin({
adminRole: 'defaultAdmin',
role: 'issuer',
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.token.setRoleAdmin.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** New admin role identifier */
newAdminRole: Hex
/** Transaction receipt */
receipt: TransactionReceipt
/** Role identifier that had its admin updated */
role: Hex
/** Address that updated the role admin */
sender: Address
}
```
## Parameters
### adminRole
* **Type:** `"defaultAdmin" | "pause" | "unpause" | "issuer" | "burnBlocked"`
New admin role.
### role
* **Type:** `"defaultAdmin" | "pause" | "unpause" | "issuer" | "burnBlocked"`
Role to set admin for.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP20 token.
# `token.setSupplyCap`
Sets the supply cap for a TIP-20 token. Requires the default admin role.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { newSupplyCap, receipt } = await client.token.setSupplyCapSync({
supplyCap: parseUnits('1000000', 6),
token: '0x20c0000000000000000000000000000000000000',
})
console.log('New supply cap:', newSupplyCap)
// @log: New supply cap: 1000000000000n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.setSupplyCap` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.token.setSupplyCap({
supplyCap: parseUnits('1000000', 6),
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.token.setSupplyCap.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** New supply cap value */
newSupplyCap: bigint
/** Transaction receipt */
receipt: TransactionReceipt
/** Address that updated the supply cap */
updater: Address
}
```
## Parameters
### supplyCap
* **Type:** `bigint`
Maximum total supply allowed for the token.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.transfer`
Transfers TIP-20 tokens from the caller to a recipient.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseUnits } from 'viem'
import { client } from './viem.config'
const { receipt } = await client.token.transferSync({
amount: parseUnits('10.5', 6),
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.transfer` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { parseUnits } from 'viem'
import { client } from './viem.config'
const hash = await client.token.transfer({
amount: parseUnits('10.5', 6),
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.token.transfer.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Amount of tokens transferred */
amount: bigint
/** Address tokens were transferred from */
from: Address
/** Transaction receipt */
receipt: TransactionReceipt
/** Address tokens were transferred to */
to: Address
}
```
## Parameters
### amount
* **Type:** `bigint`
Amount of tokens to transfer.
### to
* **Type:** `Address`
Address to transfer tokens to.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
### memo (optional)
* **Type:** `Hex`
Optional memo to attach to the transfer event.
### from (optional)
* **Type:** `Address`
Address to transfer tokens from. When specified, transfers tokens from the given address (requires prior approval). Defaults to the caller's address.
# `token.unpause`
Unpauses a TIP-20 token, allowing transfers to resume. Requires the `UNPAUSE` role. [Learn more about token roles](https://docs.tempo.xyz/protocol/tip403/spec)
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { isPaused, receipt } = await client.token.unpauseSync({
token: '0x20c0000000000000000000000000000000000000',
})
console.log('Is paused:', isPaused)
// @log: Is paused: false
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `token.unpause` action and wait for inclusion manually:
```ts twoslash
import { Actions } from 'viem/tempo'
import { client } from './viem.config'
const hash = await client.token.unpause({
token: '0x20c0000000000000000000000000000000000000',
})
const receipt = await client.waitForTransactionReceipt({ hash })
const { args }
= Actions.token.unpause.extractEvent(receipt.logs)
```
## Return Type
```ts
type ReturnType = {
/** Whether the token is paused */
isPaused: boolean
/** Transaction receipt */
receipt: TransactionReceipt
/** Address that unpaused the token */
updater: Address
}
```
## Parameters
### token
* **Type:** `Address | bigint`
Address or ID of the TIP-20 token.
# `token.watchAdminRole`
Watches for role admin update events on TIP20 tokens.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.token.watchAdminRole({
token: 1n, // Token ID or address
onRoleAdminUpdated: (args, log) => {
console.log('Role:', args.role)
console.log('New admin role:', args.newAdminRole)
console.log('Sender:', args.sender)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onRoleAdminUpdated
* **Type:** `function`
```ts
declare function onRoleAdminUpdated(args: Args, log: Log): void
type Args = {
/** The role whose admin role is being changed */
role: Hex
/** The new admin role */
newAdminRole: Hex
/** The address that initiated the change */
sender: Address
}
```
Callback to invoke when a role admin is updated.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP20 token to watch.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by role */
role?: Hex | Hex[] | null
/** Filter by new admin role */
newAdminRole?: Hex | Hex[] | null
/** Filter by sender */
sender?: Address | Address[] | null
}
```
Optional filter arguments to narrow down the events to watch.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `(error: Error) => void`
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `token.watchApprove`
Watches for token approval events on TIP20 tokens.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.token.watchApprove({
token: 0n,
onApproval: (args, log) => {
console.log('Amount:', args.amount)
console.log('Owner:', args.owner)
console.log('Spender:', args.spender)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onApproval
* **Type:** `function`
```ts
declare function onApproval(args: Args, log: Log): void
type Args = {
/** Amount approved */
amount: bigint
/** Address of the token owner */
owner: Address
/** Address of the spender */
spender: Address
}
```
Callback to invoke when tokens are approved.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP20 token to watch.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by token owner address */
owner?: Address | Address[] | null
/** Filter by spender address */
spender?: Address | Address[] | null
}
```
Filter events by owner and/or spender addresses.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `token.watchBurn`
Watches for token burn events on TIP20 tokens.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.token.watchBurn({
token: 1n, // or token address
onBurn: (args, log) => {
console.log('Amount:', args.amount)
console.log('From:', args.from)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onBurn
* **Type:** `function`
```ts
declare function onBurn(args: Args, log: Log): void
type Args = {
/** Address whose tokens were burned */
from: Address
/** Amount burned */
amount: bigint
}
```
Callback to invoke when tokens are burned.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP20 token.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by burner address */
from?: Address | Address[] | null
}
```
Optional filter arguments.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `token.watchCreate`
Watches for new TIP20 token creation events on the TIP20 Factory.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.token.watchCreate({
onTokenCreated: (args, log) => {
console.log('Token:', args.token)
console.log('Token ID:', args.tokenId)
console.log('Name:', args.name)
console.log('Symbol:', args.symbol)
console.log('Currency:', args.currency)
console.log('Quote Token:', args.quoteToken)
console.log('Admin:', args.admin)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onTokenCreated
* **Type:** `function`
```ts
declare function onTokenCreated(args: Args, log: Log): void
type Args = {
/** Address of the created token */
token: Address
/** ID of the created token */
tokenId: bigint
/** Name of the token */
name: string
/** Symbol of the token */
symbol: string
/** Currency of the token */
currency: string
/** Quote token address */
quoteToken: Address
/** Admin address */
admin: Address
}
```
Callback to invoke when a new TIP20 token is created.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by token address(es) */
token?: Address | Address[] | null
/** Filter by token ID(s) */
tokenId?: bigint | bigint[] | null
}
```
Optional filter arguments to watch for specific tokens.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `token.watchMint`
Watches for token mint events on TIP20 tokens.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.token.watchMint({
token: '0x20c0000000000000000000000000000000000001',
onMint: (args, log) => {
console.log('To:', args.to)
console.log('Amount:', args.amount)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onMint
* **Type:** `function`
```ts
declare function onMint(args: Args, log: Log): void
type Args = {
/** Address that received the tokens */
to: Address
/** Amount minted */
amount: bigint
}
```
Callback to invoke when tokens are minted.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP20 token to watch.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by recipient address */
to?: Address | Address[] | null
}
```
Optional filter arguments.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `token.watchRole`
Watches for role membership update events on TIP20 tokens.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.token.watchRole({
token: '0x...', // Address or ID of the TIP20 token
onRoleUpdated: (args, log) => {
console.log('Account:', args.account)
console.log('Has role:', args.hasRole)
console.log('Role:', args.role)
console.log('Type:', args.type) // 'granted' or 'revoked'
console.log('Sender:', args.sender)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onRoleUpdated
* **Type:** `function`
```ts
declare function onRoleUpdated(args: Args, log: Log): void
type Args = {
/** Role being updated */
role: Hex
/** Account receiving or losing the role */
account: Address
/** Address that updated the role */
sender: Address
/** Whether the account has the role */
hasRole: boolean
/** Type of role update */
type: 'granted' | 'revoked'
}
```
Callback to invoke when a role membership is updated.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP20 token.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by role */
role?: Hex | Hex[] | null
/** Filter by account */
account?: Address | Address[] | null
/** Filter by sender */
sender?: Address | Address[] | null
}
```
Filter parameters for the watch subscription.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
The callback to call when an error occurred when trying to get for a new block.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `token.watchTransfer`
Watches for token transfer events on TIP20 tokens.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const unwatch = client.token.watchTransfer({
token: 1n,
onTransfer: (args, log) => {
console.log('Amount:', args.amount)
console.log('From:', args.from)
console.log('To:', args.to)
},
})
// Later, stop watching
unwatch()
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = () => void
```
Returns a function to unsubscribe from the event.
## Parameters
### onTransfer
* **Type:** `function`
```ts
declare function onTransfer(args: Args, log: Log): void
type Args = {
/** Amount transferred */
amount: bigint
/** Address sending the tokens */
from: Address
/** Address receiving the tokens */
to: Address
}
```
Callback to invoke when tokens are transferred.
### token
* **Type:** `Address | bigint`
Address or ID of the TIP20 token to watch.
### args (optional)
* **Type:** `object`
```ts
type Args = {
/** Filter by sender address(es) */
from?: Address | Address[] | null
/** Filter by recipient address(es) */
to?: Address | Address[] | null
}
```
Optional filter to watch only transfers from or to specific addresses.
### fromBlock (optional)
* **Type:** `bigint`
Block to start listening from.
### onError (optional)
* **Type:** `function`
```ts
declare function onError(error: Error): void
```
Callback to invoke when an error occurs while watching for new blocks.
### poll (optional)
* **Type:** `true`
Whether to use polling.
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's pollingInterval config.
# `validator.add`
Adds a new validator to the validator set. Requires owner permission.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.validator.addSync({
newValidatorAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
publicKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
active: true,
inboundAddress: '192.168.1.1:8080',
outboundAddress: '192.168.1.1:8080',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `validator.add` action and wait for inclusion manually:
```ts twoslash
import { client } from './viem.config'
const hash = await client.validator.add({
newValidatorAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
publicKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
active: true,
inboundAddress: '192.168.1.1:8080',
outboundAddress: '192.168.1.1:8080',
})
const receipt = await client.waitForTransactionReceipt({ hash })
```
## Return Type
```ts
type ReturnType = {
receipt: TransactionReceipt
}
```
## Parameters
### newValidatorAddress
* **Type:** `Address`
The address of the new validator.
### publicKey
* **Type:** `Hex`
The validator's communication public key.
### active
* **Type:** `boolean`
Whether the validator should be active.
### inboundAddress
* **Type:** `string`
The validator's inbound address `:` for incoming connections.
### outboundAddress
* **Type:** `string`
The validator's outbound IP address `:` for firewall whitelisting (IP only, no hostnames).
# `validator.changeOwner`
Changes the owner of the validator config precompile. Requires current owner permission.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.validator.changeOwnerSync({
newOwner: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `validator.changeOwner` action and wait for inclusion manually:
```ts twoslash
import { client } from './viem.config'
const hash = await client.validator.changeOwner({
newOwner: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
})
const receipt = await client.waitForTransactionReceipt({ hash })
```
## Return Type
```ts
type ReturnType = {
receipt: TransactionReceipt
}
```
## Parameters
### newOwner
* **Type:** `Address`
The new owner address.
# `validator.changeStatus`
Changes a validator's active status. Requires owner permission.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.validator.changeStatusSync({
validator: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
active: false,
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `validator.changeStatus` action and wait for inclusion manually:
```ts twoslash
import { client } from './viem.config'
const hash = await client.validator.changeStatus({
validator: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
active: false,
})
const receipt = await client.waitForTransactionReceipt({ hash })
```
## Return Type
```ts
type ReturnType = {
receipt: TransactionReceipt
}
```
## Parameters
### validator
* **Type:** `Address`
The validator address.
### active
* **Type:** `boolean`
Whether the validator should be active.
# `validator.get`
Gets validator information by address.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const validator = await client.validator.get({
validator: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
})
console.log('Validator:', validator)
// @log: Validator: { publicKey: '0x...', active: true, index: 0n, validatorAddress: '0x...', inboundAddress: '...', outboundAddress: '...' }
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = {
/** The validator's communication public key */
publicKey: Hex
/** Whether the validator is active */
active: boolean
/** The validator's index */
index: bigint
/** The validator's address */
validatorAddress: Address
/** The validator's inbound address for incoming connections */
inboundAddress: string
/** The validator's outbound IP address for firewall whitelisting */
outboundAddress: string
}
```
## Parameters
### validator
* **Type:** `Address`
Validator address.
# `validator.getByIndex`
Gets a validator address by index.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const validatorAddress = await client.validator.getByIndex({
index: 0n,
})
console.log('Validator address:', validatorAddress)
// @log: Validator address: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = Address // Validator address at the given index
```
## Parameters
### index
* **Type:** `bigint`
Validator index.
# `validator.getCount`
Gets the total number of validators.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const count = await client.validator.getCount()
console.log('Validator count:', count)
// @log: Validator count: 10n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = bigint // Total number of validators
```
# `validator.getNextFullDkgCeremony`
Gets the next epoch for a full DKG ceremony.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const epoch = await client.validator.getNextFullDkgCeremony()
console.log('Next DKG ceremony epoch:', epoch)
// @log: Next DKG ceremony epoch: 100n
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = bigint // Epoch number
```
# `validator.getOwner`
Gets the owner of the validator config precompile.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const owner = await client.validator.getOwner()
console.log('Owner:', owner)
// @log: Owner: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = Address // Owner address
```
# `validator.list`
Lists the set of validators.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const validators = await client.validator.list()
console.log('Validators:', validators)
// @log: Validators: [{ publicKey: '0x...', active: true, index: 0n, ... }, ...]
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
## Return Type
```ts
type ReturnType = Array<{
/** The validator's communication public key */
publicKey: Hex
/** Whether the validator is active */
active: boolean
/** The validator's index */
index: bigint
/** The validator's address */
validatorAddress: Address
/** The validator's inbound address for incoming connections */
inboundAddress: string
/** The validator's outbound IP address for firewall whitelisting */
outboundAddress: string
}>
```
# `validator.setNextFullDkgCeremony`
Sets the next epoch for a full DKG ceremony. Requires owner permission.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.validator.setNextFullDkgCeremonySync({
epoch: 100n,
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `validator.setNextFullDkgCeremony` action and wait for inclusion manually:
```ts twoslash
import { client } from './viem.config'
const hash = await client.validator.setNextFullDkgCeremony({
epoch: 100n,
})
const receipt = await client.waitForTransactionReceipt({ hash })
```
## Return Type
```ts
type ReturnType = {
receipt: TransactionReceipt
}
```
## Parameters
### epoch
* **Type:** `bigint`
The epoch number for the next full DKG ceremony.
# `validator.update`
Updates validator information. Only callable by the validator themselves.
## Usage
:::code-group
```ts twoslash [example.ts]
import { client } from './viem.config'
const { receipt } = await client.validator.updateSync({
newValidatorAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
publicKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
inboundAddress: '192.168.1.1:8080',
outboundAddress: '192.168.1.1:8080',
})
console.log('Transaction hash:', receipt.transactionHash)
// @log: Transaction hash: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Asynchronous Usage
The example above uses a `*Sync` variant of the action, that will wait for the transaction to be included before returning.
If you are optimizing for performance, you should use the non-sync `validator.update` action and wait for inclusion manually:
```ts twoslash
import { client } from './viem.config'
const hash = await client.validator.update({
newValidatorAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
publicKey: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
inboundAddress: '192.168.1.1:8080',
outboundAddress: '192.168.1.1:8080',
})
const receipt = await client.waitForTransactionReceipt({ hash })
```
## Return Type
```ts
type ReturnType = {
receipt: TransactionReceipt
}
```
## Parameters
### newValidatorAddress
* **Type:** `Address`
The new address for this validator.
### publicKey
* **Type:** `Hex`
The validator's new communication public key.
### inboundAddress
* **Type:** `string`
The validator's inbound address `:` for incoming connections.
### outboundAddress
* **Type:** `string`
The validator's outbound IP address `:` for firewall whitelisting (IP only, no hostnames).
# `withFeePayer`
Creates a transport that routes transactions to a fee payer service when a `feePayer` is requested on an action.
* [View Guide](https://docs.tempo.xyz/guide/payments/sponsor-user-fees)
* [View Specification](https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction)
## Usage
:::code-group
```ts twoslash [example.ts]
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains'
import { withFeePayer } from 'viem/tempo'
const client = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: tempoModerato,
transport: withFeePayer(
http(), // ← Default Transport
http('https://sponsor.example.com'), // ← Fee Payer Transport // [!code hl]
),
})
// Regular transaction
const receipt1 = await client.sendTransactionSync({
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb',
})
// Sponsored transaction // [!code hl]
const receipt2 = await client.sendTransactionSync({ // [!code hl]
// [!code hl]
feePayer: true, // [!code hl]
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb', // [!code hl]
}) // [!code hl]
```
```ts twoslash [viem.config.ts] filename="viem.config.ts"
// [!include ~/snippets/tempo/viem.config.ts:setup]
```
:::
### Example Fee Payer Service
Below is an end-to-end example of a client/server fee payer setup.
See `server.ts` for the server-side implementation. It uses [`Handler.feePayer` provided by `tempo.ts/server`](https://docs.tempo.xyz/sdk/typescript/server/handler.feePayer) to handle fee payer requests.
:::code-group
```ts twoslash [client.ts]
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains'
import { withFeePayer } from 'viem/tempo'
const client = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: tempoModerato,
transport: withFeePayer(
http(),
http('http://localhost:3000'),
),
})
const hash = await client.sendTransactionSync({
feePayer: true,
to: '0x0000000000000000000000000000000000000000',
})
```
```ts twoslash [server.ts]
// @noErrors
import { createServer } from 'node:http'
import { createClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { tempoModerato } from 'viem/chains'
import { Handler } from 'tempo.ts/server'
const client = createClient({
chain: tempoModerato.extend({
// Note: the fee payer can specify their own fee token.
feeToken: '0x20c0000000000000000000000000000000000001'
}),
transport: http(),
})
const handler = Handler.feePayer({ // [!code hl]
account: privateKeyToAccount('0x...'), // [!code hl]
client, // [!code hl]
}) // [!code hl]
const server = createServer(handler.listener)
server.listen(3000)
```
:::
## Return Type
```ts
type ReturnType = Transport<'feePayer'>
```
## Parameters
### defaultTransport
* **Type:** `Transport`
The default transport to use for regular (non-sponsored) transactions.
### relayTransport
* **Type:** `Transport`
The relay transport to use for sponsored transactions. This should point to a fee payer service that will sign and submit the transaction with a fee payer signature.
### Parameters (optional)
* **Type:** `withFeePayer.Parameters`
Options for `withFeePayer` usage.
#### `policy` (optional)
* **Type:** `'sign-only' | 'sign-and-broadcast'`
* **Default:** `'sign-only'`
Controls how the fee payer handles sponsored transactions:
* **`'sign-only'`**: Fee payer co-signs the transaction and returns it to the client transport, which then broadcasts it via the default transport.
* **`'sign-and-broadcast'`**: Fee payer co-signs and broadcasts the transaction directly. The fee payer service handles both signing and submission to the blockchain.
# `TempoAddress.format`
Formats a raw Ethereum address (and optional zone ID) into a Tempo address string.
## Usage
```ts twoslash
import { TempoAddress } from 'viem/tempo'
const address = TempoAddress.format('0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28')
// @log: 'tempo1qp6z6dwvvc6vq5efyk3ms39une6etu4a9qtj2kk0'
```
### Zone Address
```ts twoslash
import { TempoAddress } from 'viem/tempo'
const address = TempoAddress.format(
'0x742d35Cc6634C0532925a3b844Bc9e7595f2bD28',
{ zoneId: 1 },
)
// @log: 'tempoz1qqqhgtf4e3nrfszn9yj68wzyhj08t90jh55q74d9uj'
```
## Parameters
### address
* **Type:** `Address`
The raw 20-byte Ethereum address.
### options.zoneId (optional)
* **Type:** `number | bigint`
Zone ID for zone addresses.
## Return Type
`TempoAddress`
The encoded Tempo address string.
# `TempoAddress.parse`
Parses a Tempo address string into a raw Ethereum address and optional zone ID.
## Usage
### Mainnet Address
```ts twoslash
import { TempoAddress } from 'viem/tempo'
const result = TempoAddress.parse(
'tempo1qp6z6dwvvc6vq5efyk3ms39une6etu4a9qtj2kk0',
)
// @log: { address: '0x742d35CC6634c0532925a3B844bc9e7595F2Bd28', zoneId: undefined }
```
### Zone Address
```ts twoslash
import { TempoAddress } from 'viem/tempo'
const result = TempoAddress.parse(
'tempoz1qqqhgtf4e3nrfszn9yj68wzyhj08t90jh55q74d9uj',
)
// @log: { address: '0x742d35CC6634c0532925a3B844bc9e7595F2Bd28', zoneId: 1 }
```
## Parameters
### tempoAddress
* **Type:** `string`
The Tempo address string to parse.
## Return Type
```ts
{
address: Address
zoneId: number | bigint | undefined
}
```
# `TempoAddress.validate`
Validates a Tempo address string.
## Usage
```ts twoslash
import { TempoAddress } from 'viem/tempo'
const valid = TempoAddress.validate(
'tempo1qp6z6dwvvc6vq5efyk3ms39une6etu4a9qtj2kk0',
)
// @log: true
```
## Parameters
### tempoAddress
* **Type:** `string`
The Tempo address string to validate.
## Return Type
`boolean`
Whether the address is valid.
# toMultisigSmartAccount (ZKsync)
Creates a multi-signature [ZKsync Smart Account](https://docs.zksync.io/build/developer-reference/account-abstraction/building-smart-accounts) from a Contract Address and the Private Key of the owner.
## Usage
```ts twoslash
import { toMultisigSmartAccount } from 'viem/zksync'
const account = toMultisigSmartAccount({
address: '0xf39Fd6e51aad8F6F4ce6aB8827279cffFb92266',
privateKeys: ['0x...', '0x...']
})
```
## Parameters
### address
* **Type:** `Hex`
Address of the deployed Account's Contract implementation.
```ts
const account = toMultisigSmartAccount({
address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // [!code focus]
privateKeys: ['0x...', '0x...']
})
```
### privateKeys
* **Type:** `Hex[]`
Private Keys of the owners.
```ts
const account = toMultisigSmartAccount({
address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
privateKeys: ['0x...', '0x...'] // [!code focus]
})
```
# toSinglesigSmartAccount (ZKsync)
Creates a single-signature [ZKsync Smart Account](https://docs.zksync.io/build/developer-reference/account-abstraction/building-smart-accounts) from a Contract Address and the Private Key of the owner.
## Usage
```ts twoslash
import { toSinglesigSmartAccount } from 'viem/zksync'
const account = toSinglesigSmartAccount({
address: '0xf39Fd6e51aad8F6F4ce6aB8827279cffFb92266',
privateKey: '0x...'
})
```
## Parameters
### address
* **Type:** `Hex`
Address of the deployed Account's Contract implementation.
```ts
const account = toSinglesigSmartAccount({
address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // [!code focus]
privateKey: '0x...'
})
```
### privateKey
* **Type:** `Hex`
Private Key of the owner.
```ts
const account = toSinglesigSmartAccount({
address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
privateKey: '0x...' // [!code focus]
})
```
# toSmartAccount (ZKsync)
Creates a [ZKsync Smart Account](https://docs.zksync.io/build/developer-reference/account-abstraction/building-smart-accounts) from a Contract Address and a custom sign function.
## Usage
```ts twoslash
import { toSmartAccount } from 'viem/zksync'
const account = toSmartAccount({
address: '0xf39Fd6e51aad8F6F4ce6aB8827279cffFb92266',
async sign({ hash }) {
// ... signing logic
return '0x...'
}
})
```
## Parameters
### address
* **Type:** `Hex`
Address of the deployed Account's Contract implementation.
```ts
const account = toSmartAccount({
address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // [!code focus]
async sign({ hash }) {
// ...
}
})
```
### sign
* **Type:** `({ hash: Hex }) => Hex`
Custom sign function for the Smart Account.
```ts
const account = toSmartAccount({
address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
async sign({ hash }) { // [!code focus]
// ... // [!code focus]
} // [!code focus]
})
```
# claimFailedDeposit
Withdraws funds from the initiated deposit, which failed when finalizing on L2.
If the deposit L2 transaction has failed, it sends an L1 transaction calling `claimFailedDeposit` method of the
L1 bridge, which results in returning L1 tokens back to the depositor.
## Usage
:::code-group
```ts [example.ts]
import { account, walletClient, zksyncClient } from './config'
import { legacyEthAddress } from 'viem/zksync'
const hash = await walletClient.claimFailedDeposit({
account,
client: zksyncClient,
depositHash: ''
})
```
```ts [config.ts]
import { createWalletClient, createPublicClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync, mainnet } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `claimFailedDeposit`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts [example.ts]
import { walletClient, zksyncClient } from './config'
import { legacyEthAddress } from 'viem/zksync'
const hash = await walletClient.claimFailedDeposit({
client: zksyncClient,
depositHash: ''
})
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
// Retrieve Account from an EIP-1193 Provider. // [!code focus]
const [account] = await window.ethereum.request({ // [!code focus]
method: 'eth_requestAccounts' // [!code focus]
}) // [!code focus]
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum) // [!code focus]
}).extend(walletActionsL1())
```
```ts [config.ts (Local Account)]
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code focus]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### client
* **Type:** `Client`
The L2 client for fetching data from L2 chain.
```ts
const hash = await walletClient.claimFailedDeposit({
client: zksyncClient, // [!code focus]
depositHash: ''
})
```
### depositHash
* **Type:** `Hash`
The L2 transaction hash of the failed deposit.
```ts
const hash = await walletClient.claimFailedDeposit({
client: zksyncClient,
depositHash: '', // [!code focus]
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
```ts
import { zksync } from 'viem/chains' // [!code focus]
const hash = await walletClient.claimFailedDeposit({
chain: zksync, // [!code focus]
client: zksyncClient,
depositHash: ''
})
```
# deployContract
Deploys a contract to the network, given bytecode & constructor arguments by using EIP712 transaction.
## Usage
:::code-group
```ts [example.ts]
import { wagmiAbi } from './abi'
import { account, walletClient } from './config'
const hash = await walletClient.deployContract({
abi,
account,
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
})
```
```ts [abi.ts]
export const wagmiAbi = [
...
{
inputs: [],
stateMutability: "nonpayable",
type: "constructor",
},
...
] as const;
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync } from 'viem/chains'
import { eip712Actions } from 'viem/zksync'
export const walletClient = createWalletClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(eip712WalletActions())
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Deploying with Constructor Args
:::code-group
```ts [example.ts] {8}
import { deployContract } from 'viem'
import { wagmiAbi } from './abi'
import { account, walletClient } from './config'
const hash = await walletClient.deployContract({
abi,
account,
args: [69420],
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
})
```
```ts [abi.ts] {4}
export const wagmiAbi = [
...
{
inputs: [{ name: "x", type: "uint32" }],
stateMutability: "nonpayable",
type: "constructor",
},
...
] as const;
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync } from 'viem/chains'
import { eip712Actions } from 'viem/zksync'
export const walletClient = createWalletClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(eip712WalletActions())
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Deploying with Factory Deps
:::code-group
```ts [example.ts] {8}
import { deployContract } from 'viem'
import { wagmiAbi } from './abi'
import { account, walletClient } from './config'
const hash = await walletClient.deployContract({
abi,
account,
args: [69420],
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
factoryDeps: [
'0x702040405260405161083e38038061083e833981016040819123456...',
'0x102030405260405161083e38038061083e833981016040819112233...'
]
})
```
```ts [abi.ts] {4}
export const wagmiAbi = [
...
{
inputs: [{ name: "x", type: "uint32" }],
stateMutability: "nonpayable",
type: "constructor",
},
...
] as const;
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync } from 'viem/chains'
import { eip712Actions } from 'viem/zksync'
export const walletClient = createWalletClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(eip712WalletActions())
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
const hash = await walletClient.deployContract({
abi: wagmiAbi, // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
})
```
### account
* **Type:** `Account | Address`
The Account to deploy the contract from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const hash = await walletClient.deployContract({
abi: wagmiAbi,
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
})
```
### bytecode
* **Type:** [`Hex`](/docs/glossary/types#hex)
The contract's bytecode.
```ts
const hash = await walletClient.deployContract({
abi: wagmiAbi,
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...', // [!code focus]
})
```
### args
* **Type:** Inferred from ABI.
Constructor arguments to call upon deployment.
```ts
const hash = await walletClient.deployContract({
abi: wagmiAbi,
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
args: [69] // [!code focus]
})
```
### deploymentType (optional)
* **Type:** `'create' | 'create2' | 'createAccount' | 'create2Account'`
Specifies the type of contract deployment. Defaults to 'create'.
```ts
const hash = await walletClient.deployContract({
abi: wagmiAbi,
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
args: [69],
deploymentType: 'create2' // [!code focus]
})
```
### salt (optional)
* **Type:** [`Hash`](/docs/glossary/types#hash)
Specifies a unique identifier for the contract deployment.
```ts
const hash = await walletClient.deployContract({
abi: wagmiAbi,
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
args: [69],
salt: '0x201050...' // [!code focus]
})
```
### gasPerPubdata (optional)
* **Type:** `bigint`
The amount of gas for publishing one byte of data on Ethereum.
```ts
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
gasPerPubdata: 50000, // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
### paymaster (optional)
* **Type:** `Account | Address`
Address of the paymaster account that will pay the fees. The `paymasterInput` field is required with this one.
```ts
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
### paymasterInput (optional)
* **Type:** `0x${string}`
Input data to the paymaster. The `paymaster` field is required with this one.
```ts
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
# deposit
Transfers the specified token from the associated account on the L1 network to the target account on the L2 network.
The token can be either ETH or any ERC20 token. For ERC20 tokens, enough approved tokens must be associated with
the specified L1 bridge (default one or the one defined in `bridgeAddress`).
In this case, depending on is the chain ETH-based or not `approveToken` or `approveBaseToken`
can be enabled to perform token approval. If there are already enough approved tokens for the L1 bridge,
token approval will be skipped.
## Usage
:::code-group
```ts [example.ts]
import { account, walletClient, zksyncClient } from './config'
import { legacyEthAddress } from 'viem/zksync'
// deposit ETH
const hash = await walletClient.deposit({
account,
client: zksyncClient,
token: legacyEthAddress,
amount: 7_000_000_000n,
to: account.address,
refundRecipient: account.address,
})
// deposit ERC20
const txHash = await walletClient.deposit({
account,
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: account.address,
approveToken: true,
refundRecipient: account.address,
})
```
```ts [config.ts]
import { createWalletClient, createPublicClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync, mainnet } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `deposit`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts [example.ts]
import { walletClient, zksyncClient } from './config'
import { legacyEthAddress } from 'viem/zksync'
// deposit ETH
const hash = await walletClient.deposit({
client: zksyncClient,
token: legacyEthAddress,
amount: 7_000_000_000n,
to: walletClient.account.address,
refundRecipient: walletClient.account.address,
})
// deposit ERC20
const txHash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
approveToken: true,
refundRecipient: walletClient.account.address,
})
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
// Retrieve Account from an EIP-1193 Provider. // [!code focus]
const [account] = await window.ethereum.request({ // [!code focus]
method: 'eth_requestAccounts' // [!code focus]
}) // [!code focus]
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum) // [!code focus]
}).extend(walletActionsL1())
```
```ts [config.ts (Local Account)]
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code focus]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### client
* **Type:** `Client`
The L2 client for fetching data from L2 chain.
```ts
const hash = await walletClient.deposit({
client: zksyncClient, // [!code focus]
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
approveToken: true,
refundRecipient: walletClient.account.address,
})
```
### token
* **Type:** `Address`
The address of the token to deposit.
```ts
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55', // [!code focus]
amount: 20n,
to: walletClient.account.address,
approveToken: true,
refundRecipient: walletClient.account.address,
})
```
### amount
* **Type:** `bigint`
The amount of the token to deposit.
```ts
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n, // [!code focus]
to: walletClient.account.address,
approveToken: true,
refundRecipient: walletClient.account.address,
})
```
### to (optional)
* **Type:** `Address`
* **Default:** `walletClient.account`
The address that will receive the deposited tokens on L2.
```ts
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address, // [!code focus]
approveToken: true,
refundRecipient: walletClient.account.address,
})
```
### operatorTip (optional)
* **Type:** `bigint`
The tip the operator will receive on top of the base cost of the transaction.
Currently, ZKsync node do not consider this tip.
```ts
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
operatorTip: 100_000n, // [!code focus]
approveToken: true,
refundRecipient: walletClient.account.address,
})
```
### l2GasLimit (optional)
* **Type:** `bigint`
Maximum amount of L2 gas that transaction can consume during execution on L2.
```ts
const hash = await walletClient.requestExecute({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
l2GasLimit: 900_000n, // [!code focus]
approveToken: true,
refundRecipient: walletClient.account.address,
})
```
### gasPerPubdataByte (optional)
* **Type:** `bigint`
The L2 gas price for each published L1 calldata byte.
```ts
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
approveToken: true,
refundRecipient: walletClient.account.address,
gasPerPubdataByte: 250_000_000_000n // [!code focus]
})
```
### refundRecipient (optional)
* **Type:** `Address`
* **Default:** `walletClient.account`
The address on L2 that will receive the refund for the transaction.
If the transaction fails, it will also be the address to receive `amount`.
```ts
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
approveToken: true,
refundRecipient: walletClient.account.address, // [!code focus]
})
```
### bridgeAddress (optional)
* **Type:** `Address`
* **Default:** ZKsync L1 shared bridge
The address of the bridge contract to be used.
```ts
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
approveToken: true,
refundRecipient: walletClient.account.address,
bridgeAddress: '0xFC073319977e314F251EAE6ae6bE76B0B3BAeeCF' // [!code focus]
})
```
### customBridgeData (optional)
* **Type:** `Hex`
Additional data that can be sent to a bridge.
```ts
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
approveToken: true,
refundRecipient: walletClient.account.address,
bridgeAddress: '0xFC073319977e314F251EAE6ae6bE76B0B3BAeeCF',
customBridgeData: '0x...' // [!code focus],
})
```
### approveToken (optional)
* **Type:** `boolean | TransactionRequest`
Whether token approval should be performed under the hood.
Set this flag to true (or provide transaction overrides) if the bridge does
not have sufficient allowance. The approval transaction is executed only if
the bridge lacks sufficient allowance; otherwise, it is skipped.
::: code-group
```ts [boolean.ts]
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
approveToken: true, // [!code focus],
refundRecipient: walletClient.account.address,
bridgeAddress: '0xFC073319977e314F251EAE6ae6bE76B0B3BAeeCF',
})
```
```ts [overrides.ts]
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
approveToken: {
maxFeePerGas: 200_000_000_000n // [!code focus],
},
refundRecipient: walletClient.account.address,
bridgeAddress: '0xFC073319977e314F251EAE6ae6bE76B0B3BAeeCF',
})
```
:::
### approveBaseToken (optional)
* **Type:** `boolean | TransactionRequest`
Whether base token approval should be performed under the hood.
Set this flag to true (or provide transaction overrides) if the bridge does
not have sufficient allowance. The approval transaction is executed only if
the bridge lacks sufficient allowance; otherwise, it is skipped.
::: code-group
```ts [boolean.ts]
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
approveBaseToken: true, // [!code focus],
refundRecipient: walletClient.account.address,
bridgeAddress: '0xFC073319977e314F251EAE6ae6bE76B0B3BAeeCF',
})
```
```ts [overrides.ts]
const hash = await walletClient.deposit({
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
approveBaseToken: {
maxFeePerGas: 200_000_000_000n // [!code focus],
},
refundRecipient: walletClient.account.address,
bridgeAddress: '0xFC073319977e314F251EAE6ae6bE76B0B3BAeeCF',
})
```
:::
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
```ts
import { zksync } from 'viem/chains' // [!code focus]
const hash = await walletClient.deposit({
chain: zksync, // [!code focus]
client: zksyncClient,
token: '0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55',
amount: 20n,
to: walletClient.account.address,
approveToken: true,
refundRecipient: walletClient.account.address,
})
```
# estimateFee
Returns an estimated Fee for requested transaction.
:::warning
**This Action is being deprecated.**
This method calls an RPC method that [will be removed in a future release](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/1066). Please use the alternatives mentioned below.
**Alternatives / Workaround**
The original returned `Fee` object contained `gasLimit`, `maxFeePerGas`, `maxPriorityFeePerGas` and `gasPerPubData`. Use the following methods to retrieve these values:
* `gasLimit`: use `eth_estimateGas` or [its correspondent viem action](/docs/actions/public/estimateGas).
* `maxFeePerGas`: use `eth_gasPrice` or [its correspondent viem action](/docs/actions/public/getGasPrice).
* `maxPriorityFeePerGas`: set to `0`.
* `gasPerPubData`: use `zks_gasPerPubdata` or [its correspondent viem action](/zksync/actions/getGasPerPubData).
:::
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const fee = await client.estimateFee({
account: '0x636A122e48079f750d44d13E5b39804227E1467e',
to: "0xa61464658AfeAf65CccaaFD3a512b69A83B77618",
value: 0n
});
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`Fee`
The fee values.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const fee = await walletClient.estimateFee({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### to
* **Type:** `0x${string}`
The transaction recipient or contract address.
```ts
const fee = await walletClient.estimateFee({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: 1000000000000000000n,
nonce: 69
})
```
### data (optional)
* **Type:** `0x${string}`
A contract hashed method call with encoded args.
```ts
const fee = await walletClient.estimateFee({
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts
const fee = await walletClient.estimateFee({
account,
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const fee = await walletClient.estimateFee({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69 // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction.
```ts
const fee = await walletClient.estimateFee({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'), // [!code focus]
nonce: 69
})
```
### gasPerPubdata (optional)
* **Type:** `bigint`
The amount of gas for publishing one byte of data on Ethereum.
```ts
const fee = await walletClient.estimateFee({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
gasPerPubdata: 50000, // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
### factoryDeps (optional)
* **Type:** `[0x${string}]`
Contains bytecode of the deployed contract.
```ts
const fee = await walletClient.estimateFee({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
factoryDeps: ['0xcde...'], // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
### paymaster (optional)
* **Type:** `Account | Address`
Address of the paymaster account that will pay the fees. The `paymasterInput` field is required with this one.
```ts
const fee = await walletClient.estimateFee({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
### paymasterInput (optional)
* **Type:** `0x${string}`
Input data to the paymaster. The `paymaster` field is required with this one.
```ts
const fee = await walletClient.estimateFee({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
# estimateGasL1ToL2
Returns an estimated gas for L1 to L2 execution
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const gas = await client.estimateGasL1ToL2({
account: '0x636A122e48079f750d44d13E5b39804227E1467e',
to: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618',
value: 0n
});
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`bigint`
The estimated gas value.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const gas = await walletClient.estimateGasL1ToL2({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### to
* **Type:** `0x${string}`
The transaction recipient or contract address.
```ts
const gas = await walletClient.estimateGasL1ToL2({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: 1000000000000000000n,
nonce: 69
})
```
### data (optional)
* **Type:** `0x${string}`
A contract hashed method call with encoded args.
```ts
const gas = await walletClient.estimateGasL1ToL2({
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts
const gas = await walletClient.estimateGasL1ToL2({
account,
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const gas = await walletClient.estimateGasL1ToL2({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69 // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction.
```ts
const gas = await walletClient.estimateGasL1ToL2({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'), // [!code focus]
nonce: 69
})
```
### gasPerPubdata (optional)
* **Type:** `bigint`
The amount of gas for publishing one byte of data on Ethereum.
```ts
const gas = await walletClient.estimateGasL1ToL2({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
gasPerPubdata: 50000, // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
### factoryDeps (optional)
* **Type:** `[0x${string}]`
Contains bytecode of the deployed contract.
```ts
const gas = await walletClient.estimateGasL1ToL2({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
factoryDeps: ['0xcde...'], // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
### paymaster (optional)
* **Type:** `Account | Address`
Address of the paymaster account that will pay the gas. The `paymasterInput` field is required with this one.
```ts
const gas = await walletClient.estimateGasL1ToL2({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
### paymasterInput (optional)
* **Type:** `0x${string}`
Input data to the paymaster. The `paymaster` field is required with this one.
```ts
const gas = await walletClient.estimateGasL1ToL2({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
# finalizeWithdrawal
Proves the inclusion of the `L2->L1` withdrawal message.
## Usage
:::code-group
```ts [example.ts]
import { account, walletClient, zksyncClient } from './config'
const hash = await walletClient.finalizeWithdrawal({
account,
client: zksyncClient,
hash: '0x…',
})
```
```ts [config.ts]
import { createWalletClient, createPublicClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync, mainnet } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `finalizeWithdrawal`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts [example.ts]
import { walletClient, zksyncClient } from './config'
const hash = await walletClient.finalizeWithdrawal({
client: zksyncClient,
hash: '0x…',
})
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
// Retrieve Account from an EIP-1193 Provider. // [!code focus]
const [account] = await window.ethereum.request({ // [!code focus]
method: 'eth_requestAccounts' // [!code focus]
}) // [!code focus]
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum) // [!code focus]
}).extend(walletActionsL1())
```
```ts [config.ts (Local Account)]
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code focus]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### client
* **Type:** `Client`
The L2 client for fetching data from L2 chain.
```ts
const hash = await walletClient.finalizeWithdrawal({
client: zksyncClient, // [!code focus]
hash: '0x…',
})
```
### hash
* **Type:** `Hex`
Hash of the L2 transaction where the withdrawal was initiated.
```ts
const hash = await walletClient.finalizeWithdrawal({
client: zksyncClient,
hash: '0x…', // [!code focus]
})
```
### index (optional)
* **Type:** `number`
* **Default:** `0`
In case there were multiple withdrawals in one transaction, you may pass an index of the
withdrawal you want to finalize.
```ts
const hash = await walletClient.finalizeWithdrawal({
client: zksyncClient,
hash: '0x…',
index: 0n, // [!code focus]
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
```ts
import { zksync } from 'viem/chains' // [!code focus]
const hash = await walletClient.finalizeWithdrawal({
chain: zksync, // [!code focus]
client: zksyncClient,
hash: '0x…',
})
```
# getAllBalances
Returns all known balances for a given account.
:::warning
**This Action has been deprecated.**
This method calls an RPC method that [has been removed from the node API](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/1019).
:::
## Usage
:::code-group
```ts [example.ts]
import { client, account } from './config'
const balances = await client.getAllBalances({
account
});
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
```
:::
## Returns
`GetAllBalancesReturnType`
Array of all known balances for an address.
## Parameters
### account
* **Type:** `Account | Address`
The Account used for check.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const balances = await client.getAllBalances({
account: "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049" // [!code focus]
});
```
# getBaseTokenL1Address
Returns the address of the ZKsync Chain's base L1 token.
:::warning
**This Action is being deprecated.**
This method calls an RPC method that [will be removed in a future release](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/1066). Please use the alternatives mentioned below.
**Alternatives / Workaround**
This method returned the address of the chain's base token contract in L1. This can be retrieved from a call to the BridgeHub contract.
1. Retrieve the BridgeHub contract address using the [`getBridgeHubContractAddress`](/zksync/actions/getBridgehubContractAddress) action.
2. Call the `baseToken(chainId)` method on the BridgeHub contract.
:::
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const address = await client.getBaseTokenL1Address();
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`Address`
Base Token L1 address.
# getBlockDetails
Returns additional ZKsync-specific information about the L2 block.
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const blockDetails = await client.getBlockDetails({
number: 1
});
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`BaseBlockDetails`
Structure that represent ZKsync-specific information about L2 block.
## Parameters
### number
Block Number
* **Type** `number`
```ts
const blockDetails = await client.getBlockDetails({
number: 1 // [!code focus]
});
```
# getBridgehubContractAddress
Returns the Bridgehub smart contract address.
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const address = await client.getBridgehubContractAddress();
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`Address`
Bridgehub smart contract address.
# getDefaultBridgeAddresses
Returns the addresses of the default ZKsync Era bridge contracts on both L1 and L2.
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const addresses = await client.getDefaultBridgeAddresses();
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`GetDefaultBridgeAddressesReturnType`
Addresses of the default ZKsync Era bridge contracts on both L1 and L2.
# getGasPerPubData
Returns the scaled gas per pubdata limit for the currently open batch.
:::info
This method is only available ZKsync chains running node API version 28.7.0 and above.
:::
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const gasPerPubDataLimit = await client.getGasPerPubData();
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`Hex`
Pubdata limit for the current batch.
# getL1Allowance
Determines the amount of approved tokens for a specific L1 bridge.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
const allowance = await publicClient.getL1Allowance({
account
token: '0x5C221E77624690fff6dd741493D735a17716c26B',
bridgeAddress: '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D',
})
```
```ts [config.ts]
import { createPublicClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { publicActionsL1 } from 'viem/zksync'
export const publicClient = createPublicClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(publicActionsL1())
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
```
:::
## Returns
`bigint`
Returns the amount of approved tokens.
## Parameters
### account
* **Type:** `Account | Address`
The Account used for check.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const allowance = await publicClient.getL1Allowance({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' // [!code focus]
blockTag: 'latest',
bridgeAddress: '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D',
token: '0x5C221E77624690fff6dd741493D735a17716c26B',
})
```
### blockTag (optional)
* **Type:** `BlockTag | undefined`
In which block an allowance should be checked on. The latest processed one is the default option.
```ts
const allowance = await publicClient.getL1Allowance({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
blockTag: 'latest', // [!code focus]
bridgeAddress: '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D',
token: '0x5C221E77624690fff6dd741493D735a17716c26B',
})
```
### bridgeAddress
* **Type:** `Address`
The address of the bridge contract to be used.
```ts
const allowance = await publicClient.getL1Allowance({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
blockTag: 'latest',
bridgeAddress: '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D', // [!code focus]
token: '0x5C221E77624690fff6dd741493D735a17716c26B',
})
```
### token
* **Type:** `Address`
The Ethereum address of the token.
```ts
const allowance = await publicClient.getL1Allowance({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
blockTag: 'latest',
bridgeAddress: '0x84DbCC0B82124bee38e3Ce9a92CdE2f943bab60D',
token: '0x5C221E77624690fff6dd741493D735a17716c26B', // [!code focus]
})
```
# getL1Balance
Returns the amount of the token held by the account on the L1 network.
## Usage
:::code-group
```ts [example.ts (token balance)]
import { account, publicClient } from './config'
const balance = await publicClient.getL1Balance({
account
token: '0x5C221E77624690fff6dd741493D735a17716c26B',
})
```
```ts [example.ts (ETH balance)]
import { account, publicClient } from './config'
const balance = await publicClient.getL1Balance({
account
})
```
```ts [config.ts]
import { createPublicClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { publicActionsL1 } from 'viem/zksync'
export const publicClient = createPublicClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(publicActionsL1())
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
```
:::
## Returns
`bigint`
Returns the amount of the tokens.
## Parameters
### account (optional)
* **Type:** `Account | Address`
The Account used for check.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const balance = await publicClient.getL1Balance({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' // [!code focus]
blockTag: 'latest',
token: '0x5C221E77624690fff6dd741493D735a17716c26B',
})
```
### blockTag (optional)
* **Type:** `BlockTag | undefined`
In which block an balance should be checked on. The latest processed one is the default option.
```ts
const balance = await publicClient.getL1Balance({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
blockTag: 'latest', // [!code focus]
token: '0x5C221E77624690fff6dd741493D735a17716c26B',
})
```
### token (optional)
* **Type:** `Address`
The address of the token. Defaults to ETH if not provided.
```ts
const balance = await publicClient.getL1Balance({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
blockTag: 'latest',
token: '0x5C221E77624690fff6dd741493D735a17716c26B', // [!code focus]
})
```
# getL1BatchBlockRange
Returns the range of blocks contained within a batch given by batch number.
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const batchBlockRange = await client.getL1BatchBlockRange({
number: 1
});
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`GetL1BatchBlockRangeReturnType`
Array of two elements representing the range of blocks within a batch.
## Parameters
### number
L1 Batch Number
* **Type** `number`
```ts
const batchBlockRange = await client.getL1BatchBlockRange({
number: 1 // [!code focus]
});
```
# getL1BatchDetails
Returns data pertaining to a given batch.
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const batchDetails = await client.getL1BatchDetails({
number: 1
});
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`GetL1BatchDetailsReturnType`
Batch details.
## Parameters
### number
L1 Batch Number
* **Type** `number`
```ts
const batchDetails = await client.getL1BatchDetails({
number: 1 // [!code focus]
});
```
# getL1BatchNumber
Returns the latest L1 batch number.
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const latestNumber = await client.getL1BatchNumber();
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`Hex`
Latest L1 batch number.
# getL1ChainId
Returns the Chain Id of underlying L1 network.
:::warning
**This Action is being deprecated.**
This method calls an RPC method that [will be removed in a future release](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/1066). Please use the alternatives mentioned below.
**Alternatives / Workaround**
The returned value can be retrieve via an onchain call to the `L1_CHAIN_ID()` method on the `L2AssetRouter` contract (deployed on `0x0000000000000000000000000000000000010003` address)
:::
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const chainId = await client.getL1ChainId();
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`Hex`
L1 Chain ID.
# getL1TokenAddress
Returns the L1 token address equivalent for a L2 token address as they are not equal.
:::info
Only works for tokens bridged on default ZKsync Era bridges.
:::
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const address = await client.getL1TokenAddress({
token: '0x3e7676937A7E96CFB7616f255b9AD9FF47363D4b'
})
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`Address`
Returns the L1 token address equivalent for a L2 token address.
## Parameters
### token
* **Type:** `Address`
The address of the token on L2.
```ts
const address = await client.getL1TokenAddress({
token: '0x3e7676937A7E96CFB7616f255b9AD9FF47363D4b'
})
```
# getL1TokenBalance
Retrieve the token balance held by the contract on L1.
## Usage
:::code-group
```ts [example.ts]
import { account, publicClient } from './config'
const balance = await publicClient.getL1TokenBalance({
account
token: '0x5C221E77624690fff6dd741493D735a17716c26B',
})
```
```ts [config.ts]
import { createPublicClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
import { publicActionsL1 } from 'viem/zksync'
export const publicClient = createPublicClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(publicActionsL1())
// JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// Local Account
export const account = privateKeyToAccount(...)
```
:::
## Returns
`bigint`
Returns the amount of the tokens.
## Parameters
### account
* **Type:** `Account | Address`
The Account used for check.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const balance = await publicClient.getL1TokenBalance({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' // [!code focus]
blockTag: 'latest',
token: '0x5C221E77624690fff6dd741493D735a17716c26B',
})
```
### blockTag (optional)
* **Type:** `BlockTag | undefined`
In which block an balance should be checked on. The latest processed one is the default option.
```ts
const balance = await publicClient.getL1TokenBalance({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
blockTag: 'latest', // [!code focus]
token: '0x5C221E77624690fff6dd741493D735a17716c26B',
})
```
### token
* **Type:** `Address`
The address of the token.
```ts
const balance = await publicClient.getL1TokenBalance({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
blockTag: 'latest',
token: '0x5C221E77624690fff6dd741493D735a17716c26B', // [!code focus]
})
```
# getL2TokenAddress
Returns the L2 token address equivalent for a L1 token address as they are not equal.
:::info
Only works for tokens bridged on default ZKsync Era bridges.
:::
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const address = await client.getL2TokenAddress({
token: '0x5C221E77624690fff6dd741493D735a17716c26B'
})
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`Address`
Returns the L2 token address equivalent for a L1 token address.
## Parameters
### token
* **Type:** `Address`
The address of the token on L1.
```ts
const address = await client.getL2TokenAddress({
token: '0x5C221E77624690fff6dd741493D735a17716c26B'
})
```
### bridgeAddress (optional)
* **Type:** `Address`
The address of custom bridge, which will be used to get l2 token address.
```ts
const address = await client.getL2TokenAddress({
token: '0x5C221E77624690fff6dd741493D735a17716c26B',
bridgeAddress: '0xf8c919286126ccf2e8abc362a15158a461429c82' // [!code focus]
})
```
# getLogProof
Returns the proof for the corresponding L2 to L1 log.
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const proof = await client.getLogProof({
txHash: '0x...',
index: 1
});
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`GetLogProofReturnType`
Proof of the corresponding L2 to L1 log
## Parameters
### txHash
Hash of the L2 transaction the L2 to L1 log was produced within.
```ts
const proof = await client.getLogProof({
txHash: '0x...', // [!code focus]
index: 1
});
```
### index (optional)
The index of the L2 to L1 log in the transaction.
```ts
const proof = await client.getLogProof({
txHash: '0x...',
index: 1 // [!code focus]
});
```
# getMainContractAddress
Returns the address of a main ZKsync Chain Contract.
:::warning
**This Action is being deprecated.**
This method calls an RPC method that [will be removed in a future release](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/1066). Please use the alternatives mentioned below.
**Alternatives / Workaround**
This method returned the address of the chain contract in L1. This can be retrieved from a call to the BridgeHub contract.
1. Retrieve the BridgeHub contract address using the [`getBridgeHubContractAddress`](/zksync/actions/getBridgehubContractAddress) action.
2. Call the `getZKChain(chainId)` method on the BridgeHub contract.
:::
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const address = await client.getMainContractAddress();
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`Address`
Main ZKsync Era smart contract address.
# getRawBlockTransaction
Returns data of transactions in a block.
:::warning
**This Action is being deprecated.**
This method calls an RPC method that [will be removed in a future release](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/1066). Please use the alternatives mentioned below.
**Alternatives / Workaround**
The returned value can be retrieved using `debug_getRawTransaction` and `debug_getRawTransactions`.
:::
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const rawTx = await client.getRawBlockTransaction({
number: 1
});
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`RawBlockTransactions`
Data of transactions in a block.
## Parameters
### number
Block number.
```ts
const rawTx = await client.getRawBlockTransaction({
number: 1 // [!code focus]
});
```
# getTestnetPaymasterAddress (depreated)
Returns the address of the testnet Paymaster.
:::warning
**This Action is being deprecated.**
This method calls an RPC method that [will be removed in a future release](https://github.com/zkSync-Community-Hub/zksync-developers/discussions/1066). Please use the alternatives mentioned below.
**Alternatives / Workaround**
The returned value can be found on each ZKsync chain technical documentation (e.g [ZKsync Era docs](https://docs.zksync.io/zksync-era/unique-features/paymaster#testnet-paymaster)).
:::
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const address = await client.getTestnetPaymasterAddress();
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`Address | null`
Testnet paymaster address if available, or `null`.
# getTransactionDetails
Returns data from a specific transaction given by the transaction hash.
## Usage
:::code-group
```ts [example.ts]
import { client } from './config'
const details = await client.getTransactionDetails({
txHash: '0x...'
});
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`TransactionDetails`
Data from a specific transaction given by the transaction hash.
## Parameters
`GetTransactionDetailsParameters`
### hash
Transaction hash
```ts
const details = await client.getTransactionDetails({
txHash: '0x...' // [!code focus]
});
```
# isWithdrawalFinalized
Returns whether the withdrawal transaction is finalized on the L1 network.
## Usage
:::code-group
```ts [example.ts]
import { client, zksyncClient } from './config'
const hash = await client.isWithdrawalFinalized({
client: zksyncClient,
hash: '0x…',
})
```
```ts [config.ts]
import { createPublicClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync, mainnet } from 'viem/chains'
import { publicActionsL2, publicActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
export const client = createPublicClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(publicActionsL1())
```
:::
## Returns
`boolean`
Whether the withdrawal transaction is finalized on the L1 network.
## Parameters
### client
* **Type:** `Client`
The L2 client for fetching data from L2 chain.
```ts
const hash = await client.isWithdrawalFinalized({
client: zksyncClient, // [!code focus]
hash: '0x…',
})
```
### hash
* **Type:** `Hex`
Hash of the L2 transaction where the withdrawal was initiated.
```ts
const hash = await client.isWithdrawalFinalized({
client: zksyncClient,
hash: '0x…', // [!code focus]
})
```
### index (optional)
* **Type:** `number`
* **Default:** `0`
In case there were multiple withdrawals in one transaction, you may pass an index of the
withdrawal you want to finalize.
```ts
const hash = await client.isWithdrawalFinalized({
client: zksyncClient,
hash: '0x…',
index: 0n, // [!code focus]
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `client.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
```ts
import { zksync } from 'viem/chains' // [!code focus]
const hash = await client.isWithdrawalFinalized({
chain: zksync, // [!code focus]
client: zksyncClient,
hash: '0x…',
})
```
# requestExecute
Requests execution of a L2 transaction from L1.
## Usage
:::code-group
```ts [example.ts]
import { account, walletClient, zksyncClient } from './config'
const hash = await walletClient.requestExecute({
account,
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x',
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n
})
```
```ts [config.ts]
import { createWalletClient, createPublicClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync, mainnet } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `requestExecute`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts [example.ts]
import { walletClient, zksyncClient } from './config'
const hash = await walletClient.requestExecute({
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x',
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n
})
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
// Retrieve Account from an EIP-1193 Provider. // [!code focus]
const [account] = await window.ethereum.request({ // [!code focus]
method: 'eth_requestAccounts' // [!code focus]
}) // [!code focus]
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum) // [!code focus]
}).extend(walletActionsL1())
```
```ts [config.ts (Local Account)]
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'
export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code focus]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### client
* **Type:** `Client`
The L2 client for fetching data from L2 chain.
```ts
const hash = await walletClient.requestExecute({
client: zksyncClient, // [!code focus]
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x',
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n
})
```
### contractAddress
* **Type:** `Address`
The L2 contract to be called.
```ts
const hash = await walletClient.requestExecute({
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(), // [!code focus]
calldata: '0x',
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n
})
```
### calldata
* **Type:** `Hex`
The input of the L2 transaction.
```ts
const hash = await walletClient.requestExecute({
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x', // [!code focus]
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n
})
```
### l2Value (optional)
* **Type:** `bigint`
The `msg.value` of L2 transaction.
```ts
const hash = await walletClient.requestExecute({
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x',
l2Value: 7_000_000_000n, // [!code focus]
l2GasLimit: 900_000n
})
```
### l2GasLimit (optional)
* **Type:** `bigint`
Maximum amount of L2 gas that transaction can consume during execution on L2.
```ts
const hash = await walletClient.requestExecute({
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x',
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n // [!code focus]
})
```
### mintValue (optional)
* **Type:** `bigint`
The amount of base token that needs to be minted on non-ETH-based L2.
```ts
const hash = await walletClient.requestExecute({
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x',
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n,
mintValue: 100_000n // [!code focus]
})
```
### factoryDeps (optional)
* **Type:** `Hex[]`
An array of L2 bytecodes that will be marked as known on L2.
```ts
const hash = await walletClient.requestExecute({
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x',
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n,
factoryDeps: ['0x...'] // [!code focus]
})
```
### operatorTip (optional)
* **Type:** `bigint`
The tip the operator will receive on top of the base cost of the transaction.
Currently, ZKsync node do not consider this tip.
```ts
const hash = await walletClient.requestExecute({
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x',
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n,
operatorTip: 100_000n // [!code focus]
})
```
### gasPerPubdataByte (optional)
* **Type:** `bigint`
The L2 gas price for each published L1 calldata byte.
```ts
const hash = await walletClient.requestExecute({
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x',
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n,
gasPerPubdataByte: 250_000_000_000n // [!code focus]
})
```
### refundRecipient (optional)
* **Type:** `Address`
* **Default:** `walletClient.account`
The address on L2 that will receive the refund for the transaction.
If the transaction fails, it will also be the address to receive `l2Value`.
```ts
const hash = await walletClient.requestExecute({
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x',
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n,
refundRecipient: '0x...' // [!code focus]
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
```ts
import { zksync } from 'viem/chains' // [!code focus]
const hash = await walletClient.requestExecute({
chain: zksync, // [!code focus]
client: zksyncClient,
contractAddress: await zksyncClient.getBridgehubContractAddress(),
calldata: '0x',
l2Value: 7_000_000_000n,
l2GasLimit: 900_000n
})
```
# sendTransaction
Creates, signs, and sends a new transaction to the network, with EIP712 transaction support.
## Usage
:::code-group
```ts [example.ts]
import { account, walletClient } from './config'
const hash = await walletClient.sendTransaction({ // [!code focus:99]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
// '0x...'
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync } from 'viem/chains'
import { eip712Actions } from 'viem/zksync'
export const walletClient = createWalletClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(eip712WalletActions())
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `sendTransaction`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts [example.ts]
import { walletClient } from './config'
const hash = await walletClient.sendTransaction({ // [!code focus:99]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
// '0x...'
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
import { eip712Actions } from 'viem/zksync'
// Retrieve Account from an EIP-712 Provider. // [!code focus]
const [account] = await window.ethereum.request({ // [!code focus]
method: 'eth_requestAccounts' // [!code focus]
}) // [!code focus]
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum) // [!code focus]
}).extend(eip712WalletActions())
```
```ts [config.ts (Local Account)]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { eip712Actions } from 'viem/zksync'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code focus]
transport: custom(window.ethereum)
}).extend(eip712WalletActions())
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const hash = await walletClient.sendTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### to
* **Type:** `0x${string}`
The transaction recipient or contract address.
```ts
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: 1000000000000000000n,
nonce: 69
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts
const hash = await walletClient.sendTransaction({
accessList: [ // [!code focus:6]
{
address: '0x1',
storageKeys: ['0x1'],
},
],
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
The chain is also used to infer its request type (e.g. the Celo chain has a `gatewayFee` that you can pass through to `sendTransaction`).
```ts
import { zksync } from 'viem/chains' // [!code focus]
const hash = await walletClient.sendTransaction({
chain: zksync, // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### data (optional)
* **Type:** `0x${string}`
A contract hashed method call with encoded args.
```ts
const hash = await walletClient.sendTransaction({
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts
const hash = await walletClient.sendTransaction({
account,
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69 // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction.
```ts
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'), // [!code focus]
nonce: 69
})
```
### gasPerPubdata (optional)
* **Type:** `bigint`
The amount of gas for publishing one byte of data on Ethereum.
```ts
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
gasPerPubdata: 50000, // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
### factoryDeps (optional)
* **Type:** `[0x${string}]`
Contains bytecode of the deployed contract.
```ts
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
factoryDeps: ['0xcde...'], // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
### paymaster (optional)
* **Type:** `Account | Address`
Address of the paymaster account that will pay the fees. The `paymasterInput` field is required with this one.
```ts
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
### paymasterInput (optional)
* **Type:** `0x${string}`
Input data to the paymaster. The `paymaster` field is required with this one.
```ts
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
nonce: 69,
value: 1000000000000000000n
})
```
# signTransaction
Signs a transaction, with EIP712 transaction support.
## Usage
:::code-group
```ts [example.ts]
import { account, walletClient } from './config'
const request = await walletClient.prepareTransactionRequest({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
const signature = await walletClient.signTransaction(request) // [!code focus:2]
// 0x02f850018203118080825208808080c080a04012522854168b27e5dc3d5839bab5e6b39e1a0ffd343901ce1622e3d64b48f1a04e00902ae0502c4728cbf12156290df99c3ed7de85b1dbfe20b5c36931733a33
const hash = await walletClient.sendRawTransaction(signature)
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync } from 'viem/chains'
import { eip712WalletActions } from 'viem/zksync'
export const walletClient = createWalletClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(eip712WalletActions())
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `prepareTransactionRequest`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts [example.ts]
import { walletClient } from './config'
const request = await walletClient.prepareTransactionRequest({
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
const signature = await walletClient.signTransaction(request) // [!code focus:2]
// 0x02f850018203118080825208808080c080a04012522854168b27e5dc3d5839bab5e6b39e1a0ffd343901ce1622e3d64b48f1a04e00902ae0502c4728cbf12156290df99c3ed7de85b1dbfe20b5c36931733a33
const hash = await client.sendRawTransaction(signature)
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
import { eip712WalletActions } from 'viem/zksync'
// Retrieve Account from an EIP-712 Provider. // [!code focus]
const [account] = await window.ethereum.request({ // [!code focus]
method: 'eth_requestAccounts' // [!code focus]
}) // [!code focus]
export const walletClient = createWalletClient({
account, // [!code focus]
transport: custom(window.ethereum)
}).extend(eip712WalletActions())
```
```ts [config.ts (Local Account)]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { eip712WalletActions } from 'viem/zksync'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code focus]
transport: custom(window.ethereum)
}).extend(eip712WalletActions())
```
:::
## Returns
[`Hex`](/docs/glossary/types#hex)
The signed serialized transaction.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const signature = await walletClient.signTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### to
* **Type:** `0x${string}`
The transaction recipient or contract address.
```ts
const signature = await walletClient.signTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: 1000000000000000000n,
nonce: 69
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts
const signature = await walletClient.signTransaction({
accessList: [ // [!code focus:6]
{
address: '0x1',
storageKeys: ['0x1'],
},
],
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
The chain is also used to infer its request type (e.g. the Celo chain has a `gatewayFee` that you can pass through to `signTransaction`).
```ts
import { zksync } from 'viem/chains' // [!code focus]
const signature = await walletClient.signTransaction({
chain: zksync, // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### data (optional)
* **Type:** `0x${string}`
A contract hashed method call with encoded args.
```ts
const signature = await walletClient.signTransaction({
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts
const signature = await walletClient.signTransaction({
account,
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const signature = await walletClient.signTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69 // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction.
```ts
const signature = await walletClient.signTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'), // [!code focus]
nonce: 69
})
```
### gasPerPubdata (optional)
* **Type:** `bigint`
The amount of gas for publishing one byte of data on Ethereum.
```ts
const hash = await walletClient.signTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
gasPerPubdata: 50000, // [!code focus]
nonce: 69
})
```
### factoryDeps (optional)
* **Type:** `[0x${string}]`
Contains bytecode of the deployed contract.
```ts
const hash = await walletClient.signTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
factoryDeps: ['0xcde...'], // [!code focus]
nonce: 69
})
```
### paymaster (optional)
* **Type:** `Account | Address`
Address of the paymaster account that will pay the fees. The `paymasterInput` field is required with this one.
```ts
const hash = await walletClient.signTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
nonce: 69
})
```
### paymasterInput (optional)
* **Type:** `0x${string}`
Input data to the paymaster. The `paymaster` field is required with this one.
```ts
const hash = await walletClient.signTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
nonce: 69
})
```
# withdraw
Initiates the withdrawal process which withdraws ETH or any ERC20 token
from the associated account on L2 network to the target account on L1 network.
## Usage
:::code-group
```ts [example.ts]
import { account, walletClient } from './config'
import { legacyEthAddress } from 'viem/zksync'
const hash = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
})
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync } from 'viem/chains'
import { eip712Actions } from 'viem/zksync'
export const walletClient = createWalletClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `withdraw`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts [example.ts]
import { walletClient } from './config'
import { legacyEthAddress } from 'viem/zksync'
const hash = await walletClient.withdraw({ // [!code focus:99]
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
})
// '0x...'
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
import { publicActionsL2 } from 'viem/zksync'
// Retrieve Account from an EIP-712 Provider. // [!code focus]
const [account] = await window.ethereum.request({ // [!code focus]
method: 'eth_requestAccounts' // [!code focus]
}) // [!code focus]
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum) // [!code focus]
}).extend(publicActionsL2())
```
```ts [config.ts (Local Account)]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { publicActionsL2 } from 'viem/zksync'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code focus]
transport: custom(window.ethereum)
}).extend(publicActionsL2())
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
const hash = await walletClient.withdraw({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
})
```
### amount
* **Type:** `bigint`
The amount of the token to withdraw.
```ts
const hash = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n, // [!code focus]
token: legacyEthAddress,
})
```
### token
* **Type:** `Address`
The address of the token on L2.
```ts
const hash = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress, // [!code focus]
})
```
### bridgeAddress (optional)
* **Type:** `Address`
The address of the bridge contract to be used. By default, uses shared bridge.
```ts
const address = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
bridgeAddress: '0xf8c919286126ccf2e8abc362a15158a461429c82' // [!code focus]
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
The chain is also used to infer its request type.
```ts
import { zksync } from 'viem/chains' // [!code focus]
const hash = await walletClient.withdraw({
chain: zksync, // [!code focus]
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
})
```
### gasPerPubdata (optional)
* **Type:** `bigint`
The amount of gas for publishing one byte of data on Ethereum.
```ts
const hash = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
gasPerPubdata: 50000, // [!code focus]
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts
const hash = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
gasPrice: parseGwei('20'), // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const hash = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const hash = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const hash = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
nonce: 69 // [!code focus]
})
```
### paymaster (optional)
* **Type:** `Account | Address`
Address of the paymaster account that will pay the fees. The `paymasterInput` field is required with this one.
```ts
const hash = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
})
```
### paymasterInput (optional)
* **Type:** `0x${string}`
Input data to the paymaster. The `paymaster` field is required with this one.
```ts
const hash = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
})
```
### to (optional)
* **Type:** `Address`
The address of the recipient on L1. Defaults to the sender address.
```ts
const hash = await walletClient.withdraw({
account,
amount: 1_000_000_000_000_000_000n,
token: legacyEthAddress,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
})
```
# writeContract
Executes a write function on a contract, with EIP712 transaction support.
## Usage
:::code-group
```ts [example.ts]
import { account, walletClient } from './config'
const hash = await walletClient.writeContract({ // [!code focus:99]
account,
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
})
// '0x...'
```
```ts [config.ts]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync } from 'viem/chains'
import { eip712WalletActions } from 'viem/zksync'
export const walletClient = createWalletClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(eip712WalletActions())
// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `sendTransaction`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts [example.ts]
import { walletClient } from './config'
const hash = await walletClient.writeContract({ // [!code focus:99]
account,
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
})
// '0x...'
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
import { eip712WalletActions } from 'viem/zksync'
// Retrieve Account from an EIP-712 Provider. // [!code focus]
const [account] = await window.ethereum.request({ // [!code focus]
method: 'eth_requestAccounts' // [!code focus]
}) // [!code focus]
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum) // [!code focus]
}).extend(eip712WalletActions())
```
```ts [config.ts (Local Account)]
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { eip712WalletActions } from 'viem/zksync'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code focus]
transport: custom(window.ethereum)
}).extend(eip712WalletActions())
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'mint',
args: [69420]
})
```
### abi
* **Type:** [`Abi`](/docs/glossary/types#abi)
The contract's ABI.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi, // [!code focus]
functionName: 'mint',
args: [69420]
})
```
### functionName
* **Type:** `string`
A function to extract from the ABI.
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint', // [!code focus]
args: [69420]
})
```
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts
await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
abi: wagmiAbi,
functionName: 'mint',
args: [69420]
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts
const hash = await walletClient.writeContract({
accessList: [ // [!code focus:6]
{
address: '0x1',
storageKeys: ['0x1'],
},
],
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420]
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
```ts
import { zksync } from 'viem/chains' // [!code focus]
const hash = await walletClient.writeContract({
chain: zksync, // [!code focus]
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420]
})
```
### data (optional)
* **Type:** `0x${string}`
A contract hashed method call with encoded args.
```ts
const hash = await walletClient.writeContract({
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420]
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts
const hash = await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
gasPrice: parseGwei('20'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const hash = await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
nonce: 69 // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction.
```ts
const hash = await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
value: parseEther('1'), // [!code focus]
})
```
### gasPerPubdata (optional)
* **Type:** `bigint`
The amount of gas for publishing one byte of data on Ethereum.
```ts
const hash = await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
gasPerPubdata: 50000, // [!code focus]
})
```
### factoryDeps (optional)
* **Type:** `[0x${string}]`
Contains bytecode of the deployed contract.
```ts
const hash = await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
factoryDeps: ['0xcde...'], // [!code focus]
})
```
### paymaster (optional)
* **Type:** `Account | Address`
Address of the paymaster account that will pay the fees. The `paymasterInput` field is required with this one.
```ts
const hash = await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
})
```
### paymasterInput (optional)
* **Type:** `0x${string}`
Input data to the paymaster. The `paymaster` field is required with this one.
```ts
const hash = await walletClient.writeContract({
address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi: wagmiAbi,
functionName: 'mint',
args: [69420],
paymaster: '0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021', // [!code focus]
paymasterInput: '0x8c5a...' // [!code focus]
})
```
# parseEip712Transaction
Parses a serialized EIP712 transaction.
## Import
```ts
import { parseEip712Transaction } from 'viem/zksync'
```
## Usage
```ts
import { parseEip712Transaction } from 'viem/zksync'
const serializedTransaction =
'0x71f87f8080808094a61464658afeaf65cccaafd3a512b69a83b77618830f42408001a073a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aa02f87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a82010e9436615cf349d7f6344891b1e7ca7c72883f5dc04982c350c080c0'
const transaction = parseEip712Transaction(serializedTransaction)
```
## Returns
`ZksyncTransactionSerializableEIP712`
The ZKsync EIP712 transaction.
## Parameters
### tx
* **Type:** [`Hex`](/docs/glossary/types#hex)
The serialized EIP712 transaction.
```ts
const serializedTransaction =
'0x71f87f8080808094a61464658afeaf65cccaafd3a512b69a83b77618830f42408001a073a20167b8d23b610b058c05368174495adf7da3a4ed4a57eb6dbdeb1fafc24aa02f87530d663a0d061f69bb564d2c6fb46ae5ae776bbd4bd2a2a4478b9cd1b42a82010e9436615cf349d7f6344891b1e7ca7c72883f5dc04982c350c080c0'
const transaction = parseEip712Transaction(serializedTransaction)
```
# signMessage (Smart Account)
Calculates an Ethereum-specific signature in [EIP-191 format](https://eips.ethereum.org/EIPS/eip-191): `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`.
Uses the Smart Account's **Owner** to sign the message.
## Usage
:::code-group
```ts twoslash [example.ts]
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config.js'
const account = await toSmartAccount({
client,
owners: [owner],
})
const signature = await account.signMessage({ // [!code focus]
message: 'hello world', // [!code focus]
}) // [!code focus]
```
```ts twoslash [config.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const owner = privateKeyToAccount('0x...')
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
## Returns
[`Hex`](/docs/glossary/types#hex)
The signed message.
## Parameters
### message
* **Type:** `string | { raw: Hex | ByteArray }`
Message to sign.
By default, viem signs the UTF-8 representation of the message.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config.js'
const account = await toSmartAccount({
client,
owners: [owner],
})
// ---cut---
const signature = await account.signMessage({
message: 'hello world', // [!code focus:1]
})
```
To sign the data representation of the message, you can use the `raw` attribute.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config.js'
const account = await toSmartAccount({
client,
owners: [owner],
})
// ---cut---
const signature = await account.signMessage({
message: { raw: '0x68656c6c6f20776f726c64' }, // [!code focus:1]
})
```
# signTypedData (Smart Account)
Signs typed data and calculates an Ethereum-specific signature in [https://eips.ethereum.org/EIPS/eip-712](https://eips.ethereum.org/EIPS/eip-712): `sign(keccak256("\x19\x01" ‖ domainSeparator ‖ hashStruct(message)))`
Uses the Smart Account's **Owner** to sign the message.
## Usage
:::code-group
```ts twoslash [example.ts]
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config.js'
import { domain, types } from './data.js'
const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
const signature = await account.signTypedData({ // [!code focus]
domain, // [!code focus]
types, // [!code focus]
primaryType: 'Mail', // [!code focus]
message: { // [!code focus]
from: { // [!code focus]
name: 'Cow', // [!code focus]
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', // [!code focus]
}, // [!code focus]
to: { // [!code focus]
name: 'Bob', // [!code focus]
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB', // [!code focus]
}, // [!code focus]
contents: 'Hello, Bob!', // [!code focus]
}, // [!code focus]
}) // [!code focus]
```
```ts twoslash [data.ts] filename="data.ts"
// All properties on a domain are optional
export const domain = {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
} as const
// The named list of all type definitions
export const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
} as const
```
```ts twoslash [config.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const owner = privateKeyToAccount('0x...')
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
## Returns
`0x${string}`
The signed data.
## Parameters
### domain
**Type:** `TypedDataDomain`
The typed data domain.
```ts
const signature = await account.signTypedData({
domain: { // [!code focus:6]
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### types
The type definitions for the typed data.
```ts
const signature = await account.signTypedData({
domain,
types: { // [!code focus:11]
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### primaryType
**Type:** Inferred `string`.
The primary type to extract from `types` and use in `value`.
```ts
const signature = await account.signTypedData({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [ // [!code focus:5]
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail', // [!code focus]
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### message
**Type:** Inferred from `types` & `primaryType`.
```ts
const signature = await account.signTypedData({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: { // [!code focus:11]
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
# signUserOperation (Smart Account)
Signs a User Operation with the Smart Account's **Owner**.
## Usage
:::code-group
```ts twoslash [example.ts]
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
const signature = await account.signUserOperation({ // [!code focus:99]
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymasterPostOpGasLimit: 0n,
paymasterVerificationGasLimit: 0n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http()
})
export const owner = privateKeyToAccount('0x...')
```
:::
## Returns
`Hex`
The User Operation signature.
## Parameters
### callData
* **Type:** `Hex`
The data to pass to the `sender` during the main execution call.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef', // [!code focus]
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymasterPostOpGasLimit: 0n,
paymasterVerificationGasLimit: 0n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### callGasLimit
* **Type:** `bigint`
The amount of gas to allocate the main execution call.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n, // [!code focus]
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymasterPostOpGasLimit: 0n,
paymasterVerificationGasLimit: 0n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### factory
* **Type:** `Address`
Account factory. Only for new accounts.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e', // [!code focus]
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymasterPostOpGasLimit: 0n,
paymasterVerificationGasLimit: 0n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### factoryData
* **Type:** `Hex`
Data for account factory.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000', // [!code focus]
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymasterPostOpGasLimit: 0n,
paymasterVerificationGasLimit: 0n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### maxFeePerGas
* **Type:** `bigint`
Maximum fee per gas.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n, // [!code focus]
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymasterPostOpGasLimit: 0n,
paymasterVerificationGasLimit: 0n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### maxPriorityFeePerGas
* **Type:** `bigint`
Maximum priority fee per gas.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
// [!code focus]
nonce: 0n,
paymasterPostOpGasLimit: 0n,
paymasterVerificationGasLimit: 0n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### nonce
* **Type:** `bigint`
Anti-replay parameter.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n, // [!code focus]
paymasterPostOpGasLimit: 0n,
paymasterVerificationGasLimit: 0n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### paymaster
* **Type:** `Address`
Address of paymaster contract.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymaster: '0xE911628bF8428C23f179a07b081325cAe376DE1f', // [!code focus]
paymasterData: '0xdeadbeef',
paymasterPostOpGasLimit: 0n,
paymasterVerificationGasLimit: 0n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### paymasterData
* **Type:** `Hex`
Data for paymaster.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymaster: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
paymasterData: '0xdeadbeef', // [!code focus]
paymasterPostOpGasLimit: 0n,
paymasterVerificationGasLimit: 0n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### paymasterPostOpGasLimit
* **Type:** `bigint`
The amount of gas to allocate for the paymaster post-operation code.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymaster: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
paymasterData: '0xdeadbeef',
paymasterPostOpGasLimit: 69420n, // [!code focus]
paymasterVerificationGasLimit: 0n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### paymasterVerificationGasLimit
* **Type:** `bigint`
The amount of gas to allocate for the paymaster validation code.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymaster: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
paymasterData: '0xdeadbeef',
paymasterPostOpGasLimit: 69420n,
paymasterVerificationGasLimit: 69420n, // [!code focus]
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### preVerificationGas
* **Type:** `bigint`
Extra gas to pay the Bundler.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymaster: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
paymasterData: '0xdeadbeef',
paymasterPostOpGasLimit: 69420n,
paymasterVerificationGasLimit: 69420n,
preVerificationGas: 53438n, // [!code focus]
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n,
})
```
### sender
* **Type:** `Address`
The account making the operation.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymaster: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
paymasterData: '0xdeadbeef',
paymasterPostOpGasLimit: 69420n,
paymasterVerificationGasLimit: 69420n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f', // [!code focus]
verificationGasLimit: 259350n,
})
```
### verificationGasLimit
* **Type:** `bigint`
The amount of gas to allocate for the verification step.
```ts twoslash
import { toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config'
export const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1.1',
})
// ---cut---
const signature = await account.signUserOperation({
callData: '0xdeadbeef',
callGasLimit: 141653n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 15000000000n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
paymaster: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
paymasterData: '0xdeadbeef',
paymasterPostOpGasLimit: 69420n,
paymasterVerificationGasLimit: 69420n,
preVerificationGas: 53438n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
verificationGasLimit: 259350n, // [!code focus]
})
```
# Coinbase Smart Wallet
The `toCoinbaseSmartAccount` implementation references the [Coinbase Smart Wallet](https://github.com/coinbase/smart-wallet) contract.
## Usage
:::code-group
```ts twoslash [example.ts]
import { toCoinbaseSmartAccount } from 'viem/account-abstraction' // [!code focus]
import { client } from './client.js'
import { owner } from './owner.js'
const account = await toCoinbaseSmartAccount({ // [!code focus]
client, // [!code focus]
owners: [owner], // [!code focus]
version: '1.1', // [!code focus]
}) // [!code focus]
```
```ts twoslash [client.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
```ts twoslash [owner.ts (Private Key)] filename="owner.ts"
import { privateKeyToAccount } from 'viem/accounts'
export const owner = privateKeyToAccount('0x...')
```
```ts twoslash [owner.ts (Passkey)] filename="owner.ts"
import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstraction'
// Register a credential (ie. passkey).
const credential = await createWebAuthnCredential({ name: 'Wallet' })
// Create a WebAuthn owner account from the credential.
export const owner = toWebAuthnAccount({ credential })
```
:::
:::tip
**Tip:** You can use a Passkey (WebAuthn) to sign User Operations. Check the **owner.ts (Passkey)** tab.
:::
## Returns
`SmartAccount`
## Parameters
### client
* **Type:** `Client`
Client used to retrieve Smart Account data.
```ts
const client = createPublicClient({ // [!code focus]
chain: mainnet, // [!code focus]
transport: http(), // [!code focus]
}) // [!code focus]
const account = await toCoinbaseSmartAccount({
client, // [!code focus]
owners: [owner],
version: '1.1',
})
```
### owners
* **Type:** `(LocalAccount | WebAuthnAccount)[]`
Owners of the Smart Account. Can be a [Local Account](/docs/accounts/local) or a [WebAuthn Account (Passkey)](/account-abstraction/accounts/webauthn).
```ts
const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...')], // [!code focus]
})
```
### ownerIndex (optional)
* **Type:** `number`
Index of the owner to use for signing messages & User Operations.
```ts
const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...'), privateKeyToAccount('0x...')],
ownerIndex: 1, // [!code focus]
version: '1.1',
})
```
### nonce (optional)
* **Type:** `bigint`
Nonce to use for the Smart Account.
```ts
const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
nonce: 1n, // [!code focus]
version: '1.1',
})
```
### version
* **Type:** `'1.1' | '1'`
* **Default:** `'1'`
Version of the Smart Account to use.
:::warning
Version bumps DO contain breaking changes.
:::
```ts
const account = await toCoinbaseSmartAccount({
client,
owners: [owner],
version: '1', // [!code focus]
})
```
# Kernel (ZeroDev) Smart Account
:::warning
**Note:** This implementation is maintained & distributed by [permissionless.js](https://docs.pimlico.io/permissionless).
:::
To implement the [Kernel (ZeroDev) Smart Account](https://github.com/zerodevapp/kernel), you can use the [`toEcdsaKernelSmartAccount`](https://docs.pimlico.io/permissionless/reference/accounts/toEcdsaKernelSmartAccount) module from [permissionless.js](https://docs.pimlico.io/permissionless/)
## Install
:::code-group
```bash [pnpm]
pnpm add permissionless
```
```bash [npm]
npm install permissionless
```
```bash [yarn]
yarn add permissionless
```
```bash [bun]
bun add permissionless
```
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { toEcdsaKernelSmartAccount } from 'permissionless/accounts' // [!code focus]
import { client } from './client.js'
import { owner } from './owner.js'
const account = await toEcdsaKernelSmartAccount({ // [!code focus]
client, // [!code focus]
owners: [owner], // [!code focus]
version: '0.3.1', // [!code focus]
}) // [!code focus]
```
```ts twoslash [client.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
```ts twoslash [owner.ts (Private Key)] filename="owner.ts"
import { privateKeyToAccount } from 'viem/accounts'
export const owner = privateKeyToAccount('0x...')
```
:::
## Returns
`SmartAccount`
## Parameters
[See Parameters](https://docs.pimlico.io/permissionless/reference/accounts/toEcdsaKernelSmartAccount#parameters)
# Light Smart Account
:::warning
**Note:** This implementation is maintained & distributed by [permissionless.js](https://docs.pimlico.io/permissionless).
:::
To implement Alchemy's [Light Account](https://github.com/alchemyplatform/light-account), you can use the [`toLightSmartAccount`](https://docs.pimlico.io/permissionless/reference/accounts/toLightSmartAccount) module from [permissionless.js](https://docs.pimlico.io/permissionless/)
## Install
:::code-group
```bash [pnpm]
pnpm add permissionless
```
```bash [npm]
npm install permissionless
```
```bash [yarn]
yarn add permissionless
```
```bash [bun]
bun add permissionless
```
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { toLightSmartAccount } from 'permissionless/accounts' // [!code focus]
import { client } from './client.js'
import { owner } from './owner.js'
const account = await toLightSmartAccount({ // [!code focus]
client, // [!code focus]
owner: owner, // [!code focus]
version: '2.0.0', // [!code focus]
}) // [!code focus]
```
```ts twoslash [client.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
```ts twoslash [owner.ts (Private Key)] filename="owner.ts"
import { privateKeyToAccount } from 'viem/accounts'
export const owner = privateKeyToAccount('0x...')
```
:::
## Returns
`SmartAccount`
## Parameters
[See Parameters](https://docs.pimlico.io/permissionless/reference/accounts/toLightSmartAccount#parameters)
# MetaMask Smart Account
:::warning
**Note:** This implementation is maintained & distributed by [MetaMask Smart Accounts Kit](https://docs.metamask.io/smart-accounts-kit).
:::
MetaMask Smart Accounts has three types of implementations, each offering unique features
and use cases. See [Hybrid smart account](https://docs.metamask.io/smart-accounts-kit/guides/smart-accounts/create-smart-account/#create-a-hybrid-smart-account), [Multisig smart account](https://docs.metamask.io/smart-accounts-kit/guides/smart-accounts/create-smart-account/#create-a-multisig-smart-account), and [Stateless 7702 smart account](https://docs.metamask.io/smart-accounts-kit/guides/smart-accounts/create-smart-account/#create-a-stateless-7702-smart-account) to learn more about
the implementations.
To implement MetaMask Smart Accounts, you can use the [`toMetaMaskSmartAccount`](https://docs.metamask.io/smart-accounts-kit/guides/smart-accounts/create-smart-account/) function from the [Smart Accounts Kit](https://docs.metamask.io/smart-accounts-kit/).
## Install
:::code-group
```bash [pnpm]
pnpm add @metamask/smart-accounts-kit
```
```bash [npm]
npm install @metamask/smart-accounts-kit
```
```bash [yarn]
yarn add @metamask/smart-accounts-kit
```
```bash [bun]
bun add @metamask/smart-accounts-kit
```
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { // [!code focus]
Implementation, // [!code focus]
toMetaMaskSmartAccount, // [!code focus]
} from "@metamask/smart-accounts-kit" // [!code focus]
import { client } from './client.js'
import { owner } from './owner.js'
const account = await toMetaMaskSmartAccount({ // [!code focus]
client, // [!code focus]
implementation: Implementation.Hybrid, // [!code focus]
deployParams: [owner.address, [], [], []], // [!code focus]
deploySalt: "0x", // [!code focus]
signer: { account: owner }, // [!code focus]
}) // [!code focus]
```
```ts twoslash [client.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
```ts twoslash [owner.ts (Private Key)] filename="owner.ts"
import { privateKeyToAccount } from 'viem/accounts'
export const owner = privateKeyToAccount('0x...')
```
:::
## Returns
`SmartAccount>`
## Parameters
[See Parameters](https://docs.metamask.io/smart-accounts-kit/reference/smart-account/#parameters-6)
# Nexus Smart Account
:::warning
**Note:** This implementation is maintained & distributed by [permissionless.js](https://docs.pimlico.io/permissionless).
:::
To implement Biconomy's [Nexus Smart Account](https://github.com/bcnmy/nexus), you can use the [`toNexusSmartAccount`](https://docs.pimlico.io/permissionless/reference/accounts/toNexusSmartAccount) module from [permissionless.js](https://docs.pimlico.io/permissionless/)
## Install
:::code-group
```bash [pnpm]
pnpm add permissionless
```
```bash [npm]
npm install permissionless
```
```bash [yarn]
yarn add permissionless
```
```bash [bun]
bun add permissionless
```
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { toNexusSmartAccount } from 'permissionless/accounts' // [!code focus]
import { client } from './client.js'
import { owner } from './owner.js'
const account = await toNexusSmartAccount({ // [!code focus]
client, // [!code focus]
owners: [owner], // [!code focus]
version: '1.0.0' // [!code focus]
}) // [!code focus]
```
```ts twoslash [client.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
```ts twoslash [owner.ts (Private Key)] filename="owner.ts"
import { privateKeyToAccount } from 'viem/accounts'
export const owner = privateKeyToAccount('0x...')
```
:::
## Returns
`SmartAccount`
## Parameters
[See Parameters](https://docs.pimlico.io/permissionless/reference/accounts/toNexusSmartAccount#parameters)
# Safe Smart Account
:::warning
**Note:** This implementation is maintained & distributed by [permissionless.js](https://docs.pimlico.io/permissionless).
:::
To implement [Safe Smart Account](https://github.com/safe-global/safe-smart-account), you can use the [`toSafeSmartAccount`](https://docs.pimlico.io/permissionless/reference/accounts/toSafeSmartAccount) module from [permissionless.js](https://docs.pimlico.io/permissionless/)
## Install
:::code-group
```bash [pnpm]
pnpm add permissionless
```
```bash [npm]
npm install permissionless
```
```bash [yarn]
yarn add permissionless
```
```bash [bun]
bun add permissionless
```
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { toSafeSmartAccount } from 'permissionless/accounts' // [!code focus]
import { client } from './client.js'
import { owner } from './owner.js'
const account = await toSafeSmartAccount({ // [!code focus]
client, // [!code focus]
owners: [owner], // [!code focus]
version: '1.4.1', // [!code focus]
}) // [!code focus]
```
```ts twoslash [client.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
```ts twoslash [owner.ts (Private Key)] filename="owner.ts"
import { privateKeyToAccount } from 'viem/accounts'
export const owner = privateKeyToAccount('0x...')
```
:::
## Returns
`SmartAccount`
## Parameters
[See Parameters](https://docs.pimlico.io/permissionless/reference/accounts/toSafeSmartAccount#parameters)
# Simple Smart Account
:::warning
**Note:** This implementation is maintained & distributed by [permissionless.js](https://docs.pimlico.io/permissionless).
:::
To implement the [Simple Smart Account](https://github.com/eth-infinitism/account-abstraction/blob/develop/contracts/samples/SimpleAccount.sol), you can use the [`toSimpleSmartAccount`](https://docs.pimlico.io/permissionless/reference/accounts/toSimpleSmartAccount) module from [permissionless.js](https://docs.pimlico.io/permissionless/)
## Install
:::code-group
```bash [pnpm]
pnpm add permissionless
```
```bash [npm]
npm install permissionless
```
```bash [yarn]
yarn add permissionless
```
```bash [bun]
bun add permissionless
```
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { toSimpleSmartAccount } from 'permissionless/accounts' // [!code focus]
import { client } from './client.js'
import { owner } from './owner.js'
const account = await toSimpleSmartAccount({ // [!code focus]
client, // [!code focus]
owners: [owner], // [!code focus]
}) // [!code focus]
```
```ts twoslash [client.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
```ts twoslash [owner.ts (Private Key)] filename="owner.ts"
import { privateKeyToAccount } from 'viem/accounts'
export const owner = privateKeyToAccount('0x...')
```
:::
## Returns
`SmartAccount`
## Parameters
[See Parameters](https://docs.pimlico.io/permissionless/reference/accounts/toSimpleSmartAccount#parameters)
# toSmartAccount
The `toSmartAccount` function allows you to create a Smart Account with a custom Account Implementation.
## Import
```ts
import { toSmartAccount } from 'viem/account-abstraction'
```
## Usage
To instantiate a Smart Account, you will need to provide an Account Implementation.
:::code-group
```ts twoslash [example.ts]
import { coinbase, toSmartAccount } from 'viem/account-abstraction'
import { client, owner } from './config.js'
const account = await toSmartAccount({
client,
entryPoint: {
abi: [/* ... */],
address: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
version: '0.7',
},
async decodeCalls(data) {
// Decode calls from calldata as defined by the Smart Account contract.
},
async encodeCalls(calls) {
// Encode calls as defined by the Smart Account contract.
},
async getAddress() {
// Get the address of the Smart Account.
},
async getFactoryArgs() {
// Build the Factory properties for the Smart Account.
},
async getNonce() {
// Get the nonce of the Smart Account.
},
async getStubSignature() {
// Get the stub signature for User Operations from the Smart Account.
},
async signMessage(message) {
// Sign message to be verified by the Smart Account contract.
},
async signTypedData(typedData) {
// Sign typed data to be verified by the Smart Account contract.
},
async signUserOperation(userOperation) {
// Sign a User Operation to be broadcasted via the Bundler.
},
// (Optional) Extend the Smart Account with custom properties.
extend: {
abi: [/* ... */],
factory: {
abi: [/* ... */],
address: '0xda4b37208c41c4f6d1b101cac61e182fe1da0754',
},
},
// (Optional) User Operation configuration.
userOperation: {
async estimateGas(userOperation) {
// Estimate gas properties for a User Operation.
},
},
})
```
```ts twoslash [config.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const owner = privateKeyToAccount('0x...')
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
## Returns
`SmartAccount`
The Smart Account.
# Solady Smart Account
The `toSoladySmartAccount` simple Smart Account Implementation that references [Solady's `ERC4337.sol`](https://github.com/Vectorized/solady/blob/main/src/accounts/ERC4337.sol) Smart Account contract.
:::warning
This implementation is unaudited. It is intended to be used for testing purposes or as a reference to implement a [Custom Account](/account-abstraction/accounts/smart/toSmartAccount).
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { toSoladySmartAccount } from 'viem/account-abstraction' // [!code focus]
import { client, owner } from './config.js'
const account = await toSoladySmartAccount({ // [!code focus]
client, // [!code focus]
owner, // [!code focus]
}) // [!code focus]
```
```ts twoslash [config.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const owner = privateKeyToAccount('0x...')
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
## Returns
`SmartAccount`
## Parameters
### entryPoint (optional)
* **Type:** `{ abi: Abi, address: Address, version: EntryPointVersion }`
Compatible EntryPoint for the Smart Account to reference. The EntryPoint is used
to:
* Determine the target EntryPoint address for the User Operation
* Compute User Operation hashes
* Retrieve the Smart Account nonce
* Distinguish which type of `UserOperation` structure to use
```ts
const account = await toSoladySmartAccount({
client,
entryPoint: { // [!code focus]
abi: [/* ... */], // [!code focus]
address: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', // [!code focus]
version: '0.7', // [!code focus]
}, // [!code focus]
owner,
})
```
### factoryAddress
* **Type:** `Address`
Factory address of the Smart Account.
```ts
const account = await toSoladySmartAccount({
client,
factoryAddress: '0xda4b37208c41c4f6d1b101cac61e182fe1da0754', // [!code focus]
owner,
})
```
### owner
* **Type:** `Address | Account`
Owner of the Smart Account.
```ts
const account = await toSoladySmartAccount({
client,
owner: privateKeyToAccount('0x...'), // [!code focus]
})
```
### salt (optional)
* **Type:** `Hex`
Salt to use for Smart Account deployment.
```ts
const account = await toSoladySmartAccount({
client,
owner,
salt: '0x5', // [!code focus]
})
```
# Thirdweb Smart Account
:::warning
**Note:** This implementation is maintained & distributed by [permissionless.js](https://docs.pimlico.io/permissionless).
:::
To implement [Thirdweb Smart Account](https://portal.thirdweb.com/), you can use the [`toThirdwebSmartAccount`](https://github.com/pimlicolabs/permissionless.js/blob/main/packages/permissionless/accounts/thirdweb/toThirdwebSmartAccount.ts) module from [permissionless.js](https://docs.pimlico.io/permissionless/)
## Install
:::code-group
```bash [pnpm]
pnpm add permissionless
```
```bash [npm]
npm install permissionless
```
```bash [yarn]
yarn add permissionless
```
```bash [bun]
bun add permissionless
```
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { toThirdwebSmartAccount } from 'permissionless/accounts' // [!code focus]
import { client } from './client.js'
import { owner } from './owner.js'
const account = await toThirdwebSmartAccount({ // [!code focus]
client, // [!code focus]
owner, // [!code focus]
}) // [!code focus]
```
```ts twoslash [client.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
```ts twoslash [owner.ts (Private Key)] filename="owner.ts"
import { privateKeyToAccount } from 'viem/accounts'
export const owner = privateKeyToAccount('0x...')
```
:::
## Returns
`SmartAccount`
## Parameters
[See Parameters](https://github.com/pimlicolabs/permissionless.js/blob/d5bb008969c23183f02c16f86f71f051cceb8ee3/packages/permissionless/accounts/thirdweb/toThirdwebSmartAccount.ts#L46-L64)
# Trust Smart Account
:::warning
**Note:** This implementation is maintained & distributed by [permissionless.js](https://docs.pimlico.io/permissionless).
:::
To implement the [Trust Smart Wallet](https://developer.trustwallet.com/developer/barz-smart-wallet/build-with-trust-wallet-and-barz-aa-sdk), you can use the [`toTrustSmartAccount`](https://docs.pimlico.io/permissionless/reference/accounts/toTrustSmartAccount) module from [permissionless.js](https://docs.pimlico.io/permissionless/)
## Install
:::code-group
```bash [pnpm]
pnpm add permissionless
```
```bash [npm]
npm install permissionless
```
```bash [yarn]
yarn add permissionless
```
```bash [bun]
bun add permissionless
```
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { toTrustSmartAccount } from 'permissionless/accounts' // [!code focus]
import { client } from './client.js'
import { owner } from './owner.js'
const account = await toTrustSmartAccount({ // [!code focus]
client, // [!code focus]
owner: owner, // [!code focus]
}) // [!code focus]
```
```ts twoslash [client.ts] filename="config.ts"
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
```ts twoslash [owner.ts (Private Key)] filename="owner.ts"
import { privateKeyToAccount } from 'viem/accounts'
export const owner = privateKeyToAccount('0x...')
```
:::
## Returns
`SmartAccount`
## Parameters
[See Parameters](https://docs.pimlico.io/permissionless/reference/accounts/toTrustSmartAccount#parameters)
# createWebAuthnCredential
Registers a **WebAuthn Credential** designed to be used to create a [WebAuthn Account](/account-abstraction/accounts/webauthn/toWebAuthnAccount).
:::note
This function uses [`ox/WebAuthnP256`](https://github.com/wevm/ox) under-the-hood.
:::
## Overview
`createWebAuthnCredential` initiates the WebAuthn (passkey) registration flow on the user's device, creating a cryptographic P256 credential that can later be used for authentication.
This function uses `navigator.credentials.create()` internally. [Read more](https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/create).
## Import
```ts twoslash
import { createWebAuthnCredential } from 'viem/account-abstraction'
```
## Usage
At minimum, you need to provide a name to identify the credential:
```ts twoslash
import {
createWebAuthnCredential,
toWebAuthnAccount
} from 'viem/account-abstraction'
// Register a credential (ie. passkey). // [!code focus]
const credential = await createWebAuthnCredential({ // [!code focus]
name: 'Example', // [!code focus]
}) // [!code focus]
// Create a WebAuthn account from the credential.
const account = toWebAuthnAccount({
credential,
})
```
The function returns a `P256Credential` object that you can then pass to `toWebAuthnAccount()` to create an account, or store in your database for later use.
## Returns
`P256Credential`
A P-256 WebAuthn Credential object with the following structure:
```ts
{
id: string // The credential ID
publicKey: Hex // Hex-encoded public key (includes 0x prefix)
raw: PublicKeyCredential // Raw credential from the Web Authentication API
}
```
This credential object is designed to be passed to `toWebAuthnAccount()` to create a `WebAuthnAccount`, which provides signing capabilities for transactions and messages.
## Parameters
### name
* **Type:** `string`
A user-friendly display name for the credential. This appears in your browser's credential manager and helps users identify which passkey they're using. Use something descriptive like "My Laptop Fingerprint" or "Security Key".
```ts twoslash
import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstraction'
// ---cut---
const credential = await createWebAuthnCredential({
name: 'Example',
})
```
### challenge (optional)
* **Type:** `Uint8Array`
A random cryptographic value that proves the credential creation request. If you don't provide one, the function generates a random one.
```ts twoslash
import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstraction'
// ---cut---
const credential = await createWebAuthnCredential({
challenge: new Uint8Array([1, 2, 3]),
name: 'Example',
})
```
### rp (optional)
* **Type:** `{ id: string; name: string }`
An object describing the relying party. [Read more](https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredentialCreationOptions#rp).
```ts twoslash
import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstraction'
// ---cut---
const credential = await createWebAuthnCredential({
name: 'Example',
rp: {
id: 'example.com',
name: 'Example',
},
})
```
### timeout (optional)
* **Type:** `number`
How long (in milliseconds) to wait for the user to complete the registration.
```ts twoslash
import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstraction'
// ---cut---
const credential = await createWebAuthnCredential({
name: 'Example',
timeout: 1000,
})
```
### excludeCredentialIds (optional)
* **Type:** `string[]`
An array of credential IDs you want to prevent from being re-registered. If a user already has a credential with one of these IDs on their device, the registration will fail. Use this to prevent duplicate credentials and ensure each device can only register once.
```ts twoslash
import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstraction'
// ---cut---
const credential = await createWebAuthnCredential({
excludeCredentialIds: ['abc', 'def'],
name: 'Example',
})
```
### createFn (optional, advanced)
* **Type:** `(options: CredentialCreationOptions) => Promise`
* **Default:** `window.navigator.credentials.create`
Allows you to override the default credential creation function. By default, it uses `window.navigator.credentials.create`, which is the standard WebAuthn API. Override this only if you're in an environment that doesn't support WebAuthn natively (React Native, test environments, etc.). Pass a custom function that accepts the same options and returns a credential or null.
```ts twoslash
// @noErrors
import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstraction'
// ---cut---
import * as passkey from 'react-native-passkeys'
const credential = await createWebAuthnCredential({
name: 'Example',
createFn: passkey.create,
})
const account = toWebAuthnAccount({
credential,
})
```
## Error Cases
The registration can fail or be cancelled for several reasons:
* The user cancels the credential creation dialog
* The device doesn't support WebAuthn
* The credential already exists (if using `excludeCredentialIds`)
* The timeout expires while waiting for user interaction
* The authenticator is locked or unavailable
Wrap the function call in a try-catch block to handle these gracefully.
# toWebAuthnAccount
Creates a **WebAuthn Account** – commonly used for **[Smart Account](/account-abstraction/accounts/smart) Owners** to sign User Operations and messages on behalf of the Smart Account.
:::note
WebAuthn Account owners are currently supported on the following Smart Account implementations:
* [`toCoinbaseSmartAccount`](/account-abstraction/accounts/smart/toCoinbaseSmartAccount#owners)
:::
## Import
```ts twoslash
import { toWebAuthnAccount } from 'viem/account-abstraction'
```
## Usage
```ts twoslash
import {
createWebAuthnCredential,
toWebAuthnAccount
} from 'viem/account-abstraction'
// Register a credential (ie. passkey).
const credential = await createWebAuthnCredential({
name: 'Example',
})
// Create a WebAuthn account from the credential. // [!code focus]
const account = toWebAuthnAccount({ // [!code focus]
credential, // [!code focus]
}) // [!code focus]
```
## Returns
`WebAuthnAccount`
A WebAuthn Account.
## Parameters
### credential
* **Type:** `P256Credential`
A P256 WebAuthn Credential.
```ts twoslash
import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstraction'
// ---cut---
const credential = await createWebAuthnCredential({
name: 'Example',
})
const account = toWebAuthnAccount({
credential, // [!code focus]
})
```
### getFn
* **Type:** `(options: CredentialRequestOptions) => Promise`
* **Default:** `window.navigator.credentials.get`
Credential request function. Useful for environments that do not support the WebAuthn API natively (i.e. React Native or testing environments).
```ts twoslash
// @noErrors
import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstraction'
// ---cut---
import * as passkey from 'react-native-passkeys' // [!code focus]
const credential = await createWebAuthnCredential({
name: 'Example',
})
const account = toWebAuthnAccount({
credential,
getFn: passkey.get, // [!code focus]
})
```
### rpId
* **Type:** `string`
* **Default:** `window.location.hostname`
Relying Party ID.
```ts twoslash
// @noErrors
import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstraction'
// ---cut---
import * as passkey from 'react-native-passkeys' // [!code focus]
const credential = await createWebAuthnCredential({
name: 'Example',
})
const account = toWebAuthnAccount({
credential,
rpId: 'example.com', // [!code focus]
})
```
# estimateUserOperationGas
Estimates the gas values for a User Operation to be executed successfully.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
const gas = await bundlerClient.estimateUserOperationGas({ // [!code focus:7]
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}]
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
export const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...')],
version: '1.1',
})
export const bundlerClient = createBundlerClient({
client,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
:::info
The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Bundler](https://www.pimlico.io), [Biconomy's Bundler](https://www.biconomy.io), or another Bundler service.
:::
### Account Hoisting
If you do not wish to pass an `account` to every `estimateUserOperationGas`, you can also hoist the Account on the Bundler Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { bundlerClient } from './config'
const gas = await bundlerClient.estimateUserOperationGas({ // [!code focus:7]
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}]
})
```
```ts twoslash [config.ts]
import { createPublicClient, http } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
export const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...')],
version: '1.1',
})
export const bundlerClient = createBundlerClient({
account, // [!code ++]
client,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
### Contract Calls
The `calls` property also accepts **Contract Calls**, and can be used via the `abi`, `functionName`, and `args` properties.
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { bundlerClient, publicClient } from './config'
import { wagmiAbi } from './abi' // [!code focus]
const gas = await bundlerClient.estimateUserOperationGas({ // [!code focus:7]
calls: [{
abi: wagmiAbi,
functionName: 'mint',
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
}],
})
```
```ts twoslash [abi.ts] filename="abi.ts"
export const wagmiAbi = [
// ...
{
inputs: [],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
// ...
] as const;
```
```ts twoslash [config.ts]
import { createPublicClient, http } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
export const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...')],
version: '1.1',
})
export const bundlerClient = createBundlerClient({
account,
client,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
## Returns
```ts
{
callGasLimit: bigint;
preVerificationGas: bigint;
verificationGasLimit: bigint;
paymasterVerificationGasLimit: bigint | undefined;
paymasterPostOpGasLimit: bigint | undefined;
}
```
The estimated gas values.
## Parameters
### account
* **Type:** `SmartAccount`
The Account to use for User Operation execution.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account, // [!code focus]
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}]
})
```
### calls
* **Type:** `{ data: Hex, to: Address, value: bigint }[]`
The calls to execute in the User Operation.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{ // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1') // [!code focus]
}] // [!code focus]
})
```
:::tip
You can also pass raw call data via the `callData` property:
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
callData: '0xdeadbeef', // [!code focus]
})
```
:::
### callGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate the main execution call.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
callGasLimit: 69420n, // [!code focus]
})
```
### factory (optional)
* **Type:** `Address`
Account Factory address.
:::warning
This property should only be populated when the Smart Account has not been deployed yet.
:::
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
factory: '0x1234567890123456789012345678901234567890', // [!code focus]
factoryData: '0xdeadbeef',
})
```
### factoryData (optional)
* **Type:** `Hex`
Call data to execute on the Account Factory to deploy a Smart Account.
:::warning
This property should only be populated when the Smart Account has not been deployed yet.
:::
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
factory: '0x1234567890123456789012345678901234567890',
factoryData: '0xdeadbeef', // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Maximum fee per gas for User Operation execution.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
maxFeePerGas: 420n, // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Maximum priority fee per gas for User Operation execution.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
maxPriorityFeePerGas: 420n,
maxFeePerGas: 10n, // [!code focus]
})
```
### nonce (optional)
* **Type:** `bigint`
Nonce for the User Operation.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
nonce: 10n, // [!code focus]
})
```
### paymaster (optional)
* **Type:** `Address | true | PaymasterClient | PaymasterActions`
Sets Paymaster configuration for the User Operation.
* If `paymaster: Address`, it will use the provided Paymaster contract address for sponsorship.
* If `paymaster: PaymasterClient`, it will use the provided [Paymaster Client](/account-abstraction/clients/paymaster) for sponsorship.
* If `paymaster: true`, it will be assumed that the Bundler Client also supports Paymaster RPC methods (e.g. `pm_getPaymasterData`), and use them for sponsorship.
* If [custom functions](/account-abstraction/clients/bundler#paymastergetpaymasterdata-optional) are provided to `paymaster`, it will use them for sponsorship.
#### Using a Paymaster Contract Address
```ts twoslash
import { account, bundlerClient } from './config'
// ---cut---
const hash = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB', // [!code focus]
paymasterData: '0xdeadbeef',
})
```
#### Using a Paymaster Client
```ts twoslash
import { account, bundlerClient } from './config'
// ---cut---
import { http, parseEther } from 'viem'
import { createPaymasterClient } from 'viem/account-abstraction'
const paymasterClient = createPaymasterClient({ // [!code focus]
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}') // [!code focus]
}) // [!code focus]
const hash = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: paymasterClient, // [!code focus]
})
```
#### Using the Bundler Client as Paymaster
```ts twoslash
import { account, bundlerClient } from './config'
// ---cut---
const hash = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: true, // [!code focus]
})
```
### paymasterContext (optional)
* **Type:** `unknown`
Paymaster specific fields.
:::warning
This property is only available if **`paymaster` is a Paymaster Client**.
:::
```ts twoslash
import { account, bundlerClient } from './config'
// ---cut---
import { http, parseEther } from 'viem'
import { createPaymasterClient } from 'viem/account-abstraction'
const paymasterClient = createPaymasterClient({
transport: http('https://public.pimlico.io/v2/11155111/rpc')
})
const hash = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: paymasterClient,
paymasterContext: { // [!code focus]
policyId: 'abc123' // [!code focus]
}, // [!code focus]
})
```
### paymasterData (optional)
* **Type:** `Address`
Call data to execute on the Paymaster contract.
:::warning
This property is only available if **`paymaster` is an address**.
:::
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB',
paymasterData: '0xdeadbeef', // [!code focus]
})
```
### paymasterPostOpGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate for the Paymaster post-operation code.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB',
paymasterData: '0xdeadbeef',
paymasterPostOpGasLimit: 69420n, // [!code focus]
})
```
### paymasterVerificationGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate for the Paymaster validation code.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB',
paymasterData: '0xdeadbeef',
paymasterVerificationGasLimit: 69420n, // [!code focus]
})
```
### preVerificationGas (optional)
* **Type:** `bigint`
Extra gas to pay the Bundler.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
preVerificationGas: 69420n, // [!code focus]
})
```
### signature (optional)
* **Type:** `Hex`
Signature for the User Operation.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
signature: '0x...', // [!code focus]
})
```
### stateOverride (optional)
* **Type:** [`StateOverride`](/docs/glossary/types#stateoverride)
The state override set is an optional address-to-state mapping, where each entry specifies some state to be ephemerally overridden prior to executing the call.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
stateOverride: [ // [!code focus]
{ // [!code focus]
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
balance: parseEther('1'), // [!code focus]
stateDiff: [ // [!code focus]
{ // [!code focus]
slot: '0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0', // [!code focus]
value: '0x00000000000000000000000000000000000000000000000000000000000001a4', // [!code focus]
}, // [!code focus]
], // [!code focus]
} // [!code focus]
], // [!code focus]
})
```
### verificationGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate for the verification step.
```ts twoslash
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
// ---cut---
const gas = await bundlerClient.estimateUserOperationGas({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
verificationGasLimit: 69420n, // [!code focus]
})
```
# getChainId
Returns the chain ID associated with the bundler
## Usage
:::code-group
```ts twoslash [example.ts]
import { bundlerClient } from './client'
const chainId = await bundlerClient.getChainId() // [!code focus:99]
// @log: 1
```
```ts twoslash [client.ts] filename="client.ts"
import { http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction'
export const bundlerClient = createBundlerClient({
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
:::info
The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Bundler](https://www.pimlico.io), [Biconomy's Bundler](https://www.biconomy.io), or another Bundler service.
:::
## Returns
`number`
The current chain ID.
# getSupportedEntryPoints
Returns the EntryPoints that the bundler supports.
## Usage
:::code-group
```ts twoslash [example.ts]
import { bundlerClient } from './client'
const entryPoints = await bundlerClient.getSupportedEntryPoints() // [!code focus:99]
// @log: ["0x0000000071727De22E5E9d8BAf0edAc6f37da032"]
```
```ts twoslash [client.ts] filename="client.ts"
import { http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction'
export const bundlerClient = createBundlerClient({
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
:::info
The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Bundler](https://www.pimlico.io), [Biconomy's Bundler](https://www.biconomy.io), or another Bundler service.
:::
## Returns
`readonly Address[]`
The EntryPoints that the bundler supports.
# getUserOperation
Retrieves information about a User Operation given a hash.
## Usage
:::code-group
```ts twoslash [example.ts]
import { bundlerClient } from './client'
const result = await bundlerClient.getUserOperation({ // [!code focus:99]
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d'
})
```
```ts twoslash [client.ts] filename="client.ts"
import { http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
export const bundlerClient = createBundlerClient({
chain: mainnet,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
:::info
The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Bundler](https://www.pimlico.io), [Biconomy's Bundler](https://www.biconomy.io), or another Bundler service.
:::
## Returns
```ts
{
blockHash: Hash,
blockNumber: bigint,
entryPoint: Address,
transactionHash: Hash,
userOperation: UserOperation
}
```
User Operation information.
## Parameters
### hash
* **Type:** `'0x${string}'`
A User Operation hash.
```ts twoslash
import { bundlerClient } from './client'
// ---cut---
const result = await publicClient.getUserOperation({
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d' // [!code focus]
})
```
# getUserOperationReceipt
Returns the User Operation Receipt given a User Operation hash.
## Usage
:::code-group
```ts twoslash [example.ts]
import { bundlerClient } from './client'
const receipt = await bundlerClient.getUserOperationReceipt({ // [!code focus:99]
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d'
})
// @log: {
// @log: blockHash: '0xaf1dadb8a98f1282e8f7b42cc3da8847bfa2cf4e227b8220403ae642e1173088',
// @log: blockNumber: 15132008n,
// @log: sender: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
// @log: ...
// @log: status: 'success',
// @log: }
```
```ts twoslash [client.ts] filename="client.ts"
import { http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
export const bundlerClient = createBundlerClient({
chain: mainnet,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
:::info
The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Bundler](https://www.pimlico.io), [Biconomy's Bundler](https://www.biconomy.io), or another Bundler service.
:::
## Returns
`UserOperationReceipt`
The User Operation receipt.
## Parameters
### hash
* **Type:** `'0x${string}'`
A User Operation hash.
```ts twoslash
import { bundlerClient } from './client'
// ---cut---
const receipt = await bundlerClient.getUserOperationReceipt({
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d' // [!code focus]
})
```
# TODO
# prepareUserOperation
Prepares a User Operation for execution and fills in missing properties.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
const userOperation = await bundlerClient.prepareUserOperation({ // [!code focus:7]
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}]
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
export const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...')],
version: '1.1',
})
export const bundlerClient = createBundlerClient({
client,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
:::info
The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Bundler](https://www.pimlico.io), [Biconomy's Bundler](https://www.biconomy.io), or another Bundler service.
:::
### Account Hoisting
If you do not wish to pass an `account` to every `prepareUserOperation`, you can also hoist the Account on the Bundler Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { bundlerClient } from './config'
const userOperation = await bundlerClient.prepareUserOperation({ // [!code focus:7]
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
export const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...')],
version: '1.1',
})
export const bundlerClient = createBundlerClient({
account, // [!code ++]
client,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
### Contract Calls
The `calls` property also accepts **Contract Calls**, and can be used via the `abi`, `functionName`, and `args` properties.
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { bundlerClient, publicClient } from './config'
import { wagmiAbi } from './abi' // [!code focus]
const userOperation = await bundlerClient.prepareUserOperation({ // [!code focus:7]
calls: [{
abi: wagmiAbi,
functionName: 'mint',
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
}],
})
```
```ts twoslash [abi.ts] filename="abi.ts"
export const wagmiAbi = [
// ...
{
inputs: [],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
// ...
] as const;
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
export const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...')],
version: '1.1',
})
export const bundlerClient = createBundlerClient({
account,
client,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
## Returns
`UserOperation`
The prepared User Operation.
## Parameters
### account
* **Type:** `SmartAccount`
The Account to use for User Operation execution.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account, // [!code focus]
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}]
})
```
### calls
* **Type:** `{ data: Hex, to: Address, value: bigint }[]`
The calls to execute in the User Operation.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{ // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1') // [!code focus]
}] // [!code focus]
})
```
:::tip
You can also pass raw call data via the `callData` property:
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
callData: '0xdeadbeef', // [!code focus]
})
```
:::
### callGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate the main execution call.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
callGasLimit: 69420n, // [!code focus]
})
```
### dataSuffix (optional)
* **Type:** `Hex`
Data to append to the end of User Operation calldata. Useful for adding [transaction attribution](https://oxlib.sh/ercs/erc8021/Attribution).
If not provided, the `dataSuffix` configured on the Bundler Client (or inherited from the underlying client) will be used.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
dataSuffix: '0xdeadbeef', // [!code focus]
})
```
### factory (optional)
* **Type:** `Address`
Account Factory address.
:::warning
This property should only be populated when the Smart Account has not been deployed yet.
:::
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
factory: '0x1234567890123456789012345678901234567890', // [!code focus]
factoryData: '0xdeadbeef',
})
```
### factoryData (optional)
* **Type:** `Hex`
Call data to execute on the Account Factory to deploy a Smart Account.
:::warning
This property should only be populated when the Smart Account has not been deployed yet.
:::
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
factory: '0x1234567890123456789012345678901234567890',
factoryData: '0xdeadbeef', // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Maximum fee per gas for User Operation execution.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
maxFeePerGas: 420n, // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Maximum priority fee per gas for User Operation execution.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
maxPriorityFeePerGas: 420n,
maxFeePerGas: 10n, // [!code focus]
})
```
### nonce (optional)
* **Type:** `bigint`
Nonce for the User Operation.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
nonce: 10n, // [!code focus]
})
```
### paymaster (optional)
* **Type:** `Address | true | PaymasterClient | PaymasterActions`
Sets Paymaster configuration for the User Operation.
* If `paymaster: Address`, it will use the provided Paymaster contract address for sponsorship.
* If `paymaster: PaymasterClient`, it will use the provided [Paymaster Client](/account-abstraction/clients/paymaster) for sponsorship.
* If `paymaster: true`, it will be assumed that the Bundler Client also supports Paymaster RPC methods (e.g. `pm_getPaymasterData`), and use them for sponsorship.
* If [custom functions](/account-abstraction/clients/bundler#paymastergetpaymasterdata-optional) are provided to `paymaster`, it will use them for sponsorship.
#### Using a Paymaster Contract Address
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB', // [!code focus]
paymasterData: '0xdeadbeef',
})
```
#### Using a Paymaster Client
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const paymasterClient = createPaymasterClient({ // [!code focus]
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}') // [!code focus]
}) // [!code focus]
const hash = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: paymasterClient, // [!code focus]
})
```
#### Using the Bundler Client as Paymaster
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: true, // [!code focus]
})
```
### paymasterContext (optional)
* **Type:** `unknown`
Paymaster specific fields.
:::warning
This property is only available if **`paymaster` is a Paymaster Client**.
:::
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const paymasterClient = createPaymasterClient({
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}')
})
const hash = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: paymasterClient,
paymasterContext: { // [!code focus]
policyId: 'abc123' // [!code focus]
}, // [!code focus]
})
```
### paymasterData (optional)
* **Type:** `Address`
Call data to execute on the Paymaster contract.
:::warning
This property is only available if **`paymaster` is an address**.
:::
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB',
paymasterData: '0xdeadbeef', // [!code focus]
})
```
### paymasterPostOpGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate for the Paymaster post-operation code.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB',
paymasterData: '0xdeadbeef',
paymasterPostOpGasLimit: 69420n, // [!code focus]
})
```
### paymasterVerificationGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate for the Paymaster validation code.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB',
paymasterData: '0xdeadbeef',
paymasterVerificationGasLimit: 69420n, // [!code focus]
})
```
### preVerificationGas (optional)
* **Type:** `bigint`
Extra gas to pay the Bundler.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
preVerificationGas: 69420n, // [!code focus]
})
```
### signature (optional)
* **Type:** `Hex`
Signature for the User Operation.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
signature: '0x...', // [!code focus]
})
```
### stateOverride (optional)
* **Type:** [`StateOverride`](/docs/glossary/types#stateoverride)
The state override set is an optional address-to-state mapping, where each entry specifies some state to be ephemerally overridden prior to executing the call.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
stateOverride: [ // [!code focus]
{ // [!code focus]
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
balance: parseEther('1'), // [!code focus]
stateDiff: [ // [!code focus]
{ // [!code focus]
slot: '0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0', // [!code focus]
value: '0x00000000000000000000000000000000000000000000000000000000000001a4', // [!code focus]
}, // [!code focus]
], // [!code focus]
} // [!code focus]
], // [!code focus]
})
```
### verificationGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate for the verification step.
```ts twoslash
import { bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const userOperation = await bundlerClient.prepareUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
verificationGasLimit: 69420n, // [!code focus]
})
```
# sendUserOperation
Broadcasts a User Operation to the Bundler.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, bundlerClient } from './config'
const hash = await bundlerClient.sendUserOperation({ // [!code focus:7]
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
export const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...')],
version: '1.1',
})
export const bundlerClient = createBundlerClient({
client,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
:::info
The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Bundler](https://www.pimlico.io), [Biconomy's Bundler](https://www.biconomy.io), or another Bundler service.
:::
### Account Hoisting
If you do not wish to pass an `account` to every `sendUserOperation`, you can also hoist the Account on the Bundler Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { bundlerClient } from './config'
const hash = await bundlerClient.sendUserOperation({ // [!code focus:7]
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
export const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...')],
version: '1.1',
})
export const bundlerClient = createBundlerClient({
account, // [!code ++]
client,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
### Contract Calls
The `calls` property also accepts **Contract Calls**, and can be used via the `abi`, `functionName`, and `args` properties.
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { bundlerClient, publicClient } from './config'
import { wagmiAbi } from './abi' // [!code focus]
const hash = await bundlerClient.sendUserOperation({ // [!code focus:7]
calls: [{
abi: wagmiAbi,
functionName: 'mint',
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
}],
})
```
```ts twoslash [abi.ts] filename="abi.ts"
export const wagmiAbi = [
// ...
{
inputs: [],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
// ...
] as const;
```
```ts twoslash [config.ts]
import { createPublicClient, http } from 'viem'
import { createBundlerClient, toCoinbaseSmartAccount } from 'viem/account-abstraction'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http()
})
export const account = await toCoinbaseSmartAccount({
client,
owners: [privateKeyToAccount('0x...')],
version: '1.1',
})
export const bundlerClient = createBundlerClient({
account,
client,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
## Returns
`Hash`
The User Operation hash.
## Parameters
### account
* **Type:** `SmartAccount`
The Account to use for User Operation execution.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account, // [!code focus]
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}]
})
```
### calls
* **Type:** `({ data?: Hex | undefined, to: Address, value?: bigint | undefined } | { abi: Abi, functionName: string, args: unknown[], to: Address, value?: bigint | undefined })[]`
The calls to execute in the User Operation.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{ // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1') // [!code focus]
}, { // [!code focus]
abi: wagmiAbi, // [!code focus]
functionName: 'mint', // [!code focus]
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', // [!code focus]
}] // [!code focus]
})
```
:::tip
You can also pass raw call data via the `callData` property:
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
callData: '0xdeadbeef', // [!code focus]
})
```
:::
### callGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate the main execution call.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
callGasLimit: 69420n, // [!code focus]
})
```
### dataSuffix (optional)
* **Type:** `Hex`
Data to append to the end of User Operation calldata. Useful for adding [transaction attribution](https://oxlib.sh/ercs/erc8021/Attribution).
If not provided, the `dataSuffix` configured on the Bundler Client (or inherited from the underlying client) will be used.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
dataSuffix: '0xdeadbeef', // [!code focus]
})
```
### factory (optional)
* **Type:** `Address`
Account Factory address.
:::warning
This property should only be populated when the Smart Account has not been deployed yet.
:::
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
factory: '0x1234567890123456789012345678901234567890', // [!code focus]
factoryData: '0xdeadbeef',
})
```
### factoryData (optional)
* **Type:** `Hex`
Call data to execute on the Account Factory to deploy a Smart Account.
:::warning
This property should only be populated when the Smart Account has not been deployed yet.
:::
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
factory: '0x1234567890123456789012345678901234567890',
factoryData: '0xdeadbeef', // [!code focus]
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Maximum fee per gas for User Operation execution.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
maxFeePerGas: 420n, // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Maximum priority fee per gas for User Operation execution.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
maxPriorityFeePerGas: 420n,
maxFeePerGas: 10n, // [!code focus]
})
```
### nonce (optional)
* **Type:** `bigint`
Nonce for the User Operation.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
nonce: 10n, // [!code focus]
})
```
### paymaster (optional)
* **Type:** `Address | true | PaymasterClient | PaymasterActions`
Sets Paymaster configuration for the User Operation.
* If `paymaster: Address`, it will use the provided Paymaster contract address for sponsorship.
* If `paymaster: PaymasterClient`, it will use the provided [Paymaster Client](/account-abstraction/clients/paymaster) for sponsorship.
* If `paymaster: true`, it will be assumed that the Bundler Client also supports Paymaster RPC methods (e.g. `pm_getPaymasterData`), and use them for sponsorship.
* If [custom functions](/account-abstraction/clients/bundler#paymastergetpaymasterdata-optional) are provided to `paymaster`, it will use them for sponsorship.
#### Using a Paymaster Contract Address
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB', // [!code focus]
paymasterData: '0xdeadbeef',
})
```
#### Using a Paymaster Client
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const paymasterClient = createPaymasterClient({ // [!code focus]
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}') // [!code focus]
}) // [!code focus]
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: paymasterClient, // [!code focus]
})
```
#### Using the Bundler Client as Paymaster
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: true, // [!code focus]
})
```
### paymasterContext (optional)
* **Type:** `unknown`
Paymaster specific fields.
:::warning
This property is only available if **`paymaster` is a Paymaster Client**.
:::
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const paymasterClient = createPaymasterClient({
transport: http('https://api.pimlico.io/v2/1/rpc?apikey={API_KEY}')
})
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: paymasterClient,
paymasterContext: { // [!code focus]
policyId: 'abc123' // [!code focus]
}, // [!code focus]
})
```
### paymasterData (optional)
* **Type:** `Address`
Call data to execute on the Paymaster contract.
:::warning
This property is only available if **`paymaster` is an address**.
:::
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB',
paymasterData: '0xdeadbeef', // [!code focus]
})
```
### paymasterPostOpGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate for the Paymaster post-operation code.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB',
paymasterData: '0xdeadbeef',
paymasterPostOpGasLimit: 69420n, // [!code focus]
})
```
### paymasterVerificationGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate for the Paymaster validation code.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
paymaster: '0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB',
paymasterData: '0xdeadbeef',
paymasterVerificationGasLimit: 69420n, // [!code focus]
})
```
### preVerificationGas (optional)
* **Type:** `bigint`
Extra gas to pay the Bundler.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
preVerificationGas: 69420n, // [!code focus]
})
```
### signature (optional)
* **Type:** `Hex`
Signature for the User Operation.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
signature: '0x...', // [!code focus]
})
```
### verificationGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate for the verification step.
```ts twoslash
import { account, bundlerClient } from './config'
import { parseEther } from 'viem'
// ---cut---
const hash = await bundlerClient.sendUserOperation({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
verificationGasLimit: 69420n, // [!code focus]
})
```
# waitForUserOperationReceipt
Waits for the User Operation to be included on a [Block](https://viem.sh/docs/glossary/terms#block) (one confirmation), and then returns the User Operation receipt.
## Usage
:::code-group
```ts twoslash [example.ts]
import { bundlerClient } from './client'
const receipt = await bundlerClient.waitForUserOperationReceipt({ // [!code focus:99]
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d'
})
// @log: {
// @log: blockHash: '0xaf1dadb8a98f1282e8f7b42cc3da8847bfa2cf4e227b8220403ae642e1173088',
// @log: blockNumber: 15132008n,
// @log: sender: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
// @log: ...
// @log: status: 'success',
// @log: }
```
```ts twoslash [client.ts] filename="client.ts"
import { http } from 'viem'
import { createBundlerClient } from 'viem/account-abstraction'
import { mainnet } from 'viem/chains'
export const bundlerClient = createBundlerClient({
chain: mainnet,
transport: http('https://public.pimlico.io/v2/1/rpc')
})
```
:::
:::info
The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using [Pimlico's Bundler](https://www.pimlico.io), [Biconomy's Bundler](https://www.biconomy.io), or another Bundler service.
:::
## Returns
`UserOperationReceipt`
The User Operation receipt.
## Parameters
### hash
* **Type:** `'0x${string}'`
A User Operation hash.
```ts twoslash
import { bundlerClient } from './client'
// ---cut---
const receipt = await bundlerClient.waitForUserOperationReceipt({
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d' // [!code focus]
})
```
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms).
```ts twoslash
import { bundlerClient } from './client'
// ---cut---
const receipt = await bundlerClient.waitForUserOperationReceipt({
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
pollingInterval: 1_000 // [!code focus]
})
```
### retryCount (optional)
* **Type:** `number`
* **Default:** `6`
The number of times to retry.
```ts twoslash
import { bundlerClient } from './client'
// ---cut---
const receipt = await bundlerClient.waitForUserOperationReceipt({
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
retryCount: 3 // [!code focus]
})
```
### timeout (optional)
* **Type:** `number`
Optional timeout (in ms) to wait before stopping polling.
```ts twoslash
import { bundlerClient } from './client'
// ---cut---
const receipt = await bundlerClient.waitForUserOperationReceipt({
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
timeout: 30_000 // [!code focus]
})
```
# getPaymasterData
Retrieves paymaster-related User Operation properties to be used for sending the User Operation.
Internally uses [ERC-7677's `pm_getPaymasterData` method](https://github.com/ethereum/ERCs/blob/master/ERCS/erc-7677.md#pm_getpaymasterdata).
## Usage
:::code-group
```ts twoslash [example.ts]
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
```ts twoslash [config.ts] filename="config.ts"
import { http } from 'viem'
import { createPaymasterClient } from 'viem/account-abstraction'
export const paymasterClient = createPaymasterClient({
transport: http('https://public.pimlico.io/v2/11155111/rpc'),
})
```
:::
## Returns
```ts
{
paymaster: Address
paymasterData: Hex
paymasterVerificationGasLimit: bigint
paymasterPostOpGasLimit: bigint
}
```
Paymasted-related User Operation properties.
## Parameters
### callData
* **Type:** `Hex`
The data to pass to the `sender` during the main execution call.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000', // [!code focus]
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### callGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate the main execution call.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n, // [!code focus]
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### chainId
* **Type:** `number`
Chain ID to target.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
chainId: 1, // [!code focus]
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### context (optional)
* **Type:** `unknown`
Paymaster specific fields.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
context: { // [!code focus]
policyId: 'abc123', // [!code focus]
}, // [!code focus]
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### entryPointAddress
* **Type:** `Address`
EntryPoint address to target.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
chainId: 1,
entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', // [!code focus]
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### factory (optional)
* **Type:** `Address`
Account Factory address.
:::warning
This property should only be populated when the Smart Account has not been deployed yet.
:::
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e', // [!code focus]
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### factoryData (optional)
* **Type:** `Hex`
Call data to execute on the Account Factory to deploy a Smart Account.
:::warning
This property should only be populated when the Smart Account has not been deployed yet.
:::
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000', // [!code focus]
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Maximum fee per gas for User Operation execution.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n, // [!code focus]
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Maximum priority fee per gas for User Operation execution.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n, // [!code focus]
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### nonce
* **Type:** `bigint`
Nonce for the User Operation.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n, // [!code focus]
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### preVerificationGas (optional)
* **Type:** `bigint`
Extra gas to pay the Bundler.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
preVerificationGas: 69420n, // [!code focus]
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### sender
* **Type:** `Address`
Sender for the User Operation.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
preVerificationGas: 69420n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f', // [!code focus]
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### signature
* **Type:** `Hex`
Signature for the User Operation.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
preVerificationGas: 69420n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c' // [!code focus]
})
```
### verificationGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate for the verification step.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c',
verificationGasLimit: 69420n, // [!code focus]
})
```
# getPaymasterStubData
Retrieves paymaster-related User Operation properties to be used for User Operation gas estimation.
Internally uses [ERC-7677's `pm_getPaymasterStubData` method](https://github.com/ethereum/ERCs/blob/master/ERCS/erc-7677.md#pm_getpaymasterstubdata).
## Usage
:::code-group
```ts twoslash [example.ts]
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
```ts twoslash [config.ts] filename="config.ts"
import { http } from 'viem'
import { createPaymasterClient } from 'viem/account-abstraction'
export const paymasterClient = createPaymasterClient({
transport: http('https://public.pimlico.io/v2/11155111/rpc'),
})
```
:::
## Returns
```ts
{
isFinal: boolean
paymaster: Address
paymasterData: Hex
paymasterVerificationGasLimit: bigint
paymasterPostOpGasLimit: bigint
sponsor: { name: string; icon: string }
}
```
Paymasted-related User Operation properties.
## Parameters
### callData
* **Type:** `Hex`
The data to pass to the `sender` during the main execution call.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000', // [!code focus]
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### callGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate the main execution call.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n, // [!code focus]
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### chainId
* **Type:** `number`
Chain ID to target.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
chainId: 1, // [!code focus]
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### context (optional)
* **Type:** `unknown`
Paymaster specific fields.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
context: { // [!code focus]
policyId: 'abc123', // [!code focus]
}, // [!code focus]
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### entryPointAddress
* **Type:** `Address`
EntryPoint address to target.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
chainId: 1,
entryPointAddress: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', // [!code focus]
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### factory (optional)
* **Type:** `Address`
Account Factory address.
:::warning
This property should only be populated when the Smart Account has not been deployed yet.
:::
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e', // [!code focus]
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### factoryData (optional)
* **Type:** `Hex`
Call data to execute on the Account Factory to deploy a Smart Account.
:::warning
This property should only be populated when the Smart Account has not been deployed yet.
:::
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000', // [!code focus]
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Maximum fee per gas for User Operation execution.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n, // [!code focus]
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Maximum priority fee per gas for User Operation execution.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n, // [!code focus]
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### nonce
* **Type:** `bigint`
Nonce for the User Operation.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n, // [!code focus]
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### preVerificationGas (optional)
* **Type:** `bigint`
Extra gas to pay the Bundler.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
preVerificationGas: 69420n, // [!code focus]
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### sender
* **Type:** `Address`
Sender for the User Operation.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
preVerificationGas: 69420n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f', // [!code focus]
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c'
})
```
### signature
* **Type:** `Hex`
Signature for the User Operation.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
preVerificationGas: 69420n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c' // [!code focus]
})
```
### verificationGasLimit (optional)
* **Type:** `bigint`
The amount of gas to allocate for the verification step.
```ts twoslash
import { paymasterClient } from './config'
const paymasterArgs = await paymasterClient.getPaymasterStubData({
callData: '0xb61d27f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000',
callGasLimit: 69420n,
factory: '0xfb6dab6200b8958c2655c3747708f82243d3f32e',
factoryData: '0xf14ddffc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb922660000000000000000000000000000000000000000000000000000000000000000',
maxFeePerGas: 14510554812n,
maxPriorityFeePerGas: 2000000000n,
nonce: 0n,
sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
signature: '0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c',
verificationGasLimit: 69420n, // [!code focus]
})
```
# createNonceManager \[Creates a Nonce Manager for automatic nonce generation]
Creates a new Nonce Manager instance to be used with a [Local Account](/docs/accounts/local). The Nonce Manager is used to automatically manage & generate nonces for transactions.
:::warning
A Nonce Manager can only be used with [Local Accounts](/docs/accounts/local) (ie. Private Key, Mnemonic, etc).
For [JSON-RPC Accounts](/docs/accounts/jsonRpc) (ie. Browser Extension, WalletConnect, Backend, etc), the Wallet or Backend will manage the nonces.
:::
## Import
```ts twoslash
import { createNonceManager } from 'viem/nonce'
```
## Usage
A Nonce Manager can be instantiated with the `createNonceManager` function with a provided `source`.
The example below demonstrates how to create a Nonce Manager with a JSON-RPC source (ie. uses `eth_getTransactionCount` as the source of truth).
```ts twoslash
import { createNonceManager, jsonRpc } from 'viem/nonce'
const nonceManager = createNonceManager({
source: jsonRpc()
})
```
:::tip
Viem also exports a default `nonceManager` instance that you can use directly.
```ts twoslash
import { nonceManager } from 'viem'
```
:::
### Integration with Local Accounts
A `nonceManager` can be passed as an option to [Local Accounts](/docs/accounts/local) to automatically manage nonces for transactions.
:::code-group
```ts twoslash [example.ts]
import { privateKeyToAccount, nonceManager } from 'viem/accounts' // [!code focus]
import { client } from './config'
const account = privateKeyToAccount('0x...', { nonceManager }) // [!code focus]
const hashes = await Promise.all([ // [!code focus]
// @log: ↓ nonce = 0
client.sendTransaction({ // [!code focus]
account, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('0.1'), // [!code focus]
}), // [!code focus]
// @log: ↓ nonce = 1
client.sendTransaction({ // [!code focus]
account, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('0.2'), // [!code focus]
}), // [!code focus]
]) // [!code focus]
```
```ts twoslash [config.ts] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createWalletClient({
chain: mainnet,
transport: http(),
})
```
:::
## Return Type
`NonceManager`
The Nonce Manager.
## Parameters
### source
* **Type:** `NonceManagerSource`
The source of truth for the Nonce Manager.
Available sources:
* `jsonRpc`
```ts twoslash
import { createNonceManager, jsonRpc } from 'viem/nonce'
const nonceManager = createNonceManager({
source: jsonRpc() // [!code focus]
})
```
# hdKeyToAccount \[A function to create a Hierarchical Deterministic (HD) Account.]
A [Hierarchical Deterministic (HD)](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#abstract) Account is derived from a [HD Key](https://github.com/paulmillr/scure-bip32#usage) and an optional HD path.
It has the ability to sign transactions and messages with the private key derived from the HD Node.
:::info
viem internally uses [`@scure/bip32`](https://github.com/paulmillr/scure-bip32), an **audited** implementation of [BIP-32 HD wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#abstract), for hierarchical deterministic (HD) wallet derivation.
:::
## Import
```ts twoslash
import { HDKey, hdKeyToAccount } from 'viem/accounts'
```
> Note: viem [re-exports `HDKey`](https://github.com/paulmillr/scure-bip32#usage) from `@scure/bip32`.
## Usage
To initialize a HD Account, you will need to pass a [`HDKey` instance](https://github.com/paulmillr/scure-bip32#usage) to `hdKeyToAccount`.
The `HDKey` instance comes with a few static methods to derive a HD Key:
* `fromMasterSeed`
* `fromExtendedKey`
* `fromJSON`
```ts twoslash
// @noErrors
import { createWalletClient, http } from 'viem'
import { HDKey, hdKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const hdKey = HDKey.fromMasterSeed(...) // [!code focus:3]
const hdKey = HDKey.fromExtendedKey(...)
const hdKey = HDKey.fromJSON({ xpriv: ... })
const account = hdKeyToAccount(hdKey) // [!code focus]
const client = createWalletClient({
account,
chain: mainnet,
transport: http(),
})
```
## Parameters
### hdKey
* **Type:** `string`
The BIP-39 mnemonic phrase.
```ts twoslash
// @noErrors
import { hdKeyToAccount } from 'viem/accounts'
// ---cut---
const hdKey = HDKey.fromMasterSeed(...)
const account = hdKeyToAccount(
hdKey, // [!code focus]
)
```
### options.accountIndex
* **Type:** `number`
* **Default:** `0`
The account index to use in the path (`"m/44'/60'/${accountIndex}'/0/0"`) to derive a private key.
```ts twoslash
// @noErrors
import { hdKeyToAccount } from 'viem/accounts'
// ---cut---
const hdKey = HDKey.fromMasterSeed(...)
const account = hdKeyToAccount(
hdKey,
{
accountIndex: 1 // [!code focus]
}
)
```
### options.addressIndex
* **Type:** `number`
* **Default:** `0`
The address index to use in the path (`"m/44'/60'/0'/0/${addressIndex}"`) to derive a private key.
```ts twoslash
// @noErrors
import { hdKeyToAccount } from 'viem/accounts'
// ---cut---
const hdKey = HDKey.fromMasterSeed(...)
const account = hdKeyToAccount(
hdKey,
{
accountIndex: 1,
addressIndex: 6 // [!code focus]
}
)
```
### options.changeIndex
* **Type:** `number`
* **Default:** `0`
The change index to use in the path (`"m/44'/60'/0'/${changeIndex}/0"`) to derive a private key.
```ts twoslash
// @noErrors
import { hdKeyToAccount } from 'viem/accounts'
// ---cut---
const hdKey = HDKey.fromMasterSeed(...)
const account = hdKeyToAccount(
hdKey,
{
accountIndex: 1,
addressIndex: 6,
changeIndex: 2 // [!code focus]
}
)
```
### options.path
* **Type:** `"m/44'/60'/${string}"`
The HD path to use to derive a private key.
```ts twoslash
// @noErrors
import { hdKeyToAccount } from 'viem/accounts'
// ---cut---
const hdKey = HDKey.fromMasterSeed(...)
const account = hdKeyToAccount(
hdKey,
{
path: "m/44'/60'/5'/0/2" // [!code focus]
}
)
```
# mnemonicToAccount \[A function to create a Mnemonic Account.]
A Mnemonic Account is a [Hierarchical Deterministic (HD) Account](/docs/accounts/local/hdKeyToAccount) that is derived from a [BIP-39 mnemonic phrase](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) and an optional HD path.
It has the ability to sign transactions and messages with the private key derived from the HD Node.
:::info
viem internally uses [`@scure/bip32`](https://github.com/paulmillr/scure-bip32), an **audited** implementation of [BIP-32 HD wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#abstract), for hierarchical deterministic (HD) wallet derivation.
:::
## Import
```ts twoslash
import { mnemonicToAccount } from 'viem/accounts'
```
## Usage
To initialize a Mnemonic Account, you will need to pass a mnemonic phrase to `mnemonicToAccount`:
```ts twoslash
import { createWalletClient, http } from 'viem'
import { mnemonicToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = mnemonicToAccount('legal winner thank year wave sausage worth useful legal winner thank yellow') // [!code focus]
const client = createWalletClient({
account,
chain: mainnet,
transport: http()
})
```
> Note: the above is a valid mnemonic, but it is not a "real" mnemonic. Please do not use it for anything other than testing.
### Generating Mnemonics
You can generate a random BIP-39 mnemonic using the `generateMnemonic` function with a wordlist:
```ts twoslash
import { english, generateMnemonic } from 'viem/accounts'
const mnemonic = generateMnemonic(english)
```
:::tip
You can customize the strength of the generated mnemonic by passing a value between 128 and 256 as the second argument to the `generateMnemonic` function. This value must be a multiple of 32.
:::
Available wordlists:
* `czech`
* `english`
* `french`
* `italian`
* `japanese`
* `korean`
* `portuguese`
* `simplifiedChinese`
* `spanish`
* `traditionalChinese`
## Parameters
### mnemonic
* **Type:** `string`
The BIP-39 mnemonic phrase.
```ts twoslash
import { mnemonicToAccount } from 'viem/accounts'
// ---cut---
const account = mnemonicToAccount(
'legal winner thank year wave sausage worth useful legal winner thank yellow' // [!code focus]
)
```
### options.passphrase
* **Type:** `string`
The BIP-39 passphrase.
```ts thoslash
import { mnemonicToAccount } from 'viem/accounts'
// ---cut---
const account = mnemonicToAccount(
'legal winner thank year wave sausage worth useful legal winner thank yellow',
{
passphrase: 'passphrase' // [!code focus]
}
)
```
### options.accountIndex
* **Type:** `number`
* **Default:** `0`
The account index to use in the path (`"m/44'/60'/${accountIndex}'/0/0"`) to derive a private key.
```ts twoslash
import { mnemonicToAccount } from 'viem/accounts'
// ---cut---
const account = mnemonicToAccount(
'legal winner thank year wave sausage worth useful legal winner thank yellow',
{
accountIndex: 1 // [!code focus]
}
)
```
### options.addressIndex
* **Type:** `number`
* **Default:** `0`
The address index to use in the path (`"m/44'/60'/0'/0/${addressIndex}"`) to derive a private key.
```ts twoslash
import { mnemonicToAccount } from 'viem/accounts'
// ---cut---
const account = mnemonicToAccount(
'legal winner thank year wave sausage worth useful legal winner thank yellow',
{
accountIndex: 1,
addressIndex: 6 // [!code focus]
}
)
```
### options.changeIndex
* **Type:** `number`
* **Default:** `0`
The change index to use in the path (`"m/44'/60'/0'/${changeIndex}/0"`) to derive a private key.
```ts twoslash
import { mnemonicToAccount } from 'viem/accounts'
// ---cut---
const account = mnemonicToAccount(
'legal winner thank year wave sausage worth useful legal winner thank yellow',
{
accountIndex: 1,
addressIndex: 6,
changeIndex: 2 // [!code focus]
}
)
```
### options.path
* **Type:** `"m/44'/60'/${string}"`
The HD path to use to derive a private key.
```ts twoslash
import { mnemonicToAccount } from 'viem/accounts'
// ---cut---
const account = mnemonicToAccount(
'legal winner thank year wave sausage worth useful legal winner thank yellow',
{
path: "m/44'/60'/5'/0/2" // [!code focus]
}
)
```
# privateKeyToAccount \[A function to create a Private Key Account.]
A Private Key Account is an interface that has the ability to sign transactions and messages with a given private key.
:::info
viem internally uses [`@noble/curves`](https://github.com/paulmillr/noble-curves), an **audited** implementation of [secp256k1](https://www.secg.org/sec2-v2.pdf), for our private key & signing implementation.
:::
## Import
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
```
## Usage
To initialize a Private Key Account, you will need to pass a private key to `privateKeyToAccount`:
```ts twoslash
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80') // [!code focus]
const client = createWalletClient({
account,
chain: mainnet,
transport: http()
})
```
> Note: the above is a valid private key, but it is not a "real" private key. Please do not use it for anything other than testing.
### Generating Private Keys
You can generate a random private key using the `generatePrivateKey` function:
```ts twoslash
import { generatePrivateKey } from 'viem/accounts'
const privateKey = generatePrivateKey()
```
## Parameters
### privateKey
* **Type:** `Hex`
The private key to use for the Account.
# signMessage (Local Account) \[Signs a message with the Account's private key.]
Calculates an Ethereum-specific signature in [EIP-191 format](https://eips.ethereum.org/EIPS/eip-191): `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`.
With the calculated signature, you can:
* use [`verifyMessage`](/docs/utilities/verifyMessage) to verify the signature,
* use [`recoverMessageAddress`](/docs/utilities/recoverMessageAddress) to recover the signing address from a signature.
## Usage
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
const signature = await account.signMessage({
// Hex data representation of message.
message: { raw: '0x68656c6c6f20776f726c64' },
})
// @log: Output: "0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"
```
## Returns
[`Hex`](/docs/glossary/types#hex)
The signed message.
## Parameters
### message
* **Type:** `string | { raw: Hex | ByteArray }`
Message to sign.
By default, viem signs the UTF-8 representation of the message.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signMessage({
message: 'hello world', // [!code focus:1]
})
```
To sign the data representation of the message, you can use the `raw` attribute.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signMessage({
message: { raw: '0x68656c6c6f20776f726c64' }, // [!code focus:1]
})
```
# signTransaction (Local Account) \[Signs a transaction with the Account's private key.]
Signs a transaction with the Account's private key.
## Usage
```ts twoslash
import { parseGwei } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
const signature = await account.signTransaction({
chainId: 1,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('3'),
gas: 21000n,
nonce: 69,
to: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
})
// @log: Output: "0x02f850018203118080825208808080c080a04012522854168b27e5dc3d5839bab5e6b39e1a0ffd343901ce1622e3d64b48f1a04e00902ae0502c4728cbf12156290df99c3ed7de85b1dbfe20b5c36931733a33"
```
### Custom serializer
viem has a built-in serializer for **Legacy**, **EIP-2930** (`0x01`) and **EIP-1559** (`0x02`) transaction types. If you would like to serialize on another transaction type that viem does not support internally, you can pass a custom serializer.
```ts
import { parseGwei } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
const signature = await account.signTransaction({
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('3'),
gas: 21000n,
nonce: 69,
to: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
}, {
serializer(transaction) { // [!code focus:16]
const {
chainId,
nonce,
// ...
} = transaction
return concatHex([
'0x69',
toRlp([
toHex(chainId),
nonce ? toHex(nonce) : '0x',
// ...
]),
])
}
})
```
## Returns
[`Hex`](/docs/glossary/types#Hex)
The signed transaction.
## Parameters
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signTransaction({
accessList: [ // [!code focus:6]
{
address: '0x1',
storageKeys: ['0x1'],
},
],
chainId: 1,
})
```
### authorizationList (optional)
* **Type:** `AuthorizationList`
Signed EIP-7702 Authorization list.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const authorization = await account.signAuthorization({
contractAddress: '0x...',
chainId: 1,
nonce: 1,
})
const signature = await account.signTransaction({
authorizationList: [authorization], // [!code focus]
chainId: 1,
})
```
### blobs (optional)
* **Type:** `Hex[]`
Blobs for [Blob Transactions](/docs/guides/blob-transactions).
```ts
import * as cKzg from 'c-kzg'
import { toBlobs, setupKzg, stringToHex } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
const hash = await account.signTransaction({
blobs: toBlobs({ data: stringToHex('blobby blob!') }), // [!code focus]
kzg,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### chainId (optional)
* **Type:** `number`
The chain ID.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signTransaction({
chainId: 1, // [!code focus]
})
```
### data (optional)
* **Type:** `0x${string}`
Transaction data.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signTransaction({
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' // [!code focus]
})
```
### gas (optional)
* **Type:** `bigint`
The gas limit for the transaction.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signTransaction({
gas: 69420n, // [!code focus]
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts twoslash
import { parseGwei } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signTransaction({
gasPrice: parseGwei('20'), // [!code focus]
})
```
### kzg (optional)
* **Type:** `KZG`
KZG implementation for [Blob Transactions](/docs/guides/blob-transactions).
See [`setupKzg`](/docs/utilities/setupKzg) for more information.
```ts
import * as cKzg from 'c-kzg'
import { toBlobs, setupKzg, stringToHex } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath) // [!code focus]
const signature = await account.signTransaction({
blobs: toBlobs({ data: stringToHex('blobby blob!') }), // [!code focus]
kzg, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
import { parseGwei } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signTransaction({
chainId: 1,
maxFeePerGas: parseGwei('20'), // [!code focus]
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
import { parseGwei } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signTransaction({
chainId: 1,
maxPriorityFeePerGas: parseGwei('3'), // [!code focus]
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signTransaction({
nonce: 69 // [!code focus]
})
```
### to (optional)
* **Type:** `Address`
The transaction recipient.
```ts twoslash
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signTransaction({
to: '0x...' // [!code focus]
})
```
### type (optional)
* **Type:** `"legacy" | "eip2930" | "eip1559"`
The transaction type.
```ts twoslash
// @noErrors
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signTransaction({
type: 'eip1559' // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction.
```ts twoslash
import { parseEther } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount('0x...')
// ---cut---
const signature = await account.signTransaction({
value: parseEther('1'), // [!code focus]
})
```
# signTypedData (Local Account) \[Signs typed data with the Account's private key.]
Signs typed data and calculates an Ethereum-specific signature in [https://eips.ethereum.org/EIPS/eip-712](https://eips.ethereum.org/EIPS/eip-712): `sign(keccak256("\x19\x01" ‖ domainSeparator ‖ hashStruct(message)))`
## Usage
:::code-group
```ts twoslash [example.ts]
import { privateKeyToAccount } from 'viem/accounts'
import { domain, types } from './data'
const account = privateKeyToAccount('0x...')
const signature = await account.signTypedData({
domain,
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
```ts twoslash [data.ts] filename="data.ts"
// All properties on a domain are optional
export const domain = {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
} as const
// The named list of all type definitions
export const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
} as const
```
:::
## Returns
`0x${string}`
The signed data.
## Parameters
### domain
**Type:** `TypedDataDomain`
The typed data domain.
```ts
const signature = await account.signTypedData({
domain: { // [!code focus:6]
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### types
The type definitions for the typed data.
```ts
const signature = await account.signTypedData({
domain,
types: { // [!code focus:11]
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### primaryType
**Type:** Inferred `string`.
The primary type to extract from `types` and use in `value`.
```ts
const signature = await account.signTypedData({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [ // [!code focus:5]
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail', // [!code focus]
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### message
**Type:** Inferred from `types` & `primaryType`.
```ts
const signature = await account.signTypedData({
domain,
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: { // [!code focus:11]
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
# toAccount \[A function to create a Custom Account.]
Creates an Account from a custom signing implementation
## Import
```ts
import { toAccount } from 'viem/accounts'
```
## Usage
```ts
import {
signMessage,
signTransaction,
signTypedData,
privateKeyToAddress,
toAccount
} from 'viem/accounts'
const privateKey = '0x...'
const account = toAccount({ // [!code focus:15]
address: getAddress(privateKey),
async signMessage({ message }) {
return signMessage({ message, privateKey })
},
async signTransaction(transaction, { serializer }) {
return signTransaction({ privateKey, transaction, serializer })
},
async signTypedData(typedData) {
return signTypedData({ ...typedData, privateKey })
},
})
```
## Parameters
### address
* **Type:** `Address`
The Address of the Account.
```ts
const account = toAccount({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // [!code focus]
async signMessage({ message }) {
return signMessage({ message, privateKey })
},
async signTransaction(transaction, { serializer }) {
return signTransaction({ privateKey, transaction, serializer })
},
async signTypedData(typedData) {
return signTypedData({ ...typedData, privateKey })
},
})
```
### signMessage
Function to sign a message in [EIP-191 format](https://eips.ethereum.org/EIPS/eip-191).
```ts
const account = toAccount({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
async signMessage({ message }) { // [!code focus:3]
return signMessage({ message, privateKey })
},
async signTransaction(transaction, { serializer }) {
return signTransaction({ privateKey, transaction, serializer })
},
async signTypedData(typedData) {
return signTypedData({ ...typedData, privateKey })
},
})
```
### signTransaction
Function to sign a transaction.
```ts
const account = toAccount({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
async signMessage({ message }) {
return signMessage({ message, privateKey })
},
async signTransaction(transaction, { serializer }) { // [!code focus:3]
return signTransaction({ privateKey, transaction, serializer })
},
async signTypedData(typedData) {
return signTypedData({ ...typedData, privateKey })
},
})
```
### signTypedData
Function to sign [EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed data.
```ts
const account = toAccount({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
async signMessage({ message }) {
return signMessage({ message, privateKey })
},
async signTransaction(transaction, { serializer }) {
return signTransaction({ privateKey, transaction, serializer })
},
async signTypedData(typedData) { // [!code focus:3]
return signTypedData({ ...typedData, privateKey })
},
})
```
# call \[An Action for executing a new message call.]
Executes a new message call immediately without submitting a transaction to the network.
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, publicClient } from './config'
const data = await publicClient.call({ // [!code focus:7]
account,
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
// @log: ↓ JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// @log: ↓ Local Account
// export const account = privateKeyToAccount(...)
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Deployless Calls
It is possible to call a function on a contract that has not been deployed yet. For instance, we may want
to call a function on an [ERC-4337 Smart Account](https://eips.ethereum.org/EIPS/eip-4337) contract which has not been deployed.
Viem offers two ways of performing a Deployless Call, via:
* [Bytecode](#bytecode)
* a [Deploy Factory](#deploy-factory): "temporarily deploys" a contract with a provided [Deploy Factory](https://docs.alchemy.com/docs/create2-an-alternative-to-deriving-contract-addresses#create2-contract-factory), and calls the function on the deployed contract.
:::tip
The **Deployless Call** pattern is also accessible via the [`readContract`](/docs/contract/readContract#deployless-reads) & [Contract Instance](/docs/contract/getContract) APIs.
:::
#### Bytecode
The example below demonstrates how we can utilize a Deployless Call **via Bytecode** to call the `name` function on the [Wagmi Example ERC721 contract](https://etherscan.io/address/0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2#code) which has not been deployed:
:::code-group
```ts twoslash [example.ts]
import { encodeFunctionData, parseAbi } from 'viem'
import { publicClient } from './config'
const data = await publicClient.call({
// Bytecode of the contract. Accessible here: https://etherscan.io/address/0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2#code
code: '0x...',
// Function to call on the contract.
data: encodeFunctionData({
abi: parseAbi(['function name() view returns (string)']),
functionName: 'name'
}),
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
#### Deploy Factory
The example below demonstrates how we can utilize a Deployless Call **via a [Deploy Factory](https://docs.alchemy.com/docs/create2-an-alternative-to-deriving-contract-addresses#create2-contract-factory)** to call the `entryPoint` function on an [ERC-4337 Smart Account](https://eips.ethereum.org/EIPS/eip-4337) which has not been deployed:
:::code-group
```ts twoslash [example.ts]
import { encodeFunctionData, parseAbi } from 'viem'
import { owner, publicClient } from './config'
const data = await publicClient.call({
// Address of the contract deployer (e.g. Smart Account Factory).
factory: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb',
// Function to execute on the factory to deploy the contract.
factoryData: encodeFunctionData({
abi: parseAbi(['function createAccount(address owner, uint256 salt)']),
functionName: 'createAccount',
args: [owner, 0n],
}),
// Function to call on the contract (e.g. Smart Account contract).
data: encodeFunctionData({
abi: parseAbi(['function entryPoint() view returns (address)']),
functionName: 'entryPoint'
}),
// Address of the contract.
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const owner = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
:::note
This example utilizes the [SimpleAccountFactory](https://github.com/eth-infinitism/account-abstraction/blob/develop/contracts/samples/SimpleAccountFactory.sol).
:::
## Returns
`0x${string}`
The call data.
## Parameters
### account
* **Type:** `Account | Address`
The Account to call from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### data
* **Type:** `0x${string}`
A contract hashed method call with encoded args.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### to
* **Type:** [`Address`](/docs/glossary/types#address)
The contract address or recipient.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
accessList: [ // [!code focus:6]
{
address: '0x1',
storageKeys: ['0x1'],
},
],
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the call against.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const data = await publicClient.call({
blockNumber: 15121123n, // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the call against.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const data = await publicClient.call({
blockTag: 'safe', // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### code (optional)
* **Type:**
Bytecode to perform the call against.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const data = await publicClient.call({
code: '0x...', // [!code focus]
data: '0xdeadbeef',
})
```
### factory (optional)
* **Type:**
Contract deployment factory address (ie. Create2 factory, Smart Account factory, etc).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
factory: '0x0000000000ffe8b47b3e2130213b802212439497', // [!code focus]
factoryData: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### factoryData (optional)
* **Type:**
Calldata to execute on the factory to deploy the contract.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
factory: '0x0000000000ffe8b47b3e2130213b802212439497',
factoryData: '0xdeadbeef', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### gas (optional)
* **Type:** `bigint`
The gas provided for transaction execution.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
gas: 1_000_000n, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseGwei } from 'viem'
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseGwei } from 'viem'
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseGwei } from 'viem'
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### nonce (optional)
* **Type:** `bigint`
Unique number identifying this transaction.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
nonce: 420, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### stateOverride (optional)
* **Type:** [`StateOverride`](/docs/glossary/types#stateoverride)
The state override set is an optional address-to-state mapping, where each entry specifies some state to be ephemerally overridden prior to executing the call.
```ts
const data = await publicClient.call({
account,
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
stateOverride: [ // [!code focus]
{ // [!code focus]
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
balance: parseEther('1'), // [!code focus]
stateDiff: [ // [!code focus]
{ // [!code focus]
slot: '0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0', // [!code focus]
value: '0x00000000000000000000000000000000000000000000000000000000000001a4', // [!code focus]
}, // [!code focus]
], // [!code focus]
} // [!code focus]
], // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const data = await publicClient.call({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'), // [!code focus]
})
```
## JSON-RPC Methods
[`eth_call`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call)
# createAccessList
Creates an [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) access list based on a transaction request.
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, publicClient } from './config'
const result = await publicClient.createAccessList({ // [!code focus:7]
data: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`{ accessList: AccessList, gasUsed: bigint }`
The access list and gas used.
## Parameters
### account (optional)
* **Type:** `Account | Address`
The Account to create an access list for.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const result = await publicClient.createAccessList({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
data: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### blockNumber (optional)
* **Type:** `number`
Block number to create an access list for.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const result = await publicClient.createAccessList({
blockNumber: 15121123n, // [!code focus]
data: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
Block tag to create an access list for.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const result = await publicClient.createAccessList({
blockTag: 'safe', // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### data (optional)
* **Type:** `0x${string}`
Contract function selector with encoded arguments.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const result = await publicClient.createAccessList({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xdeadbeef', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther, parseGwei } from 'viem'
const result = await publicClient.createAccessList({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xdeadbeef',
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther, parseGwei } from 'viem'
const result = await publicClient.createAccessList({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xdeadbeef',
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther, parseGwei } from 'viem'
const result = await publicClient.createAccessList({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xdeadbeef',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### to (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Transaction recipient.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const result = await publicClient.createAccessList({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const result = await publicClient.createAccessList({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
data: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
})
```
# createBlockFilter \[An Action for creating a new Block Filter.]
Creates a Filter to listen for new block hashes that can be used with [`getFilterChanges`](/docs/actions/public/getFilterChanges).
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const filter = await publicClient.createBlockFilter() // [!code focus:99]
// @log: { id: "0x345a6572337856574a76364e457a4366", type: 'block' }
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
[`Filter`](/docs/glossary/types#filter)
## JSON-RPC Methods
[`eth_newBlockFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newBlockFilter)
# createEventFilter \[An Action for creating a new Event Filter.]
Creates a Filter to listen for new events that can be used with [`getFilterChanges`](/docs/actions/public/getFilterChanges).
## Usage
By default, an Event Filter with no arguments will query for/listen to all events.
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const filter = await publicClient.createEventFilter()
// @log: { id: "0x345a6572337856574a76364e457a4366", type: 'event' }
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
:::tip
Check out [`createContractEventFilter`](/docs/contract/createContractEventFilter) if you are after a first-class solution for querying events on a contract without needing to manually craft ABI event parameters.
:::
## Scoping
You can also scope a Filter to a set of given attributes (listed below).
### Address
A Filter can be scoped to an **address**:
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const filter = await publicClient.createEventFilter({
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2' // [!code focus]
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Event
A Filter can be scoped to an **event**.
The `event` argument takes in an event in ABI format – we have a [`parseAbiItem` utility](/docs/abi/parseAbiItem) that you can use to convert from a human-readable event signature → ABI.
:::code-group
```ts twoslash [example.ts]
import { parseAbiItem } from 'viem' // [!code focus]
import { publicClient } from './client'
const filter = await publicClient.createEventFilter({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'), // [!code focus]
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
By default, `event` accepts the [`AbiEvent`](/docs/glossary/types#abievent) type:
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const filter = await publicClient.createEventFilter(publicClient, {
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: { // [!code focus:99]
name: 'Transfer',
inputs: [
{ type: 'address', indexed: true, name: 'from' },
{ type: 'address', indexed: true, name: 'to' },
{ type: 'uint256', indexed: false, name: 'value' }
]
}
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Arguments
A Filter can be scoped to given ***indexed* arguments**:
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const filter = await publicClient.createEventFilter({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
args: { // [!code focus:4]
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
}
})
```
Only indexed arguments in `event` are candidates for `args`.
A Filter Argument can also be an array to indicate that other values can exist in the position:
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const filter = await publicClient.createEventFilter({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
args: { // [!code focus:8]
// '0xd8da...' OR '0xa5cc...' OR '0xa152...'
from: [
'0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
'0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac',
'0xa152f8bb749c55e9943a3a0a3111d18ee2b3f94e',
],
}
})
```
### Block Range
A Filter can be scoped to a **block range**:
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const filter = await publicClient.createEventFilter({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
fromBlock: 16330000n, // [!code focus]
toBlock: 16330050n // [!code focus]
})
```
### Multiple Events
A Filter can be scoped to **multiple events**:
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbi } from 'viem'
const filter = await publicClient.createEventFilter({
events: parseAbi([ // [!code focus:4]
'event Approval(address indexed owner, address indexed sender, uint256 value)',
'event Transfer(address indexed from, address indexed to, uint256 value)',
]),
})
```
Note: A Filter scoped to multiple events cannot be also scoped with [indexed arguments](#arguments) (`args`).
### Strict Mode
By default, `createEventFilter` will include logs that [do not conform](/docs/glossary/terms#non-conforming-log) to the indexed & non-indexed arguments on the `event`.
viem will not return a value for arguments that do not conform to the ABI, thus, some arguments on `args` may be undefined.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const filter = await publicClient.createEventFilter({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
})
const logs = await publicClient.getFilterLogs({ filter })
logs[0].args
// ^?
```
You can turn on `strict` mode to only return logs that conform to the indexed & non-indexed arguments on the `event`, meaning that `args` will always be defined. The trade-off is that non-conforming logs will be filtered out.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const filter = await publicClient.createEventFilter({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
strict: true
})
const logs = await publicClient.getFilterLogs({ filter })
logs[0].args
// ^?
```
## Returns
[`Filter`](/docs/glossary/types#filter)
## Parameters
### address (optional)
* **Type:** `Address | Address[]`
The contract address or a list of addresses from which Logs should originate.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const filter = await publicClient.createEventFilter({
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2' // [!code focus]
})
```
### event (optional)
* **Type:** [`AbiEvent`](/docs/glossary/types#abievent)
The event in ABI format.
A [`parseAbiItem` utility](/docs/abi/parseAbiItem) is exported from viem that converts from a human-readable event signature → ABI.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem' // [!code focus]
const filter = await publicClient.createEventFilter({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'), // [!code focus]
})
```
### args (optional)
* **Type:** Inferred.
A list of *indexed* event arguments.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const filter = await publicClient.createEventFilter({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
args: { // [!code focus:4]
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
}
})
```
### fromBlock (optional)
* **Type:** `bigint`
Block to start querying/listening from.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const filter = await publicClient.createEventFilter({
fromBlock: 69420n // [!code focus]
})
```
### toBlock (optional)
* **Type:** `bigint`
Block to query/listen until.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const filter = await publicClient.createEventFilter({
toBlock: 70120n // [!code focus]
})
```
## JSON-RPC Methods
[`eth_newFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newfilter)
# createPendingTransactionFilter \[An Action for creating a new pending transaction filter.]
Creates a Filter to listen for new pending transaction hashes that can be used with [`getFilterChanges`](/docs/actions/public/getFilterChanges).
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const filter = await publicClient.createPendingTransactionFilter() // [!code focus:99]
// @log: Output: { id: "0x345a6572337856574a76364e457a4366", type: 'transaction' }
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
[`Filter`](/docs/glossary/types#filter)
## JSON-RPC Methods
[`eth_newPendingTransactionFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newpendingtransactionfilter)
# estimateFeesPerGas
Returns an estimate for the fees per gas (in wei) for a transaction to be likely included in the next block.
If [`chain.fees.estimateFeesPerGas`](/docs/actions/public/estimateFeesPerGas) is set on the [Client Chain](/docs/clients/public#chain-optional) or [override Chain](#chain-optional), it will use the returned value.
Otherwise, for EIP-1559 Transactions, viem will estimate the fees using a combination of the block's base fee per gas (to derive `maxFeePerGas`) + the [`estimateMaxPriorityFeePerGas` Action](/docs/actions/public/estimateMaxPriorityFeePerGas) (to derive `maxPriorityFeePerGas`). For Legacy Transactions, viem will estimate the fee based on the gas price (via the [`getGasPrice` Action](/docs/actions/public/getGasPrice)).
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const {
maxFeePerGas,
maxPriorityFeePerGas
} = await publicClient.estimateFeesPerGas()
// @log: {
// @log: maxFeePerGas: 15_000_000_000n,
// @log: maxPriorityFeePerGas: 1_000_000_000n,
// @log: }
const { gasPrice } = await publicClient.estimateFeesPerGas({
type: 'legacy'
})
// @log: { gasPrice: 15_000_000_000n }
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
[`FeeValues`](/docs/glossary/types#feevalues)
An estimate (in wei) for the fees per gas.
## Parameters
### chain (optional)
* **Type:** [Chain](/docs/glossary/types#chain)
* **Default:** [`client.chain`](/docs/clients/public#chain-optional)
Optional Chain override. Used to infer the fees per gas from [`chain.fees.estimateFeesPerGas`](/docs/actions/public/estimateFeesPerGas).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { optimism } from 'viem/chains' // [!code focus]
const { maxFeePerGas, maxPriorityFeePerGas } =
await publicClient.estimateFeesPerGas({
chain: optimism // [!code focus]
})
```
### type (optional)
* **Type:** `"legacy" | "eip1559"`
* **Default:** `"eip1559"`
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const { gasPrice } = await publicClient.estimateFeesPerGas({
type: 'legacy' // [!code focus]
})
```
# estimateGas \[An Action for estimating gas for a transaction.]
Estimates the gas necessary to complete a transaction without submitting it to the network.
For a Local Account, `prepare` defaults to `true`; set `prepare: false` to estimate directly with `eth_estimateGas`.
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, publicClient } from './config'
const gas = await publicClient.estimateGas({ // [!code focus:7]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
// @log: ↓ JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// @log: ↓ Local Account
// export const account = privateKeyToAccount('0x...')
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`bigint`
The gas estimate (in gas).
## Parameters
### account
* **Type:** `Account | Address`
The Account to estimate gas from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const gas = await publicClient.estimateGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### prepare (optional)
* **Type:** `boolean | ("blobVersionedHashes" | "chainId" | "fees" | "gas" | "nonce" | "sidecars" | "type")[]`
* **Default:** `true`
Whether to prepare the transaction request before estimating gas. Set to `false` to estimate directly with `eth_estimateGas`.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const gas = await publicClient.estimateGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
prepare: false, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### data (optional)
* **Type:** `0x${string}`
Contract code or a hashed method call with encoded args which can be generated using [encodeFunctionData](/docs/contract/encodeFunctionData).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const gas = await publicClient.estimateGas({
data: '0x...', // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther, parseGwei } from 'viem'
const gas = await publicClient.estimateGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther, parseGwei } from 'viem'
const gas = await publicClient.estimateGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther, parseGwei } from 'viem'
const gas = await publicClient.estimateGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### to (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
Transaction recipient.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const gas = await publicClient.estimateGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
})
```
### value (optional)
* **Type:** `bigint`
Value (in wei) sent with this transaction.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const gas = await publicClient.estimateGas({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the gas estimate against.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const gas = await publicClient.estimateGas({
blockNumber: 15121123n, // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the gas estimate against.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseEther } from 'viem'
const gas = await publicClient.estimateGas({
blockTag: 'safe', // [!code focus]
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### stateOverride (optional)
* **Type:** [`StateOverride`](/docs/glossary/types#stateoverride)
The state override set is an optional address-to-state mapping, where each entry specifies some state to be ephemerally overridden prior to executing the call.
```ts
const data = await publicClient.estimateGas({
account,
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
stateOverride: [ // [!code focus]
{ // [!code focus]
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
balance: parseEther('1'), // [!code focus]
stateDiff: [ // [!code focus]
{ // [!code focus]
slot: '0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0', // [!code focus]
value: '0x00000000000000000000000000000000000000000000000000000000000001a4', // [!code focus]
}, // [!code focus]
], // [!code focus]
} // [!code focus]
], // [!code focus]
})
```
## JSON-RPC Methods
[`eth_estimateGas`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas)
# estimateMaxPriorityFeePerGas
Returns an estimate for the max priority fee per gas (in wei) for a transaction to be likely included in the next block.
If [`chain.fees.defaultPriorityFee`](/docs/chains/fees#feesdefaultpriorityfee) is set on the [Client Chain](/docs/clients/public#chain-optional) or [override Chain](#chain-optional), it will use that value.
Otherwise, the Action will either call [`eth_maxPriorityFeePerGas`](https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/eth/fee_market.yaml#L9-L16) (if supported) or manually calculate the max priority fee per gas based on the current block base fee per gas + gas price.
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const maxPriorityFeePerGas = await publicClient.estimateMaxPriorityFeePerGas()
// @log: Output: 1_000_000_000n
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`bigint`
An estimate (in wei) for the max priority fee per gas.
## Parameters
### chain (optional)
* **Type:** [Chain](/docs/glossary/types#chain)
* **Default:** [`client.chain`](/docs/clients/public#chain-optional)
Optional Chain override. Used to infer the default `maxPriorityFeePerGas` from [`chain.fees.defaultPriorityFee`](/docs/chains/fees#feesdefaultpriorityfee).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { optimism } from 'viem/chains' // [!code focus]
const maxPriorityFeePerGas =
await publicClient.estimateMaxPriorityFeePerGas({
chain: optimism // [!code focus]
})
```
# getBalance
Returns the balance of an address in wei.
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const balance = await publicClient.getBalance({ // [!code focus:4]
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
})
// @log: > 10000000000000000000000n (wei)
```
```ts twoslash [client.ts] filename="client.ts"
// [!include ~/snippets/publicClient.ts]
```
:::
## Returns
`bigint`
The balance of the address in wei.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The address of the account.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const balance = await publicClient.getBalance({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `bigint`
The balance of the account at a block number.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const balance = await publicClient.getBalance({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
blockNumber: 69420n // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
The balance of the account at a block tag.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const balance = await publicClient.getBalance({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
blockTag: 'safe' // [!code focus]
})
```
## Tips
* You can convert the balance to ether units with [`formatEther`](/docs/utilities/formatEther).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { formatEther } from 'viem' // [!code focus]
const balance = await publicClient.getBalance({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
blockTag: 'safe'
})
const balanceAsEther = formatEther(balance) // [!code focus:2]
// "6.942"
```
## JSON-RPC Method
[`eth_getBalance`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getbalance)
# getBlobBaseFee
Returns the current blob base fee (in wei).
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const baseFee = await publicClient.getBlobBaseFee() // [!code focus]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`bigint`
the blob base fee (in wei).
## JSON-RPC Method
[`eth_blobBaseFee`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice)
# getBlock
Returns information about a block at a block number, hash or tag.
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const block = await publicClient.getBlock() // [!code focus:99]
// @log: Output: {
// @log: baseFeePerGas: 10789405161n,
// @log: difficulty: 11569232145203128n,
// @log: extraData: '0x75732d656173742d38',
// @log: ...
// @log: }
```
```ts twoslash [client.ts] filename="client.ts"
// [!include ~/snippets/publicClient.ts]
```
:::
## Returns
[`Block`](/docs/glossary/types#block)
Information about the block.
## Parameters
### blockHash (optional)
* **Type:** [`Hash`](/docs/glossary/types#hash)
Information at a given block hash.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const block = await publicClient.getBlock({
blockHash: '0x89644bbd5c8d682a2e9611170e6c1f02573d866d286f006cbf517eec7254ec2d' // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `bigint`
Information at a given block number.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const block = await publicClient.getBlock({
blockNumber: 42069n // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
Information at a given block tag.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const block = await publicClient.getBlock({
blockTag: 'safe' // [!code focus]
})
```
### includeTransactions (optional)
* **Type:** `boolean`
Whether or not to include transactions (as a structured array of `Transaction` objects).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const block = await publicClient.getBlock({
includeTransactions: true // [!code focus]
})
```
## Example
Check out the usage of `getBlock` in the live [Fetching Blocks Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/blocks_fetching-blocks) below.
## JSON-RPC Method
* Calls [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) for `blockNumber` & `blockTag`.
* Calls [`eth_getBlockByHash`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbyhash) for `blockHash`.
# getBlockNumber
Returns the number of the most recent block seen.
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const blockNumber = await publicClient.getBlockNumber() // [!code focus:99]
// @log: Output: 69420n
```
```ts twoslash [client.ts] filename="client.ts"
// [!include ~/snippets/publicClient.ts]
```
:::
## Returns
`bigint`
The number of the block.
## Parameters
### cacheTime (optional)
* **Type:** `number`
* **Default:** [Client's `cacheTime`](/docs/clients/public#cachetime-optional)
Time (in ms) that cached block number will remain in memory.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const block = await publicClient.getBlockNumber({
cacheTime: 4_000 // [!code focus]
})
```
By default, block numbers are cached for the period of the [Client's `cacheTime`](/docs/clients/public#cacheTime-optional).
* Setting a value of above zero will make block number remain in the cache for that period.
* Setting a value of `0` will disable the cache, and always retrieve a fresh block number.
## Example
Check out the usage of `getBlockNumber` in the live [Fetching Blocks Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/blocks_fetching-blocks) below.
## JSON-RPC Method
[`eth_blockNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blocknumber)
# getBlockTransactionCount
Returns the number of Transactions at a block number, hash or tag.
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const count = await publicClient.getBlockTransactionCount() // [!code focus:99]
// @log: Output: 23
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`number`
The block transaction count.
## Parameters
### blockHash (optional)
* **Type:** [`Hash`](/docs/glossary/types#hash)
Count at a given block hash.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const count = await publicClient.getBlockTransactionCount({
blockHash: '0x89644bbd5c8d682a2e9611170e6c1f02573d866d286f006cbf517eec7254ec2d' // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `bigint`
Count at a given block number.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const block = await publicClient.getBlockTransactionCount({
blockNumber: 42069n // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
Count at a given block tag.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const block = await publicClient.getBlockTransactionCount({
blockTag: 'safe' // [!code focus]
})
```
## JSON-RPC Method
* Calls [`eth_getBlockTransactionCountByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbynumber) for `blockNumber` & `blockTag`.
* Calls [`eth_getBlockTransactionCountByHash`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbyhash) for `blockHash`.
# getChainId
Returns the chain ID associated with the current network
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const chainId = await publicClient.getChainId() // [!code focus:99]
// @log: 1
```
```ts [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`number`
The current chain ID.
## JSON-RPC Method
* Calls [`eth_chainId`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_chainid).
# getEip712Domain
Reads the EIP-712 domain from a contract, based on the [ERC-5267 specification](https://eips.ethereum.org/EIPS/eip-5267).
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const { domain, extensions, fields } = await publicClient.getEip712Domain({
address: '0x57ba3ec8df619d4d243ce439551cce713bb17411',
})
```
```ts [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Counterfactual Call
It is possible to read the EIP-712 domain on a contract that **has not been deployed** by providing deployment factory (`factory` + `factoryData`) parameters:
:::code-group
```ts twoslash [example.ts]
import { factory, publicClient } from './config'
const { domain, extensions, fields } = await publicClient.getEip712Domain({
address: '0x57ba3ec8df619d4d243ce439551cce713bb17411',
factory: factory.address,
factoryData: encodeFunctionData({
abi: factory.abi,
functionName: 'createAccount',
args: ['0x0000000000000000000000000000000000000000', 0n]
}),
})
```
```ts [client.ts] filename="config.ts"
import { createPublicClient, http, parseAbi } from 'viem'
import { mainnet } from 'viem/chains'
export const factory = {
address: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb',
abi: parseAbi(['function createAccount(address owner, uint256 salt)']),
} as const
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`GetEip712DomainReturnType`
The EIP-712 domain (`domain`) for the contract, with `fields` and `extensions`, as per [ERC-5267](https://eips.ethereum.org/EIPS/eip-5267).
## Parameters
### address
* **Type:** `string`
The address of the contract to read the EIP-712 domain from.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const result = await publicClient.getEip712Domain({
address: '0x57ba3ec8df619d4d243ce439551cce713bb17411', // [!code focus]
})
```
### factory (optional)
* **Type:**
Contract deployment factory address (ie. Create2 factory, Smart Account factory, etc).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const result = await publicClient.getEip712Domain({
address: '0x57ba3ec8df619d4d243ce439551cce713bb17411',
factory: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb', // [!code focus]
factoryData: '0xdeadbeef',
})
```
### factoryData (optional)
* **Type:**
Calldata to execute on the factory to deploy the contract.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const result = await publicClient.getEip712Domain({
address: '0x57ba3ec8df619d4d243ce439551cce713bb17411',
factory: '0xE8Df82fA4E10e6A12a9Dab552bceA2acd26De9bb',
factoryData: '0xdeadbeef', // [!code focus]
})
```
# getFeeHistory
Returns a collection of historical gas information.
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const feeHistory = await publicClient.getFeeHistory({ // [!code focus:4]
blockCount: 4,
rewardPercentiles: [25, 75]
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
[`FeeHistory`](/docs/glossary/types#feehistory)
The fee history.
## Parameters
### blockCount
* **Type:** `number`
Number of blocks in the requested range. Between 1 and 1024 blocks can be requested in a single query. Less than requested may be returned if not all blocks are available.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const feeHistory = await publicClient.getFeeHistory({
blockCount: 4, // [!code focus]
rewardPercentiles: [25, 75]
})
```
### rewardPercentiles
* **Type:** `number[]`
A monotonically increasing list of percentile values to sample from each block's effective priority fees per gas in ascending order, weighted by gas used.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const feeHistory = await publicClient.getFeeHistory({
blockCount: 4,
rewardPercentiles: [25, 75] // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `number`
Highest number block of the requested range.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const feeHistory = await publicClient.getFeeHistory({
blockCount: 4,
blockNumber: 1551231n, // [!code focus]
rewardPercentiles: [25, 75]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
Highest number block of the requested range.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const feeHistory = await publicClient.getFeeHistory({
blockCount: 4,
blockTag: 'safe', // [!code focus]
rewardPercentiles: [25, 75]
})
```
## JSON-RPC Method
* Calls [`eth_feeHistory`](https://docs.alchemy.com/reference/eth-feehistory).
# getFilterChanges
Returns a list of logs or hashes based on a [Filter](/docs/glossary/terms#filter) since the last time it was called.
A Filter can be created from the following actions:
* [`createBlockFilter`](/docs/actions/public/createBlockFilter)
* [`createContractEventFilter`](/docs/contract/createContractEventFilter)
* [`createEventFilter`](/docs/actions/public/createEventFilter)
* [`createPendingTransactionFilter`](/docs/actions/public/createPendingTransactionFilter)
## Usage
### Blocks
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const filter = await publicClient.createBlockFilter() // [!code focus:99]
const hashes = await publicClient.getFilterChanges({ filter })
// @log: Output: ["0x10d86dc08ac2f18f00ef0daf7998dcc8673cbcf1f1501eeb2fac1afd2f851128", ...]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Contract Events
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const filter = await publicClient.createContractEventFilter({ // [!code focus:99]
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
abi: wagmiAbi,
eventName: 'Transfer'
})
const logs = await publicClient.getFilterChanges({ filter })
// @log: Output: [{ ... }, { ... }, { ... }]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Raw Events
:::code-group
```ts twoslash [example.ts]
import { parseAbiItem } from 'viem'
import { publicClient } from './client'
const filter = await publicClient.createEventFilter({ // [!code focus:99]
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed, address indexed, uint256)'),
})
const logs = await publicClient.getFilterChanges({ filter })
// @log: Output: [{ ... }, { ... }, { ... }]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Transactions
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const filter = await publicClient.createPendingTransactionFilter() // [!code focus:99]
const hashes = await publicClient.getFilterChanges({ filter })
// @log: Output: ["0x89b3aa1c01ca4da5d15eca9fab459d062db5c0c9b76609acb0741901f01f6d19", ...]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
[`Log[]`](/docs/glossary/types#log)
If the filter was created with `createContractEventFilter` or `createEventFilter`, it returns a list of logs.
**OR**
`"0x${string}"[]`
If the filter was created with `createPendingTransactionFilter`, it returns a list of transaction hashes.
**OR**
`"0x${string}"[]`
If the filter was created with `createBlockFilter`, it returns a list of block hashes.
## Parameters
### filter
* **Type:** [`Filter`](/docs/glossary/types#filter)
A created filter.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const filter = await publicClient.createPendingTransactionFilter()
const logs = await publicClient.getFilterChanges({
filter, // [!code focus]
})
```
## JSON-RPC Method
* Calls [`eth_getFilterChanges`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterchanges).
# getFilterLogs
Returns a list of **event** logs since the filter was created.
Note: `getFilterLogs` is only compatible with **event filters**.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseAbiItem } from 'viem'
import { publicClient } from './client'
const filter = await publicClient.createEventFilter({ // [!code focus:99]
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed, address indexed, uint256)'),
})
const logs = await publicClient.getFilterLogs({ filter })
// @log: [{ ... }, { ... }, { ... }]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
[`Log[]`](/docs/glossary/types#log)
A list of event logs.
## Parameters
### filter
* **Type:** [`Filter`](/docs/glossary/types#filter)
An **event** filter.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const filter = await publicClient.createEventFilter()
const logs = await publicClient.getFilterChanges({
filter, // [!code focus]
})
```
## JSON-RPC Method
[`eth_getFilterLogs`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterlogs)
# getGasPrice
Returns the current price of gas (in wei).
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const gasPrice = await publicClient.getGasPrice() // [!code focus:4]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`bigint`
The gas price (in wei).
## JSON-RPC Method
[`eth_gasPrice`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice)
# getLogs
Returns a list of **event** logs matching the provided parameters.
## Usage
By default, `getLogs` returns all events. In practice, you must use scoping to filter for specific events.
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const logs = await publicClient.getLogs() // [!code focus:99]
// @log: Output: [{ ... }, { ... }, { ... }]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Scoping
You can also scope to a set of given attributes.
:::code-group
```ts twoslash [example.ts]
import { parseAbiItem } from 'viem'
import { publicClient } from './client'
const logs = await publicClient.getLogs({ // [!code focus:99]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256)'),
args: {
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
},
fromBlock: 16330000n,
toBlock: 16330050n
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
By default, `event` accepts the [`AbiEvent`](/docs/glossary/types#abievent) type:
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const logs = await publicClient.getLogs(publicClient, {
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: { // [!code focus:8]
name: 'Transfer',
inputs: [
{ type: 'address', indexed: true, name: 'from' },
{ type: 'address', indexed: true, name: 'to' },
{ type: 'uint256', indexed: false, name: 'value' }
]
},
args: {
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
},
fromBlock: 16330000n,
toBlock: 16330050n
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Address
Logs can be scoped to an **address**:
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const logs = await publicClient.getLogs({
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2' // [!code focus]
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Event
Logs can be scoped to an **event**.
The `event` argument takes in an event in ABI format – we have a [`parseAbiItem` utility](/docs/abi/parseAbiItem) that you can use to convert from a human-readable event signature → ABI.
:::code-group
```ts twoslash [example.ts]
import { parseAbiItem } from 'viem' // [!code focus]
import { publicClient } from './client'
const logs = await publicClient.getLogs({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'), // [!code focus]
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Arguments
Logs can be scoped to given ***indexed* arguments**:
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const logs = await publicClient.getLogs({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
args: { // [!code focus:4]
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
}
})
```
Only indexed arguments in `event` are candidates for `args`.
An argument can also be an array to indicate that other values can exist in the position:
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const logs = await publicClient.getLogs({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
args: { // [!code focus:8]
// '0xd8da...' OR '0xa5cc...' OR '0xa152...'
from: [
'0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
'0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac',
'0xa152f8bb749c55e9943a3a0a3111d18ee2b3f94e',
],
}
})
```
### Block Range
Logs can be scoped to a **block range**:
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const logs = await publicClient.getLogs({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
fromBlock: 16330000n, // [!code focus]
toBlock: 16330050n // [!code focus]
})
```
### Multiple Events
Logs can be scoped to **multiple events**:
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbi } from 'viem'
const logs = await publicClient.getLogs({
events: parseAbi([ // [!code focus:4]
'event Approval(address indexed owner, address indexed sender, uint256 value)',
'event Transfer(address indexed from, address indexed to, uint256 value)',
]),
})
```
Note: Logs scoped to multiple events cannot be also scoped with [indexed arguments](#arguments) (`args`).
### Strict Mode
By default, `getLogs` will include logs that [do not conform](/docs/glossary/terms#non-conforming-log) to the indexed & non-indexed arguments on the `event`.
viem will not return a value for arguments that do not conform to the ABI, thus, some arguments on `args` may be undefined.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const logs = await publicClient.getLogs({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)')
})
logs[0].args
// ^?
```
You can turn on `strict` mode to only return logs that conform to the indexed & non-indexed arguments on the `event`, meaning that `args` will always be defined. The trade-off is that non-conforming logs will be filtered out.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const logs = await publicClient.getLogs({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
strict: true
})
logs[0].args
// ^?
```
## Returns
[`Log[]`](/docs/glossary/types#log)
A list of event logs.
## Parameters
### address
* **Type:** [`Address | Address[]`](/docs/glossary/types#address)
A contract address or a list of contract addresses. Only logs originating from the contract(s) will be included in the result.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const logs = await publicClient.getLogs({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
})
```
### event
* **Type:** [`AbiEvent`](/docs/glossary/types#abievent)
The event in ABI format.
A [`parseAbiItem` utility](/docs/abi/parseAbiItem) is exported from viem that converts from a human-readable event signature → ABI.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const logs = await publicClient.getLogs({
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'), // [!code focus]
})
```
### args
* **Type:** Inferred.
A list of *indexed* event arguments.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const logs = await publicClient.getLogs({
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
args: { // [!code focus:4]
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
},
})
```
### fromBlock
* **Type:** `bigint | 'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
Block to start including logs from. Mutually exclusive with `blockHash`.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const filter = await publicClient.createEventFilter({
fromBlock: 69420n // [!code focus]
})
```
### toBlock
* **Type:** `bigint | 'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
Block to stop including logs from. Mutually exclusive with `blockHash`.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const filter = await publicClient.createEventFilter({
toBlock: 70120n // [!code focus]
})
```
### blockHash
* **Type:** `'0x${string}'`
Block hash to include logs from. Mutually exclusive with `fromBlock`/`toBlock`.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const logs = await publicClient.getLogs({
blockHash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d' // [!code focus]
})
```
## Live Example
Check out the usage of `getLogs` in the live [Event Logs Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/logs_event-logs) below.
## JSON-RPC Method
[`eth_getLogs`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs)
# getProof
Returns the account and storage values of the specified account including the Merkle-proof.
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const proof = await publicClient.getProof({
address: '0x4200000000000000000000000000000000000016',
storageKeys: [
'0x4a932049252365b3eedbc5190e18949f2ec11f39d3bef2d259764799a1b27d99',
],
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { optimism } from 'viem/chains'
export const publicClient = createPublicClient({
chain: optimism,
transport: http()
})
```
:::
## Returns
`Proof`
Proof data.
## Parameters
### address
* **Type:** `bigint`
Account address.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const proof = await publicClient.getProof({
address: '0x4200000000000000000000000000000000000016', // [!code focus]
storageKeys: [
'0x4a932049252365b3eedbc5190e18949f2ec11f39d3bef2d259764799a1b27d99',
],
blockNumber: 42069n
})
```
### storageKeys
* **Type:** `Hash[]`
Array of storage-keys that should be proofed and included.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const proof = await publicClient.getProof({
address: '0x4200000000000000000000000000000000000016',
storageKeys: [ // [!code focus:3]
'0x4a932049252365b3eedbc5190e18949f2ec11f39d3bef2d259764799a1b27d99',
],
blockNumber: 42069n
})
```
### blockNumber (optional)
* **Type:** `bigint`
Proof at a given block number.
```ts
const proof = await publicClient.getProof({
address: '0x4200000000000000000000000000000000000016',
storageKeys: [
'0x4a932049252365b3eedbc5190e18949f2ec11f39d3bef2d259764799a1b27d99',
],
blockNumber: 42069n // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
Proof at a given block tag.
```ts
const proof = await publicClient.getProof({
address: '0x4200000000000000000000000000000000000016',
storageKeys: [
'0x4a932049252365b3eedbc5190e18949f2ec11f39d3bef2d259764799a1b27d99',
],
blockTag: 'latest' // [!code focus]
})
```
## JSON-RPC Method
* Calls [`eth_getProof`](https://eips.ethereum.org/EIPS/eip-1186).
# getTransaction
Returns information about a [Transaction](/docs/glossary/terms#transaction) given a hash or block identifier.
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const transaction = await publicClient.getTransaction({ // [!code focus:99]
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d'
})
// @log: {
// @log: blockHash: '0xaf1dadb8a98f1282e8f7b42cc3da8847bfa2cf4e227b8220403ae642e1173088',
// @log: blockNumber: 15132008n,
// @log: from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
// @log: ...
// @log: }
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
[`Transaction`](/docs/glossary/types#transaction)
The transaction information.
## Parameters
### hash (optional)
* **Type:** `'0x${string}'`
Get information about a transaction given a transaction hash.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transaction = await publicClient.getTransaction({
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d' // [!code focus]
})
```
### blockHash (optional)
* **Type:** `'0x${string}'`
Get information about a transaction given a block hash (and index).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transaction = await publicClient.getTransaction({
blockHash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d', // [!code focus:2]
index: 0
})
```
### blockNumber (optional)
* **Type:** `'0x${string}'`
Get information about a transaction given a block number (and index).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transaction = await publicClient.getTransaction({
blockNumber: 69420n, // [!code focus:2]
index: 0
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
Get information about a transaction given a block tag (and index).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transaction = await publicClient.getTransaction({
blockTag: 'safe', // [!code focus:2]
index: 0
})
```
### index (optional)
* **Type:** `number`
An index to be used with a block identifier (number, hash or tag).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transaction = await publicClient.getTransaction({
blockTag: 'safe',
index: 0 // [!code focus]
})
```
## Example
Check out the usage of `getTransaction` in the live [Fetching Transactions Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_fetching-transactions) below.
## JSON-RPC Method
[`eth_getTransactionByHash`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionByHash)
# getTransactionConfirmations
Returns the number of blocks passed (confirmations) since the transaction was processed on a block.
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const transactionReceipt = await publicClient.getTransactionReceipt({ hash: '...' })
const confirmations = await publicClient.getTransactionConfirmations({ // [!code focus:99]
transactionReceipt
})
// 15n
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
You can also fetch confirmations by Transaction hash:
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const confirmations = await publicClient.getTransactionConfirmations({ // [!code focus:99]
hash: '0x...'
})
// @log: 15n
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`bigint`
The number of blocks passed since the transaction was processed. If confirmations is `0`, then the Transaction has not been confirmed & processed yet.
## Parameters
### transactionReceipt
* **Type:** [`TransactionReceipt`](/docs/glossary/types#transactionreceipt)
The transaction receipt.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
// @noErrors
const balance = await publicClient.getTransactionConfirmations({
transactionReceipt: { ... }, // [!code focus]
})
```
### hash
* **Type:** [`Hash`](/docs/glossary/types#hash)
The hash of the transaction.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const balance = await publicClient.getTransactionConfirmations({
hash: '0x...' // [!code focus]
})
```
## Example
Check out the usage of `getTransactionConfirmations` in the live [Fetching Transactions Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_fetching-transactions) below.
## JSON-RPC Method
[`eth_getTransactionConfirmations`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionConfirmations)
# getTransactionCount
Returns the number of [Transactions](/docs/glossary/terms#transaction) an Account has broadcast / sent.
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const transactionCount = await publicClient.getTransactionCount({ // [!code focus:99]
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
})
// @log: > 420
```
```ts [client.ts] filename="client.ts"
// [!include ~/snippets/publicClient.ts]
```
:::
## Returns
`number`
The number of transactions an account has sent.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The address of the account.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transactionCount = await publicClient.getTransactionCount({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `bigint`
Get the count at a block number.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transactionCount = await publicClient.getTransactionCount({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
blockNumber: 69420n // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
Get the count at a block tag.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transactionCount = await publicClient.getTransactionCount({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
blockTag: 'safe' // [!code focus]
})
```
## Notes
* The transaction count of an account can also be used as a nonce.
## JSON-RPC Method
[`eth_getTransactionCount`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactioncount)
# getTransactionReceipt
Returns the [Transaction Receipt](/docs/glossary/terms#transaction-receipt) given a [Transaction](/docs/glossary/terms#transaction) hash.
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const transaction = await publicClient.getTransactionReceipt({ // [!code focus:99]
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d'
})
// @log: {
// @log: blockHash: '0xaf1dadb8a98f1282e8f7b42cc3da8847bfa2cf4e227b8220403ae642e1173088',
// @log: blockNumber: 15132008n,
// @log: from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
// @log: ...
// @log: status: 'success',
// @log: }
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
[`TransactionReceipt`](/docs/glossary/types#transactionreceipt)
The transaction receipt.
## Parameters
### hash
* **Type:** `'0x${string}'`
A transaction hash.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transaction = await publicClient.getTransactionReceipt({
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d' // [!code focus]
})
```
## Example
Check out the usage of `getTransactionReceipt` in the live [Fetching Transactions Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_fetching-transactions) below.
## JSON-RPC Method
[`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionReceipt)
# Introduction to Public Actions \[A brief introduction on what Public Actions are in viem.]
A Public Action is an action that maps one-to-one with a "public" Ethereum RPC method (`eth_blockNumber`, `eth_getBalance`, etc). They are used with a [Public Client](/docs/clients/public).
Public Actions do not require any special permissions nor do they provide signing capabilities to the user. Examples of Public Actions include [getting the balance of an account](/docs/actions/public/getBalance), [retrieving the details of a specific transaction](/docs/actions/public/getTransactionReceipt), and [getting the current block number](/docs/actions/public/getBlockNumber) of the network.
Public Actions provide a simple and secure way to access public data on the Ethereum blockchain. They are widely used by dapps and other applications that need to retrieve information about transactions, accounts, blocks and other data on the network.
# simulateBlocks
Simulates a set of calls on block(s) with optional block and state overrides. Internally uses the [`eth_simulateV1` JSON-RPC method](https://github.com/ethereum/execution-apis/pull/484).
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { client } from './config'
const result = await client.simulateBlocks({
blocks: [{
blockOverrides: {
number: 69420n,
},
calls: [
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('2'),
},
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'),
},
],
stateOverrides: [{
address: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
balance: parseEther('10'),
}],
}]
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
### Contract Calls
The `calls` property also accepts **Contract Calls**, and can be used via the `abi`, `functionName`, and `args` properties.
:::code-group
```ts twoslash [example.ts]
import { parseAbi, parseEther } from 'viem'
import { client } from './config'
const abi = parseAbi([
'function approve(address, uint256) returns (bool)',
'function transferFrom(address, address, uint256) returns (bool)',
])
const result = await client.simulateBlocks({ // [!code focus:99]
blocks: [{
calls: [
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'approve',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
},
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'transferFrom',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
'0x0000000000000000000000000000000000000000',
100n
],
},
],
}]
})
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
## Return Value
`SimulateBlocksReturnType`
Simulation results.
## Parameters
### blocks
Blocks to simulate.
### blocks.calls
* **Type:** `TransactionRequest[]`
Calls to simulate. Each call can consist of transaction request properties.
```ts twoslash
import { client } from './config'
// ---cut---
const result = await client.simulateBlocks({
blocks: [{
blockOverrides: {
number: 69420n,
},
calls: [ // [!code focus]
{ // [!code focus]
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929', // [!code focus]
data: '0xdeadbeef', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
}, // [!code focus]
{ // [!code focus]
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1'), // [!code focus]
}, // [!code focus]
], // [!code focus]
stateOverrides: [{
address: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
balance: parseEther('10'),
}],
}]
})
```
### blocks.blockOverrides
* **Type:** `BlockOverrides`
Values to override on the block.
```ts twoslash
import { client } from './config'
// ---cut---
const result = await client.simulateBlocks({
blocks: [{
blockOverrides: { // [!code focus]
number: 69420n, // [!code focus]
}, // [!code focus]
calls: [
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
data: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
},
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'),
},
],
stateOverrides: [{
address: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
balance: parseEther('10'),
}],
}]
})
```
### blocks.stateOverrides
* **Type:** `StateOverride`
State overrides.
```ts twoslash
import { client } from './config'
// ---cut---
const result = await client.simulateBlocks({
blocks: [{
blockOverrides: {
number: 69420n,
},
calls: [
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
data: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
},
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'),
},
],
stateOverrides: [{ // [!code focus]
address: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929', // [!code focus]
balance: parseEther('10'), // [!code focus]
}], // [!code focus]
}]
})
```
### returnFullTransactions
* **Type:** `boolean`
Whether to return the full transactions.
```ts twoslash
import { client } from './config'
// ---cut---
const result = await client.simulateBlocks({
blocks: [{
blockOverrides: {
number: 69420n,
},
calls: [
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
data: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
},
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'),
},
],
stateOverrides: [{
address: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
balance: parseEther('10'),
}],
}],
returnFullTransactions: true, // [!code focus]
})
```
### traceTransfers
* **Type:** `boolean`
Whether to trace transfers.
```ts twoslash
import { client } from './config'
// ---cut---
const result = await client.simulateBlocks({
blocks: [{
blockOverrides: {
number: 69420n,
},
calls: [
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
data: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
},
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'),
},
],
stateOverrides: [{
address: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
balance: parseEther('10'),
}],
}],
traceTransfers: true, // [!code focus]
})
```
### validation
* **Type:** `boolean`
Whether to enable validation mode.
```ts twoslash
import { client } from './config'
// ---cut---
const result = await client.simulateBlocks({
blocks: [{
blockOverrides: {
number: 69420n,
},
calls: [
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
data: '0xdeadbeef',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
},
{
from: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'),
},
],
stateOverrides: [{
address: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
balance: parseEther('10'),
}],
}],
validation: true, // [!code focus]
})
```
# simulateCalls
Simulates a set of calls for a block, and optionally provides asset changes. Internally uses the [`eth_simulateV1` JSON-RPC method](https://github.com/ethereum/execution-apis/pull/484).
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { client } from './config'
const { results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
calls: [
{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('2'),
},
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'),
},
],
})
console.log(results)
// @log: [
// @log: {
// @log: gasUsed: 21000n,
// @log: logs: [],
// @log: status: "success",
// @log: },
// @log: {
// @log: gasUsed: 21000n,
// @log: logs: [],
// @log: status: "success",
// @log: },
// @log: ]
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
### Contract Calls
The `calls` property also accepts **Contract Calls**, and can be used via the `abi`, `functionName`, and `args` properties.
:::code-group
```ts twoslash [example.ts]
import { parseAbi, parseEther } from 'viem'
import { client } from './config'
const abi = parseAbi([
'function mint()',
'function transfer(address, uint256) returns (bool)',
])
const { results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'mint',
},
{
to: '0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE',
abi,
functionName: 'transfer',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
},
],
})
console.log(results)
// @log: [
// @log: {
// @log: gasUsed: 21000n,
// @log: logs: [],
// @log: result: undefined,
// @log: status: "success",
// @log: },
// @log: {
// @log: gasUsed: 78394n,
// @log: logs: [...],
// @log: result: undefined,
// @log: status: "success",
// @log: },
// @log: {
// @log: gasUsed: 51859n,
// @log: logs: [...],
// @log: result: true,
// @log: status: "success",
// @log: },
// @log: ]
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
### Asset Changes
Providing the `traceAssetChanges` parameter (with an `account`) will return asset balance changes for the calls.
:::code-group
```ts twoslash [example.ts]
import { parseAbi, parseEther } from 'viem'
import { client } from './config'
const abi = parseAbi([
'function mint()',
'function transfer(address, uint256) returns (bool)',
])
const { assetChanges, results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1.5')
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'mint',
},
{
to: '0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE',
abi,
functionName: 'transfer',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
},
],
traceAssetChanges: true, // [!code hl]
})
console.log(assetChanges)
// @log: [
// @log: {
// @log: token: {
// @log: address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
// @log: decimals: 18,
// @log: symbol: "ETH",
// @log: },
// @log: value: {
// @log: diff: -1500000000000000000n,
// @log: post: 9850000000000000000000n,
// @log: pre: 10000000000000000000000n,
// @log: },
// @log: }
// @log: {
// @log: token: {
// @log: address: "0xfba3912ca04dd458c843e2ee08967fc04f3579c2",
// @log: decimals: 1,
// @log: symbol: "WAGMI",
// @log: },
// @log: value: {
// @log: diff: 1n,
// @log: post: 1n,
// @log: pre: 0n,
// @log: },
// @log: },
// @log: {
// @log: token: {
// @log: address: "0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce",
// @log: decimals: 18,
// @log: symbol: "SHIB",
// @log: },
// @log: value: {
// @log: diff: -1000000000000000000n,
// @log: post: 410429569258816445970930282571360n,
// @log: pre: 410429569258817445970930282571360n,
// @log: },
// @log: }
// @log: ]
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
### Reading Contracts
It is also worth noting that `simulateCalls` also supports "reading" contracts.
:::code-group
```ts twoslash [example.ts]
import { parseAbi } from 'viem'
import { client } from './config'
const abi = parseAbi([
'function totalSupply() returns (uint256)',
'function ownerOf(uint256) returns (address)',
])
const { results } = await client.simulateCalls({
calls: [
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'totalSupply',
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'ownerOf',
args: [69420n],
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'ownerOf',
args: [13371337n],
},
],
})
console.log(results)
// @log: [
// @log: {
// @log: result: 424122n,
// @log: status: "success",
// @log: },
// @log: {
// @log: result: "0xc961145a54C96E3aE9bAA048c4F4D6b04C13916b",
// @log: status: "success",
// @log: },
// @log: {
// @log: error: [ContractFunctionExecutionError: token has no owner],
// @log: status: "failure",
// @log: },
// @log: ]
```
```ts twoslash [config.ts] filename="config.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
## Return Value
`SimulateCallsReturnType`
Simulation results.
## Parameters
### calls
* **Type:** `Calls`
Calls to simulate.
```ts twoslash
import { parseEther } from 'viem'
import { client } from './config'
// ---cut---
const { results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
calls: [ // [!code focus]
{ // [!code focus]
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D', // [!code focus]
value: parseEther('2'), // [!code focus]
}, // [!code focus]
{ // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1'), // [!code focus]
}, // [!code focus]
], // [!code focus]
})
```
### calls.data
* **Type:** `Hex`
Calldata to broadcast (typically a contract function selector with encoded arguments, or contract deployment bytecode).
```ts twoslash
import { parseEther } from 'viem'
import { client } from './config'
// ---cut---
const { results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
calls: [
{
data: '0xdeadbeef', // [!code focus]
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('2'),
},
],
})
```
### calls.to
* **Type:** `Address`
The recipient address.
```ts twoslash
import { parseEther } from 'viem'
import { client } from './config'
// ---cut---
const { results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
calls: [
{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D', // [!code focus]
value: parseEther('2'),
},
],
})
```
### calls.value
* **Type:** `Address`
Value to send with the call.
```ts twoslash
import { parseEther } from 'viem'
import { client } from './config'
// ---cut---
const { results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
calls: [
{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('2'), // [!code focus]
},
],
})
```
#### calls.dataSuffix
* **Type:** Hex
Data to append to the end of the calldata.
```ts twoslash [example.ts]
import { parseAbi } from 'viem'
import { client } from './config'
const abi = parseAbi([
'function approve(address, uint256) returns (bool)',
])
// ---cut---
const { id } = await client.simulateCalls({
calls: [
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'approve',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
dataSuffix: '0xdeadbeef' // [!code focus]
}
],
})
```
### account (optional)
* **Type:** `Account | Address`
The account to simulate the calls from.
```ts twoslash
import { parseEther } from 'viem'
import { client } from './config'
// ---cut---
const { results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929', // [!code focus]
calls: [
{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('2'),
},
],
})
```
### blockNumber (optional)
* **Type:** `bigint`
The block number to simulate the calls at.
```ts twoslash
import { parseEther } from 'viem'
import { client } from './config'
// ---cut---
const { results } = await client.simulateCalls({
blockNumber: 17030000n, // [!code focus]
calls: [
{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('2'),
},
],
})
```
### blockTag (optional)
* **Type:** `BlockTag`
The block tag to simulate the calls at.
```ts twoslash
import { parseEther } from 'viem'
import { client } from './config'
// ---cut---
const { results } = await client.simulateCalls({
blockTag: 'pending', // [!code focus]
calls: [
{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('2'),
},
],
})
```
### stateOverrides (optional)
* **Type:** `StateOverride`
The state overrides to simulate the calls with.
```ts twoslash
import { parseEther } from 'viem'
import { client } from './config'
// ---cut---
const { results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
calls: [
{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('2'),
},
],
stateOverrides: [{ // [!code focus]
address: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929', // [!code focus]
balance: parseEther('10000'), // [!code focus]
}], // [!code focus]
})
```
### traceAssetChanges (optional)
* **Type:** `boolean`
Whether to trace asset changes.
```ts twoslash
import { parseEther } from 'viem'
import { client } from './config'
// ---cut---
const { results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
calls: [
{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('2'),
},
],
traceAssetChanges: true, // [!code focus]
})
```
### traceTransfers (optional)
* **Type:** `boolean`
Whether to trace transfers.
```ts twoslash
import { parseEther } from 'viem'
import { client } from './config'
// ---cut---
const { results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
calls: [
{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('2'),
},
],
traceTransfers: true, // [!code focus]
})
```
### validation (optional)
* **Type:** `boolean`
Whether to enable validation mode.
```ts twoslash
import { parseEther } from 'viem'
import { client } from './config'
// ---cut---
const { results } = await client.simulateCalls({
account: '0x5a0b54d5dc17e482fe8b0bdca5320161b95fb929',
calls: [
{
to: '0xcb98643b8786950F0461f3B0edf99D88F274574D',
value: parseEther('2'),
},
],
validation: true, // [!code focus]
})
```
# uninstallFilter
Destroys a [`Filter`](/docs/glossary/types#filter) that was created from one of the following Actions:
* [`createBlockFilter`](/docs/actions/public/createBlockFilter)
* [`createEventFilter`](/docs/actions/public/createEventFilter)
* [`createPendingTransactionFilter`](/docs/actions/public/createPendingTransactionFilter)
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const filter = await publicClient.createPendingTransactionFilter()
const uninstalled = await publicClient.uninstallFilter({ filter }) // [!code focus:99]
// true
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`boolean`
A boolean indicating if the Filter was successfully uninstalled.
## Parameters
### filter
* **Type:** [`Filter`](/docs/glossary/terms#filter)
A created filter.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const filter = await publicClient.createPendingTransactionFilter()
const uninstalled = await publicClient.uninstallFilter({
filter, // [!code focus]
})
```
## JSON-RPC Method
[`eth_uninstallFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_uninstallFilter)
# verifyHash
Verify that a hash (digest) was signed by the provided address.
Supports verification of:
* **Externally Owned Accounts**
* **Smart Contract Accounts:**
* **Deployed** (via [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271))
* **Pre-deployed** (via [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492))
* **Pre-delegated** (via [ERC-8010](https://github.com/ethereum/ERCs/pull/1186))
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, publicClient } from './client'
const valid = await publicClient.verifyHash({
address: account.address,
hash: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
signature: '0x...',
})
// @log: true
```
```ts twoslash [client.ts] filename="client.ts"
import 'viem/window'
// ---cut---
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClient = createWalletClient({
transport: custom(window.ethereum!)
})
// @log: ↓ JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// @log: ↓ Local Account
// export const account = privateKeyToAccount(...)
```
:::
## Returns
`boolean`
Whether the signed hash is valid for the given address.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The Ethereum address that signed the original hash.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyHash({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
hash: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### hash
* **Type:** `string`
The hash to be verified.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyHash({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
hash: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef', // [!code focus:1]
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### signature
* **Type:** `Hex | ByteArray | Signature`
The signature that was generated by signing the hash with the address's signer.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyHash({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
hash: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
signature: // [!code focus:2]
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### blockNumber (optional)
* **Type:** `bigint`
Only used when verifying a message that was signed by a Smart Contract Account. The block number to check if the contract was already deployed.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyHash({
blockNumber: 42069n, // [!code focus]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
hash: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
Only used when verifying a message that was signed by a Smart Contract Account. The block tag to check if the contract was already deployed.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyHash({
blockTag: 'safe', // [!code focus]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
hash: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef',
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
# verifyMessage
Verify that a message was signed by the provided address.
Supports verification of:
* **Externally Owned Accounts**
* **Smart Contract Accounts:**
* **Deployed** (via [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271))
* **Pre-deployed** (via [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492))
* **Pre-delegated** (via [ERC-8010](https://github.com/ethereum/ERCs/pull/1186))
:::info
**Why should I use this over the [`verifyMessage`](/docs/utilities/verifyMessage) util?**
This Action supports verifying messages that were signed by either a Smart Contract Account or Externally Owned Account. The [`verifyMessage`](/docs/utilities/verifyMessage.md) util only supports Externally Owned Accounts. This is getting increasingly important as more wallets implement [Account Abstraction](https://eips.ethereum.org/EIPS/eip-4337).
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient, publicClient } from './client'
const signature = await walletClient.signMessage({
account,
message: 'hello world',
})
// [!code focus:99]
const valid = await publicClient.verifyMessage({
address: account.address,
message: 'hello world',
signature,
})
// @log: true
```
```ts twoslash [client.ts] filename="client.ts"
import 'viem/window'
// ---cut---
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClient = createWalletClient({
transport: custom(window.ethereum!)
})
// @log: ↓ JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// @log: ↓ Local Account
// export const account = privateKeyToAccount(...)
```
:::
## Returns
`boolean`
Whether the signed message is valid for the given address.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The Ethereum address that signed the original message.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyMessage({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
message: 'hello world',
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### message
* **Type:** `string`
The message to be verified.
By default, viem verifies the UTF-8 representation of the message.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyMessage({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: 'hello world', // [!code focus:1]
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
To verify the data representation of the message, you can use the `raw` attribute.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyMessage({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: { raw: '0x68656c6c6f20776f726c64' }, // [!code focus:1]
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### signature
* **Type:** `Hex | ByteArray | Signature`
The signature that was generated by signing the message with the address's signer.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyMessage({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: 'hello world',
signature: // [!code focus:2]
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
# verifyTypedData
Verify that typed data was signed by the provided address.
Supports verification of:
* **Externally Owned Accounts**
* **Smart Contract Accounts:**
* **Deployed** (via [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271))
* **Pre-deployed** (via [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492))
* **Pre-delegated** (via [ERC-8010](https://github.com/ethereum/ERCs/pull/1186))
:::info
**Why should I use this over the [`verifyTypedData`](/docs/utilities/verifyTypedData) util?**
This Action supports verifying typed data that was signed by either a Smart Contract Account or Externally Owned Account (via [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492)). The [`verifyTypedData`](/docs/utilities/verifyTypedData) util only supports Externally Owned Accounts. This is getting increasingly important as more wallets implement [Account Abstraction](https://eips.ethereum.org/EIPS/eip-4337).
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient, publicClient } from './client'
import { domain, types } from './data'
const message = {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
}
const signature = await walletClient.signTypedData({
account,
domain,
types,
primaryType: 'Mail',
message,
})
// [!code focus:99]
const valid = await publicClient.verifyTypedData({
address: account.address,
domain,
types,
primaryType: 'Mail',
message,
signature,
})
// true
```
```ts twoslash [data.ts] filename="data.ts"
// All properties on a domain are optional
export const domain = {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
} as const
// The named list of all type definitions
export const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
} as const
```
```ts twoslash [client.ts] filename="client.ts"
import 'viem/window'
// ---cut---
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClient = createWalletClient({
transport: custom(window.ethereum!)
})
// @log: ↓ JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// @log: ↓ Local Account
// export const account = privateKeyToAccount(...)
```
:::
## Returns
`boolean`
Whether the signed message is valid for the given address.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The Ethereum address that signed the original message.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### domain
**Type:** `TypedDataDomain`
The typed data domain.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: { // [!code focus:6]
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### types
The type definitions for the typed data.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: { // [!code focus:11]
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### primaryType
**Type:** Inferred `string`.
The primary type to extract from `types` and use in `value`.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [ // [!code focus:5]
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail', // [!code focus]
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### message
**Type:** Inferred from `types` & `primaryType`.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: { // [!code focus:11]
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### signature
* **Type:** `Hex | ByteArray | Signature`
The signature of the typed data.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyTypedData({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...', // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `bigint`
Only used when verifying a typed data that was signed by a Smart Contract Account. The block number to check if the contract was already deployed.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyTypedData({
blockNumber: 42069n, // [!code focus]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
Only used when verifying a typed data that was signed by a Smart Contract Account. The block tag to check if the contract was already deployed.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const valid = await publicClient.verifyTypedData({
blockNumber: 42069n, // [!code focus]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
signature: '0x...',
})
```
# waitForTransactionReceipt
Waits for the [Transaction](/docs/glossary/terms#transaction) to be included on a [Block](/docs/glossary/terms#block) (one confirmation), and then returns the [Transaction Receipt](/docs/glossary/terms#transaction-receipt).
The `waitForTransactionReceipt` action additionally supports Replacement detection (e.g. sped up Transactions).
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const transaction = await publicClient.waitForTransactionReceipt( // [!code focus:99]
{ hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d' }
)
// @log: {
// @log: blockHash: '0xaf1dadb8a98f1282e8f7b42cc3da8847bfa2cf4e227b8220403ae642e1173088',
// @log: blockNumber: 15132008n,
// @log: from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
// @log: ...
// @log: status: 'success',
// @log: }
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
[`TransactionReceipt`](/docs/glossary/types#transactionreceipt)
The transaction receipt.
## Parameters
### confirmations (optional)
* **Type:** `number`
* **Default:** `1`
The number of confirmations (blocks that have passed) to wait before resolving.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transaction = await publicClient.waitForTransactionReceipt(
{
confirmations: 5, // [!code focus:1]
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d'
}
)
```
### onReplaced (optional)
* **Type:** `({ reason: 'replaced' | 'repriced' | 'cancelled', replacedTransaction: Transaction, transaction: Transaction, transactionReceipt: TransactionReceipt }) => void`
Optional callback to emit if the transaction has been replaced.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transaction = await publicClient.waitForTransactionReceipt(
{
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
onReplaced: replacement => console.log(replacement) // [!code focus:1]
}
)
```
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to the Client's `pollingInterval` config.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transaction = await publicClient.waitForTransactionReceipt(
{
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
pollingInterval: 12_000, // [!code focus:1]
}
)
```
### retryCount (optional)
* **Type:** `number`
* **Default:** `6`
Number of times to retry if the transaction or block is not found.
```ts
const transaction = await publicClient.waitForTransactionReceipt(
{
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
retryCount: 3, // [!code focus:1]
}
)
```
### retryDelay (optional)
* **Type:** `number | (({ count: number; error: Error }) => number)`
* **Default:** `({ count }) => ~~(1 << count) * 200` (exponential backoff)
Time to wait (in ms) between retries.
```ts
const transaction = await publicClient.waitForTransactionReceipt(
{
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
retryDelay: 10_000, // [!code focus:1]
}
)
```
### timeout (optional)
* **Type:** `number`
* **Default:** `180_000`
Optional timeout (in milliseconds) to wait before stopping polling.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const transaction = await publicClient.waitForTransactionReceipt(
{
hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d',
timeout: 60_000, // [!code focus:1]
}
)
```
### Notes
* Transactions can be replaced when a user modifies their transaction in their wallet (to speed up or cancel). Transactions are replaced when they are sent from the same nonce.
* There are 3 types of Transaction Replacement reasons:
* `repriced`: The gas price has been modified (ie. different `maxFeePerGas`)
* `cancelled`: The Transaction has been cancelled (ie. `value === 0n`)
* `replaced`: The Transaction has been replaced (ie. different `value` or `data`)
## Live Example
Check out the usage of `waitForTransactionReceipt` in the live [Sending Transactions Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_sending-transactions) below.
## JSON-RPC Methods
* Polls [`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionReceipt) on each block until it has been processed.
* If a Transaction has been replaced:
* Calls [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) and extracts the transactions
* Checks if one of the Transactions is a replacement
* If so, calls [`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionReceipt).
# watchBlockNumber
Watches and returns incoming block numbers.
## Usage
Pass through your Public Client, along with a listener.
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const unwatch = publicClient.watchBlockNumber( // [!code focus:99]
{ onBlockNumber: blockNumber => console.log(blockNumber) }
)
// @log: > 69420n
// @log: > 69421n
// @log: > 69422n
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Listener
`(blockNumber: bigint) => void`
The block number.
## Returns
`UnwatchFn`
A function that can be invoked to stop watching for new block numbers.
## Parameters
### emitMissed (optional)
* **Type:** `boolean`
* **Default:** `false`
Whether or not to emit missed block numbers to the callback.
Missed block numbers may occur in instances where internet connection is lost, or the block time is lesser than the [polling interval](/docs/clients/public#pollinginterval-optional) of the client.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchBlockNumber(
{
emitMissed: true, // [!code focus]
onBlockNumber: blockNumber => console.log(blockNumber),
}
)
```
### emitOnBegin (optional)
* **Type:** `boolean`
* **Default:** `false`
Whether or not to emit the latest block number to the callback when the subscription opens.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchBlockNumber(
{
emitOnBegin: true, // [!code focus]
onBlockNumber: blockNumber => console.log(blockNumber),
}
)
```
### poll (optional)
* **Type:** `boolean`
* **Default:** `false` for WebSocket Transports, `true` for non-WebSocket Transports
Whether or not to use a polling mechanism to check for new block numbers instead of a WebSocket subscription.
This option is only configurable for Clients with a [WebSocket Transport](/docs/clients/transports/websocket).
```ts twoslash
import { createPublicClient, webSocket } from 'viem'
import { mainnet } from 'viem/chains'
const publicClient = createPublicClient({
chain: mainnet,
transport: webSocket()
})
const unwatch = publicClient.watchBlockNumber(
{
onBlockNumber: blockNumber => console.log(blockNumber),
poll: true, // [!code focus]
}
)
```
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to Client's `pollingInterval` config.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchBlockNumber(
{
onBlockNumber: blockNumber => console.log(blockNumber),
pollingInterval: 12_000, // [!code focus]
}
)
```
## Example
Check out the usage of `watchBlockNumber` in the live [Watch Block Numbers Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/blocks_watching-blocks) below.
## JSON-RPC Methods
* When `poll: true`, calls [`eth_blockNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blocknumber) on a polling interval.
* When `poll: false` & WebSocket Transport, uses a WebSocket subscription via [`eth_subscribe`](https://docs.alchemy.com/reference/eth-subscribe-polygon) and the `"newHeads"` event.
# watchBlocks
Watches and returns information for incoming blocks.
## Usage
Pass through your Public Client, along with a listener.
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const unwatch = publicClient.watchBlocks( // [!code focus:99]
{ onBlock: block => console.log(block) }
)
// @log: > {
// @log: baseFeePerGas: 10789405161n,
// @log: difficulty: 11569232145203128n,
// @log: extraData: '0x75732d656173742d38',
// @log: ...
// @log: }
// @log: > {
// @log: baseFeePerGas: 12394051511n,
// @log: difficulty: 11512315412421123n,
// @log: extraData: '0x5123ab1512dd14aa',
// @log: ...
// @log: }
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`UnwatchFn`
A function that can be invoked to stop watching for new blocks.
## Parameters
### onBlock
* **Type:** `(block: Block) => void`
The block information.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchBlocks(
{ onBlock: block => console.log(block) } // [!code focus:1]
)
```
### onError (optional)
* **Type:** `(error: Error) => void`
Error thrown from getting a block.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchBlocks(
{
onBlock: block => console.log(block),
onError: error => console.log(error) // [!code focus:1]
}
)
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
Watch for new blocks on a given tag.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchBlocks(
{
blockTag: 'safe',
onBlock: block => console.log(block), // [!code focus]
}
)
```
### emitMissed (optional)
* **Type:** `boolean`
* **Default:** `false`
Whether or not to emit missed blocks to the callback.
Missed blocks may occur in instances where internet connection is lost, or the block time is lesser than the [polling interval](/docs/clients/public#pollinginterval-optional) of the client.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchBlocks(
{
emitMissed: true, // [!code focus]
onBlock: block => console.log(block),
}
)
```
### emitOnBegin (optional)
* **Type:** `boolean`
* **Default:** `false`
Whether or not to emit the block to the callback when the subscription opens.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchBlocks(
{
emitOnBegin: true, // [!code focus]
onBlock: block => console.log(block),
}
)
```
### includeTransactions (optional)
* **Type:** `boolean`
Whether or not to include transactions (as a structured array of `Transaction` objects).
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchBlocks(
{
includeTransactions: true, // [!code focus]
onBlock: block => console.log(block),
}
)
```
### poll (optional)
* **Type:** `boolean`
* **Default:** `false` for WebSocket Clients, `true` for non-WebSocket Clients
Whether or not to use a polling mechanism to check for new blocks instead of a WebSocket subscription.
This option is only configurable for Clients with a [WebSocket Transport](/docs/clients/transports/websocket).
```ts twoslash
import { createPublicClient, webSocket } from 'viem'
import { mainnet } from 'viem/chains'
const publicClient = createPublicClient({
chain: mainnet,
transport: webSocket()
})
const unwatch = publicClient.watchBlocks(
{
onBlock: block => console.log(block),
poll: true, // [!code focus]
}
)
```
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to the Client's `pollingInterval` config.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchBlocks(
{
onBlock: block => console.log(block),
pollingInterval: 1_000, // [!code focus]
}
)
```
## Example
Check out the usage of `watchBlocks` in the live [Watch Blocks Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/blocks_watching-blocks) below.
## JSON-RPC Methods
* When `poll: true`, calls [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getBlockByNumber) on a polling interval.
* When `poll: false` & WebSocket Transport, uses a WebSocket subscription via [`eth_subscribe`](https://docs.alchemy.com/reference/eth-subscribe-polygon) and the `"newHeads"` event.
# watchEvent
Watches and returns emitted [Event Logs](/docs/glossary/terms#event-log).
This Action will batch up all the Event Logs found within the [`pollingInterval`](#pollinginterval-optional), and invoke them via [`onLogs`](#onlogs).
`watchEvent` will attempt to create an [Event Filter](https://viem.sh/docs/actions/public/createEventFilter) and listen to changes to the Filter per polling interval, however, if the RPC Provider does not support Filters (ie. `eth_newFilter`), then `watchEvent` will fall back to using [`getLogs`](/docs/actions/public/getLogs) instead.
## Usage
By default, you can watch all broadcasted events to the blockchain by just passing `onLogs`.
These events will be batched up into [Event Logs](/docs/glossary/terms#event-log) and sent to `onLogs`:
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
import { wagmiAbi } from './abi'
const unwatch = publicClient.watchEvent({
onLogs: logs => console.log(logs)
})
// @log: > [{ ... }, { ... }, { ... }]
// @log: > [{ ... }, { ... }]
// @log: > [{ ... }, { ... }, { ... }, { ... }]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Scoping
You can also scope `watchEvent` to a set of given attributes (listed below).
### Address
`watchEvent` can be scoped to an **address**:
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
import { wagmiAbi } from './abi'
const unwatch = publicClient.watchEvent({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // [!code focus]
onLogs: logs => console.log(logs)
})
// @log: > [{ ... }, { ... }, { ... }]
// @log: > [{ ... }, { ... }]
// @log: > [{ ... }, { ... }, { ... }, { ... }]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Event
`watchEvent` can be scoped to an **event**.
The `event` argument takes in an event in ABI format – we have a [`parseAbiItem` utility](/docs/abi/parseAbiItem) that you can use to convert from a human-readable event signature → ABI.
:::code-group
```ts twoslash [example.ts]
import { parseAbiItem } from 'viem' // [!code focus]
import { publicClient } from './client'
import { wagmiAbi } from './abi'
const unwatch = publicClient.watchEvent({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'), // [!code focus]
onLogs: logs => console.log(logs)
})
// @log: > [{ ... }, { ... }, { ... }]
// @log: > [{ ... }, { ... }]
// @log: > [{ ... }, { ... }, { ... }, { ... }]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
By default, `event` accepts the [`AbiEvent`](/docs/glossary/types#abievent) type:
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const unwatch = publicClient.watchEvent(publicClient, {
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: { // [!code focus:8]
name: 'Transfer',
inputs: [
{ type: 'address', indexed: true, name: 'from' },
{ type: 'address', indexed: true, name: 'to' },
{ type: 'uint256', indexed: false, name: 'value' }
]
},
onLogs: logs => console.log(logs)
})
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Arguments
`watchEvent` can be scoped to given ***indexed* arguments** on the event:
:::code-group
```ts twoslash [example.ts]
import { parseAbiItem } from 'viem'
import { publicClient } from './client'
const unwatch = publicClient.watchEvent({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
args: { // [!code focus:4]
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
},
onLogs: logs => console.log(logs)
})
// > [{ ... }, { ... }, { ... }]
// > [{ ... }, { ... }]
// > [{ ... }, { ... }, { ... }, { ... }]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
Only indexed arguments in `event` are candidates for `args`.
These arguments can also be an array to indicate that other values can exist in the position:
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const unwatch = publicClient.watchEvent({
address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
args: { // [!code focus:8]
// '0xd8da...' OR '0xa5cc...' OR '0xa152...'
from: [
'0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
'0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac',
'0xa152f8bb749c55e9943a3a0a3111d18ee2b3f94e',
],
},
onLogs: logs => console.log(logs)
})
```
### Multiple Events
`watchEvent` can be scoped to **multiple events**:
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbi } from 'viem'
const unwatch = publicClient.watchEvent({
events: parseAbi([ // [!code focus:5]
'event Approval(address indexed owner, address indexed sender, uint256 value)',
'event Transfer(address indexed from, address indexed to, uint256 value)',
]),
onLogs: logs => console.log(logs)
})
```
Note: `watchEvent` scoped to multiple events cannot be also scoped with [indexed arguments](#arguments) (`args`).
## Returns
`UnwatchFn`
A function that can be invoked to stop watching for new Event Logs.
## Parameters
### onLogs
* **Type:** `(logs: Log[]) => void`
The new Event Logs.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchEvent(
{ onLogs: logs => console.log(logs) } // [!code focus:1]
)
```
### address (optional)
* **Type:** `Address | Address[]`
The contract address or a list of addresses from which Logs should originate.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchEvent(
{
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2', // [!code focus]
onLogs: logs => console.log(logs)
}
)
```
### event (optional)
* **Type:** [`AbiEvent`](/docs/glossary/types#abievent)
The event in ABI format.
A [`parseAbiItem` utility](/docs/abi/parseAbiItem) is exported from viem that converts from a human-readable event signature → ABI.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem' // [!code focus]
const unwatch = publicClient.watchEvent(
{
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'), // [!code focus]
onLogs: logs => console.log(logs)
}
)
```
### args (optional)
* **Type:** Inferred.
A list of *indexed* event arguments.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
import { parseAbiItem } from 'viem'
const unwatch = publicClient.watchEvent(
{
address: '0xfba3912ca04dd458c843e2ee08967fc04f3579c2',
event: parseAbiItem('event Transfer(address indexed from, address indexed to, uint256 value)'),
args: { // [!code focus:4]
from: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045',
to: '0xa5cc3c03994db5b0d9a5eedd10cabab0813678ac'
},
onLogs: logs => console.log(logs)
}
)
```
### batch (optional)
* **Type:** `boolean`
* **Default:** `true`
Whether or not to batch the Event Logs between polling intervals.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchEvent(
{
batch: false, // [!code focus]
onLogs: logs => console.log(logs),
}
)
```
### onError (optional)
* **Type:** `(error: Error) => void`
Error thrown from listening for new Event Logs.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchEvent(
{
onError: error => console.log(error), // [!code focus:1]
onLogs: logs => console.log(logs),
}
)
```
### poll (optional)
* **Type:** `boolean`
* **Default:** `false` for WebSocket Clients, `true` for non-WebSocket Clients
Whether or not to use a polling mechanism to check for new logs instead of a WebSocket subscription.
This option is only configurable for Clients with a [WebSocket Transport](/docs/clients/transports/websocket).
```ts twoslash
import { createPublicClient, webSocket } from 'viem'
import { mainnet } from 'viem/chains'
const publicClient = createPublicClient({
chain: mainnet,
transport: webSocket()
})
const unwatch = publicClient.watchEvent(
{
onLogs: logs => console.log(logs),
poll: true, // [!code focus]
}
)
```
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to the Client's `pollingInterval` config.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchEvent(
{
pollingInterval: 1_000, // [!code focus]
onLogs: logs => console.log(logs),
}
)
```
### fromBlock (optional)
* **Type:** `bigint`
The block number to start listening for logs from.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchEvent(
{
fromBlock: 1n, // [!code focus]
onLogs: logs => console.log(logs),
}
)
```
## Live Example
Check out the usage of `watchEvent` in the live [Event Logs Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/logs_event-logs) below.
## JSON-RPC Methods
**When poll `true` and RPC Provider supports `eth_newFilter`:**
* Calls [`eth_newFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newfilter) to create a filter (called on initialize).
* On a polling interval, it will call [`eth_getFilterChanges`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterchanges).
**When poll `true` RPC Provider does not support `eth_newFilter`:**
* Calls [`eth_getLogs`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs) for each block between the polling interval.
**When poll `false` and WebSocket Transport:**
* Uses a WebSocket subscription via `eth_subscribe` and the "logs" event.
# watchPendingTransactions
Watches and returns pending transaction hashes.
This Action will batch up all the pending transactions found within the [`pollingInterval`](#pollinginterval-optional), and invoke them via [`onTransactions`](#ontransactions).
## Usage
:::code-group
```ts twoslash [example.ts]
import { publicClient } from './client'
const unwatch = publicClient.watchPendingTransactions( // [!code focus:99]
{ onTransactions: hashes => console.log(hashes) }
)
// @log: > ['0x...', '0x...', '0x...']
// @log: > ['0x...', '0x...']
// @log: > ['0x...', '0x...', '0x...', ...]
```
```ts twoslash [client.ts] filename="client.ts"
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
## Returns
`UnwatchFn`
A function that can be invoked to stop watching for new pending transaction hashes.
## Parameters
### onTransactions
* **Type:** `(hashes: '0x${string}'[]) => void`
The new pending transaction hashes.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchPendingTransactions(
{ onTransactions: hashes => console.log(hashes) } // [!code focus:1]
)
```
### batch (optional)
* **Type:** `boolean`
* **Default:** `true`
Whether or not to batch the transaction hashes between polling intervals.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
const unwatch = publicClient.watchPendingTransactions(
{
batch: false, // [!code focus]
onTransactions: hashes => console.log(hashes),
}
)
```
### onError (optional)
* **Type:** `(error: Error) => void`
Error thrown from listening for new pending transactions.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
// @noErrors
const unwatch = publicClient.watchPendingTransactions(
{
onError: error => console.log(error), // [!code focus:1]
onTransactions: hashes => console.log(hashes),
}
)
```
### poll (optional)
* **Type:** `boolean`
* **Default:** `false` for WebSocket Clients, `true` for non-WebSocket Clients
Whether or not to use a polling mechanism to check for new pending transactions instead of a WebSocket subscription.
This option is only configurable for Clients with a [WebSocket Transport](/docs/clients/transports/websocket).
```ts twoslash
import { createPublicClient, webSocket } from 'viem'
import { mainnet } from 'viem/chains'
const publicClient = createPublicClient({
chain: mainnet,
transport: webSocket()
})
const unwatch = publicClient.watchPendingTransactions(
{
onTransactions: transactions => console.log(transactions),
poll: true, // [!code focus]
}
)
```
### pollingInterval (optional)
* **Type:** `number`
Polling frequency (in ms). Defaults to the Client's `pollingInterval` config.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
// ---cut---
// @noErrors
const unwatch = publicClient.watchPendingTransactions(
{
pollingInterval: 1_000, // [!code focus]
onTransactions: hashes => console.log(hashes),
}
)
```
## JSON-RPC Methods
* When `poll: true`
* Calls [`eth_newPendingTransactionFilter`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newpendingtransactionfilter) to initialize the filter.
* Calls [`eth_getFilterChanges`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getFilterChanges) on a polling interval.
* When `poll: false` & WebSocket Transport, uses a WebSocket subscription via [`eth_subscribe`](https://docs.alchemy.com/reference/eth-subscribe-polygon) and the `"newPendingTransactions"` event.
# dropTransaction
Remove a transaction from the mempool.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.dropTransaction({ // [!code focus:4]
hash: '0xe58dceb6b20b03965bb678e27d141e151d7d4efc2334c2d6a49b9fac523f7364'
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### hash
* **Type:** [`Hash`](/docs/glossary/types#hash)
The hash of the transaction.
```ts
await testClient.dropTransaction({
hash: '0xe58dceb6b20b03965bb678e27d141e151d7d4efc2334c2d6a49b9fac523f7364', // [!code focus]
})
```
# dumpState
Serializes the current state (including contracts code, contract's storage, accounts properties, etc.) into a savable data blob.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
const state = await testClient.dumpState()
// 0x1f8b08000000000000ffad934d8e1c310885ef52eb5e003660e636184c3651b7949948915a7df7b8934ded6bbcc23fe2f3e3c1f3f088c7effbd7e7f1f13ce00ff60c35939e4e016352131bb3658bd0f046682dcd98dfafef8f7bace3036ec7f49ffe2fde190817da82b0e9933abcd7713be291ffaf77fcf9f5f8e53ff6f6f97addde4cced6dd8b3b89e6d4d468a2a3d93e537480fd15713933f12a73ebc2b106ae561c59bae1d152784733c067f1dc49479d987295d9a2f7c8cc296e00e534797026d94ed312a9bc93b5192726d155a882999a42300ea48ce680109a80936141a2be0d8f7182f6cb4a0d4a6d96ac49d16b2834e1a5836dd0c242c0b5751ac8d9d1cb4a4d65b97620594ac2dc77a159cbb9ab349f096fedee76828ecb4cdb20d044679e1124c6c1633a4acda639d026f81ea96f15eab0963a76ca3d2f81b58705fbea3e4a59761b11f8769ce0046d5799d5ac5216a37b8e51523d96f81c839476fb54d53422393bda94af505fafbf9d0612379c040000
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Return Type
`Hex`
The state as a data blob.
# getAutomine
Returns the automatic mining status of the node.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
const isAutomining = await testClient.getAutomine() // [!code focus]
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Returns
`boolean`
Whether or not the node is auto mining.
# getTxpoolContent
Returns the details of all transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only. [Read more](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool).
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
const content = await testClient.getTxpoolContent() // [!code focus]
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Returns
Transaction pool content. [See here](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool).
# getTxpoolStatus
Returns a summary of all the transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only. [Read more](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool).
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
const status = await testClient.getTxpoolStatus() // [!code focus]
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Returns
Transaction pool status. [See here](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool).
# impersonateAccount
Impersonate an account or contract address. This lets you send transactions from that account even if you don't have access to its private key.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.impersonateAccount({ // [!code focus:4]
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The address of the target account.
```ts
await testClient.impersonateAccount({
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
})
```
# increaseTime
Jump forward in time by the given amount of time, in seconds.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.increaseTime({ // [!code focus:4]
seconds: 420,
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### seconds
* **Type:** `number`
The amount of seconds to jump forward in time.
```ts
await testClient.increaseTime({
seconds: 20, // [!code focus]
})
```
# inspectTxpool
Returns a summary of all the transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only. [Read more](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool).
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
const data = await testClient.inspectTxpool() // [!code focus]
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Returns
Transaction pool inspection data. [See here](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool).
# Introduction to Test Actions \[A brief introduction on what Test Actions are in viem.]
Test Actions are actions that map one-to-one with "test" Ethereum RPC methods (`evm_mine`, `anvil_setBalance`, `anvil_impersonate`, etc). They are used with a [Test Client](/docs/clients/test).
Test Actions are used for testing and simulation purposes. Examples of Test Actions include [mining a block](/docs/actions/test/mine), [setting the balance of an account](/docs/actions/test/setBalance), and [impersonating accounts](/docs/actions/test/impersonateAccount).
Test Actions are an essential part of viem, as they provide a way to test and simulate different scenarios on the Ethereum network. They are commonly used by developers who are building dapps and other applications that need to be tested before they are deployed to the network. By using Test Actions, developers can test the behavior of their applications in a controlled environment, without the need for a real balance or real users. This makes it easier to identify and fix bugs, and it ensures that the application will work as expected when it is deployed to the network.
# loadState
Adds state previously dumped with `dumpState` to the current chain.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.loadState({ state: '0x1f8b08000000000000ffad934d8e1c310885ef52eb5e003660e636184c3651b7949948915a7df7b8934ded6bbcc23fe2f3e3c1f3f088c7effbd7e7f1f13ce00ff60c35939e4e016352131bb3658bd0f046682dcd98dfafef8f7bace3036ec7f49ffe2fde190817da82b0e9933abcd7713be291ffaf77fcf9f5f8e53ff6f6f97addde4cced6dd8b3b89e6d4d468a2a3d93e537480fd15713933f12a73ebc2b106ae561c59bae1d152784733c067f1dc49479d987295d9a2f7c8cc296e00e534797026d94ed312a9bc93b5192726d155a882999a42300ea48ce680109a80936141a2be0d8f7182f6cb4a0d4a6d96ac49d16b2834e1a5836dd0c242c0b5751ac8d9d1cb4a4d65b97620594ac2dc77a159cbb9ab349f096fedee76828ecb4cdb20d044679e1124c6c1633a4acda639d026f81ea96f15eab0963a76ca3d2f81b58705fbea3e4a59761b11f8769ce0046d5799d5ac5216a37b8e51523d96f81c839476fb54d53422393bda94af505fafbf9d0612379c040000' })
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### state
* **Type:** `Hex`
The state as a data blob.
# mine
Mine a specified number of blocks.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.mine({ // [!code focus:4]
blocks: 1,
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### blocks
* **Type:** `number`
Number of blocks to mine.
```ts
await testClient.mine({
blocks: 1, // [!code focus:4]
})
```
### interval (optional)
* **Type:** `number`
* **Default:** `1`
Interval between each block in seconds.
```ts
await testClient.mine({
blocks: 10,
interval: 4 // [!code focus]
})
```
# removeBlockTimestampInterval
Removes [`setBlockTimestampInterval`](/docs/actions/test/setBlockTimestampInterval) if it exists.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.removeBlockTimestampInterval() // [!code focus]
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
# reset
Resets the fork back to its original state.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.reset() // [!code focus]
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### blockNumber (optional)
* **Type:** `bigint`
Resets the fork to a given block number.
```ts
await testClient.reset({
blockNumber: 69420n, // [!code focus]
jsonRpcUrl: 'https://1.rpc.thirdweb.com'
})
```
### jsonRpcUrl (optional)
* **Type:** `string`
Resets the fork with a given JSON RPC URL.
```ts
await testClient.reset({
blockNumber: 69420n,
jsonRpcUrl: 'https://1.rpc.thirdweb.com' // [!code focus]
})
```
# revert
Revert the state of the blockchain at the current block.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.revert({ // [!code focus:99]
id: '0x...'
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### id
* **Type:** `"0x${string}"`
The snapshot ID.
```ts
await testClient.revert({
id: '0x...' // [!code focus]
})
```
# sendUnsignedTransaction
Executes a transaction regardless of the signature.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
const hash = await testClient.sendUnsignedTransaction({ // [!code focus:99]
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
// '0x...'
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The transaction hash.
## Parameters
### from
* **Type:** [`Address`](/docs/glossary/types#address)
The Transaction sender.
```ts
const hash = await testClient.sendUnsignedTransaction({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### to
* **Type:** `number`
The transaction recipient or contract address.
```ts
const hash = await testClient.sendUnsignedTransaction({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts
const data = await testClient.sendUnsignedTransaction({
accessList: [ // [!code focus:6]
{
address: '0x1',
storageKeys: ['0x1'],
},
],
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### data (optional)
* **Type:** `0x${string}`
A contract hashed method call with encoded args.
```ts
const hash = await testClient.sendUnsignedTransaction({
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts
const hash = await testClient.sendUnsignedTransaction({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const hash = await testClient.sendUnsignedTransaction({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts
const hash = await testClient.sendUnsignedTransaction({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts
const hash = await testClient.sendUnsignedTransaction({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69 // [!code focus]
})
```
### value (optional)
* **Type:** `number`
Value in wei sent with this transaction.
```ts
const hash = await testClient.sendUnsignedTransaction({
from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'), // [!code focus]
nonce: 69
})
```
# setAutomine
Enables or disables the automatic mining of new blocks with each new transaction submitted to the network.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.setAutomine(true) // [!code focus]
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### enabled
* **Type:** `boolean`
```ts
await testClient.setAutomine(false) // [!code focus]
```
# setBalance
Modifies the balance of an account.
## Usage
:::code-group
```ts [example.ts]
import { parseEther } from 'viem'
import { testClient } from './client'
await testClient.setBalance({ // [!code focus:4]
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
value: parseEther('1')
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The address of the target account.
```ts
await testClient.setBalance({
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
value: parseEther('1')
})
```
### value (optional)
* **Type:** `bigint`
The value (in wei) to set.
```ts
await testClient.setBalance({
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
value: 1000000000000000000n // [!code focus]
})
```
# setBlockGasLimit
Sets the block's gas limit.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.setBlockGasLimit({ // [!code focus:4]
gasLimit: 420_000n
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### gasLimit
* **Type:** `bigint`
The gas limit.
```ts
await testClient.setBlockGasLimit({
gasLimit: 420_000n // [!code focus]
})
```
# setBlockTimestampInterval
Similar to [`increaseTime`](/docs/actions/test/increaseTime), but sets a block timestamp `interval`. The timestamp of future blocks will be computed as `lastBlock_timestamp` + `interval`.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.setBlockTimestampInterval({ // [!code focus:4]
interval: 5
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### interval
* **Type:** `number`
```ts
await testClient.setBlockTimestampInterval({
interval: 1 // [!code focus]
})
```
# setCode
Modifies the bytecode stored at an account's address.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.setCode({ // [!code focus:4]
address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79',
bytecode: '0x60806040526000600355600019600955600c80546001600160a01b031916737a250d5630b4cf539739df...'
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The account address.
```ts
await testClient.setCode({
address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79', // [!code focus]
bytecode: '0x60806040526000600355600019600955600c80546001600160a01b031916737a250d5630b4cf539739df...'
})
```
### bytecode
* **Type:** [`Hex`](/docs/glossary/types#hex)
The stored bytecode.
```ts
await testClient.setCode({
address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79',
bytecode: '0x60806040526000600355600019600955600c80546001600160a01b031916737a250d5630b4cf539739df...' // [!code focus]
})
```
# setCoinbase
Sets the coinbase address to be used in new blocks.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.setCoinbase({ // [!code focus:99]
address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79',
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The coinbase address.
```ts
await testClient.setCoinbase({
address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79', // [!code focus]
})
```
# setIntervalMining
Sets the automatic mining interval (in seconds) of blocks. Setting the interval to `0` will disable automatic mining.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.setIntervalMining({ // [!code focus:4]
interval: 5
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### interval
* **Type:** `number`
The mining interval (in seconds). Setting the interval to `0` will disable automatic mining.
```ts
await testClient.setIntervalMining({
interval: 5 // [!code focus]
})
```
# setLoggingEnabled
Enable or disable logging on the test node network.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.setLoggingEnabled(true) // [!code focus]
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
# setMinGasPrice
Change the minimum gas price accepted by the network (in wei).
> Note: `setMinGasPrice` can only be used on clients that do not have EIP-1559 enabled.
## Usage
:::code-group
```ts [example.ts]
import { parseGwei } from 'viem'
import { testClient } from './client'
await testClient.setMinGasPrice({ // [!code focus:99]
gasPrice: parseGwei('20'),
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### gasPrice
* **Type:** `bigint`
The gas price (in wei).
```ts
await testClient.setMinGasPrice({
gasPrice: parseGwei('20'), // [!code focus]
})
```
# setNextBlockBaseFeePerGas
Sets the next block's base fee per gas.
## Usage
:::code-group
```ts [example.ts]
import { parseGwei } from 'viem'
import { testClient } from './client'
await testClient.setNextBlockBaseFeePerGas({ // [!code focus:4]
baseFeePerGas: parseGwei('20')
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### baseFeePerGas
* **Type:** `bigint`
Base fee per gas.
```ts
await testClient.setNextBlockBaseFeePerGas({
baseFeePerGas: parseGwei('30') // [!code focus]
})
```
# setNextBlockTimestamp
Sets the next block's timestamp.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.setNextBlockTimestamp({ // [!code focus:4]
timestamp: 1671744314n
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### timestamp
* **Type:** `bigint`
```ts
await testClient.setNextBlockTimestamp({
timestamp: 1671744314n // [!code focus]
})
```
## Notes
* The next Block `timestamp` cannot be lesser than the current Block `timestamp`.
# setNonce
Modifies (overrides) the nonce of an account.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.setNonce({ // [!code focus:4]
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
nonce: 420
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The address of the target account.
```ts
await testClient.setNonce({
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
nonce: 420
})
```
### nonce (optional)
* **Type:** `number`
The nonce.
```ts
await testClient.setNonce({
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
nonce: 420 // [!code focus]
})
```
# setRpcUrl
Sets the backend RPC URL.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.setRpcUrl('https://eth-mainnet.g.alchemy.com/v2') // [!code focus]
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
# setStorageAt
Writes to a slot of an account's storage.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.setStorageAt({ // [!code focus:99]
address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79',
index: 2,
value: '0x0000000000000000000000000000000000000000000000000000000000000069'
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The account address.
```ts
await testClient.setStorageAt({
address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79', // [!code focus]
index: 2,
value: '0x0000000000000000000000000000000000000000000000000000000000000069'
})
```
### index
* **Type:** `number | Hash`
The storage slot (index). Can either be a number or hash value.
```ts
await testClient.setStorageAt({
address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79',
index: '0xa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49', // [!code focus]
value: '0x0000000000000000000000000000000000000000000000000000000000000069'
})
```
### value
* **Type:** `number`
The value to store as a 32 byte hex string.
```ts
await testClient.setStorageAt({
address: '0xe846c6fcf817734ca4527b28ccb4aea2b6663c79',
index: 2,
value: '0x0000000000000000000000000000000000000000000000000000000000000069' // [!code focus]
})
```
# snapshot
Snapshot the state of the blockchain at the current block.
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
const id = await testClient.snapshot() // [!code focus]
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Returns
ID of the snapshot that was created.
# stopImpersonatingAccount
Stop impersonating an account after having previously used [`impersonateAccount`](/docs/actions/test/impersonateAccount).
## Usage
:::code-group
```ts [example.ts]
import { testClient } from './client'
await testClient.stopImpersonatingAccount({ // [!code focus:4]
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC'
})
```
```ts [client.ts]
import { createTestClient, http } from 'viem'
import { foundry } from 'viem/chains'
export const testClient = createTestClient({
chain: foundry,
mode: 'anvil',
transport: http(),
})
```
:::
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
The address of the target account.
```ts
await testClient.stopImpersonatingAccount({
address: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
})
```
# addChain
Adds an EVM chain to the wallet.
## Usage
:::code-group
```ts twoslash [example.ts]
import { avalanche } from 'viem/chains'
import { walletClient } from './client'
await walletClient.addChain({ chain: avalanche }) // [!code focus]
```
```ts twoslash [client.ts] filename="client.ts"
// [!include ~/snippets/walletClient.ts]
```
:::
## Parameters
### chain
* **Type:** [`Chain`](/docs/glossary/types#chain)
The chain to add to the wallet.
## JSON-RPC Methods
[`wallet_addEtherereumChain`](https://eips.ethereum.org/EIPS/eip-3085)
# getAddresses
Returns a list of account addresses owned by the wallet or client.
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './client'
const accounts = await walletClient.getAddresses() // [!code focus:99]
// ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC']
```
```ts twoslash [client.ts] filename="client.ts"
// [!include ~/snippets/walletClient.ts]
```
:::
## Returns
[`Address[]`](/docs/glossary/types#address)
A list of checksummed addresses.
## JSON-RPC Methods
[`eth_accounts`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_accounts)
# getCallsStatus
Returns the status of a call batch that was sent via `sendCalls`.
[Read more](https://eips.ethereum.org/EIPS/eip-5792#wallet_getcallsstatus)
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const result = await walletClient.getCallsStatus({ // [!code focus:99]
id: '0x1234567890abcdef',
})
// @log: {
// @log: atomic: false,
// @log: chainId: 1,
// @log: id: '0x1234567890abcdef',
// @log: statusCode: 200,
// @log: status: 'success',
// @log: receipts: [{ ... }],
// @log: }
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
})
export const [account] = await walletClient.getAddresses()
```
:::
## Returns
`WalletGetCallsStatusReturnType`
Status of the calls.
## Parameters
### id
* **Type:** `string`
Identifier of the call batch.
# getCapabilities
Extract capabilities (grouped by chain ID) that a connected wallet supports (e.g. paymasters, session keys, etc).
[Read more](https://github.com/ethereum/EIPs/blob/815028dc634463e1716fc5ce44c019a6040f0bef/EIPS/eip-5792.md#wallet_getcapabilities)
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient } from './config'
const capabilities = await walletClient.getCapabilities({
account,
})
// @log: {
// @log: 8453: {
// @log: atomic: {
// @log: status: 'supported',
// @log: },
// @log: paymasterService: {
// @log: supported: true,
// @log: },
// @log: },
// @log: 84532: {
// @log: atomic: {
// @log: status: 'supported',
// @log: },
// @log: },
// @log: }
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
})
export const [account] = await walletClient.getAddresses()
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `getCapabilities`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const capabilities = await walletClient.getCapabilities()
```
```ts [config.ts] filename="config.ts"
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum!.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
:::
## Returns
`WalletCapabilities`
Capabilities of the wallet.
## Parameters
### account
* **Type:** `Address`
The account to get capabilities for.
```ts twoslash [example.ts]
import { walletClient } from './config'
// ---cut---
const capabilities = await walletClient.getCapabilities({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
})
```
### chainId
* **Type:** `number`
The chain ID to get capabilities for.
```ts twoslash [example.ts]
import { walletClient } from './config'
// ---cut---
const capabilities = await walletClient.getCapabilities({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
chainId: 8453, // [!code focus]
})
```
# getPermissions
Gets the wallets current permissions.
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './client'
const permissions = await walletClient.getPermissions() // [!code focus:99]
```
```ts twoslash [client.ts] filename="client.ts"
// [!include ~/snippets/walletClient.ts]
```
:::
## Returns
[`WalletPermission[]`](/docs/glossary/types#walletpermission)
The wallet permissions.
## JSON-RPC Methods
[`wallet_getPermissions`](https://eips.ethereum.org/EIPS/eip-2255)
# Introduction to Wallet Actions \[A brief introduction to Wallet Actions in viem.]
Wallet Actions are actions that map one-to-one with a "wallet" or "signable" Ethereum RPC method (`eth_requestAccounts`, `eth_sendTransaction`, etc). They are used with a [Wallet Client](/docs/clients/wallet).
Wallet Actions require special permissions and provide signing capabilities. Examples of Wallet Actions include [retrieving the user's account addresses](/docs/actions/wallet/getAddresses), [sending a transaction](/docs/actions/wallet/sendTransaction), and [signing a message](/docs/actions/wallet/signMessage).
Wallet Actions provide a secure and flexible way to access the user's accounts and perform actions on the Ethereum network. They are commonly used by dapps and other applications that need to execute transactions, interact with smart contracts, or sign messages.
# prepareTransactionRequest
Prepares a transaction request for signing by populating a nonce, gas limit, fee values, and a transaction type.
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient } from './config'
const request = await walletClient.prepareTransactionRequest({ // [!code focus:16]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
// @log: {
// @log: account: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
// @log: to: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
// @log: maxFeePerGas: 150000000000n,
// @log: maxPriorityFeePerGas: 1000000000n,
// @log: nonce: 69,
// @log: type: 'eip1559',
// @log: value: 1000000000000000000n
// @log: }
const serializedTransaction = await walletClient.signTransaction(request)
const hash = await walletClient.sendRawTransaction({ serializedTransaction })
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!)
})
// @log: ↓ JSON-RPC Account
export const account = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
// @log: ↓ Local Account
// export const account = privateKeyToAccount(...)
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `prepareTransactionRequest`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const request = await walletClient.prepareTransactionRequest({ // [!code focus:16]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
// @log: {
// @log: account: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
// @log: to: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
// @log: maxFeePerGas: 150000000000n,
// @log: maxPriorityFeePerGas: 1000000000n,
// @log: nonce: 69,
// @log: type: 'eip1559',
// @log: value: 1000000000000000000n
// @log: }
const serializedTransaction = await walletClient.signTransaction(request)
const hash = await walletClient.sendRawTransaction({ serializedTransaction })
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
```ts twoslash [config.ts (Local Account)] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
transport: http()
})
```
:::
## Returns
[`TransactionRequest`](/docs/glossary/types#transactionrequest)
The transaction request.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts twoslash
// [!include config.ts]
// ---cut---
const request = await walletClient.prepareTransactionRequest({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### to
* **Type:** `0x${string}`
The transaction recipient or contract address.
```ts twoslash
// [!include config.ts]
// ---cut---
const request = await walletClient.prepareTransactionRequest({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: 1000000000000000000n,
nonce: 69
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts twoslash
// [!include config.ts]
// ---cut---
const request = await walletClient.prepareTransactionRequest({
accessList: [ // [!code focus:6]
{
address: '0x1',
storageKeys: ['0x1'],
},
],
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### authorizationList (optional)
* **Type:** `AuthorizationList`
Signed EIP-7702 Authorization list.
```ts twoslash
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
chain: mainnet,
transport: http(),
})
// ---cut---
const authorization = await walletClient.signAuthorization({
account,
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
})
const request = await walletClient.prepareTransactionRequest({
account,
authorizationList: [authorization], // [!code focus]
data: '0xdeadbeef',
to: account.address,
})
```
:::note
**References**
* [EIP-7702 Overview](/docs/eip7702)
* [`signAuthorization` Docs](/docs/eip7702/signAuthorization)
:::
### blobs (optional)
* **Type:** `Hex[]`
Blobs for [Blob Transactions](/docs/guides/blob-transactions).
```ts
import * as cKzg from 'c-kzg'
import { toBlobs, setupKzg, stringToHex } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
const request = await walletClient.prepareTransactionRequest({
account,
blobs: toBlobs({ data: stringToHex('blobby blob!') }), // [!code focus]
kzg,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
The chain is also used to infer its request type (e.g. the Celo chain has a `gatewayFee` that you can pass through to `prepareTransactionRequest`).
```ts twoslash
// [!include config.ts]
// ---cut---
import { optimism } from 'viem/chains' // [!code focus]
const request = await walletClient.prepareTransactionRequest({
chain: optimism, // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### data (optional)
* **Type:** `0x${string}`
A contract hashed method call with encoded args.
```ts twoslash
// [!include config.ts]
// ---cut---
const request = await walletClient.prepareTransactionRequest({
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### gas (optional)
* **Type:** `bigint`
The gas limit of the transaction. If missing, it will be estimated.
```ts twoslash
// [!include config.ts]
// ---cut---
import { parseEther, parseGwei } from 'viem'
const request = await walletClient.prepareTransactionRequest({
account,
gas: 21000n, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts twoslash
// [!include config.ts]
// ---cut---
import { parseEther, parseGwei } from 'viem'
const request = await walletClient.prepareTransactionRequest({
account,
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### kzg (optional)
* **Type:** `KZG`
KZG implementation for [Blob Transactions](/docs/guides/blob-transactions).
See [`setupKzg`](/docs/utilities/setupKzg) for more information.
```ts
import * as cKzg from 'c-kzg'
import { toBlobs, setupKzg, stringToHex } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath) // [!code focus]
const request = await walletClient.prepareTransactionRequest({
account,
blobs: toBlobs({ data: stringToHex('blobby blob!') }), // [!code focus]
kzg, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include config.ts]
// ---cut---
import { parseEther, parseGwei } from 'viem'
const request = await walletClient.prepareTransactionRequest({
account,
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include config.ts]
// ---cut---
import { parseEther, parseGwei } from 'viem'
const request = await walletClient.prepareTransactionRequest({
account,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts twoslash
// [!include config.ts]
// ---cut---
const request = await walletClient.prepareTransactionRequest({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69 // [!code focus]
})
```
### nonceManager (optional)
* **Type:** `NonceManager | undefined`
Nonce Manager to consume and increment the Account nonce for the transaction request.
```ts twoslash
// @noErrors
// [!include config.ts]
// ---cut---
const request = await walletClient.prepareTransactionRequest({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonceManager: account.nonceManager // [!code focus]
})
```
### parameters (optional)
* **Type:** `("fees" | "gas" | "nonce" | "type")[]`
* **Default:** `["fees", "gas", "nonce", "type"]`
Parameters to prepare.
For instance, if `["gas", "nonce"]` is provided, then only the `gas` and `nonce` parameters will be prepared.
```ts twoslash
// [!include config.ts]
// ---cut---
const request = await walletClient.prepareTransactionRequest({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69 // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction.
```ts twoslash
// [!include config.ts]
// ---cut---
import { parseEther } from 'viem'
const request = await walletClient.prepareTransactionRequest({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'), // [!code focus]
nonce: 69
})
```
# requestAddresses
Requests a list of accounts managed by a wallet.
`requestAddresses` sends a request to the wallet, asking for permission to access the user's accounts. After the user accepts the request, it will return a list of accounts (addresses).
This API can be useful for dapps that need to access the user's accounts in order to execute transactions or interact with smart contracts.
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './client'
const accounts = await walletClient.requestAddresses() // [!code focus:99]
// ['0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC']
```
```ts twoslash [client.ts] filename="client.ts"
// [!include ~/snippets/walletClient.ts]
```
:::
## Returns
[`Address[]`](/docs/glossary/types#address)
## JSON-RPC Methods
[`eth_requestAccounts`](https://eips.ethereum.org/EIPS/eip-1102)
# requestPermissions
Requests permissions for a wallet.
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './client'
const permissions = await walletClient.requestPermissions({ eth_accounts: {} }) // [!code focus:99]
```
```ts twoslash [client.ts] filename="client.ts"
// [!include ~/snippets/walletClient.ts]
```
:::
## Returns
[`WalletPermission[]`](/docs/glossary/types#walletpermission)
The wallet permissions.
## JSON-RPC Methods
[`wallet_requestPermissions`](https://eips.ethereum.org/EIPS/eip-2255)
# sendCalls
Requests for the wallet to sign and broadcast a batch of calls to the network.
[Read more](https://eips.ethereum.org/EIPS/eip-5792#wallet_sendcalls)
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, walletClient } from './config'
const { id } = await walletClient.sendCalls({ // [!code focus:99]
account,
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
})
export const [account] = await walletClient.getAddresses()
```
:::
Notes:
* `account` and `chain` are top level properties as all calls should be sent by the same account and chain.
* Properties of `calls` items are only those shared by all transaction types (e.g. `data`, `to`, `value`). The Wallet should handle other required properties like gas & fees.
* [Read `wallet_sendCalls` on EIP-5792.](https://eips.ethereum.org/EIPS/eip-5792#wallet_sendcalls)
### Account Hoisting
If you do not wish to pass an `account` to every `sendCalls`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const { id } = await walletClient.sendCalls({ // [!code focus:99]
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
```ts [config.ts] filename="config.ts"
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum!.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
:::
### Contract Calls
The `calls` property also accepts **Contract Calls**, and can be used via the `abi`, `functionName`, and `args` properties.
:::code-group
```ts twoslash [example.ts]
import { parseAbi } from 'viem'
import { walletClient } from './config'
const abi = parseAbi([
'function approve(address, uint256) returns (bool)',
'function transferFrom(address, address, uint256) returns (bool)',
])
const { id } = await walletClient.sendCalls({ // [!code focus:99]
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'approve',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'transferFrom',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
'0x0000000000000000000000000000000000000000',
100n
],
},
],
})
```
```ts twoslash [abi.ts] filename="abi.ts"
export const wagmiAbi = [
// ...
{
inputs: [],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
// ...
] as const;
```
```ts [config.ts] filename="config.ts"
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum!.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
:::
### Compatibility Fallback
If the Wallet does not support EIP-5792 and `wallet_sendCalls`, passing the `experimental_fallback`
flag to `sendCalls` will allow Viem to fall back to executing the calls sequentially
via `eth_sendTransaction`.
:::warning
When using `experimental_fallback` with a wallet that does not support EIP-5792,
Viem will return a custom bundle identifier (`id`). While this identifier works with Viem's [`getCallsStatus`
Action](/docs/actions/wallet/getCallsStatus), it cannot be used with the native `wallet_getCallsStatus` RPC method.
:::
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, walletClient } from './config'
const { id } = await walletClient.sendCalls({
account,
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
experimental_fallback: true, // [!code focus]
})
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
})
export const [account] = await walletClient.getAddresses()
```
:::
## Returns
`{ id: string, capabilities?: WalletCapabilities }`
The identifier can be any arbitrary string. The only requirement is that for a given session, consumers should be able to call `getCallsStatus` with this identifier to retrieve a batch call status and call receipts.
## Parameters
### account
* **Type:** `Account | Address | null`
The Account to sign & broadcast the call from. If set to `null`, it is assumed that the wallet will handle filling the sender of the calls.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts).
```ts twoslash
import { walletClient } from './config'
const { id } = await walletClient.sendCalls({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
### chain
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain to broadcast the calls.
```ts twoslash
import { mainnet } from 'viem/chains'
import { walletClient } from './config'
const { id } = await walletClient.sendCalls({
chain: mainnet, // [!code focus]
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
### calls
* **Type:** `Call[]`
An array of calls to be signed and broadcasted.
```ts twoslash
import { mainnet } from 'viem/chains'
import { walletClient } from './config'
const { id } = await walletClient.sendCalls({
chain: mainnet,
calls: [ // [!code focus]
{ // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1') // [!code focus]
}, // [!code focus]
{ // [!code focus]
data: '0xdeadbeef', // [!code focus]
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
}, // [!code focus]
], // [!code focus]
})
```
#### calls.data
* **Type:** `Hex`
Calldata to broadcast (typically a contract function selector with encoded arguments, or contract deployment bytecode).
```ts twoslash
import { mainnet } from 'viem/chains'
import { walletClient } from './config'
const { id } = await walletClient.sendCalls({
chain: mainnet,
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef', // [!code focus]
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
When calling functions on contracts, it may be more convenient to pass in a [Contract Call](#contract-calls), providing the the `abi`, `functionName`, and `args` properties which will then be encoded into the appropriate `calls.data`.
```ts twoslash
import { parseAbi } from 'viem'
import { walletClient } from './config'
const abi = parseAbi([
'function approve(address, uint256) returns (bool)',
])
const { id } = await walletClient.sendCalls({
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi, // [!code focus:6]
functionName: 'approve',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
}
],
})
```
#### calls.to
* **Type:** `Address`
Recipient address of the call.
```ts twoslash
import { mainnet } from 'viem/chains'
import { walletClient } from './config'
const { id } = await walletClient.sendCalls({
chain: mainnet,
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
},
],
})
```
#### calls.value
* **Type:** `Address`
Value to send with the call.
```ts twoslash
import { mainnet } from 'viem/chains'
import { walletClient } from './config'
const { id } = await walletClient.sendCalls({
chain: mainnet,
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
#### calls.dataSuffix
* **Type:** Hex
Data to append to the end of the calldata. Useful for adding a "domain" tag.
```ts twoslash [example.ts]
import { parseAbi } from 'viem'
import { walletClient } from './config'
const abi = parseAbi([
'function approve(address, uint256) returns (bool)',
])
// ---cut---
const { id } = await walletClient.sendCalls({
calls: [
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'approve',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
dataSuffix: '0xdeadbeef' // [!code focus]
}
],
})
```
### capabilities
* **Type:** `WalletCapabilities`
Capability metadata for the calls (e.g. specifying a paymaster).
```ts twoslash
import { walletClient } from './config'
const { id } = await walletClient.sendCalls({
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
capabilities: { // [!code focus]
paymasterService: { // [!code focus]
url: 'https://...' // [!code focus]
} // [!code focus]
} // [!code focus]
})
```
### forceAtomic
* **Type:** `boolean`
* **Default:** `false`
Force the calls to be executed atomically. [See more](https://eips.ethereum.org/EIPS/eip-5792#call-execution-atomicity)
```ts twoslash
import { walletClient } from './config'
const { id } = await walletClient.sendCalls({
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
forceAtomic: true, // [!code focus]
})
```
### id
* **Type:** `string`
Attribute the call batch with an identifier.
```ts twoslash
import { walletClient } from './config'
const { id } = await walletClient.sendCalls({
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
id: '', // [!code focus]
})
```
# sendCallsSync
Requests for the wallet to sign and broadcast a batch of calls to the network, and waits for the calls to be included in a block.
[Read more](https://eips.ethereum.org/EIPS/eip-5792#wallet_sendcalls)
:::warning
This Action is only recommended to be used on chains with low block times and fast finality (most chains apart from `mainnet`).
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, walletClient } from './config'
const status = await walletClient.sendCallsSync({ // [!code focus:99]
account,
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
})
export const [account] = await walletClient.getAddresses()
```
:::
Notes:
* `account` and `chain` are top level properties as all calls should be sent by the same account and chain.
* Properties of `calls` items are only those shared by all transaction types (e.g. `data`, `to`, `value`). The Wallet should handle other required properties like gas & fees.
* [Read `wallet_sendCalls` on EIP-5792.](https://eips.ethereum.org/EIPS/eip-5792#wallet_sendcalls)
### Account Hoisting
If you do not wish to pass an `account` to every `sendCalls`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({ // [!code focus:99]
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
```ts [config.ts] filename="config.ts"
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum!.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
:::
### Contract Calls
The `calls` property also accepts **Contract Calls**, and can be used via the `abi`, `functionName`, and `args` properties.
:::code-group
```ts twoslash [example.ts]
import { parseAbi } from 'viem'
import { walletClient } from './config'
const abi = parseAbi([
'function approve(address, uint256) returns (bool)',
'function transferFrom(address, address, uint256) returns (bool)',
])
const status = await walletClient.sendCallsSync({ // [!code focus:99]
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'approve',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'transferFrom',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
'0x0000000000000000000000000000000000000000',
100n
],
},
],
})
```
```ts twoslash [abi.ts] filename="abi.ts"
export const wagmiAbi = [
// ...
{
inputs: [],
name: "mint",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
// ...
] as const;
```
```ts [config.ts] filename="config.ts"
import 'viem/window'
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum!.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
:::
### Compatibility Fallback
If the Wallet does not support EIP-5792 and `wallet_sendCalls`, passing the `experimental_fallback`
flag to `sendCalls` will allow Viem to fall back to executing the calls sequentially
via `eth_sendTransaction`.
:::warning
When using `experimental_fallback` with a wallet that does not support EIP-5792,
Viem will return a custom bundle identifier (`id`). While this identifier works with Viem's [`getCallsStatus`
Action](/docs/actions/wallet/getCallsStatus), it cannot be used with the native `wallet_getCallsStatus` RPC method.
:::
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, walletClient } from './config'
const status = await walletClient.sendCallsSync({
account,
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
experimental_fallback: true, // [!code focus]
})
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
})
export const [account] = await walletClient.getAddresses()
```
:::
## Returns
`WalletGetCallsStatusReturnType`
Status of the calls.
## Parameters
### account
* **Type:** `Account | Address | null`
The Account to sign & broadcast the call from. If set to `null`, it is assumed that the wallet will handle filling the sender of the calls.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts).
```ts twoslash
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
### chain
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain to broadcast the calls.
```ts twoslash
import { mainnet } from 'viem/chains'
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({
chain: mainnet, // [!code focus]
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
### calls
* **Type:** `Call[]`
An array of calls to be signed and broadcasted.
```ts twoslash
import { mainnet } from 'viem/chains'
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({
chain: mainnet,
calls: [ // [!code focus]
{ // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1') // [!code focus]
}, // [!code focus]
{ // [!code focus]
data: '0xdeadbeef', // [!code focus]
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
}, // [!code focus]
], // [!code focus]
})
```
#### calls.data
* **Type:** `Hex`
Calldata to broadcast (typically a contract function selector with encoded arguments, or contract deployment bytecode).
```ts twoslash
import { mainnet } from 'viem/chains'
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({
chain: mainnet,
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef', // [!code focus]
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
When calling functions on contracts, it may be more convenient to pass in a [Contract Call](#contract-calls), providing the the `abi`, `functionName`, and `args` properties which will then be encoded into the appropriate `calls.data`.
```ts twoslash
import { parseAbi } from 'viem'
import { walletClient } from './config'
const abi = parseAbi([
'function approve(address, uint256) returns (bool)',
])
const status = await walletClient.sendCallsSync({
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi, // [!code focus:6]
functionName: 'approve',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
}
],
})
```
#### calls.to
* **Type:** `Address`
Recipient address of the call.
```ts twoslash
import { mainnet } from 'viem/chains'
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({
chain: mainnet,
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC', // [!code focus]
},
],
})
```
#### calls.value
* **Type:** `Address`
Value to send with the call.
```ts twoslash
import { mainnet } from 'viem/chains'
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({
chain: mainnet,
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1') // [!code focus]
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
})
```
#### calls.dataSuffix
* **Type:** Hex
Data to append to the end of the calldata. Useful for adding a "domain" tag.
```ts twoslash [example.ts]
import { parseAbi } from 'viem'
import { walletClient } from './config'
const abi = parseAbi([
'function approve(address, uint256) returns (bool)',
])
// ---cut---
const status = await walletClient.sendCallsSync({
calls: [
{
to: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
abi,
functionName: 'approve',
args: [
'0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
100n
],
dataSuffix: '0xdeadbeef' // [!code focus]
}
],
})
```
### capabilities
* **Type:** `WalletCapabilities`
Capability metadata for the calls (e.g. specifying a paymaster).
```ts twoslash
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
capabilities: { // [!code focus]
paymasterService: { // [!code focus]
url: 'https://...' // [!code focus]
} // [!code focus]
} // [!code focus]
})
```
### forceAtomic
* **Type:** `boolean`
* **Default:** `false`
Force the calls to be executed atomically. [See more](https://eips.ethereum.org/EIPS/eip-5792#call-execution-atomicity)
```ts twoslash
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
forceAtomic: true, // [!code focus]
})
```
### id
* **Type:** `string`
Attribute the call batch with an identifier.
```ts twoslash
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
id: '', // [!code focus]
})
```
### pollingInterval (optional)
* **Type:** `number`
* **Default:** `walletClient.pollingInterval`
The polling interval to poll for the calls status.
```ts twoslash
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
{
data: '0xdeadbeef',
to: '0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC',
},
],
pollingInterval: 1_000, // [!code focus]
})
```
### timeout (optional)
* **Type:** `number`
* **Default:** `chain.blockTime * 3`
The timeout to wait for the calls status.
```ts twoslash
import { walletClient } from './config'
const status = await walletClient.sendCallsSync({
calls: [
{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
},
],
timeout: 20_000, // [!code focus]
})
```
# sendRawTransaction
Sends a **signed** transaction to the network. Can be used with both [Public Clients](/docs/clients/public) and [Wallet Clients](/docs/clients/wallet)
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient } from './config'
const request = await walletClient.prepareTransactionRequest({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
const serializedTransaction = await walletClient.signTransaction(request)
const hash = await walletClient.sendRawTransaction({ serializedTransaction }) // [!code focus]
```
```ts twoslash [config.ts] filename="config.ts"
// [!include ~/snippets/walletClient.ts]
export const [account] = await walletClient.getAddresses()
// @log: ↑ JSON-RPC Account
// export const account = privateKeyToAccount(...)
// @log: ↑ Local Account
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### serializedTransaction
* **Type:** `Hex`
The signed serialized transaction.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const signature = await walletClient.sendRawTransaction({
serializedTransaction: '0x02f850018203118080825208808080c080a04012522854168b27e5dc3d5839bab5e6b39e1a0ffd343901ce1622e3d64b48f1a04e00902ae0502c4728cbf12156290df99c3ed7de85b1dbfe20b5c36931733a33' // [!code focus]
})
```
# sendRawTransactionSync
Sends a **signed** transaction to the network, and waits for the transaction to be included in a block.
:::warning
This Action is only recommended to be used on chains with low block times and fast finality (most chains apart from `mainnet`).
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient } from './config'
const request = await walletClient.prepareTransactionRequest({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
const serializedTransaction = await walletClient.signTransaction(request)
const receipt = await walletClient.sendRawTransactionSync({ serializedTransaction }) // [!code focus]
```
```ts twoslash [config.ts] filename="config.ts"
// [!include ~/snippets/walletClient.ts]
export const [account] = await walletClient.getAddresses()
// @log: ↑ JSON-RPC Account
// export const account = privateKeyToAccount(...)
// @log: ↑ Local Account
```
:::
## Returns
[`TransactionReceipt`](/docs/glossary/types#transaction-receipt)
The [Transaction receipt](/docs/glossary/terms#transaction-receipt).
## Parameters
### serializedTransaction
* **Type:** `Hex`
The signed serialized transaction.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const signature = await walletClient.sendRawTransaction({
serializedTransaction: '0x02f850018203118080825208808080c080a04012522854168b27e5dc3d5839bab5e6b39e1a0ffd343901ce1622e3d64b48f1a04e00902ae0502c4728cbf12156290df99c3ed7de85b1dbfe20b5c36931733a33' // [!code focus]
})
```
### throwOnReceiptRevert (optional)
* **Type:** `boolean`
Whether to throw an error if the transaction was detected as reverted.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const receipt = await walletClient.sendRawTransactionSync({
serializedTransaction: '0x02f850018203118080825208808080c080a04012522854168b27e5dc3d5839bab5e6b39e1a0ffd343901ce1622e3d64b48f1a04e00902ae0502c4728cbf12156290df99c3ed7de85b1dbfe20b5c36931733a33',
throwOnReceiptRevert: true // [!code focus]
})
```
### timeout (optional)
* **Type:** `number`
Timeout for the transaction to be included in a block.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const receipt = await walletClient.sendRawTransactionSync({
serializedTransaction: '0x02f850018203118080825208808080c080a04012522854168b27e5dc3d5839bab5e6b39e1a0ffd343901ce1622e3d64b48f1a04e00902ae0502c4728cbf12156290df99c3ed7de85b1dbfe20b5c36931733a33',
timeout: 20_000 // [!code focus]
})
```
# sendTransaction
Creates, signs, and sends a new transaction to the network.
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient } from './config'
const hash = await walletClient.sendTransaction({ // [!code focus:99]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
// '0x...'
```
```ts twoslash [config.ts] filename="config.ts"
// [!include ~/snippets/walletClient.ts]
export const [account] = await walletClient.getAddresses()
// @log: ↑ JSON-RPC Account
// export const account = privateKeyToAccount(...)
// @log: ↑ Local Account
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `sendTransaction`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const hash = await walletClient.sendTransaction({ // [!code focus:99]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
// '0x...'
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
```ts twoslash [config.ts (Local Account)] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
transport: http()
})
```
:::
## Returns
[`Hash`](/docs/glossary/types#hash)
The [Transaction](/docs/glossary/terms#transaction) hash.
## Parameters
### account
* **Type:** `Account | Address | null`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc). If set to `null`, it is assumed that the transport will handle filling the sender of the transaction.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const hash = await walletClient.sendTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### to
* **Type:** `0x${string}`
The transaction recipient or contract address.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: 1000000000000000000n,
nonce: 69
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const hash = await walletClient.sendTransaction({
accessList: [ // [!code focus:6]
{
address: '0x1',
storageKeys: ['0x1'],
},
],
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### authorizationList (optional)
* **Type:** `AuthorizationList`
Signed EIP-7702 Authorization list.
```ts twoslash
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
chain: mainnet,
transport: http(),
})
// ---cut---
const authorization = await walletClient.signAuthorization({
account,
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
})
const hash = await walletClient.sendTransaction({
account,
authorizationList: [authorization], // [!code focus]
data: '0xdeadbeef',
to: account.address,
})
```
:::note
**References**
* [EIP-7702 Overview](/docs/eip7702)
* [`signAuthorization` Docs](/docs/eip7702/signAuthorization)
:::
### blobs (optional)
* **Type:** `Hex[]`
Blobs for [Blob Transactions](/docs/guides/blob-transactions).
```ts
import * as cKzg from 'c-kzg'
import { toBlobs, setupKzg, stringToHex } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
const hash = await walletClient.sendTransaction({
account,
blobs: toBlobs({ data: stringToHex('blobby blob!') }), // [!code focus]
kzg,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
The chain is also used to infer its request type (e.g. the Celo chain has a `gatewayFee` that you can pass through to `sendTransaction`).
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
import { optimism } from 'viem/chains' // [!code focus]
const hash = await walletClient.sendTransaction({
chain: optimism, // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### data (optional)
* **Type:** `0x${string}`
A contract hashed method call with encoded args.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const hash = await walletClient.sendTransaction({
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### gas (optional)
* **Type:** `bigint`
The gas limit of the transaction. If missing, it will be estimated.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const hash = await walletClient.sendTransaction({
account,
gas: 21000n, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const hash = await walletClient.sendTransaction({
account,
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### kzg (optional)
* **Type:** `KZG`
KZG implementation for [Blob Transactions](/docs/guides/blob-transactions).
See [`setupKzg`](/docs/utilities/setupKzg) for more information.
```ts
import * as cKzg from 'c-kzg'
import { toBlobs, setupKzg, stringToHex } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath) // [!code focus]
const hash = await walletClient.sendTransaction({
account,
blobs: toBlobs({ data: stringToHex('blobby blob!') }), // [!code focus]
kzg, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const hash = await walletClient.sendTransaction({
account,
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const hash = await walletClient.sendTransaction({
account,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69 // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const hash = await walletClient.sendTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'), // [!code focus]
nonce: 69
})
```
## Tips
* For dapps: When using this action, it is assumed that the user has connected to their wallet (e.g. given permission for the dapp to access their accounts via [`requestAddresses`](/docs/actions/wallet/requestAddresses)). You can also check if the user has granted access to their accounts via [`getAddresses`](/docs/actions/wallet/getAddresses)
## Live Example
Check out the usage of `sendTransaction` in the live [Sending Transactions Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_sending-transactions) below.
## JSON-RPC Methods
* JSON-RPC Accounts:
* [`eth_sendTransaction`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction)
* Local Accounts:
* [`eth_sendRawTransaction`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendrawtransaction)
# sendTransactionSync
Creates, signs, and sends a new transaction to the network, and waits for the transaction to be included in a block. Returns the transaction receipt.
:::warning
This Action is only recommended to be used on chains with low block times and fast finality (most chains apart from `mainnet`).
:::
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient } from './config'
const receipt = await walletClient.sendTransactionSync({ // [!code focus:99]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
```ts twoslash [config.ts] filename="config.ts"
// [!include ~/snippets/walletClient.ts]
export const [account] = await walletClient.getAddresses()
// @log: ↑ JSON-RPC Account
// export const account = privateKeyToAccount(...)
// @log: ↑ Local Account
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `sendTransaction`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const receipt = await walletClient.sendTransactionSync({ // [!code focus:99]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
```ts twoslash [config.ts (Local Account)] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
transport: http()
})
```
:::
## Returns
[`TransactionReceipt`](/docs/glossary/types#transaction-receipt)
The [Transaction receipt](/docs/glossary/terms#transaction-receipt).
## Parameters
### account
* **Type:** `Account | Address | null`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc). If set to `null`, it is assumed that the transport will handle filling the sender of the transaction.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### to
* **Type:** `0x${string}`
The transaction recipient or contract address.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: 1000000000000000000n,
nonce: 69
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
accessList: [ // [!code focus:6]
{
address: '0x1',
storageKeys: ['0x1'],
},
],
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### authorizationList (optional)
* **Type:** `AuthorizationList`
Signed EIP-7702 Authorization list.
```ts twoslash
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
chain: mainnet,
transport: http(),
})
// ---cut---
// @noErrors
const authorization = await walletClient.signAuthorization({
account,
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
})
const receipt = await walletClient.sendTransactionSync({
account,
authorizationList: [authorization], // [!code focus]
data: '0xdeadbeef',
to: account.address,
})
```
:::note
**References**
* [EIP-7702 Overview](/docs/eip7702)
* [`signAuthorization` Docs](/docs/eip7702/signAuthorization)
:::
### blobs (optional)
* **Type:** `Hex[]`
Blobs for [Blob Transactions](/docs/guides/blob-transactions).
```ts
import * as cKzg from 'c-kzg'
import { toBlobs, setupKzg, stringToHex } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
const receipt = await walletClient.sendTransactionSync({
account,
blobs: toBlobs({ data: stringToHex('blobby blob!') }), // [!code focus]
kzg,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
The chain is also used to infer its request type (e.g. the Celo chain has a `gatewayFee` that you can pass through to `sendTransactionSync`).
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
import { optimism } from 'viem/chains' // [!code focus]
const receipt = await walletClient.sendTransactionSync({
chain: optimism, // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### data (optional)
* **Type:** `0x${string}`
A contract hashed method call with encoded args.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### gas (optional)
* **Type:** `bigint`
The gas limit of the transaction. If missing, it will be estimated.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
account,
gas: 21000n, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
account,
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### kzg (optional)
* **Type:** `KZG`
KZG implementation for [Blob Transactions](/docs/guides/blob-transactions).
See [`setupKzg`](/docs/utilities/setupKzg) for more information.
```ts
import * as cKzg from 'c-kzg'
import { toBlobs, setupKzg, stringToHex } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath) // [!code focus]
const receipt = await walletClient.sendTransactionSync({
account,
blobs: toBlobs({ data: stringToHex('blobby blob!') }), // [!code focus]
kzg, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
account,
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
account,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69 // [!code focus]
})
```
### pollingInterval (optional)
* **Type:** `number`
* **Default:** `walletClient.pollingInterval`
The polling interval to poll for the transaction receipt.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69,
pollingInterval: 1_000 // [!code focus]
})
```
### throwOnReceiptRevert (optional)
* **Type:** `boolean`
Whether to throw an error if the transaction was detected as reverted.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69,
throwOnReceiptRevert: true // [!code focus]
})
```
### timeout (optional)
* **Type:** `number`
* **Default:** `chain.blockTime * 3`
The timeout to wait for the transaction receipt.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69,
timeout: 20_000 // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const receipt = await walletClient.sendTransactionSync({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'), // [!code focus]
nonce: 69
})
```
## Tips
* For dapps: When using this action, it is assumed that the user has connected to their wallet (e.g. given permission for the dapp to access their accounts via [`requestAddresses`](/docs/actions/wallet/requestAddresses)). You can also check if the user has granted access to their accounts via [`getAddresses`](/docs/actions/wallet/getAddresses)
## JSON-RPC Methods
* JSON-RPC Accounts:
* [`eth_sendTransaction`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction)
* Local Accounts:
* `eth_sendRawTransactionSync`
# showCallsStatus
Requests for the wallet to show information about a call batch that was sent via `sendCalls`.
[Read more.](https://github.com/ethereum/EIPs/blob/1663ea2e7a683285f977eda51c32cec86553f585/EIPS/eip-5792.md#wallet_showcallsstatus)
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
await walletClient.showCallsStatus({ // [!code focus:99]
id: '0x1234567890abcdef',
})
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
})
export const [account] = await walletClient.getAddresses()
```
:::
## Returns
`void`
## Parameters
### id
* **Type:** `string`
Identifier of the call batch.
# signMessage
Calculates an Ethereum-specific signature in [EIP-191 format](https://eips.ethereum.org/EIPS/eip-191): `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`.
With the calculated signature, you can:
* use [`verifyMessage`](/docs/utilities/verifyMessage) to verify the signature,
* use [`recoverMessageAddress`](/docs/utilities/recoverMessageAddress) to recover the signing address from a signature.
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient } from './config'
const signature_1 = await walletClient.signMessage({ // [!code focus:99]
account,
message: 'hello world',
})
// @log: Output: "0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"
const signature_2 = await walletClient.signMessage({
account,
// Hex data representation of message.
message: { raw: '0x68656c6c6f20776f726c64' },
})
// @log: Output: "0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"
```
```ts twoslash [config.ts] filename="client.ts"
// [!include ~/snippets/walletClient.ts]
export const [account] = await walletClient.getAddresses()
// @log: ↑ JSON-RPC Account
// export const account = privateKeyToAccount(...)
// @log: ↑ Local Account
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `signMessage`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#withaccount).
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const signature = await walletClient.signMessage({ // [!code focus:99]
message: 'hello world',
})
// @log: "0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
```ts twoslash [config.ts (Local Account)] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
transport: http()
})
```
:::
## Returns
[`Hex`](/docs/glossary/types#hex)
The signed message.
## Parameters
### account
* **Type:** `Account | Address`
Account to use for signing.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const signature = await walletClient.signMessage({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
message: 'hello world',
})
```
### message
* **Type:** `string | { raw: Hex | ByteArray }`
Message to sign.
By default, viem signs the UTF-8 representation of the message.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const signature = await walletClient.signMessage({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: 'hello world', // [!code focus:1]
})
```
To sign the data representation of the message, you can use the `raw` attribute.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const signature = await walletClient.signMessage({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
message: { raw: '0x68656c6c6f20776f726c64' }, // [!code focus:1]
})
```
## JSON-RPC Methods
* JSON-RPC Accounts:
* [`personal_sign`](https://docs.metamask.io/guide/signing-data#personal-sign)
* Local Accounts
* Signs locally. No JSON-RPC request.
# signTransaction
Signs a transaction.
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient } from './config'
const request = await walletClient.prepareTransactionRequest({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
const signature = await walletClient.signTransaction(request) // [!code focus:2]
// 0x02f850018203118080825208808080c080a04012522854168b27e5dc3d5839bab5e6b39e1a0ffd343901ce1622e3d64b48f1a04e00902ae0502c4728cbf12156290df99c3ed7de85b1dbfe20b5c36931733a33
const hash = await walletClient.sendRawTransaction(signature)
```
```ts twoslash [config.ts] filename="config.ts"
// [!include ~/snippets/walletClient.ts]
export const [account] = await walletClient.getAddresses()
// @log: ↑ JSON-RPC Account
// export const account = privateKeyToAccount(...)
// @log: ↑ Local Account
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `prepareTransactionRequest`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#account).
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
const request = await walletClient.prepareTransactionRequest({
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
const signature = await walletClient.signTransaction(request) // [!code focus:2]
// 0x02f850018203118080825208808080c080a04012522854168b27e5dc3d5839bab5e6b39e1a0ffd343901ce1622e3d64b48f1a04e00902ae0502c4728cbf12156290df99c3ed7de85b1dbfe20b5c36931733a33
const hash = await walletClient.sendRawTransaction(signature)
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
```ts twoslash [config.ts (Local Account)] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
transport: http()
})
```
:::
## Returns
[`Hex`](/docs/glossary/types#hex)
The signed serialized transaction.
## Parameters
### account
* **Type:** `Account | Address`
The Account to send the transaction from.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const signature = await walletClient.signTransaction({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### to
* **Type:** `0x${string}`
The transaction recipient or contract address.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const signature = await walletClient.signTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // [!code focus]
value: 1000000000000000000n,
nonce: 69
})
```
### accessList (optional)
* **Type:** [`AccessList`](/docs/glossary/types#accesslist)
The access list.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const signature = await walletClient.signTransaction({
accessList: [ // [!code focus:6]
{
address: '0x1',
storageKeys: ['0x1'],
},
],
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
})
```
### authorizationList (optional)
* **Type:** `AuthorizationList`
Signed EIP-7702 Authorization list.
```ts twoslash
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
const account = privateKeyToAccount('0x...')
export const walletClient = createWalletClient({
chain: mainnet,
transport: http(),
})
// ---cut---
const authorization = await walletClient.signAuthorization({
account,
contractAddress: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2',
})
const signature = await walletClient.signTransaction({
account,
authorizationList: [authorization], // [!code focus]
data: '0xdeadbeef',
to: account.address,
})
```
:::note
**References**
* [EIP-7702 Overview](/docs/eip7702)
* [`signAuthorization` Docs](/docs/eip7702/signAuthorization)
:::
### blobs (optional)
* **Type:** `Hex[]`
Blobs for [Blob Transactions](/docs/guides/blob-transactions).
```ts
import * as cKzg from 'c-kzg'
import { toBlobs, setupKzg, stringToHex } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath)
const hash = await walletClient.signTransaction({
account,
blobs: toBlobs({ data: stringToHex('blobby blob!') }), // [!code focus]
kzg,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### chain (optional)
* **Type:** [`Chain`](/docs/glossary/types#chain)
* **Default:** `walletClient.chain`
The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.
The chain is also used to infer its request type (e.g. the Celo chain has a `gatewayFee` that you can pass through to `signTransaction`).
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
import { optimism } from 'viem/chains' // [!code focus]
const signature = await walletClient.signTransaction({
chain: optimism, // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### data (optional)
* **Type:** `0x${string}`
A contract hashed method call with encoded args.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const signature = await walletClient.signTransaction({
data: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n
})
```
### gas (optional)
* **Type:** `bigint`
The gas limit of the transaction. If missing, it will be estimated.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const signature = await walletClient.signTransaction({
account,
gas: 21000n, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### gasPrice (optional)
* **Type:** `bigint`
The price (in wei) to pay per gas. Only applies to [Legacy Transactions](/docs/glossary/terms#legacy-transaction).
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const signature = await walletClient.signTransaction({
account,
gasPrice: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### kzg (optional)
* **Type:** `KZG`
KZG implementation for [Blob Transactions](/docs/guides/blob-transactions).
See [`setupKzg`](/docs/utilities/setupKzg) for more information.
```ts
import * as cKzg from 'c-kzg'
import { toBlobs, setupKzg, stringToHex } from 'viem'
import { mainnetTrustedSetupPath } from 'viem/node'
const kzg = setupKzg(cKzg, mainnetTrustedSetupPath) // [!code focus]
const signature = await walletClient.signTransaction({
account,
blobs: toBlobs({ data: stringToHex('blobby blob!') }), // [!code focus]
kzg, // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8'
})
```
### maxFeePerGas (optional)
* **Type:** `bigint`
Total fee per gas (in wei), inclusive of `maxPriorityFeePerGas`. Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const signature = await walletClient.signTransaction({
account,
maxFeePerGas: parseGwei('20'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### maxPriorityFeePerGas (optional)
* **Type:** `bigint`
Max priority fee per gas (in wei). Only applies to [EIP-1559 Transactions](/docs/glossary/terms#eip-1559-transaction)
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const signature = await walletClient.signTransaction({
account,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'), // [!code focus]
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
})
```
### nonce (optional)
* **Type:** `number`
Unique number identifying this transaction.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const signature = await walletClient.signTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: 1000000000000000000n,
nonce: 69 // [!code focus]
})
```
### value (optional)
* **Type:** `bigint`
Value in wei sent with this transaction.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
// @noErrors
const signature = await walletClient.signTransaction({
account,
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1'), // [!code focus]
nonce: 69
})
```
# signTypedData
Signs typed data and calculates an Ethereum-specific signature in [https://eips.ethereum.org/EIPS/eip-712](https://eips.ethereum.org/EIPS/eip-712): `sign(keccak256("\x19\x01" ‖ domainSeparator ‖ hashStruct(message)))`
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient } from './config'
import { domain, types } from './data'
const signature = await walletClient.signTypedData({
account,
domain,
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
```ts twoslash [data.ts]
// All properties on a domain are optional
export const domain = {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
} as const
// The named list of all type definitions
export const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
} as const
```
```ts twoslash [config.ts] filename="config.ts"
// [!include ~/snippets/walletClient.ts]
export const [account] = await walletClient.getAddresses()
// @log: ↑ JSON-RPC Account
// export const account = privateKeyToAccount(...)
// @log: ↑ Local Account
```
:::
### Account Hoisting
If you do not wish to pass an `account` to every `signTypedData`, you can also hoist the Account on the Wallet Client (see `config.ts`).
[Learn more](/docs/clients/wallet#withaccount).
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './config'
import { domain, types } from './data'
const signature = await walletClient.signTypedData({
domain,
types,
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
```ts twoslash [data.ts]
// All properties on a domain are optional
export const domain = {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
} as const
// The named list of all type definitions
export const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
} as const
```
```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
// Retrieve Account from an EIP-1193 Provider.
const [account] = await window.ethereum.request({
method: 'eth_requestAccounts'
})
export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum!)
})
```
```ts twoslash [config.ts (Local Account)] filename="config.ts"
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
transport: http()
})
```
:::
## Returns
`0x${string}`
The signed data.
## Parameters
### account
* **Type:** `Account | Address`
The Account to use for signing.
Accepts a [JSON-RPC Account](/docs/clients/wallet#json-rpc-accounts) or [Local Account (Private Key, etc)](/docs/clients/wallet#local-accounts-private-key-mnemonic-etc).
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus]
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### domain
**Type:** `TypedDataDomain`
The typed data domain.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: { // [!code focus:6]
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### types
The type definitions for the typed data.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: { // [!code focus:11]
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### primaryType
**Type:** Inferred `string`.
The primary type to extract from `types` and use in `value`.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [ // [!code focus:5]
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail', // [!code focus]
message: {
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
### message
**Type:** Inferred from `types` & `primaryType`.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const signature = await walletClient.signTypedData({
account: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
domain: {
name: 'Ether Mail',
version: '1',
chainId: 1,
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
},
types: {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
Mail: [
{ name: 'from', type: 'Person' },
{ name: 'to', type: 'Person' },
{ name: 'contents', type: 'string' },
],
},
primaryType: 'Mail',
message: { // [!code focus:11]
from: {
name: 'Cow',
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
},
to: {
name: 'Bob',
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
},
contents: 'Hello, Bob!',
},
})
```
## Live Example
Check out the usage of `signTypedData` in the live [Sign Typed Data Example](https://stackblitz.com/github/wevm/viem/tree/main/examples/signing_typed-data) below.
## JSON-RPC Methods
* JSON-RPC Accounts:
* [`eth_signTypedData_v4`](https://docs.metamask.io/guide/signing-data#signtypeddata-v4)
* Local Accounts
* Signs locally. No JSON-RPC request.
# switchChain
Switch the target chain in a wallet.
## Usage
:::code-group
```ts twoslash [example.ts]
import { avalanche } from 'viem/chains'
import { walletClient } from './client'
await walletClient.switchChain({ id: avalanche.id }) // [!code focus]
```
```ts twoslash [client.ts] filename="client.ts"
// [!include ~/snippets/walletClient.ts]
```
:::
## Parameters
### id
* **Type:** `number`
The Chain ID.
## JSON-RPC Methods
[`wallet_switchEthereumChain`](https://eips.ethereum.org/EIPS/eip-3326)
# waitForCallsStatus
Waits for a call batch to be confirmed & included on a [Block](/docs/glossary/terms#block) before returning the status & receipts.
## Usage
:::code-group
```ts twoslash [example.ts]
import { parseEther } from 'viem'
import { account, walletClient } from './config'
const { id } = await walletClient.sendCalls({
account,
calls: [{
to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
value: parseEther('1')
}],
})
const result = await walletClient.waitForCallsStatus({ // [!code focus]
id, // [!code focus]
}) // [!code focus]
// @log: {
// @log: atomic: false,
// @log: chainId: 1,
// @log: id: '0x1234567890abcdef',
// @log: statusCode: 200,
// @log: status: 'success',
// @log: receipts: [{ ... }],
// @log: }
```
```ts twoslash [config.ts] filename="config.ts"
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!),
})
export const [account] = await walletClient.getAddresses()
```
:::
## Returns
`WaitForCallsStatusReturnType`
Status and receipts of the calls.
## Parameters
### id
* **Type:** `string`
Identifier of the call batch.
```ts
const result = await walletClient.waitForCallsStatus({
id: '0xdeadbeef', // [!code focus]
})
```
### pollingInterval
* **Type:** `number`
* **Default:** `client.pollingInterval`
Polling interval in milliseconds.
```ts
const result = await walletClient.waitForCallsStatus({
id: '0xdeadbeef',
pollingInterval: 1_000, // [!code focus]
})
```
### retryCount
* **Type:** `number`
* **Default:** `4`
Number of times to retry if the call bundle fails.
```ts
const result = await walletClient.waitForCallsStatus({
id: '0xdeadbeef',
retryCount: 10, // [!code focus]
})
```
### retryDelay
* **Type:** `number`
* **Default:** `({ count }) => ~~(1 << count) * 200`
Time to wait (in ms) between retries.
```ts
const result = await walletClient.waitForCallsStatus({
id: '0xdeadbeef',
retryDelay: 1_000, // [!code focus]
})
```
### status
* **Type:** `(parameters: { statusCode: number, status: string | undefined }) => boolean`
* **Default:** `(parameters) => parameters.statusCode >= 200`
Status to wait for. Defaults to non-pending status codes (`>=200`).
```ts
const result = await walletClient.waitForCallsStatus({
id: '0xdeadbeef',
status: ({ status }) => status === 'success', // [!code focus]
})
```
### throwOnFailure
* **Type:** `boolean`
* **Default:** `false`
Whether to throw an error if the call bundle fails.
```ts
const result = await walletClient.waitForCallsStatus({
id: '0xdeadbeef',
throwOnFailure: true, // [!code focus]
})
```
### timeout
* **Type:** `number`
* **Default:** `60_000`
Timeout in milliseconds before `waitForCallsStatus` stops polling.
```ts
const result = await walletClient.waitForCallsStatus({
id: '0xdeadbeef',
timeout: 10_000, // [!code focus]
})
```
# watchAsset
Requests that the user tracks the token in their wallet. Returns a boolean indicating if the token was successfully added.
## Usage
:::code-group
```ts twoslash [example.ts]
import { walletClient } from './client'
const success = await walletClient.watchAsset({ // [!code focus:99]
type: 'ERC20',
options: {
address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
decimals: 18,
symbol: 'WETH',
},
})
```
```ts twoslash [client.ts] filename="client.ts"
// [!include ~/snippets/walletClient.ts]
```
:::
## Returns
`boolean`
Boolean indicating if the token was successfully added.
## Parameters
### type
* **Type:** `string`
Token type.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut--
const success = await walletClient.watchAsset({
type: 'ERC20', // [!code focus]
options: {
address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
decimals: 18,
symbol: 'WETH',
},
});
```
### options.address
* **Type:** [`Address`](/docs/glossary/types#address)
The address of the token contract.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const success = await walletClient.watchAsset({
type: 'ERC20',
options: {
address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // [!code focus]
decimals: 18,
symbol: 'WETH',
},
});
```
### options.decimals
* **Type:** `number`
The number of token decimals.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const success = await walletClient.watchAsset({
type: 'ERC20',
options: {
address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
decimals: 18, // [!code focus]
symbol: 'WETH',
},
});
```
### options.symbol
* **Type:** `string`
A ticker symbol or shorthand, up to 11 characters.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const success = await walletClient.watchAsset({
type: 'ERC20',
options: {
address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
decimals: 18,
symbol: 'WETH', // [!code focus]
}
})
```
### options.image
* **Type:** `string`
A string url of the token logo.
```ts twoslash
// [!include ~/snippets/walletClient.ts]
// ---cut---
const success = await walletClient.watchAsset({
type: 'ERC20',
options: {
address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
decimals: 18,
symbol: 'WETH',
image: 'https://weth.com/icon.png', // [!code focus]
}
})
```
## JSON-RPC Methods
[`wallet_watchAsset`](https://eips.ethereum.org/EIPS/eip-747)
# Custom Transport \[A function to create a Custom Transport for a Client]
The `custom` Transport accepts an [EIP-1193 `request` function](https://eips.ethereum.org/EIPS/eip-1193#request-1) as a parameter. This transport is useful for integrating with injected wallets, wallets that provide an EIP-1193 provider (eg. WalletConnect or Coinbase SDK), or even providing your own custom `request` function.
## Import
```ts twoslash
import { custom } from 'viem'
```
## Usage
You can use any [EIP-1193 compatible](https://eips.ethereum.org/EIPS/eip-1193) Ethereum Provider with the `custom` Transport:
```ts twoslash
import 'viem/window'
// ---cut---
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
const client = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum!)
})
```
Or you can define your own:
```ts twoslash
// @noErrors
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'
import { customRpc } from './rpc'
const client = createWalletClient({
chain: mainnet,
transport: custom({
async request({ method, params }) {
const response = await customRpc.request(method, params)
return response
}
})
})
```
## Parameters
### provider
* **Type:** `custom`
An [EIP-1193 `request` function](https://eips.ethereum.org/EIPS/eip-1193#request) function.
```ts twoslash
// @noErrors
import { custom } from 'viem'
// ---cut---
import { customRpc } from './rpc'
const transport = custom({
async request({ method, params }) { // [!code focus:3]
const response = await customRpc.request(method, params)
return response
}
})
```
### key (optional)
* **Type:** `string`
* **Default:** `"custom"`
A key for the Transport.
```ts twoslash
import 'viem/window'
import { custom } from 'viem'
// ---cut---
const transport = custom(
window.ethereum!,
{
key: 'windowProvider', // [!code focus]
}
)
```
### name (optional)
* **Type:** `string`
* **Default:** `"Ethereum Provider"`
A name for the Transport
```ts twoslash
import 'viem/window'
import { custom } from 'viem'
// ---cut---
const transport = custom(
window.ethereum!,
{
name: 'Window Ethereum Provider', // [!code focus]
}
)
```
### retryCount (optional)
* **Type:** `number`
* **Default:** `3`
The max number of times to retry when a request fails.
```ts twoslash
import 'viem/window'
import { custom } from 'viem'
// ---cut---
const transport = custom(window.ethereum!, {
retryCount: 5, // [!code focus]
})
```
### retryDelay (optional)
* **Type:** `number`
* **Default:** `150`
The base delay (in ms) between retries. By default, the Transport will use [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) (`~~(1 << count) * retryDelay`), which means the time between retries is not constant.
```ts twoslash
import 'viem/window'
import { custom } from 'viem'
// ---cut---
const transport = custom(window.ethereum!, {
retryDelay: 100, // [!code focus]
})
```
## Gotchas
* If you are pairing the `custom` Transport with a [Public Client](/docs/clients/public), ensure that your provider supports [Public Actions](/docs/actions/public/introduction).
# Fallback Transport \[A function to create a Fallback Transport for a Client]
The `fallback` Transport consumes **multiple** Transports. If a Transport request fails, it will fall back to the next one in the list.
## Import
```ts twoslash
import { fallback } from 'viem'
```
## Usage
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: fallback([ // [!code focus]
http('https://1.rpc.thirdweb.com/...'), // [!code focus]
http('https://mainnet.infura.io/v3/...') // [!code focus]
]), // [!code focus]
})
```
### Transport Ranking
Transport Ranking enables each of the Transports passed to the `fallback` Transport are automatically ranked based on their **latency** & **stability** via a weighted moving score algorithm.
Every 10 seconds (`interval`), the `fallback` Transport will ping each transport in the list. For the past 10 pings (`sampleCount`), they will be ranked based on if they responded (stability) and how fast they responded (latency). The algorithm applies a weight of `0.7` to the stability score, and a weight of `0.3` to the latency score to derive the final score which it is ranked on.
The Transport that has the best latency & stability score over the sample period is prioritized first.
You can turn on automated ranking with the `rank` option:
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createPublicClient({
chain: mainnet,
transport: fallback([
http('https://1.rpc.thirdweb.com/...'),
http('https://mainnet.infura.io/v3/...')
], { rank: true }), // [!code focus]
})
```
You can also modify the default rank config:
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
// ---cut---
const client = createPublicClient({
chain: mainnet,
transport: fallback(
[
http('https://1.rpc.thirdweb.com/...'),
http('https://mainnet.infura.io/v3/...')
],
{ // [!code focus:9]
rank: {
interval: 60_000,
sampleCount: 5,
timeout: 500,
weights: {
latency: 0.3,
stability: 0.7
}
}
}
),
})
```
## Parameters
### rank (optional)
* **Type:** `boolean | RankOptions`
* **Default:** `false`
Whether or not to automatically rank the Transports based on their latency & stability. Set to `false` to disable automatic ranking.
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const thirdweb = http('')
const infura = http('')
// ---cut---
const transport = fallback([thirdweb, infura], {
rank: false, // [!code focus]
})
```
### rank.interval (optional)
* **Type:** `number`
* **Default:** `client.pollingInterval`
The polling interval (in ms) at which the ranker should ping the RPC URL.
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const thirdweb = http('')
const infura = http('')
// ---cut---
const transport = fallback([thirdweb, infura], {
rank: { // [!code focus:3]
interval: 5_000
},
})
```
### rank.ping (optional)
* **Type:** `({ transport }: { transport: Transport }) => Promise`
* **Default:** `({ transport }) => transport.request({ method: 'net_listening' })`
Function to call to ping the Transport. Defaults to calling the `net_listening` method to check if the Transport is online.
```ts twoslash
// @noErrors
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const thirdweb = http('')
const infura = http('')
// ---cut---
const transport = fallback([thirdweb, infura], {
rank: { // [!code focus:3]
ping: ({ transport }) => transport.request({ method: 'eth_blockNumber' })
},
})
```
### rank.sampleCount (optional)
* **Type:** `number`
* **Default:** `10`
The number of previous samples to perform ranking on.
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const thirdweb = http('')
const infura = http('')
// ---cut---
const transport = fallback([thirdweb, infura], {
rank: { // [!code focus:3]
sampleCount: 10
},
})
```
### rank.timeout (optional)
* **Type:** `number`
* **Default:** `1_000`
Timeout when sampling transports.
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const thirdweb = http('')
const infura = http('')
// ---cut---
const transport = fallback([thirdweb, infura], {
rank: { // [!code focus:3]
timeout: 500
},
})
```
### rank.weights.latency (optional)
* **Type:** `number`
* **Default:** `0.3`
The weight to apply to the latency score. The weight is proportional to the other values in the `weights` object.
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const thirdweb = http('')
const infura = http('')
// ---cut---
const transport = fallback([thirdweb, infura], {
rank: {
weights: {
latency: 0.4, // [!code focus:3]
stability: 0.6
}
},
})
```
### rank.weights.stability (optional)
* **Type:** `number`
* **Default:** `0.7`
The weight to apply to the stability score. The weight is proportional to the other values in the `weights` object.
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const thirdweb = http('')
const infura = http('')
// ---cut---
const transport = fallback([thirdweb, infura], {
rank: {
weights: {
latency: 0.4,
stability: 0.6 // [!code focus:3]
}
},
})
```
### retryCount (optional)
* **Type:** `number`
* **Default:** `3`
The max number of times to retry when a request fails.
> Note: The fallback will first try all the Transports before retrying.
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const thirdweb = http('')
const infura = http('')
// ---cut---
const transport = fallback([thirdweb, infura], {
retryCount: 5, // [!code focus]
})
```
### retryDelay (optional)
* **Type:** `number`
* **Default:** `150`
The base delay (in ms) between retries. By default, the Transport will use [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) (`~~(1 << count) * retryDelay`), which means the time between retries is not constant.
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const thirdweb = http('')
const infura = http('')
// ---cut---
const transport = fallback([thirdweb, infura], {
retryDelay: 100, // [!code focus]
})
```
### shouldThrow (optional)
* **Type:** `function`
Whether the `fallback` Transport should immediately throw an error, or continue and try the next Transport.
```ts twoslash
import { createPublicClient, fallback, http } from 'viem'
import { mainnet } from 'viem/chains'
const thirdweb = http('')
const infura = http('')
// ---cut---
const transport = fallback([thirdweb, infura], {
shouldThrow: (err: Error) => { // [!code focus]
return err.message.includes('sad times') // [!code focus]
}, // [!code focus]
})
```
# HTTP Transport \[A function to create a HTTP Transport for a Client]
The `http` Transport connects to a JSON-RPC API via HTTP.
## Import
```ts twoslash
import { http } from 'viem'
```
## Usage
```ts twoslash {4}
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http('https://1.rpc.thirdweb.com/...'), // [!code focus]
})
```
:::warning\[Warning]
If no `url` is provided, then the transport will fall back to a public RPC URL on the chain. It is highly recommended to provide an authenticated RPC URL to prevent rate-limiting.
:::
### Batch JSON-RPC
The `http` Transport supports Batch JSON-RPC. This means that multiple JSON-RPC requests can be sent in a single HTTP request.
The Transport will batch up Actions over a given period and execute them in a single Batch JSON-RPC HTTP request. By default, this period is a [zero delay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop#zero_delays) meaning that the batch request will be executed at the end of the current [JavaScript message queue](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop#queue). Consumers can specify a custom time period `wait` (in ms).
You can enable Batch JSON-RPC by setting the `batch` flag to `true`:
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
batch: true // [!code focus]
})
```
Now when you invoke Actions, the `http` Transport will batch and send over those requests at the end of the message queue (or custom time period) in a single Batch JSON-RPC HTTP request:
```ts twoslash
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http('https://1.rpc.thirdweb.com/...'),
})
// ---cut---
// The below will send a single Batch JSON-RPC HTTP request to the RPC Provider.
const [blockNumber, balance, ensName] = await Promise.all([
client.getBlockNumber(),
client.getBalance({ address: '0xd2135CfB216b74109775236E36d4b433F1DF507B' }),
client.getEnsName({ address: '0xd2135CfB216b74109775236E36d4b433F1DF507B' }),
])
```
## Parameters
### url (optional)
* **Type:** `string`
* **Default:** `chain.rpcUrls.default.http[0]`
URL of the JSON-RPC API.
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...')
```
### batch (optional)
* **Type:** `boolean | BatchOptions`
* **Default:** `false`
Toggle to enable Batch JSON-RPC
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
batch: true // [!code focus]
})
```
### batch.batchSize (optional)
* **Type:** `number`
* **Default:** `1_000`
The maximum number of JSON-RPC requests to send in a batch.
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
batch: {
batchSize: 2_000 // [!code focus]
}
})
```
### batch.wait (optional)
* **Type:** `number`
* **Default:** `0` ([zero delay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop#zero_delays))
The maximum number of milliseconds to wait before sending a batch.
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
batch: {
wait: 16 // [!code focus]
}
})
```
### fetchOptions (optional)
* **Type:** [`RequestInit`](https://developer.mozilla.org/en-US/docs/Web/API/fetch)
[Fetch options](https://developer.mozilla.org/en-US/docs/Web/API/fetch) to pass to the internal `fetch` function. Useful for passing auth headers or cache options.
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
fetchOptions: { // [!code focus:5]
headers: {
'Authorization': 'Bearer ...'
}
}
})
```
### key (optional)
* **Type:** `string`
* **Default:** `"http"`
A key for the Transport.
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
key: 'alchemy', // [!code focus]
})
```
### methods (optional)
* **Type:** `{ include?: string[], exclude?: string[] }`
Methods to include or exclude from sending RPC requests.
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
methods: {
include: ['eth_sendTransaction', 'eth_signTypedData_v4'],
},
})
```
### name (optional)
* **Type:** `string`
* **Default:** `"HTTP JSON-RPC"`
A name for the Transport
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
name: 'Alchemy HTTP Provider', // [!code focus]
})
```
### onFetchRequest (optional)
* **Type:** `(request: Request) => void`
A callback to handle the fetch request. Useful for logging or debugging.
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
onFetchRequest(request) {
console.log(request) // [!code focus]
}
})
```
### onFetchResponse (optional)
* **Type:** `(response: Response) => void`
A callback to handle the fetch response. Useful for logging or debugging.
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
onFetchResponse(response) {
console.log(response) // [!code focus]
}
})
```
### retryCount (optional)
* **Type:** `number`
* **Default:** `3`
The max number of times to retry when a request fails.
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
retryCount: 5, // [!code focus]
})
```
### retryDelay (optional)
* **Type:** `number`
* **Default:** `150`
The base delay (in ms) between retries. By default, the Transport will use [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) (`~~(1 << count) * retryDelay`), which means the time between retries is not constant.
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
retryDelay: 100, // [!code focus]
})
```
### timeout (optional)
* **Type:** `number`
* **Default:** `10_000`
The timeout for requests.
```ts twoslash
import { http } from 'viem'
// ---cut---
const transport = http('https://1.rpc.thirdweb.com/...', {
timeout: 60_000, // [!code focus]
})
```
# IPC Transport \[A function to create an IPC Transport for a Client]
The `ipc` Transport connects to a JSON-RPC API via IPC (inter-process communication).
## Import
```ts twoslash
import { ipc } from 'viem/node'
```
## Usage
```ts twoslash
import { createPublicClient } from 'viem'
import { ipc } from 'viem/node'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: ipc('/tmp/reth.ipc'), // [!code hl]
})
```
## Parameters
### path
* **Type:** `string`
IPC Path the transport should connect to.
```ts twoslash
import { ipc } from 'viem/node'
// ---cut---
const transport = ipc('/tmp/reth.ipc')
```
### key (optional)
* **Type:** `string`
* **Default:** `"ipc"`
A key for the Transport.
```ts twoslash
import { ipc } from 'viem/node'
// ---cut---
const transport = ipc('/tmp/reth.ipc', {
key: 'reth-ipc', // [!code focus]
})
```
### methods (optional)
* **Type:** `{ include?: string[], exclude?: string[] }`
Methods to include or exclude from sending RPC requests.
```ts twoslash
import { ipc } from 'viem/node'
// ---cut---
const transport = ipc('/tmp/reth.ipc', {
methods: {
include: ['eth_sendTransaction', 'eth_signTypedData_v4'],
},
})
```
### name (optional)
* **Type:** `string`
* **Default:** `"IPC JSON-RPC"`
A name for the Transport
```ts twoslash
import { ipc } from 'viem/node'
// ---cut---
const transport = ipc('/tmp/reth.ipc', {
name: 'Reth IPC', // [!code focus]
})
```
### reconnect (optional)
* **Type:** `boolean | { maxAttempts?: number, delay?: number }`
* **Default:** `true`
Whether or not to attempt to reconnect on socket failure.
```ts twoslash
import { ipc } from 'viem/node'
// ---cut---
const transport = ipc('/tmp/reth.ipc', {
reconnect: false, // [!code focus]
})
```
#### reconnect.attempts (optional)
* **Type:** `number`
* **Default:** `5`
The max number of times to attempt to reconnect.
```ts twoslash
import { ipc } from 'viem/node'
// ---cut---
const transport = ipc('/tmp/reth.ipc', {
reconnect: {
attempts: 10, // [!code focus]
}
})
```
#### reconnect.delay (optional)
* **Type:** `number`
* **Default:** `2_000`
Retry delay (in ms) between reconnect attempts.
```ts twoslash
import { ipc } from 'viem/node'
// ---cut---
const transport = ipc('/tmp/reth.ipc', {
reconnect: {
delay: 1_000, // [!code focus]
}
})
```
### retryCount (optional)
* **Type:** `number`
* **Default:** `3`
The max number of times to retry when a request fails.
```ts twoslash
import { ipc } from 'viem/node'
// ---cut---
const transport = ipc('/tmp/reth.ipc', {
retryCount: 5, // [!code focus]
})
```
### retryDelay (optional)
* **Type:** `number`
* **Default:** `150`
The base delay (in ms) between retries. By default, the Transport will use [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) (`~~(1 << count) * retryDelay`), which means the time between retries is not constant.
```ts twoslash
import { ipc } from 'viem/node'
// ---cut---
const transport = ipc('/tmp/reth.ipc', {
retryDelay: 100, // [!code focus]
})
```
### timeout (optional)
* **Type:** `number`
* **Default:** `10_000`
The timeout for async IPC requests.
```ts twoslash
import { ipc } from 'viem/node'
// ---cut---
const transport = ipc('/tmp/reth.ipc', {
timeout: 60_000, // [!code focus]
})
```
# WebSocket Transport \[A function to create a WebSocket Transport for a Client]
The `webSocket` Transport connects to a JSON-RPC API via a WebSocket.
## Import
```ts twoslash
import { webSocket } from 'viem'
```
## Usage
```ts twoslash {4}
import { createPublicClient, webSocket } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: webSocket('wss://1.rpc.thirdweb.com/...'), // [!code focus]
})
```
:::warning\[Warning]
If no `url` is provided, then the transport will fall back to a public RPC URL on the chain. It is highly recommended to provide an authenticated RPC URL to prevent rate-limiting.
:::
## Parameters
### url
* **Type:** `string`
URL of the JSON-RPC API.
```ts twoslash
import { webSocket } from 'viem'
// ---cut---
const transport = webSocket('wss://1.rpc.thirdweb.com/...')
```
### keepAlive (optional)
* **Type:** `boolean | { interval?: number }`
* **Default:** `true`
Whether or not to send keep-alive ping messages.
```ts twoslash
import { webSocket } from 'viem'
// ---cut---
const transport = webSocket('wss://1.rpc.thirdweb.com/...', {
keepAlive: { interval: 1_000 }, // [!code focus]
})
```
### key (optional)
* **Type:** `string`
* **Default:** `"webSocket"`
A key for the Transport.
```ts twoslash
import { webSocket } from 'viem'
// ---cut---
const transport = webSocket('wss://1.rpc.thirdweb.com/...', {
key: 'alchemy', // [!code focus]
})
```
### methods (optional)
* **Type:** `{ include?: string[], exclude?: string[] }`
Methods to include or exclude from sending RPC requests.
```ts twoslash
import { webSocket } from 'viem'
// ---cut---
const transport = webSocket('wss://1.rpc.thirdweb.com/...', {
methods: {
include: ['eth_sendTransaction', 'eth_signTypedData_v4'],
},
})
```
### name (optional)
* **Type:** `string`
* **Default:** `"WebSocket JSON-RPC"`
A name for the Transport
```ts twoslash
import { webSocket } from 'viem'
// ---cut---
const transport = webSocket('wss://1.rpc.thirdweb.com/...', {
name: 'Alchemy WebSocket Provider', // [!code focus]
})
```
### reconnect (optional)
* **Type:** `boolean | { maxAttempts?: number, delay?: number }`
* **Default:** `true`
Whether or not to attempt to reconnect on socket failure.
```ts twoslash
import { webSocket } from 'viem'
// ---cut---
const transport = webSocket('wss://1.rpc.thirdweb.com/...', {
reconnect: false, // [!code focus]
})
```
#### reconnect.attempts (optional)
* **Type:** `number`
* **Default:** `5`
The max number of times to attempt to reconnect.
```ts twoslash
import { webSocket } from 'viem'
// ---cut---
const transport = webSocket('wss://1.rpc.thirdweb.com/...', {
reconnect: {
attempts: 10, // [!code focus]
}
})
```
#### reconnect.delay (optional)
* **Type:** `number`
* **Default:** `2_000`
Retry delay (in ms) between reconnect attempts.
```ts twoslash
import { webSocket } from 'viem'
// ---cut---
const transport = webSocket('wss://1.rpc.thirdweb.com/...', {
reconnect: {
delay: 1_000, // [!code focus]
}
})
```
### retryCount (optional)
* **Type:** `number`
* **Default:** `3`
The max number of times to retry when a request fails.
```ts twoslash
import { webSocket } from 'viem'
// ---cut---
const transport = webSocket('wss://1.rpc.thirdweb.com/...', {
retryCount: 5, // [!code focus]
})
```
### retryDelay (optional)
* **Type:** `number`
* **Default:** `150`
The base delay (in ms) between retries. By default, the Transport will use [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) (`~~(1 << count) * retryDelay`), which means the time between retries is not constant.
```ts twoslash
import { webSocket } from 'viem'
// ---cut---
const transport = webSocket('wss://1.rpc.thirdweb.com/...', {
retryDelay: 100, // [!code focus]
})
```
### timeout (optional)
* **Type:** `number`
* **Default:** `10_000`
The timeout for async WebSocket requests.
```ts twoslash
import { webSocket } from 'viem'
// ---cut---
const transport = webSocket('wss://1.rpc.thirdweb.com/...', {
timeout: 60_000, // [!code focus]
})
```
# getEnsAddress
Gets address for ENS name.
Calls `resolve(bytes, bytes)` on ENS Universal Resolver Contract to resolve the ENS name to address.
## Usage
:::code-group
```ts [example.ts]
import { normalize } from 'viem/ens'
import { publicClient } from './client'
const ensAddress = await publicClient.getEnsAddress({
name: normalize('wevm.eth'),
})
// '0xd2135CfB216b74109775236E36d4b433F1DF507B'
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
:::warning
Since ENS names prohibit certain forbidden characters (e.g. underscore) and have other validation rules, you likely want to [normalize ENS names](https://docs.ens.domains/contract-api-reference/name-processing#normalising-names) with [UTS-46 normalization](https://unicode.org/reports/tr46) before passing them to `getEnsAddress`. You can use the built-in [`normalize`](/docs/ens/utilities/normalize) function for this.
:::
### Chain-specific Resolution
`getEnsAddress` also supports chain-specific address resolution via [ENSIP-19](https://docs.ens.domains/ensip/19/).
In order to use chain-specific resolution, you must:
1. Ensure your client is configured with `mainnet` (or another L1 that supports ENS Universal Resolver)
2. Pass a `coinType` parameter to `getEnsAddress` (as seen in `example.ts`)
```ts
import { createPublicClient, http } from 'viem'
import { mainnet, base } from 'viem/chains'
import { normalize, toCoinType } from 'viem/ens'
export const publicClient = createPublicClient({
chain: mainnet, // [!code focus]
transport: http()
})
const ensAddress = await publicClient.getEnsAddress({
name: normalize('wevm.eth'),
coinType: toCoinType(base.id), // [!code focus]
})
// '0xd2135CfB216b74109775236E36d4b433F1DF507B'
```
## Returns
[`Address`](/docs/glossary/types#address)
The address that resolves to provided ENS name.
Returns `null` if ENS name does not resolve to address.
## Parameters
### name
* **Type:** `string`
Name to get the address for.
```ts
const ensAddress = await publicClient.getEnsAddress({
name: normalize('wevm.eth'), // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the read against.
```ts
const ensAddress = await publicClient.getEnsAddress({
name: normalize('wevm.eth'),
blockNumber: 15121123n, // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the read against.
```ts
const ensAddress = await publicClient.getEnsAddress({
name: normalize('wevm.eth'),
blockTag: 'safe', // [!code focus]
})
```
### coinType (optional)
* **Type:** `number`
The [ENSIP-9](https://docs.ens.domains/ens-improvement-proposals/ensip-9-multichain-address-resolution) coin type (chain) to fetch the address for
```ts
import { base } from 'viem/chains'
const ensAddress = await publicClient.getEnsAddress({
name: normalize('wevm.eth'),
coinType: toCoinType(base.id), // [!code focus]
})
```
### gatewayUrls (optional)
* **Type:** `string[]`
A set of Universal Resolver gateways, used for resolving CCIP-Read requests made through the ENS Universal Resolver Contract.
```ts
const ensAddress = await publicClient.getEnsAddress({
name: normalize('wevm.eth'),
gatewayUrls: ["https://ccip.ens.xyz"], // [!code focus]
})
```
### strict (optional)
* **Type:** `boolean`
* **Default:** `false`
A boolean value that when set to true will strictly propagate all ENS Universal Resolver Contract errors.
```ts
const ensAddress = await publicClient.getEnsAddress({
name: normalize('wevm.eth'),
strict: true, // [!code focus]
})
```
### universalResolverAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
* **Default:** `client.chain.contracts.ensUniversalResolver.address`
Address of ENS Universal Resolver Contract.
```ts
const ensAddress = await publicClient.getEnsAddress({
name: normalize('wevm.eth'),
universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', // [!code focus]
})
```
## Live Example
Check out the usage of `getEnsAddress` in the live [ENS Examples](https://stackblitz.com/github/wevm/viem/tree/main/examples/ens) below.
# getEnsAvatar
Gets the avatar of an ENS name.
Calls [`getEnsText`](/docs/ens/actions/getEnsText) with `key` set to `'avatar'`.
## Usage
:::code-group
```ts [example.ts]
import { normalize } from 'viem/ens'
import { publicClient } from './client'
const ensText = await publicClient.getEnsAvatar({
name: normalize('wevm.eth'),
})
// 'https://ipfs.io/ipfs/Qma8mnp6xV3J2cRNf3mTth5C8nV11CAnceVinc3y8jSbio'
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
:::warning
Since ENS names prohibit certain forbidden characters (e.g. underscore) and have other validation rules, you likely want to [normalize ENS names](https://docs.ens.domains/contract-api-reference/name-processing#normalising-names) with [UTS-46 normalization](https://unicode.org/reports/tr46) before passing them to `getEnsAddress`. You can use the built-in [`normalize`](/docs/ens/utilities/normalize) function for this.
:::
## Returns
`string | null`
The avatar URI for ENS name.
Returns `null` if the avatar cannot be resolved from the ENS name.
## Parameters
### name
* **Type:** `string`
ENS name to get Text for.
```ts
const ensText = await publicClient.getEnsAvatar({
name: normalize('wevm.eth'), // [!code focus]
})
```
### assetGatewayUrls (optional)
* **Type:** `{ ipfs?: string; arweave?: string }`
Gateway urls to resolve IPFS and/or Arweave assets.
```ts
const ensText = await publicClient.getEnsAvatar({
name: normalize('wevm.eth'),
assetGatewayUrls: { // [!code focus:3]
ipfs: 'https://cloudflare-ipfs.com'
}
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the read against.
```ts
const ensText = await publicClient.getEnsAvatar({
name: normalize('wevm.eth'),
blockNumber: 15121123n, // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the read against.
```ts
const ensText = await publicClient.getEnsAvatar({
name: normalize('wevm.eth'),
blockTag: 'safe', // [!code focus]
})
```
### gatewayUrls (optional)
* **Type:** `string[]`
A set of Universal Resolver gateways, used for resolving CCIP-Read requests made through the ENS Universal Resolver Contract.
```ts
const ensText = await publicClient.getEnsAvatar({
name: normalize('wevm.eth'),
gatewayUrls: ["https://ccip.ens.xyz"], // [!code focus]
})
```
### strict (optional)
* **Type:** `boolean`
* **Default:** `false`
A boolean value that when set to true will strictly propagate all ENS Universal Resolver Contract errors.
```ts
const ensText = await publicClient.getEnsAvatar({
name: normalize('wevm.eth'),
strict: true, // [!code focus]
})
```
### universalResolverAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
* **Default:** `client.chain.contracts.ensUniversalResolver.address`
Address of ENS Universal Resolver Contract.
```ts
const ensText = await publicClient.getEnsAvatar({
name: normalize('wevm.eth'),
universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', // [!code focus]
})
```
# getEnsName
Gets primary name for specified address.
Calls `reverse(bytes)` on ENS Universal Resolver Contract to "reverse resolve" the address to the primary ENS name.
## Usage
:::code-group
```ts [example.ts]
import { publicClient } from './client'
const ensName = await publicClient.getEnsName({
address: '0xd2135CfB216b74109775236E36d4b433F1DF507B',
})
// 'wevm.eth'
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
### Chain-specific Resolution
`getEnsName` also supports chain-specific name resolution via [ENSIP-19](https://docs.ens.domains/ensip/19/).
In order to use chain-specific resolution, you must:
1. Ensure your client is configured with `mainnet` (or another L1 that supports ENS Universal Resolver)
2. Pass a `coinType` parameter to `getEnsName` (as seen in `example.ts`)
```ts
import { createPublicClient, http, toCoinType } from 'viem'
import { mainnet, base } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet, // [!code focus]
transport: http()
})
const ensName = await publicClient.getEnsName({
address: '0xd2135CfB216b74109775236E36d4b433F1DF507B',
coinType: toCoinType(base.id), // [!code focus]
})
// 'wevm.eth'
```
## Returns
`string`
The primary ENS name for the address.
Returns `null` if address does not have primary name assigned.
## Parameters
### address
* **Type:** [`Address`](/docs/glossary/types#address)
Address to get primary ENS name for.
```ts
const ensName = await publicClient.getEnsName({
address: '0xd2135CfB216b74109775236E36d4b433F1DF507B', // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the read against.
```ts
const ensName = await publicClient.getEnsName({
address: '0xd2135CfB216b74109775236E36d4b433F1DF507B',
blockNumber: 15121123n, // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the read against.
```ts
const ensName = await publicClient.getEnsName({
address: '0xd2135CfB216b74109775236E36d4b433F1DF507B',
blockTag: 'safe', // [!code focus]
})
```
### coinType (optional)
* **Type:** `bigint`
ENSIP-9 compliant coinType (chain) to get ENS name for.
```ts
import { base } from 'viem/chains'
const ensName = await publicClient.getEnsName({
address: '0xd2135CfB216b74109775236E36d4b433F1DF507B',
coinType: toCoinType(base.id), // [!code focus]
})
```
### gatewayUrls (optional)
* **Type:** `string[]`
A set of Universal Resolver gateways, used for resolving CCIP-Read requests made through the ENS Universal Resolver Contract.
```ts
const ensName = await publicClient.getEnsName({
address: '0xd2135CfB216b74109775236E36d4b433F1DF507B',
gatewayUrls: ["https://ccip.ens.xyz"], // [!code focus]
})
```
### strict (optional)
* **Type:** `boolean`
* **Default:** `false`
A boolean value that when set to true will strictly propagate all ENS Universal Resolver Contract errors.
```ts
const ensName = await publicClient.getEnsName({
address: '0xd2135CfB216b74109775236E36d4b433F1DF507B',
strict: true, // [!code focus]
})
```
### universalResolverAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
* **Default:** `client.chain.contracts.ensUniversalResolver.address`
Address of ENS Universal Resolver Contract.
```ts
const ensName = await publicClient.getEnsName({
address: '0xd2135CfB216b74109775236E36d4b433F1DF507B',
universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', // [!code focus]
})
```
## Live Example
Check out the usage of `getEnsName` in the live [ENS Examples](https://stackblitz.com/github/wevm/viem/tree/main/examples/ens) below.
# getEnsResolver
Gets resolver for ENS name.
Calls `findResolver(bytes)` on ENS Universal Resolver Contract to retrieve the resolver of an ENS name.
## Usage
:::code-group
```ts [example.ts]
import { normalize } from 'viem/ens'
import { publicClient } from './client'
const resolverAddress = await publicClient.getEnsResolver({
name: normalize('wevm.eth'),
})
// '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41'
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
})
```
:::
:::warning
Since ENS names prohibit certain forbidden characters (e.g. underscore) and have other validation rules, you likely want to [normalize ENS names](https://docs.ens.domains/contract-api-reference/name-processing#normalising-names) with [UTS-46 normalization](https://unicode.org/reports/tr46) before passing them to `getEnsResolver`. You can use the built-in [`normalize`](/docs/ens/utilities/normalize) function for this.
:::
## Returns
[`Address`](/docs/glossary/types#address)
The address of the resolver.
## Parameters
### name
* **Type:** `string`
Name to get the address for.
```ts
const ensName = await publicClient.getEnsResolver({
name: normalize('wevm.eth'), // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the read against.
```ts
const ensName = await publicClient.getEnsResolver({
name: normalize('wevm.eth'),
blockNumber: 15121123n, // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the read against.
```ts
const ensName = await publicClient.getEnsResolver({
name: normalize('wevm.eth'),
blockTag: 'safe', // [!code focus]
})
```
### universalResolverAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
* **Default:** `client.chain.contracts.ensUniversalResolver.address`
Address of ENS Universal Resolver Contract.
```ts
const ensName = await publicClient.getEnsResolver({
name: normalize('wevm.eth'),
universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', // [!code focus]
})
```
# getEnsText
Gets a text record for specified ENS name.
Calls `resolve(bytes, bytes)` on ENS Universal Resolver Contract.
## Usage
:::code-group
```ts [example.ts]
import { normalize } from 'viem/ens'
import { publicClient } from './client'
const ensText = await publicClient.getEnsText({
name: normalize('wevm.eth'),
key: 'com.twitter',
})
// 'wevm_dev'
```
```ts [client.ts]
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
```
:::
:::warning
Since ENS names prohibit certain forbidden characters (e.g. underscore) and have other validation rules, you likely want to [normalize ENS names](https://docs.ens.domains/contract-api-reference/name-processing#normalising-names) with [UTS-46 normalization](https://unicode.org/reports/tr46) before passing them to `getEnsText`. You can use the built-in [`normalize`](/docs/ens/utilities/normalize) function for this.
:::
## Returns
`string | null`
The text record for ENS name.
Returns `null` if name does not have text assigned.
## Parameters
### name
* **Type:** `string`
ENS name to get Text for.
```ts
const ensText = await publicClient.getEnsText({
name: normalize('wevm.eth'), // [!code focus]
key: 'com.twitter',
})
```
### key
* **Type:** `string`
ENS key to get Text for.
```ts
const ensText = await publicClient.getEnsText({
name: normalize('wevm.eth'),
key: 'com.twitter', // [!code focus]
})
```
### blockNumber (optional)
* **Type:** `number`
The block number to perform the read against.
```ts
const ensText = await publicClient.getEnsText({
name: normalize('wevm.eth'),
key: 'com.twitter',
blockNumber: 15121123n, // [!code focus]
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
The block tag to perform the read against.
```ts
const ensText = await publicClient.getEnsText({
name: normalize('wevm.eth'),
key: 'com.twitter',
blockTag: 'safe', // [!code focus]
})
```
### gatewayUrls (optional)
* **Type:** `string[]`
A set of Universal Resolver gateways, used for resolving CCIP-Read requests made through the ENS Universal Resolver Contract.
```ts
const ensText = await publicClient.getEnsText({
name: normalize('wevm.eth'),
key: 'com.twitter',
gatewayUrls: ["https://ccip.ens.xyz"], // [!code focus]
})
```
### strict (optional)
* **Type:** `boolean`
* **Default:** `false`
A boolean value that when set to true will strictly propagate all ENS Universal Resolver Contract errors.
```ts
const ensText = await publicClient.getEnsText({
name: normalize('wevm.eth'),
key: 'com.twitter',
strict: true, // [!code focus]
})
```
### universalResolverAddress (optional)
* **Type:** [`Address`](/docs/glossary/types#address)
* **Default:** `client.chain.contracts.ensUniversalResolver.address`
Address of ENS Universal Resolver Contract.
```ts
const ensText = await publicClient.getEnsText({
name: normalize('wevm.eth'),
key: 'com.twitter',
universalResolverAddress: '0x74E20Bd2A1fE0cdbe45b9A1d89cb7e0a45b36376', // [!code focus]
})
```
# labelhash
Hashes ENS label.
## Import
```ts
import { labelhash, normalize } from 'viem/ens'
```
## Usage
```ts
import { labelhash, normalize } from 'viem/ens'
labelhash(normalize('awkweb')) // [!code focus:2]
// '0x7aaad03ddcacc63166440f59c14a1a2c97ee381014b59c58f55b49ab05f31a38'
```
:::warning
Since ENS names prohibit certain forbidden characters (e.g. underscore) and have other validation rules, you likely want to [normalize ENS labels](https://docs.ens.domains/contract-api-reference/name-processing#normalising-names) with [UTS-46 normalization](https://unicode.org/reports/tr46) before passing them to `labelhash`. You can use the built-in [`normalize`](/docs/ens/utilities/normalize) function for this.
:::
## Returns
`string`
The hashed ENS label.
## Parameters
### name
* **Type:** `string`
A ENS label.
# namehash
Hashes ENS name.
## Import
```ts
import { namehash, normalize } from 'viem/ens'
```
## Usage
```ts
import { namehash, normalize } from 'viem/ens'
namehash('wevm.eth') // [!code focus:2]
// '0xf246651c1b9a6b141d19c2604e9a58f567973833990f830d882534a747801359'
```
:::warning
Since ENS names prohibit certain forbidden characters (e.g. underscore) and have other validation rules, you likely want to [normalize ENS names](https://docs.ens.domains/contract-api-reference/name-processing#normalising-names) with [UTS-46 normalization](https://unicode.org/reports/tr46) before passing them to `namehash`. You can use the built-in [`normalize`](/docs/ens/utilities/normalize) function for this.
:::
## Returns
`string`
The hashed ENS name.
## Parameters
### name
* **Type:** `string`
A ENS name.
# normalize
Normalizes ENS name to [UTS51](https://unicode.org/reports/tr51) and [ENSIP-15](https://github.com/ensdomains/docs/blob/9edf9443de4333a0ea7ec658a870672d5d180d53/ens-improvement-proposals/ensip-15-normalization-standard.md).
Internally uses [`@adraffy/ens-normalize`](https://github.com/adraffy/ens-normalize.js).
## Import
```ts
import { normalize } from 'viem/ens'
```
## Usage
```ts
import { normalize } from 'viem/ens'
normalize('wagmi-d𝝣v.eth') // [!code focus:2]
// 'wagmi-dξv.eth'
```
## Returns
`string`
The normalized ENS label.
## Parameters
### name
* **Type:** `string`
A ENS name.
# verifySiweMessage
Verifies [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) formatted message was signed.
See [`createSiweMessage`](/docs/siwe/utilities/createSiweMessage) for info on how to create a EIP-4361 formatted message.
## Usage
:::code-group
```ts twoslash [example.ts]
import { account, walletClient, publicClient } from './client'
import { message } from './message'
const signature = await walletClient.signMessage({ account, message })
// [!code focus:99]
const valid = await publicClient.verifySiweMessage({
message,
signature,
})
// @log: true
```
```ts twoslash [client.ts] filename="client.ts"
import 'viem/window'
// ---cut---
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import { mainnet } from 'viem/chains'
export const publicClient = createPublicClient({
chain: mainnet,
transport: http()
})
export const walletClient = createWalletClient({
transport: custom(window.ethereum!)
})
// @log: ↓ JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// @log: ↓ Local Account
// export const account = privateKeyToAccount(...)
```
```ts twoslash [message.ts] filename="message.ts"
// ---cut---
import { createSiweMessage, generateSiweNonce } from 'viem/siwe'
import { mainnet } from 'viem/chains'
import { account } from './client'
export const message = createSiweMessage({
address: account.address,
chainId: mainnet.id,
domain: 'example.com',
nonce: generateSiweNonce(),
uri: 'https://example.com/path',
version: '1',
})
```
:::
## Returns
`boolean`
Whether the signed message is valid for the given address.
## Parameters
### message
* **Type:** `string`
[EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) formatted message to be verified.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
import { createSiweMessage, generateSiweNonce } from 'viem/siwe'
// ---cut---
const valid = await publicClient.verifySiweMessage({
message: createSiweMessage({ // [!code focus:1]
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
chainId: 1, // [!code focus:1]
domain: 'example.com', // [!code focus:1]
nonce: generateSiweNonce(), // [!code focus:1]
uri: 'https://example.com/path', // [!code focus:1]
version: '1', // [!code focus:1]
}), // [!code focus:1]
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### signature
* **Type:** `Hex`
The signature that was generated by signing the message with the address's signer.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c', // [!code focus:1]
})
```
### address (optional)
* **Type:** `Address`
Ethereum address to check against.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
address: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### blockNumber (optional)
* **Type:** `number`
Only used when verifying a message that was signed by a Smart Contract Account. The block number to check if the contract was already deployed.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
blockNumber: 42069n, // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### blockTag (optional)
* **Type:** `'latest' | 'earliest' | 'pending' | 'safe' | 'finalized'`
* **Default:** `'latest'`
Only used when verifying a message that was signed by a Smart Contract Account. The block tag to check if the contract was already deployed.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
blockTag: 'safe', // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### domain (optional)
* **Type:** `string`
[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) authority to check against.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
domain: 'viem.sh', // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### nonce (optional)
* **Type:** `string`
Random string to check against.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
import { generateSiweNonce } from 'viem/siwe'
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
nonce: generateSiweNonce(), // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### scheme (optional)
* **Type:** `string`
[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) URI scheme to check against.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
scheme: 'https', // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
### time (optional)
* **Type:** `Date`
* **Default:** `new Date()`
Current time to check optional [`expirationTime`](/docs/siwe/utilities/createSiweMessage#expirationtime-optional) and [`notBefore`](/docs/siwe/utilities/createSiweMessage#notbefore-optional) message fields.
```ts twoslash
// [!include ~/snippets/publicClient.ts]
declare const message: string
// ---cut---
const valid = await publicClient.verifySiweMessage({
time: new Date(), // [!code focus:1]
message,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
```
# createSiweMessage
Creates [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) formatted message.
## Import
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
```
## Usage
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
})
```
## Returns
`string`
EIP-4361 formatted message.
## Parameters
### address
* **Type:** `Address`
The Ethereum address performing the signing.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e', // [!code focus]
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
})
```
### chainId
* **Type:** `number`
The [EIP-155](https://eips.ethereum.org/EIPS/eip-155) Chain ID to which the session is bound.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
chainId: 1, // [!code focus]
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
})
```
### domain
* **Type:** `string`
[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) authority that is requesting the signing.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
chainId: 1,
domain: 'example.com', // [!code focus]
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
})
```
### nonce
* **Type:** `string`
A random string typically chosen by the relying party and used to prevent replay attacks.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz', // [!code focus]
uri: 'https://example.com/path',
version: '1',
})
```
### uri
* **Type:** `string`
[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) URI referring to the resource that is the subject of the signing (as in the subject of a claim).
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path', // [!code focus]
version: '1',
})
```
### version
* **Type:** `'1'`
The current version of the SIWE Message.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1', // [!code focus]
})
```
### expirationTime (optional)
* **Type:** `Date`
Time when the signed authentication message is no longer valid.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
expirationTime: new Date(), // [!code focus]
})
```
### issuedAt (optional)
* **Type:** `Date`
Time when the message was generated, typically the current time.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
issuedAt: new Date(), // [!code focus]
})
```
### notBefore (optional)
* **Type:** `Date`
Time when the signed authentication message will become valid.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
notBefore: new Date(), // [!code focus]
})
```
### requestId (optional)
* **Type:** `string`
A system-specific identifier that may be used to uniquely refer to the sign-in request.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
requestId: '123e4567-e89b-12d3-a456-426614174000', // [!code focus]
})
```
### resources (optional)
* **Type:** `string[]`
A list of information or references to information the user wishes to have resolved as part of authentication by the relying party.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
resources: [ // [!code focus]
'https://example.com/foo', // [!code focus]
'https://example.com/bar', // [!code focus]
'https://example.com/baz', // [!code focus]
], // [!code focus]
})
```
### scheme (optional)
* **Type:** `string`
[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) URI scheme of the origin of the request.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
scheme: 'https', // [!code focus]
})
```
### statement (optional)
* **Type:** `string`
A human-readable ASCII assertion that the user will sign.
```ts twoslash
import { createSiweMessage } from 'viem/siwe'
const message = createSiweMessage({
address: '0xa0cf798816d4b9b9866b5330eea46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
statement: 'I accept the ExampleOrg Terms of Service: https://example.com/tos', // [!code focus]
})
```
# generateSiweNonce
Generates random [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) nonce.
## Import
```ts twoslash
import { generateSiweNonce } from 'viem/siwe'
```
## Usage
```ts twoslash
import { generateSiweNonce } from 'viem/siwe'
const nonce = generateSiweNonce()
```
## Returns
`string`
A randomly generated EIP-4361 nonce.
# parseSiweMessage
Parses [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) formatted message into message fields object.
## Import
```ts twoslash
import { parseSiweMessage } from 'viem/siwe'
```
## Usage
```ts twoslash
import { parseSiweMessage } from 'viem/siwe'
const message = `example.com wants you to sign in with your Ethereum account:
0xA0Cf798816D4b9b9866b5330EEa46a18382f251e
I accept the ExampleOrg Terms of Service: https://example.com/tos
URI: https://example.com/path
Version: 1
Chain ID: 1
Nonce: foobarbaz
Issued At: 2023-02-01T00:00:00.000Z`
const fields = parseSiweMessage(message)
fields.address
// ^?
```
## Returns
`SiweMessage`
EIP-4361 fields object
## Parameters
### message
* **Type:** `string`
EIP-4361 formatted message
# validateSiweMessage
Validates [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) message.
## Import
```ts twoslash
import { validateSiweMessage } from 'viem/siwe'
```
## Usage
```ts twoslash
import { validateSiweMessage } from 'viem/siwe'
const valid = validateSiweMessage({
address: '0xd2135CfB216b74109775236E36d4b433F1DF507B',
message: {
address: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
chainId: 1,
domain: 'example.com',
nonce: 'foobarbaz',
uri: 'https://example.com/path',
version: '1',
},
})
```
## Returns
`boolean`
Whether the message fields are valid.
## Parameters
### message
* **Type:** `Partial`
EIP-4361 message fields.
### address (optional)
* **Type:** `string`
Ethereum address to check against.
### domain (optional)
* **Type:** `string`
[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) authority to check against.
### nonce (optional)
* **Type:** `string`
Random string to check against.
### scheme (optional)
* **Type:** `string`
[RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) URI scheme to check against.
### time (optional)
* **Type:** `Date`
* **Default:** `new Date()`
Current time to check optional [`expirationTime`](http://localhost:5173/docs/siwe/utilities/createSiweMessage#expirationtime-optional) and [`notBefore`](/docs/siwe/utilities/createSiweMessage#notbefore-optional) message fields.
# getL2HashFromPriorityOp
Returns the hash of the L2 priority operation from a given L1 transaction receipt.
## Import
```ts
import { getL2HashFromPriorityOp } from 'viem/zksync'
```
## Usage
:::code-group
```ts [example.ts]
import { client, zksyncClient } from './config'
import { getL2HashFromPriorityOp } from 'viem/zksync'
const receipt = await client.waitForTransactionReceipt({
hash: '0x...'
})
const l2Hash = getL2HashFromPriorityOp(
receipt,
await zksyncClient.getMainContractAddress()
)
```
```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync, mainnet } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})
export const zksyncClient = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```
:::
## Returns
`Hash`
The hash of the L2 priority operation.
## Parameters
### receipt
* **Type:** [`TransactionReceipt`](/docs/glossary/types#transactionreceipt)
The L1 transaction receipt.
```ts
const l2Hash = getL2HashFromPriorityOp(
receipt, // [!code focus]
'0x14b947814912c71bdbc3275c143a065d2ecafaba'
)
```
### zksync
* **Type:** `Address`
The address of the ZKsync Era main contract.
```ts
const l2Hash = getL2HashFromPriorityOp(
receipt,
'0x14b947814912c71bdbc3275c143a065d2ecafaba' // [!code focus]
)
```
# getApprovalBasedPaymasterInput
Returns encoded formatted approval-based paymaster params.
## Import
```ts
import { getApprovalBasedPaymasterInput } from 'viem/zksync'
```
## Usage
```ts
import { getApprovalBasedPaymasterInput } from 'viem/zksync'
const data = getApprovalBasedPaymasterInput({
innerInput: '0x',
minAllowance: 1n,
token: "0x65C899B5fb8Eb9ae4da51D67E1fc417c7CB7e964",
})
```
## Returns
`EncodeFunctionDataReturnType`
The `Hex` value of the provided approval-based paymaster inputs.
## Parameters
### token
* **Type:** `Address`
The token address.
```ts
const data = getApprovalBasedPaymasterInput({
innerInput: '0x',
minAllowance: 1n,
token: "0x65C899B5fb8Eb9ae4da51D67E1fc417c7CB7e964", // [!code focus]
})
```
### minAllowance
* **Type:** `bigint`
Minimum allowance (in wei) of token that can be sent towards the paymaster.
```ts
const data = getApprovalBasedPaymasterInput({
innerInput: new Uint8Array(),
minAllowance: 1n, // [!code focus]
token: "0x65C899B5fb8Eb9ae4da51D67E1fc417c7CB7e964",
})
```
### innerInput
* **Type:** `Hex | ByteArray`
Additional payload that can be sent to the paymaster to implement any logic .
```ts
const data = getApprovalBasedPaymasterInput({
innerInput: "0x0005040302010", // [!code focus]
minAllowance: 1n,
token: "0x65C899B5fb8Eb9ae4da51D67E1fc417c7CB7e964",
})
```
# getGeneralPaymasterInput
Returns encoded formatted general-based paymaster params.
## Import
```ts
import { getGeneralPaymasterInput } from 'viem/zksync'
```
## Usage
```ts
import { getGeneralPaymasterInput } from 'viem/zksync'
const data = getGeneralPaymasterInput({
innerInput: '0x',
})
```
## Returns
`EncodeFunctionDataReturnType`
The `Hex` value of the provided general-based paymaster inputs.
## Parameters
### innerInput
Additional payload that can be sent to the paymaster to implement any logic
* **Type:** `Hex` or `ByteArray`
```ts
const data = getGeneralPaymasterInput({
innerInput: new Uint8Array([0, 1, 2, 3, 4, 5]), // [!code focus]
})
```
```ts
const data = getGeneralPaymasterInput({
innerInput: "0x0005040302010", // [!code focus]
})
```