StdConfig
StdConfig
is a powerful contract that provides bidirectional (read/write) configuration management for Solidity tests and scripts. It parses TOML configuration files, automatically resolves environment variables, and provides type-safe access to configuration values.
Import
import {StdConfig} from "forge-std/StdConfig.sol";
import {Variable, LibVariable} from "forge-std/LibVariable.sol";
// Enable global usage of LibVariable
using LibVariable for Variable global;
Direct Usage
While typically used through the Config
abstract contract, you can instantiate StdConfig
directly:
contract MyTest is Test {
using LibVariable for Variable;
StdConfig config;
function setUp() public {
config = new StdConfig("./config.toml", false);
vm.makePersistent(address(config));
}
}
Configuration File Structure
StdConfig expects a specific TOML structure where top-level keys represent chain identifiers, and variables are organized by type in sub-tables:
[<chain>]
endpoint_url = "https://..." # Required RPC URL
[<chain>.<type>]
variable_name = value
Where:
<chain>
is either a chain ID (uint) or a valid chain alias<type>
must be one of:bool
,address
,uint
,int
,bytes32
,string
,bytes
Getter Functions
get
Retrieves a variable as a generic Variable
container that must be cast to the appropriate type.
function get(uint256 chainId, string memory key) public view returns (Variable memory)
function get(string memory key) public view returns (Variable memory)
// With explicit chain ID
uint256 value = config.get(1, "important_number").toUint256();
// Using current fork's chain ID
vm.selectFork(forkOf[1]);
address weth = config.get("weth").toAddress();
getRpcUrl
Returns the RPC URL for a specific chain.
function getRpcUrl(uint256 chainId) public view returns (string memory)
function getRpcUrl() public view returns (string memory)
getChainIds
Returns all configured chain IDs.
function getChainIds() public view returns (uint256[] memory)
Setter Functions
All setter methods update the in-memory state and optionally write changes back to the TOML file.
set
Sets a value for a given key. Overloaded for all supported types and their arrays.
// Single values
function set(uint256 chainId, string memory key, bool value) public
function set(uint256 chainId, string memory key, address value) public
function set(uint256 chainId, string memory key, uint256 value) public
function set(uint256 chainId, string memory key, int256 value) public
function set(uint256 chainId, string memory key, bytes32 value) public
function set(uint256 chainId, string memory key, string memory value) public
function set(uint256 chainId, string memory key, bytes memory value) public
// Arrays
function set(uint256 chainId, string memory key, bool[] memory values) public
function set(uint256 chainId, string memory key, address[] memory values) public
// ... and so on for all types
There are also variants without chainId
that use the current fork's chain ID.
writeUpdatesBackToFile
Enables or disables automatic writing to the TOML file.
function writeUpdatesBackToFile(bool enabled) public
Type Conversion with LibVariable
The LibVariable
library provides safe type conversion for Variable
structs:
Single Value Conversions
variable.toBool() // Returns bool
variable.toAddress() // Returns address
variable.toUint256() // Returns uint256
variable.toUint128() // Returns uint128 (with overflow check)
variable.toUint64() // Returns uint64 (with overflow check)
variable.toUint32() // Returns uint32 (with overflow check)
variable.toUint16() // Returns uint16 (with overflow check)
variable.toUint8() // Returns uint8 (with overflow check)
variable.toInt256() // Returns int256
variable.toInt128() // Returns int128 (with overflow check)
// ... similar for other int sizes
variable.toBytes32() // Returns bytes32
variable.toString() // Returns string
variable.toBytes() // Returns bytes
Array Conversions
variable.toBoolArray() // Returns bool[]
variable.toAddressArray() // Returns address[]
variable.toUint256Array() // Returns uint256[]
variable.toUint128Array() // Returns uint128[] (with overflow checks)
// ... and so on for all types
Environment Variable Resolution
StdConfig automatically resolves environment variables in the TOML file:
[mainnet]
endpoint_url = "${MAINNET_RPC_URL}"
[mainnet.address]
admin = "${ADMIN_ADDRESS}"
Complete Example
contract ConfigExample is Test {
using LibVariable for Variable;
StdConfig config;
function setUp() public {
// Set environment variables
vm.setEnv("MAINNET_RPC", "https://eth.llamarpc.com");
vm.setEnv("ADMIN_ADDRESS", "0x1234567890123456789012345678901234567890");
// Load config with write capability
config = new StdConfig("./config.toml", true);
vm.makePersistent(address(config));
}
function test_readAndWrite() public {
// Read various types
bool isLive = config.get(1, "is_live").toBool();
address weth = config.get(1, "weth").toAddress();
uint256 number = config.get(1, "important_number").toUint256();
// Read arrays
address[] memory admins = config.get(1, "admins").toAddressArray();
uint256[] memory values = config.get(1, "values").toUint256Array();
// Update configuration
config.set(1, "new_contract", address(0xdead));
config.set(1, "deployment_block", block.number);
config.set(1, "is_deployed", true);
// Changes are written to config.toml automatically
}
function test_multiChain() public {
// Get all configured chains
uint256[] memory chains = config.getChainIds();
for (uint256 i = 0; i < chains.length; i++) {
uint256 chainId = chains[i];
string memory rpcUrl = config.getRpcUrl(chainId);
// Create fork for this chain
uint256 forkId = vm.createFork(rpcUrl);
vm.selectFork(forkId);
// Now config.get() without chainId uses this fork's chain
address chainWeth = config.get("weth").toAddress();
}
}
}
Error Handling
StdConfig and LibVariable provide comprehensive error messages:
NotInitialized()
: Variable doesn't exist in configurationTypeMismatch(expected, actual)
: Variable type doesn't match expected typeUnsafeCast(message)
: Value doesn't fit in target type (overflow/underflow)InvalidChainKey(aliasOrId)
: Invalid chain identifierChainNotInitialized(chainId)
: Chain not found in configuration
See Also
- Config - Abstract contract for easier usage
- Scripting with Config - Guide for orchestrating scripts