# 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', '<apiKey>') // [!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/<apiKey>') // [!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', '<apiKey>') // [!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/<apiKey>') // [!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', '<apiKey>') // [!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/<apiKey>') // [!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', '<apiKey>') // [!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/<apiKey>') // [!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', '<apiKey>') // [!code hl]
const infura = new providers.InfuraProvider('homestead', '<apiKey>') // [!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/<apiKey>') // [!code hl]
const infura = http('https://mainnet.infura.io/v3/<apiKey>') // [!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/<apiKey>') // [!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/<apiKey>') // [!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')
```
