Solidity deploy
Skill 0xlayerghost/solidity-agent-kit/skills/solidity-deploy
Agent skills for Solidity & DeFi development with Foundry. Security, testing, deployment — all in one kit.
npx -y skills add 0xlayerghost/solidity-agent-kit --skill solidity-deployAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
[AUTO-INVOKE] MUST be invoked BEFORE deploying contracts or writing deployment scripts (*.s.sol). Covers pre-flight checks, forge script commands, post-deployment validation, and verification. Trigger: any task involving forge script, contract deployment, or block explorer verification.
SKILL.md
7.3 KB, as published. Nobody here has run it
Deployment Workflow
Language Rule
- Always respond in the same language the user is using. If the user asks in Chinese, respond in Chinese. If in English, respond in English.
Pre-deployment Checklist (all must pass)
| Step | Command / Action |
|---|---|
| Format code | forge fmt |
| Run all tests | forge test — zero failures required |
| Check gas report | forge test --gas-report — review critical functions |
| Verify config | Manually check config/*.json parameters |
| Dry-run | forge script <Script> --fork-url <RPC_URL> -vvvv (no --broadcast) |
| Check balance | cast balance <DEPLOYER> --rpc-url <RPC_URL> — sufficient gas? |
| Gas limit set | Deployment command must include --gas-limit |
Deployment Decision Rules
| Situation | Rule |
|---|---|
| Default deployment | No --verify — contracts are not verified on block explorers by default |
| User requests verification | Add --verify and --etherscan-api-key to the command |
| Post-deploy verification | Use forge verify-contract as a separate step |
| Multi-chain deploy | Separate scripts per chain, never batch multiple chains in one script |
| Proxy deployment | Deploy implementation first, then proxy — verify both separately |
| Upgradeable contract | Use OpenZeppelin Upgrades Plugin (see below) — never hand-roll proxy deployment |
Post-deployment Operations (all required)
- Update addresses in
config/*.jsonanddeployments/latest.env - Test critical functions:
cast callto verify on-chain state is correct - Record changes in
docs/CHANGELOG.md - Submit PR with deployment transaction hash link
- If verification needed, run
forge verify-contractseparately
Key Security Rule
- Never pass private keys directly in commands. Use Foundry Keystore (
cast wallet import) to manage keys securely. - Never include
--broadcastin templates. The user must explicitly add it when ready to deploy.
Command Templates
# Dry-run (simulation only, no on-chain execution)
forge script script/Deploy.s.sol:DeployScript \
--rpc-url <RPC_URL> \
--gas-limit 5000000 \
-vvvv
# When user is ready to deploy, instruct them to add:
# --account <KEYSTORE_NAME> --broadcast
# Verify existing contract separately
forge verify-contract <ADDRESS> <CONTRACT> \
--chain-id <CHAIN_ID> \
--etherscan-api-key <API_KEY> \
--constructor-args $(cast abi-encode "constructor(address)" <ARG>)
# Quick on-chain read test after deployment
cast call <CONTRACT_ADDRESS> "functionName()" --rpc-url <RPC_URL>
Upgradeable Contract Deployment (OpenZeppelin Upgrades Plugin)
For any upgradeable contract (UUPS, Transparent, Beacon), use the OpenZeppelin Foundry Upgrades Plugin instead of hand-rolling proxy deployment scripts.
Why Use the Plugin
| Manual Approach | With Plugin |
|---|---|
| ~30 lines: deploy impl → deploy proxy → encode initializer → wire up | 1 line: Upgrades.deployUUPSProxy(...) |
| ~20 lines: deploy new impl → validate storage → upgrade proxy | 1 line: Upgrades.upgradeProxy(...) |
| Storage layout compatibility: check by eye | Auto-checked, incompatible layouts are rejected |
Forgot _disableInitializers()? No warning | Auto-validated |
Installation
forge install OpenZeppelin/openzeppelin-foundry-upgrades
forge install OpenZeppelin/openzeppelin-contracts-upgradeable
Add to remappings.txt:
@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
Deploy Script Template (UUPS)
// script/Deploy.s.sol
import {Script, console} from "forge-std/Script.sol";
import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";
import {MyContract} from "../src/MyContract.sol";
contract DeployScript is Script {
function run() public {
vm.startBroadcast();
// One line: deploys impl + proxy + calls initialize
address proxy = Upgrades.deployUUPSProxy(
"MyContract.sol",
abi.encodeCall(MyContract.initialize, (msg.sender))
);
console.log("Proxy:", proxy);
console.log("Impl:", Upgrades.getImplementationAddress(proxy));
vm.stopBroadcast();
}
}
Upgrade Script Template
// script/Upgrade.s.sol
import {Script, console} from "forge-std/Script.sol";
import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";
contract UpgradeScript is Script {
function run() public {
address proxy = vm.envAddress("PROXY_ADDRESS");
vm.startBroadcast();
// One line: validates storage layout + deploys new impl + upgrades proxy
Upgrades.upgradeProxy(proxy, "MyContractV2.sol", "");
console.log("Upgraded. New impl:", Upgrades.getImplementationAddress(proxy));
vm.stopBroadcast();
}
}
Add @custom:oz-upgrades-from MyContract annotation to V2 contract for automatic reference:
/// @custom:oz-upgrades-from MyContract
contract MyContractV2 is Initializable, OwnableUpgradeable, UUPSUpgradeable {
// ...
}
Commands
# Deploy proxy (dry-run) — --ffi is required for storage layout checks
forge script script/Deploy.s.sol --rpc-url <RPC_URL> --ffi -vvvv
# Deploy proxy (broadcast)
forge script script/Deploy.s.sol --rpc-url <RPC_URL> --ffi --account <KEYSTORE_NAME> --broadcast
# Upgrade proxy (dry-run)
PROXY_ADDRESS=0x... forge script script/Upgrade.s.sol --rpc-url <RPC_URL> --ffi -vvvv
# Upgrade proxy (broadcast)
PROXY_ADDRESS=0x... forge script script/Upgrade.s.sol --rpc-url <RPC_URL> --ffi --account <KEYSTORE_NAME> --broadcast
# Validate upgrade without deploying (useful for CI)
# Use Upgrades.validateUpgrade("MyContractV2.sol", opts) in a test
Plugin API Quick Reference
| Function | Purpose |
|---|---|
Upgrades.deployUUPSProxy(contract, data) | Deploy UUPS proxy + impl + initialize |
Upgrades.deployTransparentProxy(contract, admin, data) | Deploy Transparent proxy + impl + initialize |
Upgrades.upgradeProxy(proxy, newContract, data) | Validate + deploy new impl + upgrade |
Upgrades.validateUpgrade(contract, opts) | Validate only, no deploy (for CI/tests) |
Upgrades.getImplementationAddress(proxy) | Get current implementation address |
Upgrades.prepareUpgrade(contract, opts) | Validate + deploy new impl, return address (for multisig) |
Key Rules
- Always use
--ffiflag — the plugin needs it for storage layout validation - Always add
--sender <ADDRESS>for upgrades — must match proxy owner, otherwiseOwnableUnauthorizedAccount - Use
Upgradesin scripts,UnsafeUpgradesonly in tests —UnsafeUpgradesskips all safety checks - Keep V1 source code in project when upgrading — plugin needs it for storage comparison. Or use
@custom:oz-upgrades-fromannotation - Never hand-roll proxy deployment when this plugin is available — the storage layout check alone prevents critical bugs