Deployment
Detects deployment cost inefficiencies in Solidity: factory patterns that deploy full contracts when ERC-1167 minimal proxies would suffice, non-payable admin functions with unnecessary ETH check overhead, dead code paths inflating bytecode, and opportunities for vanity addresses via CREATE2 for high-frequency contracts. Covers DP-001 (minimal proxy factories), DP-002 (payable admin functions), DP-003 (dead code removal), DP-004 (vanity addresses). Use when writing constructors, factory contracts, or reviewing bytecode size.From its SKILL.md
npx -y skills add zaryab2000/decipher-gas-optimizoor --skill deploymentAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 7 stars7 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.
SKILL.md
8.3 KB, as published. Nobody here has run it
Purpose
Identify deployment cost inefficiencies: factory patterns deploying full contracts instead of minimal proxies, dead code inflating bytecode, and configuration-level savings (payable admin functions, vanity addresses for ultra-high-frequency protocols). Deployment cost is 200 gas/byte of bytecode and is paid once per instance — reducing it compounds at factory scale.
When to Use
- Writing or reviewing factory contracts
- Reviewing constructors and
new ContractName()patterns - Pre-deployment review of bytecode size
- Reviewing contracts with known dead or conditional code paths
- Reviewing admin functions in high-frequency DeFi protocols
When NOT to Use
- Contracts that are already using proxies (ERC-1967, UUPS, Beacon)
- Singleton contracts deployed once with no factory pattern
- When dead code was intentionally preserved for a future activation
Rationalizations to Reject
| Rationalization | Why It's Wrong | Required Action |
|---|---|---|
| "It's only one deployment" | Factory contracts deploy potentially thousands of instances; 491,000 gas × 1,000 users = 491M gas wasted | Estimate scale before dismissing |
| "The optimizer removes dead code" | The optimizer eliminates some dead paths but not all — unused internal functions and if(false) branches often survive | Always measure with forge build --sizes before and after |
| "payable is risky" | The risk is locked ETH if no withdrawal exists — document the precondition, don't skip the optimization | Apply with the ETH-recovery check, not instead of it |
| "We can refactor after launch" | Deployment cost is paid at deploy time; you cannot retroactively reduce it for already-deployed instances | Fix the factory pattern before any significant user adoption |
Platform Detection
Trigger fires when:
- A factory function uses
new ContractName()to deploy multiple instances Bashis available to runforge build --sizesfor bytecode measurement
Quick Reference
- Factory deploying
new ContractName()for each user? → ERC-1167 minimal proxy (DP-001, ~491,000 gas saved per clone) - Admin function called thousands of times? →
payableremoves ~24 gas/call ETH check (DP-002) - Dead
if(CONSTANT_FALSE)branch or unusedinternal/privatefunction? → remove it (DP-003, 200 gas/byte) - CREATE2 factory for ultra-high-frequency protocol (millions of calls/day)? → consider vanity address (DP-004, ~12 gas/call/leading-zero-byte)
Workflow
-
Find factory patterns — does it use
new ContractName()? Search the contract fornewkeywords. For eachnewdeployment, ask: (a) Are multiple instances of this contract expected? (b) Do all instances share the same logic (same bytecode)? (c) Do instances only differ in their initial storage state (set via constructor arguments)? If yes to all three, the factory is an ERC-1167 minimal proxy candidate (DP-001). Estimate savings: (full_bytecode_size × 200 gas − 41,000 gas) per instance. The implementation must be refactored to useinitialize()instead of a constructor. -
Find dead code — constant-false branches, unreachable code, unused private/internal functions. Look for
if (CONSTANT)where the constant is provably false;internalorprivatefunctions with no call sites in the contract; functions explicitly marked deprecated with no callers. Removing dead code saves 200 gas per byte at deployment — measure withforge build --sizesbefore and after. Also flag any code path that the optimizer does not eliminate (some patterns require explicit removal). -
Find non-payable admin functions — would
payablesave meaningful gas? For functions with explicit access control (onlyOwner, onlyAdmin) called frequently, consider whether the ~24 gas/call saving from removing themsg.value == 0check justifies the risk. This is a micro-optimization — apply only after storage, loop, calldata, and struct optimizations are done. Note: addingpayableto a function in a contract with no ETH withdrawal mechanism risks permanently locking any accidentally sent ETH.
Output Format
Report each finding with: pattern ID, contract/function, file and line reference, gas estimate, and the exact change required.
Example finding (DP-001):
DP-001 | VaultFactory.sol:12 | VaultFactory.createVault()
Severity : critical
Gas saved : ~491,000 gas per vault deployment
(full Vault ~532,000 gas vs ERC-1167 clone ~41,000 gas)
Before:
function createVault() external returns (address) {
Vault vault = new Vault(msg.sender); // 500,000+ gas per user
vaults.push(address(vault));
return address(vault);
}
After:
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
address public immutable IMPLEMENTATION;
constructor() {
IMPLEMENTATION = address(new VaultImpl()); // deployed once
}
function createVault() external returns (address) {
address clone = Clones.clone(IMPLEMENTATION); // ~41,000 gas
VaultImpl(clone).initialize(msg.sender);
vaults.push(clone);
return clone;
}
Migration: Refactor Vault constructor to initialize() with _initialized
guard. Add _disableInitializers() in VaultImpl constructor (OpenZeppelin
pattern) to prevent initializing the implementation contract itself.
Verify:
forge test --match-test testCreateVault --gas-report
forge test -vvvv # DELEGATECALL visible in clone function calls
Example finding (DP-003):
DP-003 | TokenSale.sol:14 | dead _applyPresaleDiscount() branch
Severity : low
Gas saved : 200 gas/byte × bytecode removed (measure with forge build --sizes)
Issue:
bool public constant IS_PRESALE = false;
function buy(uint256 amount) external payable {
if (IS_PRESALE) {
_applyPresaleDiscount(amount); // dead — IS_PRESALE is false
}
_processPurchase(amount);
}
function _applyPresaleDiscount(uint256 amount) internal pure returns (uint256) {
return amount * 80 / 100; // unreachable internal function
}
Fix: Remove the if (IS_PRESALE) block and _applyPresaleDiscount entirely.
The optimizer may eliminate some dead code — measure before and after.
Verify:
forge build --sizes # bytecode size before vs after
Supporting Docs
Only read these files when explicitly needed — do not load all three by default:
| File | Read only when… |
|---|---|
resources/PATTERNS.md | You need DP-004 (vanity address via CREATE2) details or full ERC-1167 clone implementation not shown above |
resources/CHECKLIST.md | Producing a formal /decipher-gas-optimizoor:analyze report and confirming all deployment patterns were checked |
resources/EXAMPLE_FINDING.md | Generating a report and needing the exact output format for a factory optimization finding |
docs/evm-gas-reference.md | You need authoritative opcode costs (SSTORE, CREATE, DELEGATECALL) to back a gas estimate |
Example finding (DP-002):
DP-002 | AdminControl.sol:22 | setConfig() non-payable admin function
Severity : low
Gas saved : ~24 gas per call
Context : admin function called ~1,000 times/year — marginal impact
Before:
function setConfig(uint256 value) external {
require(msg.sender == ADMIN);
// ...
}
After:
function setConfig(uint256 value) external payable {
require(msg.sender == ADMIN);
// ...
}
Warning: Only safe if the contract has a mechanism to recover accidentally
sent ETH, or if the admin is trusted not to send ETH accidentally. Apply
only after all higher-priority optimizations are addressed.
Verify:
forge snapshot --diff # ~24 gas reduction per call