foundry-rs / foundry

Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.
https://getfoundry.sh
Apache License 2.0
8.31k stars 1.76k forks source link

Dynamic linking stops working for version `forge 0.2.0 (fd87888 2024-06-17T00:19:40.934209349Z)` #8223

Closed nakedkoalacapital closed 4 months ago

nakedkoalacapital commented 4 months ago

Component

Forge

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

What version of Foundry are you on?

forge 0.2.0 (fd87888 2024-06-17T00:19:40.934209349Z)

What command(s) is the bug in?

script deployment

Operating System

None

Describe the bug

Previously, I used a old version of forge (can't remember the version). and I used 0.8.20 solc and set shanghai as evm_version in toml.

Under the previous setup, dynamic linking to external library worked. I had a main contract and a external library with public function as its dependency. When I deploy the main contract using foundry script, the external library was deployed first and then the main contract second. The linking worked without me having to specify anything in the toml

After upgrade to the new version and using 0.8.24 and set cancun as evm_version. dynamic linking stops working. I deployed the previous setup. the the first transaction foundry send ( supposed to be external contract deployment) ends up to be some random transaction (interaction with some shitcoin). The main contract was still deployed as part of the 2nd transaction.

I have tried to deploy the external library separately and link it back to the main contract. But i am seeing Error (1130): Invalid use of a library name.

The actual transaction can't be shared here due to privacy concern. But I'd happy to share the problematic txns via private chat TG is @NakedKoalaCapital.

Minimum Example displaying this issue

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

library ExecutionLibStub {
    // This contract is just a wrapper to deploy the library
    function F() external {}
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import "src/onchain/ExecutionLibStub.sol";

contract ExecutorStub {
    // This contract is just a wrapper to deploy the library
    function F() public {
        ExecutionLibStub.F();
    }
}
contract DeployExecutionStub is Script {
    function run() external {
        uint256 deployerPrivateKey = vm.envUint("ADMIN_EOA_PK");
        vm.startBroadcast(deployerPrivateKey);
        ExecutorStub executor = new ExecutorStub();
        vm.stopBroadcast();
    }
}
forge script script/utils.s.sol:DeployExecutionStub  --rpc-url local_geth_node --with-gas-price 3000000000  --broadcast
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
via_ir = true
optimizer = true
optimizer_runs = 2000
evm_version = 'cancun'
solc = "0.8.24"

With this minimum setup, 2 transaction are created. 1st one interacts with 0x4e59b44847b379578588920cA78FbF26c0B4956C and has method id of 0x00000000

2nd contract is a contract creation

Update: Now using forge 0.2.0 (d7eac74 2024-06-21T00:16:53.812858792Z). The weird interaction with 0x4e59b44847b379578588920cA78FbF26c0B4956C went away but then external library ExecutionLibStub wasn't deployed. Only ExecutorStub was deployed.

klkvr commented 4 months ago

0x4e59b44847b379578588920cA78FbF26c0B4956C is a CREATE2 deployment factory - https://github.com/foundry-rs/foundry/blob/d7eac74cfd786447cec9650048e2d2fac63fba0c/crates/evm/core/src/constants.rs#L41

since #7711 forge routes all library deployments through it, if it's available on the current network. This allows it to only deploy library once, and then just reuse it if it was already deployed.

So what you see is that first time, library was deployed through CREATE2 factory, and then the contract itself was deployed, thus resulting in 2 transactions.

But on the second time, forge detected that library was already deployed and skipped it, thus resulting in a single deployment transaction of a contract.

This should also show up in script artifacts under run/