# EVM

Armchain runs a full **Ethereum Virtual Machine (EVM)** supporting the **London** hard fork. If you've written Solidity contracts for Ethereum, they'll work on Armchain without any changes. The differences are at the network and signing level, not the contract level.

This page covers EVM compatibility details, gas costs, precompiled contracts, and what's different from Ethereum.

## EVM Version and Hard Fork Support

| Hard Fork      | Status      | Key Features                                             |
| -------------- | ----------- | -------------------------------------------------------- |
| Homestead      | ✅ Supported | Basic EVM                                                |
| Byzantium      | ✅ Supported | `REVERT`, precompiles, `STATICCALL`                      |
| Constantinople | ✅ Supported | `CREATE2`, bitwise shifting                              |
| Istanbul       | ✅ Supported | `CHAINID` opcode, gas repricing                          |
| Berlin         | ✅ Supported | EIP-2929 (gas cost changes), EIP-2930 (access lists)     |
| London         | ✅ Supported | EIP-1559 (dynamic base fee), EIP-3529 (refund reduction) |
| Shanghai       | ❌ Not yet   | `PUSH0` opcode                                           |

### Solidity Compiler Compatibility

Use Solidity `0.8.x` for best results. Recommended pragma:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
```

> Avoid Shanghai/Cancun features (e.g., `PUSH0`, transient storage) as they are not yet supported.

## How the EVM Fits into Armchain

```
┌──────────────────────────────┐
│      Lachesis Consensus       │
│    (DAG event ordering)       │
└──────────┬───────────────────┘
           │ Ordered events
           ▼
┌──────────────────────────────┐
│       Block Assembly          │
│  (group events into blocks)   │
└──────────┬───────────────────┘
           │ Block with transactions
           ▼
┌──────────────────────────────┐
│   State Transition (EVM)      │
│  - Execute each transaction   │
│  - Update state trie          │
│  - Generate receipts & logs   │
│  - Compute state root         │
└──────────┬───────────────────┘
           │ Final state
           ▼
┌──────────────────────────────┐
│      Finalized Block          │
│  (state root, receipts,       │
│   logs - PERMANENT)           │
└──────────────────────────────┘
```

### State Transition

The state transition model is a fork of go-ethereum's `core/state_transition.go`, adapted for Armchain:

1. **Pre-validation**: Check nonce, balance, gas limits
2. **Gas purchase**: Deduct upfront gas cost from sender
3. **EVM execution**: Run contract bytecode
4. **Gas refund**: Refund unused gas (with EIP-3529 limits)
5. **Reward**: Validator receives transaction fees

### Key Differences from Ethereum

| Aspect              | Ethereum                 | Armchain                                      |
| ------------------- | ------------------------ | --------------------------------------------- |
| Block Production    | Single proposer per slot | All validators create events in parallel      |
| Finality            | \~15 minutes (2 epochs)  | Instant (aBFT)                                |
| Block Time          | 12 seconds fixed         | Variable (event-driven)                       |
| Transaction Signing | ECDSA (secp256k1)        | ML-DSA44 (Type 3)                             |
| Empty Block Policy  | Always produces blocks   | Skips empty blocks (1 min devnet, 3s fakenet) |

## Transaction Pool

Armchain maintains a standard Ethereum-compatible transaction pool (mempool):

```
┌─────────────────────────────────┐
│         Transaction Pool         │
├─────────────────────────────────┤
│  Pending:  Txns ready for        │
│            inclusion             │
│  Queued:   Txns with future      │
│            nonces                │
├─────────────────────────────────┤
│  Validation:                     │
│  - Signature valid (ML-DSA44)?   │
│  - Sufficient balance?           │
│  - Nonce correct?                │
│  - Gas price meets minimum?      │
│  - Gas limit within bounds?      │
└─────────────────────────────────┘
```

### Gas Price Model (EIP-1559)

Armchain uses EIP-1559 dynamic fee pricing:

```javascript
// Transaction fee structure
{
  maxFeePerGas: "20000000000",         // Maximum total fee (20 Gwei)
  maxPriorityFeePerGas: "2000000000",  // Tip to validator (2 Gwei)
  gasLimit: "21000",                    // Gas units
  type: 3                               // PQC transaction
}

// Actual fee = min(maxFeePerGas, baseFee + maxPriorityFeePerGas) × gasUsed
```

| Parameter           | Value              |
| ------------------- | ------------------ |
| Minimum Gas Price   | 1 Gwei             |
| Max Block Gas       | 20,500,000         |
| Base Fee Adjustment | EIP-1559 algorithm |

## Precompiled Contracts

Armchain supports all Ethereum precompiles through Berlin, plus a new PQC-specific precompile:

| Address    | Contract       | Purpose                                                                                                              |
| ---------- | -------------- | -------------------------------------------------------------------------------------------------------------------- |
| `0x01`     | ecRecover      | ECDSA public key recovery (retained for smart contract compatibility; **not used** for Armchain transaction signing) |
| `0x02`     | SHA-256        | SHA-256 hash                                                                                                         |
| `0x03`     | RIPEMD-160     | RIPEMD-160 hash                                                                                                      |
| `0x04`     | Identity       | Data copy                                                                                                            |
| `0x05`     | ModExp         | Modular exponentiation                                                                                               |
| `0x06`     | ecAdd          | BN256 point addition                                                                                                 |
| `0x07`     | ecMul          | BN256 scalar multiplication                                                                                          |
| `0x08`     | ecPairing      | BN256 pairing check                                                                                                  |
| `0x09`     | Blake2F        | BLAKE2b compression                                                                                                  |
| **`0x13`** | **pqcRecover** | **ML-DSA44 signature recovery (Armchain-specific)**                                                                  |

### pqcRecover Precompile (`0x13`)

The `pqcRecover` precompile recovers the signer's Ethereum address from an ML-DSA44 signature. This is the post-quantum equivalent of `ecRecover` and is the correct precompile to use for on-chain signature verification on Armchain.

**Input**: `signatureBlob` (3,732 bytes, containing the ML-DSA44 signature + public key)

**Output**: 32-byte padded address (last 20 bytes are the signer's address)

**Behavior**:

1. Validates the ML-DSA44 signature format
2. Extracts the public key from the signature blob
3. Derives the Ethereum address from the ML-DSA44 public key (`keccak256(publicKey)`, last 20 bytes)
4. Returns the 32-byte zero-padded address

**Solidity usage**:

```solidity
/// @notice Recover signer address from an ML-DSA44 signature
/// @param signature The 3,732-byte signature blob (signature + public key)
/// @return signer The recovered address
function pqcRecover(bytes memory signature) internal view returns (address signer) {
    (bool success, bytes memory result) = address(0x13).staticcall(signature);
    require(success, "pqcRecover failed");
    signer = address(uint160(uint256(bytes32(result))));
}
```

> **Note**: `ecRecover` (`0x01`) still exists for backward compatibility with contracts that use ECDSA internally (e.g., signature verification of off-chain ECDSA signatures). However, all Armchain transaction signatures use ML-DSA44, so `pqcRecover` (`0x13`) should be used for verifying Armchain transaction/message signatures on-chain.

## Smart Contract Considerations

### Contract Size Limit

The maximum smart contract bytecode size is **24,576 bytes** (same as Ethereum's EIP-170 limit).

### Gas Costs

Gas costs follow Berlin pricing:

| Operation            | Gas Cost                |
| -------------------- | ----------------------- |
| Simple transfer      | 21,000                  |
| Storage write (cold) | 20,000                  |
| Storage write (warm) | 5,000                   |
| Storage read (cold)  | 2,100                   |
| Storage read (warm)  | 100                     |
| Contract creation    | 32,000 + bytecode costs |
| `CALL` (cold)        | 2,600                   |
| `LOG` per topic      | 375                     |

### Token Standards

All standard ERC token interfaces work on Armchain:

* **ERC-20**: Fungible tokens
* **ERC-721**: Non-fungible tokens (NFTs)
* **ERC-1155**: Multi-token standard
* **ERC-4626**: Tokenized vaults

### Solidity Example

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract ArmToken is ERC20 {
    constructor(uint256 initialSupply) ERC20("Arm Token", "ARMT") {
        _mint(msg.sender, initialSupply);
    }
}
```

This deploys and works identically on Armchain as it would on Ethereum.

## Further Reading

* [Consensus (Lachesis aBFT)](/architecture/consensus.md): How blocks are produced
* [Transaction Lifecycle](/architecture/transaction-lifecycle.md): From submission to EVM execution
* [Smart Contract Development](/developers/overview.md): Writing contracts for Armchain
* [Transaction Types](/pqc/transaction-types.md): Type 3 PQC transactions


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.armchain.org/architecture/evm.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
