agentleFS
G1JoshiG1Joshi/Agent-Skills/skills/languages/solidity/SKILL.md

solidity

Skill15 starsChanged 42 days agoMITView on GitHub

Expert Solidity smart contract assistance covering EVM, OpenZeppelin, ERC-20/721/1155, and reentrancy guards. Use when developing Ethereum contracts, DeFi protocols, NFT systems, or Web3 dApps.

3 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

6 rules. 0 are common, 1 is distinctive, and 5 are very specific to this project.

  • 0

    Common

    Most of the 3 edited versions we read keep these.

  • 1

    Distinctive

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Update contract state before making external ether transfers:

    line 150
  2. Very specific:

    Use Solidity ^0.8.24 or higher with native arithmetic overflow protection and custom errors (error MyError()) instead of string require …

    line 178
  3. Very specific:

    Always adhere to the Checks-Effects-Interactions (CEI) pattern and apply ReentrancyGuard to all state-changing transfer functions.

    line 179
  4. Very specific:

    Test smart contracts rigorously with Foundry (forge test, fuzzing, and invariant testing) and formal verification tools.

    line 180
  5. Very specific:

    Use OpenZeppelin's SafeERC20 wrapper to prevent silent transfer failures from non-standard ERC-20 tokens.

    line 181
  6. Very specific:

    Use tx.origin for authorization.

    line 185

“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Solidity

Solidity is an object-oriented, high-level language for implementing smart contracts on the Ethereum Virtual Machine (EVM), featuring strict typing and gas-optimized storage patterns.

When to Use

  • Ethereum & EVM Smart Contract Development: Building decentralized protocols on Ethereum, Arbitrum, Optimism, Polygon, and Base.
  • DeFi Financial Protocols: Automated market makers (AMMs), lending pools, yield aggregators, and staking vaults.
  • Token Standards & Digital Assets: Implementing ERC-20 fungible tokens, ERC-721/ERC-1155 non-fungible tokens, and ERC-4337 smart accounts.
  • On-Chain Governance & DAOs: Implementing multisigs, timelocks, and decentralized voting mechanisms.

Quick Start

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract SimpleStorage {
    uint256 private storedData;
    event DataChanged(uint256 newValue);

    function set(uint256 x) public {
        storedData = x;
        emit DataChanged(x);
    }

    function get() public view returns (uint256) {
        return storedData;
    }
}

Core Concepts

Secure ERC-20 Vault with OpenZeppelin & Custom Errors

Gas-optimized token vault with reentrancy protection and custom error revert reasons:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";

error ZeroDepositAmount();
error InsufficientBalance(uint256 available, uint256 requested);

contract TokenVault is ReentrancyGuard, Ownable2Step {
    using SafeERC20 for IERC20;

    IERC20 public immutable token;
    mapping(address => uint256) public userBalances;

    event Deposited(address indexed user, uint256 amount);
    event Withdrawn(address indexed user, uint256 amount);

    constructor(IERC20 _token) Ownable2Step(msg.sender) {
        token = _token;
    }

    function deposit(uint256 amount) external nonReentrant {
        if (amount == 0) revert ZeroDepositAmount();
        userBalances[msg.sender] += amount;
        token.safeTransferFrom(msg.sender, address(this), amount);
        emit Deposited(msg.sender, amount);
    }

    function withdraw(uint256 amount) external nonReentrant {
        uint256 balance = userBalances[msg.sender];
        if (amount > balance) revert InsufficientBalance(balance, amount);
        userBalances[msg.sender] = balance - amount;
        token.safeTransfer(msg.sender, amount);
        emit Withdrawn(msg.sender, amount);
    }
}

Storage, Memory & Calldata Gas Layout

Understanding the EVM data locations to minimize transaction execution costs:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract StorageLayout {
    // Storage variables packed into 32-byte slots
    struct UserProfile {
        uint128 balance; // slot 0 (16 bytes)
        uint64 lastLogin; // slot 0 (8 bytes)
        uint64 flags;     // slot 0 (8 bytes) - total 32 bytes packed
        address owner;    // slot 1 (20 bytes)
    }

    mapping(uint256 => UserProfile) public profiles;

    // Use 'calldata' for read-only external array arguments to avoid memory copying
    function batchCheckFlags(bytes32[] calldata hashes) external view returns (bool) {
        for (uint256 i = 0; i < hashes.length; ++i) {
            if (hashes[i] == bytes32(0)) return false;
        }
        return true;
    }
}

Checks-Effects-Interactions & Upgradeability (UUPS)

Preventing reentrancy vulnerabilities and managing proxy upgrades:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract VaultV1 is Initializable, OwnableUpgradeable, UUPSUpgradeable {
    uint256 public totalYield;

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(address initialOwner) public initializer {
        __Ownable_init(initialOwner);
        __UUPSUpgradeable_init();
    }

    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}

Common Patterns

Checks-Effects-Interactions Pattern (Reentrancy Prevention)

Problem: External calls made before internal state updates allow recursive reentrancy attacks draining contract funds.

Solution: Update contract state before making external ether transfers:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Vault {
    mapping(address => uint256) public balances;

    function withdraw() external {
        // 1. Checks
        uint256 amount = balances[msg.sender];
        require(amount > 0, "Insufficient balance");

        // 2. Effects
        balances[msg.sender] = 0;

        // 3. Interactions
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
    }
}

Best Practices

Do:

  • Use Solidity ^0.8.24 or higher with native arithmetic overflow protection and custom errors (error MyError()) instead of string require messages.
  • Always adhere to the Checks-Effects-Interactions (CEI) pattern and apply ReentrancyGuard to all state-changing transfer functions.
  • Test smart contracts rigorously with Foundry (forge test, fuzzing, and invariant testing) and formal verification tools.
  • Use OpenZeppelin's SafeERC20 wrapper to prevent silent transfer failures from non-standard ERC-20 tokens.

Don't:

  • Use tx.origin for authorization; always use msg.sender to defend against phishing and proxy attacks.
  • Rely on block.timestamp or block.number for random number generation; integrate Chainlink VRF.
  • Deploy unverified or unaudited contracts to production mainnets.

Troubleshooting

ErrorCauseSolution
Transaction reverted: function call failedrequire condition evaluated to false or gas limit exceeded.Check revert reason in block explorer or run test with Hardhat/Foundry traces.
Error: Gas estimation failedTransaction will inevitably revert under current contract state.Verify caller account permissions, allowance, and input parameters.
Compiler version mismatchpragma solidity declaration incompatible with local solc version.Update compiler version in hardhat.config.js or foundry.toml.

References

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.