foundry icon indicating copy to clipboard operation
foundry copied to clipboard

script fail to resolve deployed contract name

Open 0xCalibur opened this issue 3 years ago • 9 comments

Component

Forge

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

  • [X] Foundry
  • [X] Foundryup

What version of Foundry are you on?

forge 0.2.0 (b83b316 2023-01-25T00:12:19.890671Z)

What command(s) is the bug in?

forge script ./script/MyScript.s.sol --rpc-url --private-key -vvvv;

Operating System

macOS (Apple Silicon)

Describe the bug

Context: I'm using the run-latest.json files to extract informations using jq but noticed that in some cases, for transactionType "CREATE", the contractName field was undefined. So, I tried to reproduce the bug with the simplest example I could.

Script:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Script.sol";
import "/MyContract.sol";

contract MyScript is Script {
    function run() public {
        vm.startBroadcast();

        new MyContract(
            address(0),
            address(0),
            address(0),
            0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f,
            0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
        );

        vm.stopBroadcast();
    }
}

Contract:


contract MyContract {
    address public immutable var1;
    address public immutable var2;
    address public immutable var3;
    address public immutable var4;
    address public immutable var5;

    constructor(
        address _var1,
        address _var2,
        address _var3,
        address _var4,
        address _var5
    ) {
        var1 = _var1;
        var2 = _var2;
        var3 = _var3;
        var4 = _var4;
        var5 = _var5;
    }
}

Command:

forge script ./script/MyScript.s.sol --rpc-url <rpc>  --private-key <pk>  -vvvv;

Output:

[⠒] Compiling...
[⠑] Compiling 1 files with 0.8.16
[⠃] Solc 0.8.16 finished in 534.70ms
Compiler run successful
Traces:
  [131496] MyScript::run() 
    ├─ [0] VM::startBroadcast() 
    │   └─ ← ()
    ├─ [74726] → new <Unknown>@0xcF4f8E9A113433046B990980ebce5c3fA883067f
    │   └─ ← 369 bytes of code
    ├─ [0] VM::stopBroadcast() 
    │   └─ ← ()
    └─ ← ()

Script ran successfully.

## Setting up (1) EVMs.
==========================
Simulated On-chain Traces:

  [136778] → new <Unknown>@0xcF4f8E9A113433046B990980ebce5c3fA883067f
    └─ ← 369 bytes of code

==========================
Chain 42161
Estimated gas price: 0.1 gwei
Estimated total gas used for script: 1841715
Estimated amount required: 0.0001841715 ETH
==========================

SIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more.

But if I change the script to:

pragma solidity ^0.8.13;

import "forge-std/Script.sol";
import "/MyContract.sol";

contract MyScript is Script {
    function run() public {
        vm.startBroadcast();

        new MyContract(
            address(0),
            address(0),
            address(0),
            address(0),
            0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
        );

        vm.stopBroadcast();
    }
}

The deployed contract name is resolved:

## Setting up (1) EVMs.
==========================
Simulated On-chain Traces:

  [136538] → new MyContract@0xcF4f8E9A113433046B990980ebce5c3fA883067f
    └─ ← 369 bytes of code


==========================

Expectation: It should show new MyContract@0xcF4f8E9A113433046B990980ebce5c3fA883067f instead of new <Unknown>@0xcF4f8E9A113433046B990980ebce5c3fA883067f

0xCalibur avatar Jan 25 '23 03:01 0xCalibur

I'm trying to debug the Forge source code to have more hint about what is happening and what I've been observing so far is a problem when decoding the script trace.

cli/src/cmd/forge/script/mod.rs

impl ScriptArgs {
    pub fn decode_traces(
        ...
    }
}

In the case where the contract name is Unknown the contract isn't present inside decoder.contracts but only the Script contract name. Otherwise, when MyContract is resolved, it's getting added inside decoder.contracts

For example, when iterating decoder.contracts:

0x5b73c5498c1e3b4dba84de0f1833c4a029d90519, "/home/user/hello_foundry/script/Script.s.sol:CounterScript"

versus:

0x1fa02b2d6a771842690194cf62d91bdd92bfe28d, "/home/user/hello_foundry/src/MyContract.sol:MyContract"
0x5b73c5498c1e3b4dba84de0f1833c4a029d90519, "/home/user/hello_foundry/script/Script.s.sol:CounterScript"

0xCalibur avatar Feb 11 '23 00:02 0xCalibur

Update:

image

The problem seems to be the diff matching here. In the case where the contract is Unknown, it's because it's not getting matched here.

From my understand it's trying to mach bytecode artifact with trace bytecode?

0xCalibur avatar Feb 11 '23 00:02 0xCalibur

image

Just saw this, seems like this is the problem here.

0xCalibur avatar Feb 11 '23 01:02 0xCalibur

Ah interesting. It could be possible that the diff score is higher than expected because of the heavy usage of immutables, which get inlined in the bytecode. @joshieDo this seems like an interesting edge case, if you have a solution top of your mind. @0xCalibur what is the value returned by diff_score here? maybe we can tune it up a little bit

gakonst avatar Feb 11 '23 01:02 gakonst

Thx @gakonst for looking this up!

score: 0.8373983739837398 when the constructor args are address(0), address(0), address(0), 0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f, 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1

score: 0 when they are all address(0)

0xCalibur avatar Feb 11 '23 01:02 0xCalibur

Now that we have sourcemap parsing, we could just check the sourcemap and get the name and look it up. That may be the most reliable (but requires knowing import statements as well in the case that there is a renaming).

brockelmore avatar Feb 11 '23 06:02 brockelmore

I am also having this issue running the deploy script in the ArtGobblers repo with the ChainlinkV1RandProvider contract.

It generates the following in the run-latest.json:

{
  "hash": "0xfde96ba37a6f889a63cc99d0a7923ed798b108d1657c125011b88e38df1a55f3",
  "transactionType": "CREATE",
  "contractName": null, // <--- 
  "contractAddress": "0x38628490c3043E5D0bbB26d5a0a62fC77342e9d5",
  "function": null,
  "arguments": null,
  "transaction": {
    "type": "0x02",
    "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
    "gas": "0x7ad72",
    "value": "0x0",
    "data": "0x....",
    "nonce": "0x1f2",
    "accessList": []
  },
  "additionalContracts": [],
  "isFixedGasLimit": false
},

colinnielsen avatar Aug 16 '23 03:08 colinnielsen

Seems like it wasn't fixed yet... When passing address(0) to all immutable arguments - it gets contractName correctly, but with real values I still get null

vicnaum avatar Oct 03 '23 16:10 vicnaum

Having the same bug under pretty much same circumstances. A temporary workaround seems to be removing the cache folder.

0xalbert avatar Feb 05 '24 21:02 0xalbert

Unable to reproduce with @0xCalibur's example, now correctly yields:

Traces:
  [110432] MyScript::run()
    ├─ [0] VM::startBroadcast()
    │   └─ ← [Return] 
    ├─ [74726] → new MyContract@0x90193C961A926261B756D1E5bb255e67ff9498A1
    │   └─ ← [Return] 369 bytes of code
    ├─ [0] VM::stopBroadcast()
    │   └─ ← [Return] 
    └─ ← [Stop] 

The ArtGobblers repo mentioned by @colinnielsen now correctly yields:

"contractName": "ChainlinkV1RandProvider"

There have been significant improvements around this since the ticket was raised (cc @klkvr) so I'm assuming it has been fixed.

Feel free to re-open the ticket if any of you run into this problem again.

For now - marking as resolved

zerosnacks avatar Jun 28 '24 13:06 zerosnacks