# Compilation

***

[`zksolc`](https://github.com/matter-labs/era-compiler-solidity/releases) is the compiler used by Validium to convert solidity code to zkEVM-compatible bytecode. It uses the same input format as `solc` but the output bytecodes and their respective hashes. Internally it uses a custom-compiled [`solc`](https://github.com/matter-labs/era-solidity/releases).

Below are the common compilation differences development teams will need to address when making use of Foundry ZKsync.

#### Contract Bytecode Access <a href="#contract-bytecode-access" id="contract-bytecode-access"></a>

Contract bytecode cannot be accessed on the Validium architecture due to the way zkEVM handles certain instructions like `EXTCODECOPY`. As a result, using `address(..).code` in a Solidity contract will produce a compile-time error with `zksolc`.

**Issue**

The `EXTCODECOPY` instruction is not supported in Validium's architecture. Any attempt to access a contract's bytecode using `address(..).code` will fail to compile.

**Problematic Code**

This code will fail during compilation because `address(..).code` is unsupported in Validium:

```solidity
contract FooBar {
    function number() return (uint8) {
        return 10;
    }
}

contract FooTest is Test {
    function testFoo() public {
        FooBar target = new FooBar();
        address(target).code;   // will fail at compile-time
    }
}
```

**Compilation Error**

When you attempt to compile this code, you will see the following error message:

```bash
Error
Error: LLVM IR generator definition pass: 11508:17 The `EXTCODECOPY` instruction is not supported
--> test/FooTest.t.sol:FooTest
```

**Solution**

To work around this limitation, you can use Foundry's FFI (Foreign Function Interface) functionality to access contract bytecode and hash it externally, and then pass it back into the contract. This approach leverages cheatcodes to read the bytecode from a file.

**Fixed Code Example**

Here's how you can modify the code to avoid the use of `address(..).code`:

```solidity
contract Calculator {
    function add(uint8 a, uint8 b) return (uint8) {
        return a + b;
    }
}

contract FooTest is Test {
    function testFoo() public {
        string memory artifact = vm.readFile(
            "zkout/FooTest.sol/Calculator.json"
        );
        bytes32 bytecodeHash = vm.parseJsonBytes32(artifact, ".hash");
        bytes32 salt = 0x0000000000000000000000000000000000000001;

        ISystemContractDeployer deployer = ISystemContractDeployer(
            address(0x0000000000000000000000000000000000008006)
        );
        address addr = deployer.getNewAddressCreate2(
            address(this),
            salt,
            bytecodeHash,
            ""
        );
    }
}
```

**Additional Configuration**

This solution requires enabling read permissions in the `foundry.toml` file for the file access during testing:

```bash
[profile.default]
fs_permissions = [{ access = "read", path = "./zkout/FooTest.sol/Calculator.json"}]
```

#### Contract Size Limit <a href="#contract-size-limit" id="contract-size-limit"></a>

The `zksolc` compiler enforces a limit on the number of instructions a contract can have, capped at **2^16 instructions**. If a contract exceeds this limit, the compilation will fail.

**Issue**

Contracts with a large number of instructions will not compile on ZKsync due to the **65535 addressable space** limitation imposed by `zksolc`.

**Problematic Scenario**

If you attempt to compile a large contract that exceeds this instruction limit, the compilation will fail with an error.

**Example of Compilation Error**

```bash
Error: assembly-to-bytecode conversion: assembly parse error Label DEFAULT_UNWIND was tried to be used
for either PC or constant at offset 65947 that is more than 65535 addressable space
```

This error indicates that the contract's instruction count has exceeded the maximum allowed limit.

**Solution**

There are three possible solutions to address this issue:

1. **Attempt Compilation with `--zk-force-evmla=true`:** You can attempt to compile the contract using ZKsync's EVM legacy architecture by adding the `--zk-force-evmla=true` flag. This can sometimes bypass the contract size limit by compiling in a different mode.\
   Example command:

   ```bash
   forge build --zk-force-evmla=true --zksync
   ```
2. **Use the `--zk-fallback-oz=true` flag:** If the contract size still exceeds the limit, try compiling with optimization level `-Oz` by using the `--zk-fallback-oz=true` flag. This tells the compiler to fall back to `-Oz` optimization when the bytecode is too large, potentially reducing the contract size further.\
   Example command:

   ```bash
   forge build --zk-fallback-oz=true --zksync
   ```
3. **Split the Contract into Smaller Units**: If neither of the above flags resolves the issue, the contract must be refactored into smaller, modular contracts. This involves separating your logic into different contracts and using contract inheritance or external contract calls to maintain functionality.

**Example of Refactoring**

Here’s an example of splitting a large contract into smaller units:

Before (single large contract):

```solidity
contract LargeContract {
    function largeFunction1() public { /* complex logic */ }
    function largeFunction2() public { /* complex logic */ }
    // Additional large functions and state variables...
}
```

After (split into smaller contracts):

```solidity
contract ContractPart1 {
    function part1Function() public { /* logic from largeFunction1 */ }
}

contract ContractPart2 {
    function part2Function() public { /* logic from largeFunction2 */ }
}

contract MainContract is ContractPart1, ContractPart2 {
    // Logic to combine the functionalities of both parts
}
```

#### Non-inlineable Libraries <a href="#non-inlineable-libraries" id="non-inlineable-libraries"></a>

Libraries that contain public or external methods cannot be inlined when compiling to ZKsync VM bytecode. Although Solidity can inline libraries during EVM compilation, this inlining is not supported in the Yul intermediate representation, which is used by `zksolc` to compile for ZKsync.

**Issue**

On ZKsync, if your project contains non-inlineable libraries, the compilation will fail because these libraries cannot be inlined during the Yul to ZKsync bytecode compilation step.

**Problematic Scenario**

Consider the following library that calculates the square of a number:

```solidity
pragma solidity ^0.8.0;

library MiniMath {
    function square(uint256 x) public pure returns (uint256) {
         return x * x;
    }
}
```

Now, assume you have a smart contract that uses this library:

```solidity
pragma solidity ^0.8.0;

import "./MiniMath.sol";

contract Main {
    uint256 public lastNumber;

    function storeSquare(uint256 x) public {
        uint256 square = MiniMath.square(x);
        lastNumber = square;
    }
}
```

When you try to compile this project, the compiler will fail because the `MiniMath` library is not inlined due to the `public` method.

**Example of Compilation Error**

{% code overflow="wrap" %}

```bash
Error:
Missing libraries detected [MiniMath { contract_name: "Main", contract_path: "contracts/Main.sol", missing_libraries: [] }]
```

{% endcode %}

This error indicates that the `MiniMath` library is missing because it cannot be inlined and must be deployed separately.

**Solution**

Libraries with public or external methods must be deployed separately, and their addresses must be passed to the compiler. The library methods will be called through their deployed address, replacing inlining.

**Steps to Fix**

1. **Deploy the Missing Libraries**: Run the following command to deploy the missing library:

   <pre class="language-bash" data-overflow="wrap"><code class="lang-bash">forge create --deploy-missing-libraries --private-key &#x3C;PRIVATE_KEY> --rpc-url &#x3C;RPC_URL> --chain &#x3C;CHAIN_ID> --zksync
   </code></pre>

   \
   This command will deploy the library (`MiniMath` in this case) to the specified network.
2. **Compile the Main Contract**: After deploying the library, proceed with compiling the main contract by specifying the deployed library addresses during compilation:

   ```bash
   forge build --zksync
   ```

   \
   The deployed address will be linked to the main contract, and library methods will be invoked via external calls rather than inline.


---

# 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://validium.gitbook.io/docs/tooling/foundary/migration-guide/compilation.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.
