# Smart Contract Patterns (MegaEVM)

## MegaEVM vs Standard EVM

MegaEVM is fully compatible with Ethereum contracts but has different:
- **Gas costs** (especially SSTORE)
- **Block metadata limits** (volatile data access)
- **Contract size limits** (512 KB)

## Contract Limits

| Resource | Limit |
|----------|-------|
| Contract code | 512 KB |
| Calldata | 128 KB |
| eth_call/estimateGas | 10M gas (public), higher on VIP |

## Volatile Data Access Control

After accessing block metadata, transaction is limited to 20M additional compute gas.

**Affected opcodes:**
- `TIMESTAMP` / `block.timestamp`
- `NUMBER` / `block.number`
- `BLOCKHASH` / `blockhash(n)`

```solidity
// ❌ Problematic pattern
function process() external {
    uint256 ts = block.timestamp;  // Triggers limit
    // Complex computation here will hit 20M gas ceiling
    for (uint i = 0; i < 10000; i++) {
        // Heavy work...
    }
}

// ✅ Better: access metadata late
function process() external {
    // Do heavy computation first
    for (uint i = 0; i < 10000; i++) {
        // Heavy work...
    }
    // Access metadata at the end
    emit Processed(block.timestamp);
}
```

**Spec:** https://github.com/megaeth-labs/mega-evm/blob/main/specs/MiniRex.md#28-volatile-data-access-control

## High-Precision Timestamps

For microsecond precision, use the oracle instead of `block.timestamp`:

```solidity
interface ITimestampOracle {
    /// @notice Returns timestamp in microseconds
    function timestamp() external view returns (uint256);
}

contract MyContract {
    ITimestampOracle constant ORACLE = 
        ITimestampOracle(0x6342000000000000000000000000000000000002);
    
    function getTime() external view returns (uint256) {
        return ORACLE.timestamp(); // Microseconds, not seconds
    }
}
```

## Storage Patterns

### Avoid Dynamic Mappings

```solidity
// ❌ Expensive: each new key = new storage slot = 2M+ gas
mapping(address => uint256) public balances;

// ✅ Better: fixed-size or use RedBlackTreeLib
uint256[100] public fixedBalances;
```

### Solady RedBlackTreeLib

```solidity
import {RedBlackTreeLib} from "solady/src/utils/RedBlackTreeLib.sol";

contract OptimizedStorage {
    using RedBlackTreeLib for RedBlackTreeLib.Tree;
    RedBlackTreeLib.Tree private _tree;
    
    // Tree manages contiguous storage slots
    // Insert/remove reuses slots instead of allocating new ones
    
    function insert(uint256 key, uint256 value) external {
        _tree.insert(key);
        // Store value in separate packed array
    }
}
```

## Gas Estimation

Always use remote estimation:

```solidity
// foundry.toml
[profile.default]
# Don't rely on local simulation
```

```bash
# Deploy with explicit gas, skip simulation
forge script Deploy.s.sol \
    --rpc-url https://mainnet.megaeth.com/rpc \
    --gas-limit 5000000 \
    --skip-simulation \
    --broadcast
```

## Events and Logs

LOG opcodes have quadratic cost above 4KB data:

```solidity
// ❌ Expensive: large event data
event LargeData(bytes data); // If data > 4KB, quadratic cost

// ✅ Better: emit hash, store off-chain
event DataStored(bytes32 indexed hash);
```

## SELFDESTRUCT

EIP-6780 style SELFDESTRUCT is being implemented. Check current status:
- Same-tx destruction works
- Cross-tx destruction behavior may vary

## Deployment Patterns

### Factory Contracts

```solidity
contract Factory {
    function deploy(bytes32 salt, bytes memory bytecode) 
        external 
        returns (address) 
    {
        address addr;
        assembly {
            addr := create2(0, add(bytecode, 32), mload(bytecode), salt)
        }
        require(addr != address(0), "Deploy failed");
        return addr;
    }
}
```

### Proxy Patterns

Standard proxy patterns (EIP-1967, UUPS, Transparent) work normally. Consider:
- Storage slot allocation costs on first write
- Upgrade authorization patterns

## Testing Contracts

```solidity
// Use Foundry with remote RPC
contract MyTest is Test {
    function setUp() public {
        // Fork MegaETH testnet for realistic gas costs
        vm.createSelectFork("https://carrot.megaeth.com/rpc");
    }
    
    function testGasCost() public {
        uint256 gasBefore = gasleft();
        // Your operation
        uint256 gasUsed = gasBefore - gasleft();
        console.log("Gas used:", gasUsed);
    }
}
```

## SSTORE2: On-Chain Data Storage

For storing large immutable data on-chain (HTML, images, metadata), use the **SSTORE2** pattern — store data as contract bytecode instead of storage slots.

### Why SSTORE2 on MegaETH?

| Approach | Write Cost | Read Cost |
|----------|------------|-----------|
| SSTORE (storage slots) | 2M+ gas per new slot | 100-2100 gas |
| SSTORE2 (bytecode) | ~10K gas per byte | **FREE** (EXTCODECOPY) |

SSTORE2 is ideal for write-once, read-many data — content is immutable once deployed.

### How It Works

1. Deploy a contract with data as bytecode
2. Read data via `EXTCODECOPY` (no gas for view calls)

```solidity
// Writing: Deploy data as contract bytecode
library SSTORE2 {
    function write(bytes memory data) internal returns (address) {
        // Prepend STOP opcode so contract can't be called
        bytes memory bytecode = abi.encodePacked(
            hex"00", // STOP opcode
            data
        );
        
        address pointer;
        assembly {
            pointer := create(0, add(bytecode, 32), mload(bytecode))
        }
        require(pointer != address(0), "Deploy failed");
        return pointer;
    }
    
    function read(address pointer) internal view returns (bytes memory) {
        uint256 size;
        assembly { size := extcodesize(pointer) }
        
        bytes memory data = new bytes(size - 1); // Skip STOP opcode
        assembly {
            extcodecopy(pointer, add(data, 32), 1, sub(size, 1))
        }
        return data;
    }
}
```

### MegaETH Gas Estimation for SSTORE2

```javascript
// MegaETH multidimensional gas model for bytecode deployment
const MEGAETH_GAS = {
  INTRINSIC_COMPUTE: 21_000n,
  INTRINSIC_STORAGE: 39_000n,
  CONTRACT_CREATION_COMPUTE: 32_000n,
  CODE_DEPOSIT_PER_BYTE: 10_000n,
  CALLDATA_NONZERO_PER_BYTE: 160n,
};

function estimateDeployGas(dataSizeBytes) {
  const dataSize = BigInt(dataSizeBytes);
  
  const computeGas = MEGAETH_GAS.INTRINSIC_COMPUTE 
    + MEGAETH_GAS.CONTRACT_CREATION_COMPUTE;
  
  const storageGas = MEGAETH_GAS.INTRINSIC_STORAGE
    + (dataSize * MEGAETH_GAS.CODE_DEPOSIT_PER_BYTE)
    + (dataSize * MEGAETH_GAS.CALLDATA_NONZERO_PER_BYTE);
  
  return (computeGas + storageGas) * 150n / 100n; // 50% buffer
}
```

### Use Cases

- **On-chain websites/HTML** — permanent, censorship-resistant hosting
- **NFT metadata** — fully on-chain images/JSON
- **Large configs** — immutable protocol parameters
- **Data availability** — store proofs, attestations

### Chunking Large Data

For data > 24KB, chunk into multiple contracts:

```javascript
const CHUNK_SIZE = 15000; // 15KB per chunk

function chunkData(data) {
  const chunks = [];
  for (let i = 0; i < data.length; i += CHUNK_SIZE) {
    chunks.push(data.slice(i, i + CHUNK_SIZE));
  }
  return chunks;
}
```

### Solady Implementation

Solady provides an optimized SSTORE2:

```solidity
import {SSTORE2} from "solady/src/utils/SSTORE2.sol";

// Write
address pointer = SSTORE2.write(data);

// Read
bytes memory data = SSTORE2.read(pointer);
```

**Reference implementation:** See [warren-deploy](https://clawdhub.ai/planetai87/warren-deploy) for a complete on-chain website deployment system using SSTORE2 on MegaETH.

## EIP-6909: Minimal Multi-Token Standard

For contracts managing multiple token types, prefer [EIP-6909](https://eips.ethereum.org/EIPS/eip-6909) over ERC-1155.

### Why EIP-6909 on MegaETH?

| Feature | MegaETH Benefit |
|---------|-----------------|
| No mandatory callbacks | Less gas, simpler integrations |
| No batching in spec | Allows MegaETH-optimized implementations |
| Single contract | Fewer SSTORE operations (expensive) |
| Granular approvals | Per-token-ID OR full operator access |
| Minimal interface | Smaller bytecode |

### Storage Efficiency

One EIP-6909 contract vs. N separate ERC-20 contracts:

```solidity
// ❌ Deploying many ERC-20s = many new storage slots
// Each contract: new code, new storage initialization

// ✅ Single EIP-6909 = shared storage
// Multiple token IDs in one contract, slot reuse
```

### Basic Implementation

```solidity
// Using Solady's ERC6909 (gas-optimized)
import {ERC6909} from "solady/src/tokens/ERC6909.sol";

contract MultiToken is ERC6909 {
    function name(uint256 id) public view override returns (string memory) {
        // Return name for token ID
    }
    
    function symbol(uint256 id) public view override returns (string memory) {
        // Return symbol for token ID
    }
    
    function tokenURI(uint256 id) public view override returns (string memory) {
        // Return metadata URI for token ID
    }
    
    function mint(address to, uint256 id, uint256 amount) external {
        _mint(to, id, amount);
    }
}
```

### Key Differences from ERC-1155

| | ERC-1155 | EIP-6909 |
|-|----------|----------|
| Callbacks | Required | None |
| Batch transfers | In spec | Implementation choice |
| Approvals | Operator only | Operator + per-ID allowance |
| Complexity | Higher | Minimal |

### Use Cases

- **DEXes**: LP tokens for multiple pairs in one contract
- **Games**: Multiple item/asset types
- **DeFi vaults**: Multiple share classes
- **NFT editions**: Fungible editions of NFTs

### Solady Implementation

Solady provides a gas-optimized EIP-6909:
```bash
forge install vectorized/solady
```

```solidity
import {ERC6909} from "solady/src/tokens/ERC6909.sol";
```

**Docs**: https://github.com/Vectorized/solady/blob/main/src/tokens/ERC6909.sol

## OP Stack Compatibility

MegaETH uses OP Stack. Standard bridge contracts and predeploys are available:

| Contract | Address |
|----------|---------|
| WETH9 | `0x4200000000000000000000000000000000000006` |
| Multicall3 | `0xcA11bde05977b3631167028862bE2a173976CA11` |
| L2CrossDomainMessenger | `0x4200000000000000000000000000000000000007` |

See OP Stack docs for full predeploy list.

## Common Issues

### "Intrinsic gas too low"
Local simulation uses wrong opcode costs. Use `--skip-simulation` or remote estimation.

### "Out of gas" after block.timestamp
Hitting volatile data access limit. Restructure to access metadata late.

### Transaction stuck
Check nonce with `eth_getTransactionCount` using `pending` tag.
