# `EEVM.SystemContracts`
[🔗](https://github.com/mw2000/eevm/blob/v0.1.0/lib/eevm/system_contracts.ex#L1)

Genesis setup for the system contracts that blocks call from Cancun on.

| EIP | From | Address | Called |
|-----|------|---------|--------|
| EIP-4788 beacon roots | Cancun | `0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02` | block start |
| EIP-2935 block hashes | Prague | `0x0000F90827F1C53a10cb7A02335B175320002935` | block start |
| EIP-7002 withdrawal requests | Prague | `0x00000961Ef480Eb55e80D19ad83579A64c007002` | block end |
| EIP-7251 consolidation requests | Prague | `0x0000BBdDc7CE488642fb579F8B00f3a590007251` | block end |

On mainnet each contract was deployed by an ordinary transaction before its
fork activated. A chain started from scratch, such as a devnet or a test,
has no such history, so `genesis_accounts/1` returns the contracts a fork
calls as genesis accounts, and `install/2` writes them into a database.

Block execution never installs them itself: a Prague block whose state
lacks the EIP-7002 or EIP-7251 contract fails with `:system_contract_empty`,
as those EIPs require. A missing EIP-4788 or EIP-2935 contract makes its
block-start call a no-op. `EEVM.SystemContracts.BeaconRoots` and
`EEVM.SystemContracts.BlockHashes` drive and read those two contracts.

# `genesis_accounts`

```elixir
@spec genesis_accounts(EEVM.Config.t() | EEVM.HardforkConfig.spec_id()) :: %{
  required(non_neg_integer()) =&gt; %{balance: 0, nonce: 1, code: binary()}
}
```

Returns the system contracts that blocks of `fork` call, as genesis accounts
in the shape `EEVM.Database.InMemory.new/1` takes:
`%{address => %{balance: 0, nonce: 1, code: code}}`.

`fork` is an `EEVM.Config` or a hardfork name. Each contract is included
from the fork that activates its EIP, with its canonical deployed code and
the nonce of 1 that its deployment left on mainnet, so state roots match
other clients'. Forks before Cancun need none.

## Examples

    iex> EEVM.SystemContracts.genesis_accounts(:prague) |> Map.keys() |> Enum.sort()
    [
      0x00000961EF480EB55E80D19AD83579A64C007002,
      0x0000BBDDC7CE488642FB579F8B00F3A590007251,
      0x0000F90827F1C53A10CB7A02335B175320002935,
      0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02
    ]
    iex> EEVM.SystemContracts.genesis_accounts(EEVM.Config.new(:cancun))
    %{0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02 => %{balance: 0, nonce: 1,
      code: EEVM.SystemContracts.BeaconRoots.deployed_bytecode()}}
    iex> EEVM.SystemContracts.genesis_accounts(:shanghai)
    %{}

# `install`

```elixir
@spec install(EEVM.Database.t(), EEVM.Config.t() | EEVM.HardforkConfig.spec_id()) ::
  EEVM.Database.t()
```

Writes the accounts `genesis_accounts/1` returns for `fork` into `db`,
replacing any accounts at those addresses but keeping their storage.

## Example

    iex> db = EEVM.SystemContracts.install(EEVM.Database.InMemory.new(), :prague)
    iex> EEVM.Database.get_nonce(db, 0x00000961EF480EB55E80D19AD83579A64C007002)
    1

---

*Consult [api-reference.md](api-reference.md) for complete listing*
