Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
1982a2f
feat: config helper contract
0xrusowsky Aug 22, 2025
03c82f0
feat: auto-load config
0xrusowsky Aug 23, 2025
bbd5f8d
add unit tests
0xrusowsky Aug 24, 2025
7e67e9c
test all types
0xrusowsky Aug 24, 2025
df41ccf
test: write config
0xrusowsky Aug 25, 2025
cd346a6
update Vm docs
0xrusowsky Aug 25, 2025
8128951
rename to `vm.activeChain()` to `vm.getChainId()`
0xrusowsky Aug 25, 2025
a1fe691
improve docs
0xrusowsky Aug 25, 2025
405d958
more docs
0xrusowsky Aug 25, 2025
158f4db
fix doc typo
0xrusowsky Aug 25, 2025
bad0161
update fn names to `get` and `set` for consistency
0xrusowsky Aug 25, 2025
a3c4e60
use backwards compatible solidity
0xrusowsky Aug 25, 2025
2be7d97
fix: pragma
0xrusowsky Aug 25, 2025
3dbe7d3
fix: use backwards compatible solidity
0xrusowsky Aug 25, 2025
f30626e
don't use `string.concat`
0xrusowsky Aug 25, 2025
53a4cc5
add abidecoder v2
0xrusowsky Aug 25, 2025
279f9e7
use pragma experimental ABIEncoderV2
0xrusowsky Aug 25, 2025
dc4315b
Merge branch 'master' into rusowsky/config-helper
0xrusowsky Aug 25, 2025
fae314f
fix: constructor visibility
0xrusowsky Aug 25, 2025
a97051f
Merge branch 'rusowsky/config-helper' of github.com:foundry-rs/forge-…
0xrusowsky Aug 25, 2025
b98e7a4
use initializer rather than constructor
0xrusowsky Aug 25, 2025
4ad83e2
style: fmt
0xrusowsky Aug 25, 2025
251258e
smarter storage layout
0xrusowsky Aug 25, 2025
20047e2
don't use `string.concat`
0xrusowsky Aug 25, 2025
07cdba7
run `vm.py`
0xrusowsky Aug 25, 2025
6a53426
use constructor and disable warning
0xrusowsky Aug 25, 2025
c6aecac
better security and UX with `LibVariable` (#716)
0xrusowsky Aug 26, 2025
c4122e2
backwards-compatibility: drop custom errors + global 'using for' (#717)
0xrusowsky Aug 26, 2025
61431b0
missing experimental abi
0xrusowsky Aug 26, 2025
2a386d9
style: fmt + typos
0xrusowsky Aug 26, 2025
d3b49b4
more style
0xrusowsky Aug 26, 2025
3c91387
ci: exclude `test/Config.t.sol` for stable
0xrusowsky Aug 26, 2025
8a264ef
update Vm.t.sol with new hash
0xrusowsky Aug 26, 2025
a5d3fc0
Revert "backwards-compatibility: drop custom errors + global 'using f…
0xrusowsky Aug 26, 2025
21f844d
CI: skip config-related contracts in old versions
0xrusowsky Aug 26, 2025
3c23f73
ci: always skip test
0xrusowsky Aug 26, 2025
1465e12
fix: ci
0xrusowsky Aug 26, 2025
8fa3ec5
fix: typo
0xrusowsky Aug 26, 2025
e178cd0
set `writeToFile` on constructor
0xrusowsky Aug 26, 2025
319ae20
downcast support for all uint types
0xrusowsky Aug 27, 2025
3cf9c66
fix: mistakenly erased fn sig
0xrusowsky Aug 27, 2025
b6128a0
add integer support
0xrusowsky Aug 27, 2025
8bd86d7
more tests
0xrusowsky Aug 27, 2025
a686262
style: fmt
0xrusowsky Aug 27, 2025
e764436
tests for fn `writeUpdatesBackToFile()`
0xrusowsky Aug 27, 2025
8afa879
fix: rmv .env file
0xrusowsky Aug 27, 2025
0f97a2f
fix: use `string.concat()` again
0xrusowsky Sep 3, 2025
a59383a
style: fmt
0xrusowsky Sep 3, 2025
93c3d25
fix: more `string.concat()`
0xrusowsky Sep 3, 2025
b4ce8ee
chore: run `vm.py`
0xrusowsky Sep 3, 2025
c49c8ab
update solc ignored error codes
0xrusowsky Sep 3, 2025
75ac3e3
fix: forbid writting to file unless scripting
0xrusowsky Sep 3, 2025
c086c2e
improve docs
0xrusowsky Sep 3, 2025
9802415
Update StdConfig.sol
0xrusowsky Sep 3, 2025
2788a6c
more docs
0xrusowsky Sep 3, 2025
16d1087
Update src/StdConfig.sol
zerosnacks Sep 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,15 @@ jobs:
- uses: actions/checkout@v4
- uses: foundry-rs/foundry-toolchain@v1
- run: forge --version
- run: forge build --skip test --deny-warnings ${{ matrix.flags }}
- run: |
case "${{ matrix.flags }}" in
*"solc:0.8.0"* | *"solc:0.7"* | *"solc:0.6"*)
forge build --skip test --skip Config --skip StdConfig --skip LibVariable --deny-warnings ${{ matrix.flags }}
;;
*)
forge build --skip test --deny-warnings ${{ matrix.flags }}
;;
esac
# via-ir compilation time checks.
- if: contains(matrix.flags, '--via-ir')
run: forge build --skip test --deny-warnings ${{ matrix.flags }} --contracts 'test/compilation/*'
Expand All @@ -48,7 +56,12 @@ jobs:
with:
version: ${{ matrix.toolchain }}
- run: forge --version
- run: forge test -vvv
- run: |
if [ "${{ matrix.toolchain }}" = "stable" ]; then
forge test -vvv --no-match-path "test/Config.t.sol"
else
forge test -vvv
fi

fmt:
runs-on: ubuntu-latest
Expand Down
12 changes: 8 additions & 4 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
[profile.default]
fs_permissions = [{ access = "read-write", path = "./"}]
fs_permissions = [{ access = "read-write", path = "./" }]
optimizer = true
optimizer_runs = 200

# A list of solidity error codes to ignore.
# 3860 = init-code-size
ignored_error_codes = [3860]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for other reviewers - this already happens in master but not showing up as no ignored_error_codes specified


[rpc_endpoints]
# The RPC URLs are modified versions of the default for testing initialization.
mainnet = "https://eth.merkle.io" # Different API key.
optimism_sepolia = "https://sepolia.optimism.io/" # Adds a trailing slash.
mainnet = "https://eth.merkle.io" # Different API key.
optimism_sepolia = "https://sepolia.optimism.io/" # Adds a trailing slash.
arbitrum_one_sepolia = "https://sepolia-rollup.arbitrum.io/rpc/" # Adds a trailing slash.
needs_undefined_env_var = "${UNDEFINED_RPC_URL_PLACEHOLDER}"

Expand All @@ -20,4 +24,4 @@ multiline_func_header = 'attributes_first'
quote_style = 'double'
number_underscore = 'preserve'
single_line_statement_blocks = 'preserve'
ignore = ["src/console.sol", "src/console2.sol"]
ignore = ["src/console.sol", "src/console2.sol"]
6 changes: 6 additions & 0 deletions src/Base.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,28 @@ abstract contract CommonBase {
/// @dev Cheat code address.
/// Calculated as `address(uint160(uint256(keccak256("hevm cheat code"))))`.
address internal constant VM_ADDRESS = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D;

/// @dev console.sol and console2.sol work by executing a staticcall to this address.
/// Calculated as `address(uint160(uint88(bytes11("console.log"))))`.
address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67;

/// @dev Used when deploying with create2.
/// Taken from https://github.com/Arachnid/deterministic-deployment-proxy.
address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C;

/// @dev The default address for tx.origin and msg.sender.
/// Calculated as `address(uint160(uint256(keccak256("foundry default caller"))))`.
address internal constant DEFAULT_SENDER = 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38;

/// @dev The address of the first contract `CREATE`d by a running test contract.
/// When running tests, each test contract is `CREATE`d by `DEFAULT_SENDER` with nonce 1.
/// Calculated as `VM.computeCreateAddress(VM.computeCreateAddress(DEFAULT_SENDER, 1), 1)`.
address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f;

/// @dev Deterministic deployment address of the Multicall3 contract.
/// Taken from https://www.multicall3.com.
address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11;

/// @dev The order of the secp256k1 curve.
uint256 internal constant SECP256K1_ORDER =
115792089237316195423570985008687907852837564279074904382605163141518161494337;
Expand Down
60 changes: 60 additions & 0 deletions src/Config.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {console} from "./console.sol";
import {StdConfig} from "./StdConfig.sol";
import {CommonBase} from "./Base.sol";

/// @notice Boilerplate to streamline the setup of multi-chain environments.
abstract contract Config is CommonBase {
// -- STORAGE (CONFIG + CHAINS + FORKS) ------------------------------------

/// @dev Contract instance holding the data from the TOML config file.
StdConfig internal config;

/// @dev Array of chain IDs for which forks have been created.
uint256[] internal chainIds;

/// @dev A mapping from a chain ID to its initialized fork ID.
mapping(uint256 => uint256) internal forkOf;

// -- HELPER FUNCTIONS -----------------------------------------------------

/// @notice Loads configuration from a file.
///
/// @dev This function instantiates a `Config` contract, caching all its config variables.
///
/// @param filePath: the path to the TOML configuration file.
/// @param writeToFile: whether updates are written back to the TOML file.
function _loadConfig(string memory filePath, bool writeToFile) internal {
console.log("----------");
console.log(string.concat("Loading config from '", filePath, "'"));
config = new StdConfig(filePath, writeToFile);
vm.makePersistent(address(config));
console.log("Config successfully loaded");
console.log("----------");
}

/// @notice Loads configuration from a file and creates forks for each specified chain.
///
/// @dev This function instantiates a `Config` contract, caching all its config variables,
/// reads the configured chain ids, and iterates through them to create a fork for each one.
/// It also creates a map `forkOf[chainId] -> forkId` to easily switch between forks.
///
/// @param filePath: the path to the TOML configuration file.
/// @param writeToFile: whether updates are written back to the TOML file.
function _loadConfigAndForks(string memory filePath, bool writeToFile) internal {
_loadConfig(filePath, writeToFile);

console.log("Setting up forks for the configured chains...");
uint256[] memory chains = config.getChainIds();
for (uint256 i = 0; i < chains.length; i++) {
uint256 chainId = chains[i];
uint256 forkId = vm.createFork(config.getRpcUrl(chainId));
forkOf[chainId] = forkId;
chainIds.push(chainId);
}
console.log("Forks successfully created");
console.log("----------");
}
}
Loading