# Porting Existing Apps

OVM 1.0 Page

This page refers to the current state of the Optimistic Ethereum network. Some of the information may be relevant to OVM 2.0, which will be deployed in October, but some of it may change.

# Differences from L1 Ethereum

Optimistic Ethereum contracts are (currently) subject to a few limitations that don't exist on Ethereum These limitations arise because contracts need to be executable under two circumstances:

  1. In Optimistic Ethereum itself, for normal operations.
  2. Inside a virtualized environment on the main Ethereum network in case of a transaction result challenge.

During a transaction result challenge, a transaction is re-executed on L1 in order to check the result of the transaction on L2. Certain opcodes like CHAINID and TIMESTAMP would cause this re-execution to produce completely different results. This could result in a legitimate transaction result being considered invalid even if the result was completely correct.

Optimistic Ethereum circumvents this problem by using a slightly modified Solidity compiler. Where the standard compiler produces those opcodes, the Optimistic version produces a call to a special contract (the "Execution Manager") that provides consistent behavior for these opcodes, whether we're running in L1 or L2. You can see the list of replaced opcodes here.

As a result of the requirement that we have this modified compiler, there are a few key differences between the process of developing apps for Ethereum and for Optimistic Ethereum. Here are the most important things to keep in mind.

# Solidity contracts

Contracts must currently be written in Solidity. You must also use a Solidity version that has a corresponding modified compiler. You can find a full list of supported versions over on GitHub (opens new window).

We're actively exploring support for other languages (like Vyper) and alternative protocol designs that may obviate the need for the modified compiler entirely.

# Contract bytecode size

The contract code size limit on Optimistic Ethereum is the same 24 kB (opens new window) limit as on Ethereum. However, the modified Solidity compiler replaces certain opcodes with contract calls (which take up a few bytes). This means that a contract that was close to the limit when compiled with normal Solidity might be over the limit with our version of the compiler.

If you're finding that your contracts are exceeding the 24 kB limit, you should consider moving some of your code into external libraries (opens new window).

# Constructor parameters

Contracts must run through a static analysis that guarantees that they do not contain any banned opcodes. Under a few special circumstances, contract constructors can fail to pass this static analysis even though the rest of the contract is considered "safe". As a result, users need to be careful when designing contracts with constructors.

Generally speaking, we encourage devs to follow these guidelines:

  1. If you're able to change your inputs without breaking the contract, then you're probably fine when using constructors. You may have to try different input configurations until you find an input that passes the static analysis. For instance, if you're passing an address as an input, you may have to try multiple different addresses until you find one that works.
  2. If you are not able to change your inputs without breaking the contract, then you should explicitly test the constructor with the inputs that you expect to provide. If you find that you are unable to pass the static analysis, you should consider using the initializable (opens new window) pattern linked below.
  3. If you're designing a contract factory system, you should be very careful about using constructors. You should almost definitely be using the initialaizable pattern instead.

# Using the initializable pattern

You can sidestep these issues with constructors by using the initializable (opens new window) contract pattern. Instead of putting the initialization code in the constructor, put it in an externally accessible function that can only be called once by the contract's creator.

# Tests need to run on geth

Both Hardhat and Truffle allow you to run contract tests against their own implementations of the EVM. However, to test contracts that run on Optimistic Ethereum you need to run them on a local copy of Optimistic Ethereum (which is built on top of geth (opens new window)).

There are two issues involved in running your tests against a geth instance, rather than an EVM running inside your development environment:

  1. Tests will take longer. For development purposes, Geth is quite a bit slower than the Hardhat (opens new window) EVM or Truffle's ganache (opens new window). You will likely have to make more liberal use of asynchronous (opens new window) functions within your tests.
  2. Both Truffle (opens new window) and Hardhat (opens new window) support custom debugging methods such as evm_snapshot and evm_revert. You cannot use these methods in tests for Optimistic Ethereum contracts because they are not available in geth. Nor can you use Hardhat's console.log (opens new window).

# Workflow

Roughly speaking, these are the steps you need to take to develop for Optimistic Ethereum:

  1. Develop the decentralized application normally, writing the contracts in Solidity and the user interface as you normally would.
  2. Create an Optimistic Ethereum development node
  3. Compile for Optimistic Ethereum using a supported environment such as Hardhat or Truffle.
  4. Run your tests on the Optimistic Ethereum development node you created.
  5. Deploy your dapp to the Optimistic Kovan network and test it in that environment.
  6. Upload and verify the contracts' source code on Optimistic Kovan Etherscan (opens new window)
  7. Ask to be added to the Optimistic Ethereum whitelist (opens new window)
  8. Once added, deploy your contracts to the Optimistic Ethereum network. Then, upload and verify your contracts' source code on Optimistic Etherscan (opens new window).