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, SHA3net_*
- Network ID, peer count, listening statuseth_*
- All standard Ethereum methodsdebug_*
- Debugging and tracingtxpool_*
- Transaction pool inspection
3. Tool Compatibility
Development Frameworks:
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
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
Update RPC Endpoint:
// Old
const web3 = new Web3('https://mainnet.infura.io/v3/...');
// New
const web3 = new Web3('https://testnet-rpc.iopn.tech');
Update Chain ID:
// Old
const chainId = 1; // Ethereum mainnet
// New
const chainId = 984; // OPN Chain
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