// SPDX-License-Identifier: MIT pragma solidity >=0.7.0 <0.9.0; import "../src/Test.sol"; contract StdChainsMock is Test { function exposed_getChain(string memory chainAlias) public returns (Chain memory) { return getChain(chainAlias); } function exposed_getChain(uint256 chainId) public returns (Chain memory) { return getChain(chainId); } function exposed_setChain(string memory chainAlias, ChainData memory chainData) public { setChain(chainAlias, chainData); } function exposed_setFallbackToDefaultRpcUrls(bool useDefault) public { setFallbackToDefaultRpcUrls(useDefault); } } contract StdChainsTest is Test { function test_ChainRpcInitialization() public { // RPCs specified in `foundry.toml` should be updated. assertEq(getChain(1).rpcUrl, "https://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX"); assertEq(getChain("optimism_sepolia").rpcUrl, "https://sepolia.optimism.io/"); assertEq(getChain("arbitrum_one_sepolia").rpcUrl, "https://sepolia-rollup.arbitrum.io/rpc/"); // Environment variables should be the next fallback assertEq(getChain("arbitrum_nova").rpcUrl, "https://nova.arbitrum.io/rpc"); vm.setEnv("ARBITRUM_NOVA_RPC_URL", "myoverride"); assertEq(getChain("arbitrum_nova").rpcUrl, "myoverride"); vm.setEnv("ARBITRUM_NOVA_RPC_URL", "https://nova.arbitrum.io/rpc"); // Cannot override RPCs defined in `foundry.toml` vm.setEnv("MAINNET_RPC_URL", "myoverride2"); assertEq(getChain("mainnet").rpcUrl, "https://eth-mainnet.alchemyapi.io/v2/WV407BEiBmjNJfKo9Uo_55u0z0ITyCOX"); // Other RPCs should remain unchanged. assertEq(getChain(31337).rpcUrl, "http://127.0.0.1:8545"); assertEq(getChain("sepolia").rpcUrl, "https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001"); } // Named with a leading underscore to clarify this is not intended to be run as a normal test, // and is intended to be used in the below `test_Rpcs` test. function _testRpc(string memory rpcAlias) internal { string memory rpcUrl = getChain(rpcAlias).rpcUrl; vm.createSelectFork(rpcUrl); } // Ensure we can connect to the default RPC URL for each chain. // Currently commented out since this is slow and public RPCs are flaky, often resulting in failing CI. // function test_Rpcs() public { // _testRpc("mainnet"); // _testRpc("sepolia"); // _testRpc("holesky"); // _testRpc("optimism"); // _testRpc("optimism_sepolia"); // _testRpc("arbitrum_one"); // _testRpc("arbitrum_one_sepolia"); // _testRpc("arbitrum_nova"); // _testRpc("polygon"); // _testRpc("polygon_amoy"); // _testRpc("avalanche"); // _testRpc("avalanche_fuji"); // _testRpc("bnb_smart_chain"); // _testRpc("bnb_smart_chain_testnet"); // _testRpc("gnosis_chain"); // _testRpc("moonbeam"); // _testRpc("moonriver"); // _testRpc("moonbase"); // _testRpc("base_sepolia"); // _testRpc("base"); // _testRpc("blast_sepolia"); // _testRpc("blast"); // _testRpc("fantom_opera"); // _testRpc("fantom_opera_testnet"); // _testRpc("fraxtal"); // _testRpc("fraxtal_testnet"); // _testRpc("berachain_bartio_testnet"); // } function test_ChainNoDefault() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); vm.expectRevert("StdChains getChain(string): Chain with alias \"does_not_exist\" not found."); stdChainsMock.exposed_getChain("does_not_exist"); } function test_SetChainFirstFails() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); vm.expectRevert("StdChains setChain(string,ChainData): Chain ID 31337 already used by \"anvil\"."); stdChainsMock.exposed_setChain("anvil2", ChainData("Anvil", 31337, "URL")); } function test_ChainBubbleUp() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); stdChainsMock.exposed_setChain("needs_undefined_env_var", ChainData("", 123456789, "")); vm.expectRevert( "Failed to resolve env var `UNDEFINED_RPC_URL_PLACEHOLDER` in `${UNDEFINED_RPC_URL_PLACEHOLDER}`: environment variable not found" ); stdChainsMock.exposed_getChain("needs_undefined_env_var"); } function test_CannotSetChain_ChainIdExists() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); stdChainsMock.exposed_setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); vm.expectRevert('StdChains setChain(string,ChainData): Chain ID 123456789 already used by "custom_chain".'); stdChainsMock.exposed_setChain("another_custom_chain", ChainData("", 123456789, "")); } function test_SetChain() public { setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); Chain memory customChain = getChain("custom_chain"); assertEq(customChain.name, "Custom Chain"); assertEq(customChain.chainId, 123456789); assertEq(customChain.chainAlias, "custom_chain"); assertEq(customChain.rpcUrl, "https://custom.chain/"); Chain memory chainById = getChain(123456789); assertEq(chainById.name, customChain.name); assertEq(chainById.chainId, customChain.chainId); assertEq(chainById.chainAlias, customChain.chainAlias); assertEq(chainById.rpcUrl, customChain.rpcUrl); customChain.name = "Another Custom Chain"; customChain.chainId = 987654321; setChain("another_custom_chain", customChain); Chain memory anotherCustomChain = getChain("another_custom_chain"); assertEq(anotherCustomChain.name, "Another Custom Chain"); assertEq(anotherCustomChain.chainId, 987654321); assertEq(anotherCustomChain.chainAlias, "another_custom_chain"); assertEq(anotherCustomChain.rpcUrl, "https://custom.chain/"); // Verify the first chain data was not overwritten chainById = getChain(123456789); assertEq(chainById.name, "Custom Chain"); assertEq(chainById.chainId, 123456789); } function test_SetNoEmptyAlias() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); vm.expectRevert("StdChains setChain(string,ChainData): Chain alias cannot be the empty string."); stdChainsMock.exposed_setChain("", ChainData("", 123456789, "")); } function test_SetNoChainId0() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); vm.expectRevert("StdChains setChain(string,ChainData): Chain ID cannot be 0."); stdChainsMock.exposed_setChain("alias", ChainData("", 0, "")); } function test_GetNoChainId0() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); vm.expectRevert("StdChains getChain(uint256): Chain ID cannot be 0."); stdChainsMock.exposed_getChain(0); } function test_GetNoEmptyAlias() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); vm.expectRevert("StdChains getChain(string): Chain alias cannot be the empty string."); stdChainsMock.exposed_getChain(""); } function test_ChainIdNotFound() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); vm.expectRevert("StdChains getChain(string): Chain with alias \"no_such_alias\" not found."); stdChainsMock.exposed_getChain("no_such_alias"); } function test_ChainAliasNotFound() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); vm.expectRevert("StdChains getChain(uint256): Chain with ID 321 not found."); stdChainsMock.exposed_getChain(321); } function test_SetChain_ExistingOne() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); assertEq(getChain(123456789).chainId, 123456789); setChain("custom_chain", ChainData("Modified Chain", 999999999, "https://modified.chain/")); vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); stdChainsMock.exposed_getChain(123456789); Chain memory modifiedChain = getChain(999999999); assertEq(modifiedChain.name, "Modified Chain"); assertEq(modifiedChain.chainId, 999999999); assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); } function test_DontUseDefaultRpcUrl() public { // We deploy a mock to properly test the revert. StdChainsMock stdChainsMock = new StdChainsMock(); // Should error if default RPCs flag is set to false. stdChainsMock.exposed_setFallbackToDefaultRpcUrls(false); vm.expectRevert(); stdChainsMock.exposed_getChain(31337); vm.expectRevert(); stdChainsMock.exposed_getChain("sepolia"); } }