Scripting
Forge scripts are Solidity files that deploy contracts and execute transactions on-chain. They replace deployment scripts traditionally written in JavaScript.
Script structure
Scripts inherit from Script and implement a run() function:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {Script} from "forge-std/Script.sol";
import {Counter} from "../src/Counter.sol";
contract DeployScript is Script {
function run() public {
vm.startBroadcast();
Counter counter = new Counter();
counter.setNumber(42);
vm.stopBroadcast();
}
}Key elements:
- Inherit from
forge-std/Script.sol - Script files end with
.s.sol - Wrap deployment logic in
vm.startBroadcast()/vm.stopBroadcast()
Running scripts
Simulate a deployment (no transactions sent):
$ forge script script/Deploy.s.solBroadcast transactions to a network:
$ forge script script/Deploy.s.sol --broadcast --rpc-url $RPC_URLProviding a private key
$ forge script script/Deploy.s.sol --broadcast --rpc-url $RPC_URL --account deployerBroadcasting from a specific address
To broadcast from a specific address:
vm.startBroadcast(deployerAddress);Or use the key at a specific index from a mnemonic:
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);Verifying deployed contracts
Verify on Etherscan during deployment:
$ forge script script/Deploy.s.sol \
--broadcast \
--rpc-url $RPC_URL \
--verify \
--etherscan-api-key $ETHERSCAN_API_KEYResuming failed broadcasts
If a broadcast fails partway through, resume from where it left off:
$ forge script script/Deploy.s.sol --broadcast --rpc-url $RPC_URL --resumeMulti-chain deployments
Deploy to multiple chains by running the script with different RPC URLs:
$ forge script script/Deploy.s.sol --broadcast --rpc-url $MAINNET_RPC
$ forge script script/Deploy.s.sol --broadcast --rpc-url $ARBITRUM_RPC
$ forge script script/Deploy.s.sol --broadcast --rpc-url $OPTIMISM_RPCReading deployment artifacts
Scripts write transaction receipts to broadcast/. Access deployed addresses in subsequent scripts:
function run() public {
string memory json = vm.readFile("broadcast/Deploy.s.sol/1/run-latest.json");
address counter = vm.parseJsonAddress(json, ".transactions[0].contractAddress");
}Script cheatcodes
Scripts have access to all cheatcodes. Common ones for scripting:
// Read environment variables
string memory rpcUrl = vm.envString("RPC_URL");
uint256 privateKey = vm.envUint("PRIVATE_KEY");
// Read/write files
string memory config = vm.readFile("config.json");
vm.writeFile("output.txt", "deployed");
// Parse JSON
address addr = vm.parseJsonAddress(json, ".address");
// Console logging
console.log("Deploying to:", block.chainid);Dry run
Test a script without sending transactions:
$ forge script script/Deploy.s.sol --rpc-url $RPC_URLThis simulates against the live chain state and shows what would happen.
Was this helpful?
