forge-std icon indicating copy to clipboard operation
forge-std copied to clipboard

getChain fails on chain aliases defined in foundry.toml

Open emo-eth opened this issue 2 years ago • 1 comments

The comment for getChain(string memory chainAlias) says // The RPC URL will be fetched from config or defaultRpcUrls if possible., so it seems to me that intended behavior is not to fail on aliases besides the hard-coded canonical ones.

Here's a minimal reproduction.

In foundry.toml, add the stanza:

[rpc_endpoints]
my_alias = 'https://mycoolalias.com'

Test:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import { Test } from "forge-std/Test.sol";

contract AliasTest is Test {
    function testGetChain() public {
        assertEq(getChain("my_alias").rpcUrl, "https://mycoolalias.com");
    }

    function testRpcUrl() public {
        assertEq(vm.rpcUrl("my_alias"), "https://mycoolalias.com");
    }
}

The root of the issue is in StdChains.getChain:

        chain = chains[chainAlias];
        require(
            chain.chainId != 0,
            string(abi.encodePacked("StdChains getChain(string): Chain with alias \"", chainAlias, "\" not found."))
        );

        chain = getChainWithUpdatedRpcUrl(chainAlias, chain);

A chain is validated as existing before calling getChainWithUpdatedRpcUrl, which uses vm.rpcUrl to fetch an alias from the config.

Another pain point is that there is no way of specifying chainId in the config – but the method checks chainId to see if it's been defined.

StdChains uses VmSafe,so it's not possible to spin up a temporary fork and call chainId() and set the chainId on the Chain struct without changing or casting the VmSafe to a regular Vm. Otherwise a fix would look something like this:

// The RPC URL will be fetched from config or defaultRpcUrls if possible.
    function getChain(string memory chainAlias) internal virtual returns (Chain memory chain) {
        require(bytes(chainAlias).length != 0, "StdChains getChain(string): Chain alias cannot be the empty string.");

        initializeStdChains();
        chain = chains[chainAlias];
        bool uninitialized = chain.chainId == 0;
        chain = getChainWithUpdatedRpcUrl(chainAlias, chain);

        require(
            chain.chainId != 0,
            string(abi.encodePacked("StdChains getChain(string): Chain with alias \"", chainAlias, "\" not found."))
        );
        // If the chain was not initialized, save it.
        if (uninitialized) {
            chains[chainAlias] = chain;
        }
    }

emo-eth avatar Aug 24 '23 19:08 emo-eth

Thanks for the details! For chains not present in the default list, you should be able to use the setChain method here to define new chains. Adding this makes both tests pass:

function setUp() public {
    Chain memory chain =
        Chain({name: "MyCoolChain", chainId: 123, chainAlias: "my_alias", rpcUrl: ""});
    setChain("my_alias", chain);
}

mds1 avatar Aug 28 '23 18:08 mds1

Think this can be closed?

Sabnock01 avatar Aug 09 '24 06:08 Sabnock01