Detects public functions that could be external and explicit getters that duplicate auto-generated Solidity getters. external functions skip the internal entry point and enable calldata for array/struct parameters, saving ~24+ gas per call for simple types and thousands for arrays. Covers VI-001 (public → external when no internal calls) and VI-002 (remove duplicate manual getters). Use when writing or reviewing function declarations in Foundry-based Solidity projects.
npx claudepluginhub zaryab2000/decipher-gas-optimizoor --plugin decipher-gas-optimizoorThis skill is limited to using the following tools:
Identify functions declared `public` that are never called internally and remove
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
Guides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Identify functions declared public that are never called internally and remove
manual getter functions that duplicate Solidity's auto-generated getters. Both
changes reduce unnecessary bytecode and enable downstream optimizations.
public functions generate two ABI dispatch entry points: one for external calls
(reads from calldata) and one for internal calls (parameters on stack/memory).
external eliminates the internal entry point, enabling calldata for reference
parameters.
public functionsexternal — already optimalpublic functions_fn()) or this.fn() — must stay publicTrigger on any .sol file containing public function declarations or manual
view getter functions. No tooling prerequisites beyond Read.
# Find public functions
grep -n "public" src/**/*.sol | grep -v "^.*\/\/"
# Find manual getter candidates (view returns single value)
grep -n "view returns" src/**/*.sol
| Situation | Action |
|---|---|
| Function called only externally? | Change to external (VI-001) |
| Function takes array/struct params AND is external? | Also use calldata (VI-001 + CD-001) |
Manual getter for a public state variable? | Remove it (VI-002) |
Function called internally (same contract, no this.)? | Must stay public or internal |
Function called via this.fn() from inside the contract? | Must stay public |
Required by interface (e.g., ERC-20 balanceOf)? | Keep with appropriate visibility |
Step 1 — Find all public functions
public visibilityStep 2 — Search for internal call sites
public function named fnName: scan the full contract source for
bare fnName( calls (without this. prefix) inside other function bodiesview functions whose entire body is
return stateVar or return mapping[param] where stateVar/mapping is already
public (VI-002 candidate)Step 3 — Apply changes
public to external. For array, struct, bytes, or string
parameters, also change memory to calldata (combines VI-001 + CD-001)forge test --gas-report to confirm savings; forge test for regressionsReport each finding using this structure:
**[SEVERITY] Description**
**File:** path/to/Contract.sol, line N
**Technique:** VI-00X
**Estimated saving:** ~X gas per call
[before code block]
[after code block]
**Verification:** rg "fnName\(" --type sol / forge test --gas-report
[MEDIUM] batchTransfer is public but never called internally — change to external (VI-001)
File: src/NFTMarket.sol, line 24
Technique: VI-001 + CD-001
Estimated saving: ~984 gas per call (array copy + dispatcher overhead)
Before:
function batchTransfer(uint256[] memory ids, address to) public {
for (uint256 i = 0; i < ids.length; ++i) {
tokenOwner[ids[i]] = to;
}
}
After:
function batchTransfer(uint256[] calldata ids, address to) external {
uint256 len = ids.length;
for (uint256 i = 0; i < len; ++i) {
tokenOwner[ids[i]] = to;
}
}
Verification: rg "batchTransfer\(" --type sol (confirm no internal callers) then forge test --gas-report
Only read these files when explicitly needed — do not load all three by default:
| File | Read only when… |
|---|---|
resources/PATTERNS.md | You need VI-001 gas savings for large array parameters (>10 elements) or the VI-002 inheritance edge case |
resources/CHECKLIST.md | Producing a formal /decipher-gas-optimizoor:analyze report and confirming all public functions were audited |
resources/EXAMPLE_FINDING.md | Generating a report and needing the exact output format for a multi-function NFT contract finding |
docs/evm-gas-reference.md | You need calldata byte costs to quantify savings for array/struct parameters |