matter-labs / foundry-zksync

Fork of Foundry tailored for zkSync environment

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Calling SystemContractsCaller.systemCallWithReturndata in EVM context is not supported

wshino opened this issue · comments

Component

Forge

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

  • Foundry
  • Foundryup

What version of Foundry are you on?

forge 0.0.2 (fb6d0c5 2024-08-08T00:23:13.752629000Z)

What command(s) is the bug in?

forge test --match-test "testComputeCreate2Address" --system-mode=true --zksync --gas-limit 1000000000--chain 300 -vvv --via-ir

Operating System

macOS (Apple Silicon)

Describe the bug

I created the test case regarding create2 following zkSync way.

L2ContractHelper.computeCreate2Address works fine.
But when I called SystemContractsCaller.systemCallWithReturndata, it returned InvalidOperandOOG

I've set is_system = true in foundry.toml.

Is there any hint to resolve it?

The full log is here. Thank you.
https://gist.github.com/wshino/c13c05afeff62c52fae0d029bd6077bf

Hey, thanks for the report! Could you share here the testComputeCreate2Address to better understand the console logs? Thank you!

@Karrq Ah sorry it's my bad. The following link is the implementation.
https://github.com/zkemail/ether-email-auth/blob/30058943b7b286dc726614d43eb10173da80df6e/packages/contracts/test/ComputeCreate2Address.t.sol

First I get the computed address via L2ContractHelper.computeCreate2Address.
Until now, deployments were performed in the same way as for normal EVMs. In this way, it was possible to verify that the calculated address and the deployed contract's address matched. However, this did not seem to work correctly in production, so I changed to an implementation using SystemContractsCaller.
But when I try to deploy the contract via SystemContractsCaller. The InvalidOperandOOG error happened the following line.

        (bool success, bytes memory returnData) = SystemContractsCaller
            .systemCallWithReturndata(
                uint32(gasleft()),
                address(DEPLOYER_SYSTEM_CONTRACT),
                uint128(0),
                abi.encodeCall(
                    DEPLOYER_SYSTEM_CONTRACT.create2,
                    (
                        accountSalt,
                        bytecodeHash,
                        abi.encode(
                            address(emailAuth),
                            abi.encodeCall(
                                EmailAuth.initialize,
                                (
                                    recoveredAccount,
                                    accountSalt,
                                    address(this)
                                )
                            )
                        )
                    )
                )
            );

I have not tried it yet, but I have heard that it works fine with zksync-hardhat.

Is there any updates?

commented

Hi! Sorry for the long wait.
After debugging, I found that the issue is due to SystemContractsCaller being a library, therefore the call environment in which the system call happens is NOT a zkSync environment, which leads to this error.

The way I fixed the issue locally was thru a factory contract, which would then be 100% run in zkVM (here's a patch for your test to use this pattern).


Looking at the test I can see that previously you had used the usual approach for the deployment (via new) and for all intents and purposes that should have been sufficient (and it would also work nicely in a script, where you would be able to broadcast this deployment): could you elaborate on the failure you encountered (the comment "not working actually by clave side")?

I also tried to understand the context of your test, and found that you were having issues with the bytecode size limit, and had to switch to slower compilation because of that - I suggest looking into creating a separate foundry profile, which would allow you to specify entirely different configuration for zksync, like different folders for these sources, so that you would only need to use via-ir with this second profile

Lastly, creationCode doesn't return the expected value to be used for zksync only in the EVM context (to test contracts or any contracts executed when vm.zkVm(false)), due to it being a compile-time concept and the contract being compiled via Solc. Usage of creationCode in contracts being executed entirely in the zkVM work as expected (like the factory contract above).
Currently, the only way to retrieve the proper creationCode value during EVM is to read the artifact output thru cheatcodes.

Thank you for your reply and details. Indeed the previous logic it works fine. But the problem is that the calculated address value is different from the actual deployed address. That's the reason I updated the logic. Fortunately the test case using SystemContractsCaller it works fine with hardhat zksync.

Currently we froze our contract code for audit. Next time to fix some vulnerability and audit report issues, I will modify this logic through factory contract. Thank you so much.

commented

Okay I see, I'll check and get back to you why you might be observing this, considering we have a test for the create2 address computation:

function testZkContractsCreate2() public {
vm.selectFork(forkEra);
string memory artifact = vm.readFile("zk/zkout/ConstantNumber.sol/ConstantNumber.json");
bytes32 bytecodeHash = vm.parseJsonBytes32(artifact, ".hash");
address sender = address(0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496);
bytes32 salt = "12345";
bytes32 constructorInputHash = keccak256(abi.encode());
address expectedDeployedAddress =
_computeCreate2Address(sender, salt, bytes32(bytecodeHash), constructorInputHash);
// deploy via create2
address actualDeployedAddress = address(new ConstantNumber{salt: salt}());
assertEq(expectedDeployedAddress, actualDeployedAddress);
}

Yes, with hardhat it would work because the hardhat deployment generates transactions directly, meanwhile foundry runs the script written in solidity and collects any external call as a broadcastable tx, which is then broadcasted

commented

Hey @wshino I added a new test covering your usecase, but I wasn't able to reproduce your error with it, so I'm not sure why you are getting a different address than expected.
Please let me know if you still encounter this issue, but otherwise I'll go ahead and close it for now since the original has been resolved (or at least a workaround is known).
Thanks!

@Karrq Thank you for your test case and trying to reproduce it. Actually the different deployed address problem couldn't be reproduce with foundry zksync, it only happened on zkSync sepolia testnet. Perhaps it can be reproduced on zkSync maininet too.
Anyway I'm going to implement the above logic through factory contract. it can be solved InvalidOperandOOG error.