matter-labs / foundry-zksync

Fork of Foundry tailored for zkSync environment
Apache License 2.0
299 stars 130 forks source link

Unable to deploy using create2 factory #484

Closed brotherlymite closed 3 months ago

brotherlymite commented 3 months ago

Component

Forge

Have you ensured that all of these are up to date?

What version of Foundry are you on?

forge 0.0.2 (825ca04 2024-07-18T00:23:04.198436000Z)

What command(s) is the bug in?

forge script

Operating System

macOS (Apple Silicon)

Describe the bug

I'm unable to deploy contracts using create2 factories, when using just the create2 opcode directly in scripts everything works fine, example (using this helper lib to deploy) but facing some issues with create2 factories.

aave-proposals-v3 repo heavily depends on create2 factories and when trying to use for example the Create2Factory.sol contract, deployed here on zksync-era-mainnet, we get the following error: revert: Create2: Failed on deploy. To reproduce, you can run make deploy-libs on this branch.

Tried to use the zkSync create2Factory contract from safe-singleton-factory repo but unable to deploy using that as well. To reproduce, run make deploy-libs on this branch.

Could be because how factoryDeps is handled, but unsure why this is happening.

On a separate note, the default create2 factory in foundry-zksync still points to the non-zksync address and should be patched as well.

nbaztec commented 3 months ago

Hi @brotherlymite, a known limitation of foundry-zksync is that scripts and tests are initially run in EVM mode so compile-time constructs like type(BorrowLogic).creationCode would correspond to EVM code. To circumvent that the script can be slightly modified as such:


contract ZkDeployLib is Script {
  function run() public {
    vm.startBroadcast();      // <-- move broadcast here
    new DeployLib().run();
    vm.stopBroadcast();      // <-- move broadcast here
  }
}

contract DeployLib is Script {
  address public constant CREATE_2_FACTORY = 0xB1DDc8cfcB1A46095C6d5F81ad76F69188B381b8;

  function run() external {
    _deploy();
  }

  function _deploy() internal {
    // Create2 Factory using: https://github.com/matter-labs/zksync/blob/master/contracts/contracts/Create2Factory.sol
    Create2Factory(CREATE_2_FACTORY).deploy(
      bytes32(0), // salt
      (type(BorrowLogic).creationCode)
    );
  }
}

and run the new ZkDeployLib contract instead

forge script --zksync - scripts/misc/DeployLib.sol:ZkDeployLib ..

Note that in the release you are using, broadcasting without simulation will fail while estimating gas, so as a workaround you'll need to omit the --skip-simulation flag, so the simulation can fill in the necessary parameters. This issue has been fixed in the latest v0.0.3-alpha.1 release today, which also brings in other upstream foundry changes, if you wish to switch over to that version.

brotherlymite commented 3 months ago

Hi @nbaztec

I tried adding a wrapper as you suggested and it works fine, it deploys an additional factory contract but it should be alright for our use case.

However, is it possible to get the zkSync creation code (type(Contract).creationCode) in the scripts via some flags, as for example the aave-proposals-v3 repo we use to create proposals on aave, we compute the create2 addresses in the scripts which has a dependency on the type(Contract).creationCode. And as it corresponds to the EVM code, we're not able to compute the create2 address correctly.

Strangely, even when using the zkSync bytecode to compute the already deployed contract using computeAddress() on the Create2Factory.sol, we are getting incorrect create2 address. Example, we deployed the BorrowLogic contract using this Create2Factory contract, but we are unable to compute the correct create2 address for this.

Same on the tests we tried, but on the tests it is expected I think as it runs in the EVM mode?

nbaztec commented 3 months ago

However, is it possible to get the zkSync creation code (type(Contract).creationCode) in the scripts via some flags

This is currently a limitation of zksolc where it only returns the hash. However, ffi cheatcode can be used to obtain this information from the compiled artifacts as we do in our tests.

Strangely, even when using the zkSync bytecode to compute the already deployed contract using computeAddress() on the Create2Factory.sol, we are getting incorrect create2 address

Perhaps the sender address is of the wrapped in contract. We have some tests (and here) that compute the create2 addresses, perhaps you can take a look into them to debug why the address is different by playing around with different senders. The call traces and addresses are available with setting RUST_LOG=info forge script ....

brotherlymite commented 3 months ago

@nbaztec thank you, will fetch the bytecode hash from zkout and using it will be able to compute the create2 address.