Ethers.StateOverride (Ethers v0.8.0)

Copy Markdown View Source

State overrides for simulation RPC calls (eth_call and eth_estimateGas).

State overrides let a call run against a modified view of the chain state without sending any transaction: spoof an account's balance or nonce, replace the code at an address (e.g. run a contract that is not deployed), or rewrite individual storage slots. They are supported by all major execution clients (geth, reth, anvil, ...).

Pass them to Ethers.call/2, Ethers.estimate_gas/2 (and by extension any generated contract function piped into those) with the :state_overrides option:

MyToken.transfer(receiver, 1000)
|> Ethers.call(
  from: whale,
  state_overrides: %{
    whale => %{balance: Ethers.Utils.to_wei(100)},
    token_address => %{state_diff: %{balance_slot => balance_value}}
  }
)

Structure

A state override set is a map of address => account override. Following Ethers conventions, every value has exactly one accepted representation — native types, never hex strings:

  • :balance - fake balance to set for the account (non_neg_integer)
  • :nonce - fake nonce to set for the account (non_neg_integer)
  • :code - fake EVM bytecode to inject into the account (raw binary, not hex encoded — hex decode first if you have "0x..." bytecode e.g. from eth_getCode)
  • :state - fake key-value mapping to override all slots in the account storage
  • :state_diff - fake key-value mapping to override individual slots in the account storage (all other slots keep their on-chain values)

:state and :state_diff are mutually exclusive per account. Their keys (storage slots) and values (storage words) accept a non_neg_integer or a raw 32-byte binary (e.g. a keccak-derived mapping slot), and are encoded as 32-byte hex words.

Addresses are hex strings ("0x..."), like everywhere else in Ethers.

Summary

Types

Overrides for a single account. See the module documentation for the accepted keys.

A storage slot or storage value: a non-negative integer or a raw 32-byte binary.

t()

A state override set: a map of account address to account override.

Functions

Encodes a state override set into the JSON-RPC representation.

Types

account_override()

@type account_override() :: %{
  optional(:balance) => non_neg_integer(),
  optional(:nonce) => non_neg_integer(),
  optional(:code) => binary(),
  optional(:state) => %{required(storage_word()) => storage_word()},
  optional(:state_diff) => %{required(storage_word()) => storage_word()}
}

Overrides for a single account. See the module documentation for the accepted keys.

storage_word()

@type storage_word() :: non_neg_integer() | <<_::256>>

A storage slot or storage value: a non-negative integer or a raw 32-byte binary.

t()

@type t() :: %{required(Ethers.Types.t_address()) => account_override()}

A state override set: a map of account address to account override.

Functions

to_rpc_map(state_overrides)

@spec to_rpc_map(t()) :: {:ok, map()} | {:error, term()}

Encodes a state override set into the JSON-RPC representation.

Returns {:ok, rpc_map} with all quantities, code and storage words hex-encoded, or {:error, reason} if the input is not a valid state override set.

Examples

iex> Ethers.StateOverride.to_rpc_map(%{
...>   "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1" => %{balance: 1000, nonce: 3}
...> })
{:ok, %{"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1" => %{balance: "0x3E8", nonce: "0x3"}}}