forge-deploy
A cli and associated contracts to keep track of deployments by name and reuse them in solidity.
It tries to keep compatibility with hardhat-deploy as far as possible (work in progress).
Features
- generate type-safe deployment function for forge contracts. no need to pass in string of text and hope the abi encoded args are in the correct order.
- save deployments in json file (based on hardhat-deploy schema)
How to use
-
have a forge project and cd into it
mkdir my-project; cd my-project; forge init; -
add the forge package
forge install wighawag/forge-deploy@v0.0.9; -
install the cli tool locally as the tool is likely to evolve rapidly
cargo install --version 0.0.9 --root . forge-deploy;This will install version 0.0.9 in the bin folder,
You can then execute it via
./bin/forge-deploy <command>you can also compile it directly from the
lib/forge-deploy/folder. -
add to .gitignore the generated file + the binary we just installed
cat >> .gitignore <<EOF # forge-deploy /generated /deployments/localhost /deployments/31337 # forge-deploy cli binary /.crates2.json /.crates.toml /bin EOF -
generate the type-safe deployment functions
./bin/forge-deploy gen-deployer; -
add a deploy script
add the file
script/Deploy.s.solwith this content:// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import "forge-deploy/DeployScript.sol"; import "generated/deployer/DeployerFunctions.g.sol"; contract Deployments is DeployScript { using DeployerFunctions for Deployer; function deploy(bytes calldata) external returns (Counter) { return deployer.deploy_Counter("MyCounter"); } } -
you also need to allow forge to read and write on certain paths by editing foundry.toml:
echo '\nfs_permissions = [{ access = "read", path = "./deployments"}, { access = "read", path = "./out"}, { access = "read", path = "./contexts.json"}]' >> foundry.toml;You might wonder what
context.json. This is a configuration file. Its name might change in the future, but as of now, it let you configure context (like localhost, sepolia, mainnet) and specify a list of tag that you can then use in your deploy script to trigger diferent execution path. -
You can now execute the script via forge script
Note that you need to execute
./bin/forge-deploy syncdirectly afterwardFor example:
forge script script/Counter.s.sol --rpc-url $RPC_URL --broadcast --private-key $DEPLOYER_PRIVATE_KEY -v && ./bin/forge-deploy sync;with anvil and default account
forge script script/Counter.s.sol --rpc-url http://localhost:8545 --broadcast --private-key ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 -v && ./bin/forge-deploy sync; -
If you use just, see example in examples/basic with its own justfile
Quick Start
Get anvil started somewhere:
anvil;
then copy and execute this and see the result
mkdir my-forge-deploy-project;
cd my-forge-deploy-project;
forge init;
forge install wighawag/forge-deploy@v0.0.9;
cargo install --version 0.0.9 --root . forge-deploy;
echo '\nfs_permissions = [{ access = "read", path = "./deployments"}, { access = "read", path = "./out"}, { access = "read", path = "./contexts.json"}]' >> foundry.toml;
cat >> .gitignore <<EOF
# forge-deploy
/generated
/deployments/localhost
/deployments/31337
# forge-deploy cli binary
/.crates2.json
/.crates.toml
/bin
EOF
./bin/forge-deploy gen-deployer;
cat > script/Deploy.s.sol <<EOF
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-deploy/DeployScript.sol";
import "generated/deployer/DeployerFunctions.g.sol";
contract Deployments is DeployScript {
using DeployerFunctions for Deployer;
function deploy(bytes calldata) external returns (Counter) {
return deployer.deploy_Counter("MyCounter");
}
}
EOF
forge script script/Deploy.s.sol --rpc-url http://localhost:8545 --broadcast --private-key ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 -v && ./bin/forge-deploy sync;
More info
Note that the generated solidity is optional.
You can instead simply use the default deploy function
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-deploy/DeployScript.sol";
import "forge-deploy/DefaultDeployerFunction.sol";
contract CounterScript is DeployScript {
using DefaultDeployerFunction for Deployer;
function deploy() override internal {
.deploy("MyCounter2", "Counter.sol:Counter", "", DeployOptions({
deterministic: 0,
proxyOnTag: "",
proxyOwner: address(0)
}));
}
}