@@ -14,7 +14,8 @@ import {VmSafe} from "./Vm.sol";
1414 * `setChainWithDefaultRpcUrl` call in the `initialize` function.
1515 *
1616 * There are two main ways to use this contract:
17- * 1. Set a chain with `setChain(string memory chainAlias, Chain memory chain)`
17+ * 1. Set a chain with `setChain(string memory chainAlias, ChainData memory chain)` or
18+ * `setChain(string memory chainAlias, Chain memory chain)`
1819 * 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`.
1920 *
2021 * The first time either of those are used, chains are initialized with the default set of RPC URLs.
@@ -25,25 +26,33 @@ import {VmSafe} from "./Vm.sol";
2526 *
2627 * The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say
2728 * we want to retrieve `mainnet`'s RPC URL:
28- * - If you haven't set any mainnet chain info with `setChain` and you haven't specified that
29- * chain in `foundry.toml`, the default data and RPC URL will be returned.
29+ * - If you haven't set any mainnet chain info with `setChain`, you haven't specified that
30+ * chain in `foundry.toml` and no env var is set , the default data and RPC URL will be returned.
3031 * - If you have set a mainnet RPC URL in `foundry.toml` it will return that, if valid (e.g. if
3132 * a URL is given or if an environment variable is given and that environment variable exists).
3233 * Otherwise, the default data is returned.
3334 * - If you specified data with `setChain` it will return that.
3435 *
35- * Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> defaults.
36+ * Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> environment variable -> defaults.
3637 */
3738abstract contract StdChains {
3839 VmSafe private constant vm = VmSafe (address (uint160 (uint256 (keccak256 ("hevm cheat code " )))));
3940
4041 bool private initialized;
4142
43+ struct ChainData {
44+ string name;
45+ uint256 chainId;
46+ string rpcUrl;
47+ }
48+
4249 struct Chain {
4350 // The chain name.
4451 string name;
4552 // The chain's Chain ID.
4653 uint256 chainId;
54+ // The chain's alias. (i.e. what gets specified in `foundry.toml`).
55+ string chainAlias;
4756 // A default RPC endpoint for this chain.
4857 // NOTE: This default RPC URL is included for convenience to facilitate quick tests and
4958 // experimentation. Do not use this RPC URL for production test suites, CI, or other heavy
@@ -88,12 +97,13 @@ abstract contract StdChains {
8897 }
8998
9099 // set chain info, with priority to argument's rpcUrl field.
91- function setChain (string memory chainAlias , Chain memory chain ) internal virtual {
100+ function setChain (string memory chainAlias , ChainData memory chain ) internal virtual {
92101 require (
93- bytes (chainAlias).length != 0 , "StdChains setChain(string,Chain): Chain alias cannot be the empty string. "
102+ bytes (chainAlias).length != 0 ,
103+ "StdChains setChain(string,ChainData): Chain alias cannot be the empty string. "
94104 );
95105
96- require (chain.chainId != 0 , "StdChains setChain(string,Chain ): Chain ID cannot be 0. " );
106+ require (chain.chainId != 0 , "StdChains setChain(string,ChainData ): Chain ID cannot be 0. " );
97107
98108 initialize ();
99109 string memory foundAlias = idToAlias[chain.chainId];
@@ -102,7 +112,7 @@ abstract contract StdChains {
102112 bytes (foundAlias).length == 0 || keccak256 (bytes (foundAlias)) == keccak256 (bytes (chainAlias)),
103113 string (
104114 abi.encodePacked (
105- "StdChains setChain(string,Chain ): Chain ID " ,
115+ "StdChains setChain(string,ChainData ): Chain ID " ,
106116 vm.toString (chain.chainId),
107117 " already used by \" " ,
108118 foundAlias,
@@ -114,22 +124,39 @@ abstract contract StdChains {
114124 uint256 oldChainId = chains[chainAlias].chainId;
115125 delete idToAlias[oldChainId];
116126
117- chains[chainAlias] = chain;
127+ chains[chainAlias] =
128+ Chain ({name: chain.name, chainId: chain.chainId, chainAlias: chainAlias, rpcUrl: chain.rpcUrl});
118129 idToAlias[chain.chainId] = chainAlias;
119130 }
120131
132+ // set chain info, with priority to argument's rpcUrl field.
133+ function setChain (string memory chainAlias , Chain memory chain ) internal virtual {
134+ setChain (chainAlias, ChainData ({name: chain.name, chainId: chain.chainId, rpcUrl: chain.rpcUrl}));
135+ }
136+
137+ function _toUpper (string memory str ) private pure returns (string memory ) {
138+ bytes memory strb = bytes (str);
139+ bytes memory copy = new bytes (strb.length );
140+ for (uint256 i = 0 ; i < strb.length ; i++ ) {
141+ bytes1 b = strb[i];
142+ if (b >= 0x61 && b <= 0x7A ) {
143+ copy[i] = bytes1 (uint8 (b) - 32 );
144+ } else {
145+ copy[i] = b;
146+ }
147+ }
148+ return string (copy);
149+ }
150+
121151 // lookup rpcUrl, in descending order of priority:
122- // current -> config (foundry.toml) -> default
123- function getChainWithUpdatedRpcUrl (string memory chainAlias , Chain memory chain )
124- private
125- view
126- returns (Chain memory )
127- {
152+ // current -> config (foundry.toml) -> environment variable -> default
153+ function getChainWithUpdatedRpcUrl (string memory chainAlias , Chain memory chain ) private returns (Chain memory ) {
128154 if (bytes (chain.rpcUrl).length == 0 ) {
129155 try vm.rpcUrl (chainAlias) returns (string memory configRpcUrl ) {
130156 chain.rpcUrl = configRpcUrl;
131157 } catch (bytes memory err ) {
132- chain.rpcUrl = defaultRpcUrls[chainAlias];
158+ chain.rpcUrl =
159+ vm.envOr (string (abi.encodePacked (_toUpper (chainAlias), "_RPC_URL " )), defaultRpcUrls[chainAlias]);
133160 // distinguish 'not found' from 'cannot read'
134161 bytes memory notFoundError =
135162 abi.encodeWithSignature ("CheatCodeError " , string (abi.encodePacked ("invalid rpc url " , chainAlias)));
@@ -150,36 +177,43 @@ abstract contract StdChains {
150177 initialized = true ;
151178
152179 // If adding an RPC here, make sure to test the default RPC URL in `testRpcs`
153- setChainWithDefaultRpcUrl ("anvil " , Chain ("Anvil " , 31337 , "http://127.0.0.1:8545 " ));
180+ setChainWithDefaultRpcUrl ("anvil " , ChainData ("Anvil " , 31337 , "http://127.0.0.1:8545 " ));
181+ setChainWithDefaultRpcUrl (
182+ "mainnet " , ChainData ("Mainnet " , 1 , "https://mainnet.infura.io/v3/6770454bc6ea42c58aac12978531b93f " )
183+ );
184+ setChainWithDefaultRpcUrl (
185+ "goerli " , ChainData ("Goerli " , 5 , "https://goerli.infura.io/v3/6770454bc6ea42c58aac12978531b93f " )
186+ );
187+ setChainWithDefaultRpcUrl (
188+ "sepolia " , ChainData ("Sepolia " , 11155111 , "https://sepolia.infura.io/v3/6770454bc6ea42c58aac12978531b93f " )
189+ );
190+ setChainWithDefaultRpcUrl ("optimism " , ChainData ("Optimism " , 10 , "https://mainnet.optimism.io " ));
191+ setChainWithDefaultRpcUrl ("optimism_goerli " , ChainData ("Optimism Goerli " , 420 , "https://goerli.optimism.io " ));
192+ setChainWithDefaultRpcUrl ("arbitrum_one " , ChainData ("Arbitrum One " , 42161 , "https://arb1.arbitrum.io/rpc " ));
154193 setChainWithDefaultRpcUrl (
155- "mainnet " , Chain ( " Mainnet " , 1 , "https://mainnet.infura .io/v3/6770454bc6ea42c58aac12978531b93f " )
194+ "arbitrum_one_goerli " , ChainData ( " Arbitrum One Goerli " , 421613 , "https://goerli-rollup.arbitrum .io/rpc " )
156195 );
196+ setChainWithDefaultRpcUrl ("arbitrum_nova " , ChainData ("Arbitrum Nova " , 42170 , "https://nova.arbitrum.io/rpc " ));
197+ setChainWithDefaultRpcUrl ("polygon " , ChainData ("Polygon " , 137 , "https://polygon-rpc.com " ));
157198 setChainWithDefaultRpcUrl (
158- "goerli " , Chain ( " Goerli " , 5 , "https://goerli.infura.io/v3/6770454bc6ea42c58aac12978531b93f " )
199+ "polygon_mumbai " , ChainData ( " Polygon Mumbai " , 80001 , "https://rpc-mumbai.maticvigil.com " )
159200 );
201+ setChainWithDefaultRpcUrl ("avalanche " , ChainData ("Avalanche " , 43114 , "https://api.avax.network/ext/bc/C/rpc " ));
160202 setChainWithDefaultRpcUrl (
161- "sepolia " , Chain ( " Sepolia " , 11155111 , "https://sepolia.infura.io/v3/6770454bc6ea42c58aac12978531b93f " )
203+ "avalanche_fuji " , ChainData ( " Avalanche Fuji " , 43113 , "https://api.avax-test.network/ext/bc/C/rpc " )
162204 );
163- setChainWithDefaultRpcUrl ("optimism " , Chain ("Optimism " , 10 , "https://mainnet.optimism.io " ));
164- setChainWithDefaultRpcUrl ("optimism_goerli " , Chain ("Optimism Goerli " , 420 , "https://goerli.optimism.io " ));
165- setChainWithDefaultRpcUrl ("arbitrum_one " , Chain ("Arbitrum One " , 42161 , "https://arb1.arbitrum.io/rpc " ));
166205 setChainWithDefaultRpcUrl (
167- "arbitrum_one_goerli " , Chain ( " Arbitrum One Goerli " , 421613 , "https://goerli-rollup.arbitrum.io/rpc " )
206+ "bnb_smart_chain " , ChainData ( " BNB Smart Chain " , 56 , "https://bsc-dataseed1.binance.org " )
168207 );
169- setChainWithDefaultRpcUrl ("arbitrum_nova " , Chain ("Arbitrum Nova " , 42170 , "https://nova.arbitrum.io/rpc " ));
170- setChainWithDefaultRpcUrl ("polygon " , Chain ("Polygon " , 137 , "https://polygon-rpc.com " ));
171- setChainWithDefaultRpcUrl ("polygon_mumbai " , Chain ("Polygon Mumbai " , 80001 , "https://rpc-mumbai.maticvigil.com " ));
172- setChainWithDefaultRpcUrl ("avalanche " , Chain ("Avalanche " , 43114 , "https://api.avax.network/ext/bc/C/rpc " ));
173208 setChainWithDefaultRpcUrl (
174- "avalanche_fuji " , Chain ("Avalanche Fuji " , 43113 , "https://api.avax-test.network/ext/bc/C/rpc " )
209+ "bnb_smart_chain_testnet " ,
210+ ChainData ("BNB Smart Chain Testnet " , 97 , "https://data-seed-prebsc-1-s1.binance.org:8545 " )
175211 );
176- setChainWithDefaultRpcUrl ("bnb_smart_chain " , Chain ("BNB Smart Chain " , 56 , "https://bsc-dataseed1.binance.org " ));
177- setChainWithDefaultRpcUrl ("bnb_smart_chain_testnet " , Chain ("BNB Smart Chain Testnet " , 97 , "https://data-seed-prebsc-1-s1.binance.org:8545 " ));// forgefmt: disable-line
178- setChainWithDefaultRpcUrl ("gnosis_chain " , Chain ("Gnosis Chain " , 100 , "https://rpc.gnosischain.com " ));
212+ setChainWithDefaultRpcUrl ("gnosis_chain " , ChainData ("Gnosis Chain " , 100 , "https://rpc.gnosischain.com " ));
179213 }
180214
181215 // set chain info, with priority to chainAlias' rpc url in foundry.toml
182- function setChainWithDefaultRpcUrl (string memory chainAlias , Chain memory chain ) private {
216+ function setChainWithDefaultRpcUrl (string memory chainAlias , ChainData memory chain ) private {
183217 string memory rpcUrl = chain.rpcUrl;
184218 defaultRpcUrls[chainAlias] = rpcUrl;
185219 chain.rpcUrl = "" ;
0 commit comments