Install
$ agentstack add skill-dirtybits-agent-skills-ethereum-development ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Ethereum Development
Purpose
Use this skill to build, review, debug, test, deploy, and operate Ethereum and EVM systems. It covers the full path from protocol design to Solidity implementation, frontend/client integration, transaction mechanics, gas optimization, security hardening, deployment verification, and post-deploy monitoring.
The operating standard is: no contract or integration is production-ready merely because it compiles or a happy-path test passes. Production readiness requires invariants, adversarial tests, deployment rehearsal, verification, monitoring, and explicit risk acceptance.
When To Use
Use this skill when the task involves:
- Solidity smart contract design, implementation, refactoring, or review
- Foundry or Hardhat project setup, tests, scripts, fork testing, fuzzing, invariant testing, gas snapshots, or deployments
- dApp integration with viem, ethers, wagmi, RainbowKit, ConnectKit, WalletConnect, or EIP-1193 providers
- Ethereum RPC, traces, storage slots, logs, receipts, fee estimation, nonce management, mempool behavior, or transaction debugging
- Token standards: ERC-20, ERC-721, ERC-1155, ERC-4626, ERC-2612, ERC-2981, ERC-4337/account abstraction
- Protocol features: staking, vesting, vaults, swaps, auctions, governance, payments, allowlists, claims, cross-chain messaging, oracle-dependent flows
- Indexers, bots, keepers, relayers, Defender automation, subgraphs, Ponder, or backend services consuming contract events
- Security review, gas optimization, upgrade safety, deployment runbooks, mainnet readiness, and incident response
Do not use this skill as a substitute for protocol design. If incentives, custody, governance, or tokenomics are still unclear, pair it with web3-protocol-design first.
Core Principles
- Start with state, actors, and invariants. Define who can do what, which assets move, and what must always hold before editing contracts.
- Prefer boring audited dependencies. Use OpenZeppelin and proven libraries when they fit; avoid custom crypto, proxy, token, permit, and math code without a reason.
- Minimize authority and blast radius. Every privileged function needs a scoped role, bounds, event emission, production owner, delay or multisig path, and monitoring.
- Treat all external calls as adversarial. ETH receivers, token contracts, oracle adapters, AMMs, bridges, hooks, callbacks, and proxies can revert, reenter, grief, or behave non-standardly.
- Keep value math in base units. Never use floating point for token amounts. Be explicit about decimals and rounding direction.
- Test behavior and invariants, not implementation trivia. Cover normal flows, edge cases, reverts, authorization, events, accounting, fuzz properties, invariants, and fork integrations.
- Assume public mempools are hostile. Consider MEV, frontrunning, backrunning, sandwiching, nonce replacement, replay, reorgs, stale state, and gas griefing.
- Never broadcast from guesses. Confirm chain ID, RPC, signer, nonce, gas, constructor args, initializer data, salts, proxy admin, verification inputs, and expected addresses before deploying.
Discovery Workflow
Before making changes:
- Check git status and read project instructions.
- Identify the stack:
- Foundry:
foundry.toml,src/,test/,script/,forge,cast,anvil - Hardhat:
hardhat.config.*,contracts/,test/,scripts/, TypeChain - Frontend:
package.json, wagmi, viem, ethers, RainbowKit, ConnectKit - Indexer/backend:
subgraph.yaml,ponder.config.*, event consumers, relayers, keeper scripts
- Inspect compiler settings: Solidity version, optimizer runs, EVM version, viaIR, remappings, libraries, and dependency versions.
- Locate address books, deployment artifacts, ABIs, generated clients, verification data, and prior audit notes.
- Determine the target network and environment: local, fork, testnet, staging, mainnet, or multi-chain.
- Identify all externally owned accounts, multisigs, timelocks, keepers, relayers, oracle feeds, bridges, and protocol dependencies.
Design And Implementation Workflow
- Write or infer a one-sentence goal and explicit non-goals.
- List actors, assets, contract state, off-chain services, and external dependencies.
- Define lifecycle flows: initialize, deposit, withdraw, transfer, claim, settle, upgrade, pause, recover, shutdown.
- Write invariants first. Examples:
- total shares never exceed claimable assets beyond intentional debt
- only authorized roles can change parameters
- a signature/nonce can be used at most once
- user funds cannot be trapped by another user's revert
- supply caps and per-user limits are always enforced
- Implement the smallest change consistent with existing project conventions.
- Add or update tests before declaring success.
- Run formatters, compile, targeted tests, and broader tests appropriate to risk.
- For public network actions, prepare a runbook and get explicit approval before broadcasting.
Solidity Guidance
State And Storage
- Pack storage deliberately when it does not obscure correctness.
- Avoid unbounded iteration over user-controlled arrays in state-changing functions.
- Be explicit about upgradeable storage layout. Append storage only unless namespaced storage is intentionally used.
- Use
constantandimmutablewhere safe, but do not trade away upgrade requirements. - Know storage slot mechanics for mappings and dynamic arrays when debugging:
- mapping value slot:
keccak256(abi.encode(key, mappingSlot)) - dynamic array data starts at
keccak256(arraySlot)
Function Design
- Validate inputs early; order cheap checks before expensive reads/calls.
- Use custom errors in new Solidity code unless project conventions differ.
- Emit events for externally meaningful state changes; index fields used by indexers.
- Follow checks-effects-interactions and consider pull-payment patterns.
- Treat ERC-20/721/1155 calls as external calls with arbitrary behavior.
- Do not rely on
transfer/sendgas assumptions for ETH. - Avoid hidden dependencies on
block.timestamporblock.numberprecision.
Tokens
Handle non-standard token behavior:
- no return value, false return value, revert-on-zero, revert-on-nonzero-to-nonzero allowance
- fee-on-transfer, rebasing, blacklists, pausable transfers, ERC-777 hooks
- unusual decimals, changing decimals, proxy tokens, permit variants
- ERC-4626 share/asset rounding and inflation attacks
Signatures
- Prefer EIP-712 typed data for structured signatures.
- Domain-separate by name, version, chain ID, and verifying contract.
- Include nonce, deadline, signer, target contract, value/amount, and chain-specific context.
- Consume nonces exactly once and test replay failure.
- Consider EIP-1271 smart contract signatures when supporting smart wallets.
Upgradeable Contracts
- Use OpenZeppelin upgradeable patterns when possible.
- Never initialize upgradeable state in constructors.
- Disable initializers on implementation contracts where appropriate.
- Test initializer and reinitializer paths cannot be called twice.
- Verify proxy admin, implementation, upgrade authority, storage layout, and initializer calldata.
- Run storage layout tooling before upgrades.
EVM And Transaction Mechanics
EVM Basics To Remember
- Stack machine with 256-bit words and max stack depth of 1024.
- Memory is transient, byte-addressed, and has expansion costs.
- Storage is persistent 32-byte slots and usually dominates gas costs.
CALL,DELEGATECALL,STATICCALL,CREATE,CREATE2, logs, and SSTORE have security and gas implications.delegatecallexecutes callee code in caller storage context. Treat it as highly privileged.
Transaction Types
- Type 0 legacy:
gasPrice - Type 1 access list: EIP-2930
- Type 2 EIP-1559:
maxFeePerGas,maxPriorityFeePerGas - Blob transactions on applicable networks: EIP-4844 semantics for blob gas
Operational checks:
- Confirm nonce with pending state when replacing or submitting multiple txs.
- Set
maxFeePerGashigh enough to survive base fee movement; tip should reflect urgency. - For replacement, increase fee enough for the client/network replacement rule.
- Inspect receipts for
status, logs, gas used, effective gas price, and contract address.
Common Transaction Errors
nonce too low: local nonce behind or tx already mined/replaced. Check pending nonce.replacement transaction underpriced: replacement fee bump too small.intrinsic gas too low: calldata/access list/value transfer base cost issue.execution reverted: simulate/trace and decode custom error.out of gas: estimate plus trace; distinguish actual gas shortage from infinite/reverting path.insufficient funds: include value + gas limit * max fee, not only transfer amount.
Tooling Recipes
Foundry
forge fmt
forge build
forge build --sizes
forge test
forge test -vvv --match-test
forge test --match-contract
forge test --gas-report
forge coverage
forge snapshot
forge inspect storage-layout
anvil --chain-id 31337
cast call "fn()" --rpc-url "$RPC_URL"
cast send "fn(uint256)" 1 --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY"
cast storage --rpc-url "$RPC_URL"
cast run --trace --rpc-url "$RPC_URL"
cast sig "fn(address,uint256)"
cast code --rpc-url "$RPC_URL"
Fork testing:
forge test --fork-url "$MAINNET_RPC_URL" --fork-block-number -vvv
Deployment rehearsal:
forge script script/Deploy.s.sol:Deploy --rpc-url "$RPC_URL" --sender --dry-run -vvvv
forge script script/Deploy.s.sol:Deploy --rpc-url "$RPC_URL" --broadcast --verify -vvvv
Hardhat
npm test
npx hardhat compile
npx hardhat test
npx hardhat test test/.ts
npx hardhat node
npx hardhat run scripts/deploy.ts --network
npx hardhat verify --network
Follow the repo's package manager and lockfile: npm, pnpm, yarn, or bun.
viem Client Examples
Read storage slot for mapping(address => uint256) balances at slot 0:
import { createPublicClient, encodeAbiParameters, http, keccak256 } from "viem";
import { mainnet } from "viem/chains";
const client = createPublicClient({ chain: mainnet, transport: http() });
export async function getRawBalanceSlot(contract: `0x${string}`, user: `0x${string}`) {
// Solidity mapping slots use keccak256(abi.encode(key, slot)) with 32-byte ABI padding.
const slot = keccak256(
encodeAbiParameters([{ type: "address" }, { type: "uint256" }], [user, 0n]),
);
return client.getStorageAt({ address: contract, slot });
}
Send an EIP-1559 transaction:
import { createWalletClient, http, parseEther, parseGwei } from "viem";
const wallet = createWalletClient({ transport: http() });
const hash = await wallet.sendTransaction({
account,
to: recipient,
value: parseEther("0.1"),
maxFeePerGas: parseGwei("30"),
maxPriorityFeePerGas: parseGwei("2"),
});
Gas Optimization Checklist
Optimize only after correctness is established and measured.
| Technique | Typical Benefit | Caution | |---|---:|---| | Storage packing | high | Can reduce readability; verify layout for upgrades | | Cache storage reads | medium/high | Do not cache stale values across external calls | | Use calldata for read-only external params | low/medium | Not for values that must be mutated | | Custom errors | low/medium | Keep errors descriptive enough for debugging | | Unchecked increments | low | Only where overflow is impossible by construction | | Short-circuit cheap checks first | variable | Preserve intended revert precedence if tested | | Avoid repeated hashing/encoding | variable | Do not precompute with wrong domain/context | | Batch operations | variable | Beware block gas limit and DoS loops |
Gas test template:
function test_GasBudget() public {
uint256 beforeGas = gasleft();
target.optimizedFunction();
uint256 used = beforeGas - gasleft();
assertLt(used, 50_000, "gas budget exceeded");
}
Testing Strategy
Minimum expected verification for contract changes:
- Build/compile passes.
- Unit tests for every touched public/external behavior.
- Revert tests for invalid inputs, unauthorized callers, and unsafe states.
- Event tests for indexer-facing behavior.
- Edge cases: zero amounts, max amounts, duplicate calls, expired deadlines, changed price, depleted balances, dust, paused state.
- Fuzz tests for arithmetic and user-controlled inputs.
- Invariant tests for value/accounting/authorization state machines.
- Fork tests for live integrations pinned to a block number.
- Gas snapshot/report if gas matters.
Foundry invariant example:
function invariant_TotalAssetsCoverShares() public view {
assertGe(asset.balanceOf(address(vault)), vault.totalAssetsRequired());
}
Hardhat examples:
await expect(contract.connect(attacker).adminOnlyAction()).to.be.reverted;
await expect(contract.doThing(amount))
.to.emit(contract, "ThingDone")
.withArgs(user.address, amount);
Security Review Checklist
Authorization
- Can unauthorized users reach privileged behavior through direct calls, callbacks, delegatecalls, multicalls, proxies, or initialization paths?
- Are roles initialized correctly and transferred to production owners?
- Can admins rug, freeze, alter claims, sweep assets, or bypass delays? If yes, is it intended, bounded, documented, and monitored?
Accounting
- Are deposits, withdrawals, shares, rewards, fees, debt, and dust conserved?
- Is rounding direction intentional and tested?
- Do fee-on-transfer, rebasing, and non-standard decimals break accounting?
- Are ERC-4626 inflation/donation attacks considered where relevant?
External Calls And Reentrancy
- Can reentrancy occur through token hooks, receiver callbacks, fallback ETH receivers, protocol callbacks, or multicall?
- Are external return values checked?
- Can a malicious token or external protocol block everyone by reverting?
Oracles And Prices
- Reject stale, zero, negative, paused, incomplete, or incorrectly-decimaled prices.
- Confirm heartbeat, deviation threshold, base/quote direction, sequencer uptime feeds on L2s, and fallback behavior.
- Consider manipulation cost for TWAPs and low-liquidity pools.
MEV And Ordering
- Are slippage limits, deadlines, nonces, and recipient checks present?
- Can auctions, liquidations, claims, or swaps be sandwiched, frontrun, griefed, or backrun?
- Is commit-reveal or private orderflow needed?
Upgrades
- Storage layout compatible?
- Initializers protected?
- Implementation cannot be initialized or abused?
- Upgrade authority held by expected timelock/multisig?
- Rollback or pause plan exists?
Denial Of Service
- Are loops bounded?
- Can one user's revert block batch processing?
- Can queues, withdrawals, disputes, claims, or settlements handle partial failure?
Frontend And Client Integration
- Keep address maps chain-specific and explicit; never silently fall back to mainnet/testnet.
- Use typed ABIs or generated clients when available.
- Keep internal token math in
bigint/BigNumber base units; format only at UI boundaries. - Handle wallet disconnect, wrong chain, unsupported chain, pending tx, replaced tx, revert, RPC outage, and indexer lag.
- Simulate or estimate before sending where possible, but treat simulation as advisory, not finality.
- Surface tx hash, explorer link, pending/confirmed/failed state, and retry guidance.
- For reads, consider block tags and stale cache behavior.
Indexing, Bots, And Backends
- Treat events as an API: stable names, indexed fields, enough data for consumers.
- Handle reorgs by waiting confirmations and supporting rollback/replay.
- Store cursor/checkpoint state transactionally.
- Make relayers and keepers idempotent. A duplicate execution attempt should not corrupt state.
- Rate-limit RPC calls and use backoff for 429/5xx resp
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: dirtybits
- Source: dirtybits/agent-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.