EVM Compatibility

Overview

OPN Chain provides full Ethereum Virtual Machine (EVM) compatibility, allowing developers to deploy existing Ethereum smart contracts without modification. This compatibility extends beyond basic functionality to include the latest Ethereum improvements, development tools, and ecosystem standards.

Compatibility Levels

1. Binary Compatibility

Complete Bytecode Support:

  • All EVM opcodes supported

  • Identical gas costs for operations

  • Same execution semantics

  • Bit-for-bit compatibility

Example:

// This Ethereum contract works identically on OPN Chain
contract Example {
    mapping(address => uint256) public balances;
    
    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }
    
    function withdraw(uint256 amount) public {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        payable(msg.sender).transfer(amount);
    }
}

2. API Compatibility

JSON-RPC Compliance:

// All standard Ethereum RPC methods work
const web3 = new Web3('https://testnet-rpc.iopn.tech');

// Ethereum methods work identically
const balance = await web3.eth.getBalance(address);
const block = await web3.eth.getBlock('latest');
const receipt = await web3.eth.getTransactionReceipt(txHash);

Supported Method Namespaces:

  • web3_* - Client version, SHA3

  • net_* - Network ID, peer count, listening status

  • eth_* - All standard Ethereum methods

  • debug_* - Debugging and tracing

  • txpool_* - Transaction pool inspection

3. Tool Compatibility

Development Frameworks:

Tool
Compatibility
Notes

Hardhat

✅ Full

No modifications needed

Truffle

✅ Full

Standard config works

Foundry

✅ Full

Native support

Remix

✅ Full

Direct deployment

Brownie

✅ Full

Python framework

Ape

✅ Full

Modern Python tool

Example Hardhat Config:

module.exports = {
  networks: {
    opn: {
      url: "https://testnet-rpc.iopn.tech",
      chainId: 984,
      accounts: [process.env.PRIVATE_KEY]
    }
  },
  solidity: "0.8.30"
};

4. Library Compatibility

Web3 Libraries:

// Web3.js
const Web3 = require('web3');
const web3 = new Web3('https://testnet-rpc.iopn.tech');

// Ethers.js
const { ethers } = require('ethers');
const provider = new ethers.providers.JsonRpcProvider('https://testnet-rpc.iopn.tech');

// Viem
import { createPublicClient, http } from 'viem';
const client = createPublicClient({
  chain: opnChain,
  transport: http('https://testnet-rpc.iopn.tech')
});

Smart Contract Standards

ERC Standards Support

Standard
Description
Support

ERC-20

Fungible tokens

✅ Full

ERC-721

Non-fungible tokens

✅ Full

ERC-1155

Multi tokens

✅ Full

ERC-165

Interface detection

✅ Full

ERC-2981

NFT royalties

✅ Full

ERC-4626

Tokenized vaults

✅ Full

ERC-4337

Account abstraction

✅ Full

Example Implementations

ERC-20 Token:

// Standard OpenZeppelin ERC-20 works perfectly
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyToken is ERC20 {
    constructor() ERC20("MyToken", "MTK") {
        _mint(msg.sender, 1000000 * 10**18);
    }
}

ERC-721 NFT:

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract MyNFT is ERC721 {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
    
    constructor() ERC721("MyNFT", "MNFT") {}
    
    function mint(address to) public returns (uint256) {
        _tokenIds.increment();
        uint256 newTokenId = _tokenIds.current();
        _mint(to, newTokenId);
        return newTokenId;
    }
}

Address System

Address Format

OPN Chain uses the standard Ethereum address format:

  • 20-byte addresses (40 hex characters)

  • Checksummed addresses supported

  • Same derivation paths as Ethereum

// Address validation works identically
function isValidAddress(address) {
    return /^0x[a-fA-F0-9]{40}$/.test(address);
}

// Checksum validation
const { toChecksumAddress, isAddress } = require('ethereum-address');
const checksummed = toChecksumAddress('0x742d35cc6634c0532925a3b844bc9e7595f2bd40');

Key Derivation

HD Wallet Compatibility:

// Same derivation path as Ethereum
const hdPath = "m/44'/60'/0'/0/0";

// Works with all Ethereum wallets
const { hdkey } = require('ethereumjs-wallet');
const { mnemonicToSeedSync } = require('bip39');

const seed = mnemonicToSeedSync(mnemonic);
const hdWallet = hdkey.fromMasterSeed(seed);
const wallet = hdWallet.derivePath(hdPath).getWallet();

Transaction Format

Transaction Types

OPN Chain supports all Ethereum transaction types:

Legacy Transactions (Type 0):

{
  nonce: '0x0',
  gasPrice: '0x1a13b8600', // 7 Gwei
  gasLimit: '0x5208',
  to: '0x742d35Cc6634C0532925a3b844Bc9e7595f2bD40',
  value: '0xde0b6b3a7640000', // 1 ETH in wei
  data: '0x',
  v: '0x7e5', // chainId * 2 + 35
  r: '0x...',
  s: '0x...'
}

EIP-2930 Access List Transactions (Type 1):

{
  chainId: '0x3d8',
  nonce: '0x0',
  gasPrice: '0x1a13b8600',
  gasLimit: '0x5208',
  to: '0x...',
  value: '0x...',
  data: '0x',
  accessList: [
    {
      address: '0x...',
      storageKeys: ['0x...', '0x...']
    }
  ]
}

EIP-1559 Transactions (Type 2):

{
  chainId: '0x3d8',
  nonce: '0x0',
  maxPriorityFeePerGas: '0x3b9aca00', // 1 Gwei
  maxFeePerGas: '0x2540be400', // 10 Gwei
  gasLimit: '0x5208',
  to: '0x...',
  value: '0x...',
  data: '0x',
  accessList: []
}

Gas Compatibility

Gas Costs

OPN Chain uses Ethereum-compatible gas costs:

// Gas costs match Ethereum exactly
contract GasExample {
    uint256 public value; // SSTORE: 20,000 gas (new slot)
    
    function update(uint256 newValue) public {
        value = newValue; // SSTORE: 5,000 gas (update)
    }
    
    function read() public view returns (uint256) {
        return value; // SLOAD: 2,100 gas
    }
}

Gas Estimation

// Gas estimation works identically
const contract = new web3.eth.Contract(abi, address);

// Estimate gas for a transaction
const gasEstimate = await contract.methods
  .transfer(recipient, amount)
  .estimateGas({ from: sender });

// Add 10% buffer for safety
const gasLimit = Math.floor(gasEstimate * 1.1);

Event System

Event Emission

contract EventExample {
    event Transfer(
        address indexed from,
        address indexed to,
        uint256 value
    );
    
    function transfer(address to, uint256 value) public {
        // Event emission identical to Ethereum
        emit Transfer(msg.sender, to, value);
    }
}

Event Filtering

// Event filtering works exactly like Ethereum
const filter = {
    address: contractAddress,
    topics: [
        web3.utils.sha3('Transfer(address,address,uint256)'),
        null, // any from address
        web3.utils.padLeft(toAddress, 64) // specific to address
    ],
    fromBlock: 0,
    toBlock: 'latest'
};

const events = await web3.eth.getPastLogs(filter);

State Management

Storage Layout

Storage layout matches Ethereum exactly:

contract StorageExample {
    uint256 a;      // slot 0
    uint256 b;      // slot 1
    address c;      // slot 2 (uses 20 bytes)
    bool d;         // slot 2 (uses 1 byte, packed with c)
    
    mapping(address => uint256) e; // slot 3 (base slot)
    uint256[] f;    // slot 4 (length), data at keccak256(4)
}

State Access

// Direct storage access works identically
const slot0 = await web3.eth.getStorageAt(contractAddress, 0);
const slot1 = await web3.eth.getStorageAt(contractAddress, 1);

// Mapping access calculation
const mappingSlot = 3;
const key = '0x742d35Cc6634C0532925a3b844Bc9e7595f2bD40';
const dataSlot = web3.utils.soliditySha3(
    { type: 'address', value: key },
    { type: 'uint256', value: mappingSlot }
);
const value = await web3.eth.getStorageAt(contractAddress, dataSlot);

Precompiled Contracts

All Ethereum precompiled contracts are available:

contract PrecompileExample {
    // ecrecover at 0x01
    function recoverSigner(bytes32 hash, uint8 v, bytes32 r, bytes32 s) 
        public pure returns (address) 
    {
        return ecrecover(hash, v, r, s);
    }
    
    // SHA256 at 0x02
    function hashSHA256(bytes memory data) public pure returns (bytes32) {
        return sha256(data);
    }
    
    // And all others...
}

Differences from Ethereum

Block Time

The main difference is block time:

// OPN Chain: ~1 second blocks
// Ethereum: ~12 second blocks

// Adjust time-based logic accordingly
contract TimeAware {
    // Ethereum: 7200 blocks ≈ 1 day
    // OPN Chain: 86400 blocks ≈ 1 day
    uint256 constant BLOCKS_PER_DAY = 86400;
}

Finality Model

// OPN Chain has instant finality
// No need to wait for confirmations

const receipt = await web3.eth.sendTransaction(tx);
// Transaction is immediately final after 1 confirmation

// Ethereum requires multiple confirmations
// OPN Chain is final after 1 block

Gas Price Stability

// OPN Chain has stable gas prices
const gasPrice = await web3.eth.getGasPrice();
// Always returns minimum (7 Gwei) or slightly above

// No need for complex gas price strategies
const tx = {
    gasPrice: '7000000000', // 7 Gwei always works
    // No need for maxFeePerGas/maxPriorityFeePerGas complexity
};

Migration Guide

From Ethereum

  1. Update RPC Endpoint:

// Old
const web3 = new Web3('https://mainnet.infura.io/v3/...');

// New
const web3 = new Web3('https://testnet-rpc.iopn.tech');
  1. Update Chain ID:

// Old
const chainId = 1; // Ethereum mainnet

// New  
const chainId = 984; // OPN Chain
  1. Adjust Block Timing:

// Old (Ethereum)
uint256 constant DAY = 7200; // blocks

// New (OPN)
uint256 constant DAY = 86400; // blocks

That's it! Everything else remains the same.

Testing Compatibility

// Test script to verify compatibility
async function testCompatibility() {
    const web3 = new Web3('https://testnet-rpc.iopn.tech');
    
    console.log('Testing OPN Chain compatibility...');
    
    // Test 1: Basic connectivity
    const chainId = await web3.eth.getChainId();
    console.assert(chainId === 984, 'Chain ID matches');
    
    // Test 2: Account access
    const accounts = await web3.eth.getAccounts();
    console.log('Accounts accessible:', accounts.length > 0);
    
    // Test 3: Gas estimation
    const gasPrice = await web3.eth.getGasPrice();
    console.log('Gas price:', web3.utils.fromWei(gasPrice, 'gwei'), 'Gwei');
    
    // Test 4: Block data
    const block = await web3.eth.getBlock('latest');
    console.log('Latest block:', block.number);
    
    console.log('✅ All compatibility tests passed!');
}

testCompatibility().catch(console.error);

Best Practices

1. Use Standard Tools

Stick to standard Ethereum development tools:

  • OpenZeppelin for contracts

  • Hardhat/Foundry for development

  • Ethers.js/Web3.js for integration

2. Test Thoroughly

// Use the same test suites
describe('Token Contract', () => {
    it('should deploy on OPN Chain', async () => {
        const Token = await ethers.getContractFactory('Token');
        const token = await Token.deploy();
        await token.deployed();
        
        expect(await token.totalSupply()).to.equal(expectedSupply);
    });
});

3. Monitor Differences

// Account for block time differences in time-sensitive contracts
contract Auction {
    uint256 constant DURATION = 86400; // 1 day in blocks on OPN
    
    uint256 public endBlock;
    
    function startAuction() public {
        endBlock = block.number + DURATION;
    }
}

Conclusion

OPN Chain's EVM compatibility means you can bring your entire Ethereum toolkit, knowledge, and existing contracts to a faster, more efficient blockchain. The few differences (like block time) are easy to account for, while the benefits of instant finality and low, stable gas costs make development simpler and more predictable.


Last updated