---
description: >-
  Understand the differences in deploying smart contracts on ZKSync using
  foundry-zksync.
---

# Deployment

***

#### Address Derivation <a href="#address-derivation" id="address-derivation"></a>

**Issue**

ZKsync uses a different strategy for deriving addresses in `CREATE` and `CREATE2` operations compared to Ethereum. This can cause discrepancies if your project relies on hardcoded Ethereum-style addresses for contract deployment.

**Problematic Code**

In Ethereum, you might have code that calculates the address of a contract deployed using `CREATE2` based on a salt and bytecode hash:

```solidity
  function computeCreate2Address(
      address deployer,
      bytes32 salt,
      bytes memory bytecode
  ) public pure returns (address) {
      return address(uint160(uint(keccak256(abi.encodePacked(
          bytes1(0xff),
          deployer,
          salt,
          keccak256(bytecode)
      )))));
  }
```

This method won’t work in ZKsync because the address derivation logic is different. To learn more about these differences refer to the documentation on [Differences with address derivation](../../../../developer-reference/ethereum-differences/evm-instructions#address-derivation).

**Error**

When deploying contracts using `CREATE2`, the actual address of the deployed contract may differ from the expected address derived using Ethereum’s method. This can cause failures when interacting with contracts by their derived address.

**Solution**

To derive ZKsync-compatible `CREATE2` addresses, you need to use ZKsync's specific hashing mechanism that includes a `zksyncCreate2` prefix.

**Fixed Code Example**

The following is an example of how you can compute a valid `CREATE2` address for ZKSync. This function uses ZKsync’s specific address derivation logic and ensures the contract addresses are correctly computed.

```solidity
    function computeCreate2Address(
        address _sender,
        bytes32 _salt,
        bytes32 _bytecodeHash,
        bytes32 _constructorInputHash
    ) external pure returns (address) {
        bytes32 senderBytes = bytes32(uint256(uint160(_sender)));
        bytes32 data = keccak256(
            bytes.concat(keccak256("zksyncCreate2"), senderBytes, _salt, _bytecodeHash, _constructorInputHash)
        );

        return address(uint160(uint256(data)));
    }
```

#### Batch Transactions <a href="#batch-transactions" id="batch-transactions"></a>

**Issue**

In Foundry ZKsync, batched transactions may be executed out of order, which can cause failures if subsequent transactions depend on the execution of prior transactions.

**Problematic Code**

In Ethereum, you might use batched transactions within your scripts like this:

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

contract FooScript is Script {
    function run() public {
        vm.startBroadcast();
        Calculator calc = new Calculator();     // tx1
        uint8 sum = calc.add(1, 2);             // tx2
        vm.stopBroadcast();
    }
}
```

In this example, the deployment of the `Calculator` contract (tx1) and the invocation of `add` (tx2) are batched together. However, on ZKsync, tx2 might execute before tx1, causing the script to fail.

**Error**

The error occurs when the second transaction (`tx2`) is executed before the first transaction (`tx1`), leading to a failure since the contract isn't deployed yet:

```bash
Error: Transaction reverted: contract not deployed
```

**Solution**

To ensure transactions are executed correctly on ZKsync using Foundry ZKsync, use the `--slow` flag, which sends transactions one at a time and keeps them in order.

**Fixed Code Example**

Here’s how you can run the script with proper transaction execution:

{% code overflow="wrap" %}
```bash
forge script script/FooTest.s.sol:FooScript --zksync --rpc-url https://sepolia.era.zksync.dev --broadcast --slow
```
{% endcode %}

The `--slow` flag forces transactions to be sent individually to the RPC endpoint, ensuring they are executed in the correct order.

#### Bytecode Hash <a href="#bytecode-hash" id="bytecode-hash"></a>

[Bytecode hashes output by `zksolc` are fundamentally different](https://docs.zksync.io/zk-stack/components/zksync-evm/bootloader#bytecode-hashes) from the hash obtained via solc. The most glaring difference is the first (most-significant) byte denotes the version of the format, which at present is `1`. This leads to all `zksolc` bytecode hashes to begin with `1`, whereas `solc` bytecodes are merely the `keccak` hash of the bytecode.

Any code making assumptions about bytecode hashes around EVM-scope will need to be migrated to accommodate for ZKsync's bytecode hashes.
