Claude
Skills
Sign in
Back

rr-solidity

Included with Lifetime
$97 forever

---

General

What this skill does

---
name: rr-solidity
description: Comprehensive Solidity smart contract development skill using Foundry framework. Use for writing, testing, deploying, and auditing Solidity contracts with security-first practices. Also triggers when working with .sol files, Foundry project files (foundry.toml), test files (.t.sol), or smart contract deployment scripts. Example triggers: "Write smart contract", "Create Solidity test", "Deploy contract", "Audit smart contract", "Fix security vulnerability", "Write Foundry test", "Set up Foundry project"
---

# Solidity Development with Foundry

## Overview

Comprehensive skill for professional Solidity smart contract development using the Foundry framework. Provides security-first development practices, testing patterns, static analysis integration (Slither, solhint), and deployment workflows for EVM-compatible blockchains.

## When to Use This Skill

Automatically activate when:
- Working with `.sol` (Solidity) files
- User mentions smart contracts, blockchain, Web3, DeFi, or Ethereum
- Foundry project detected (`foundry.toml` present)
- User requests contract deployment, testing, or security auditing
- Working with forge, cast, or anvil commands
- Implementing ERC standards (ERC20, ERC721, ERC1155, etc.)


## Development Workflow

### 1. Write Secure Contracts

Follow security-first patterns from `references/solidity-security.md`:

**Always implement:**
- Checks-Effects-Interactions (CEI) pattern
- Access control (Ownable, AccessControl)
- Input validation
- Emergency pause mechanisms
- Pull over push for payments
- Custom errors for gas efficiency

**Example contract structure:**

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";

contract MyContract is Ownable, Pausable {
    /*//////////////////////////////////////////////////////////////
                                 ERRORS
    //////////////////////////////////////////////////////////////*/

    error InvalidInput();
    error InsufficientBalance();

    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event ActionCompleted(address indexed user, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            STATE VARIABLES
    //////////////////////////////////////////////////////////////*/

    mapping(address => uint256) public balances;

    /*//////////////////////////////////////////////////////////////
                              CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor() Ownable(msg.sender) {}

    /*//////////////////////////////////////////////////////////////
                           EXTERNAL FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    function deposit() external payable whenNotPaused {
        if (msg.value == 0) revert InvalidInput();
        balances[msg.sender] += msg.value;
        emit ActionCompleted(msg.sender, msg.value);
    }

    function withdraw(uint256 amount) external whenNotPaused {
        // CEI Pattern: Checks
        if (amount == 0) revert InvalidInput();
        if (balances[msg.sender] < amount) revert InsufficientBalance();

        // Effects
        balances[msg.sender] -= amount;

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

        emit ActionCompleted(msg.sender, amount);
    }
}
```

### 2. Write Comprehensive Tests

Follow testing patterns from `references/foundry-testing.md`:

**Test structure:**

```solidity
import {Test, console} from "forge-std/Test.sol";
import {MyContract} from "../src/MyContract.sol";

contract MyContractTest is Test {
    MyContract public myContract;

    address constant OWNER = address(1);
    address constant USER = address(2);

    function setUp() public {
        vm.prank(OWNER);
        myContract = new MyContract();
    }

    // Unit tests
    function test_Deposit() public { }

    // Edge cases
    function test_RevertWhen_ZeroDeposit() public { }

    // Fuzz tests
    function testFuzz_Deposit(uint256 amount) public { }

    // Invariant tests
    function invariant_TotalBalanceMatchesContract() public { }
}
```

**Run tests:**

```bash
forge test              # Run all tests
forge test -vvv         # Verbose output
forge test --gas-report # Include gas costs
forge coverage          # Coverage report
```

### 3. Security Analysis

**Run comprehensive security checks:**

```bash
# Static analysis with Slither
slither . --exclude-optimization --exclude-informational

# Linting with solhint
solhint 'src/**/*.sol' 'test/**/*.sol'

# Or use the automated script
bash scripts/check_security.sh
```

**Pre-deployment checklist** (from `references/solidity-security.md`):
- [ ] Reentrancy protection implemented
- [ ] Access controls on privileged functions
- [ ] Input validation on all external functions
- [ ] Emergency pause mechanism
- [ ] External calls follow CEI pattern
- [ ] Events emitted for state changes
- [ ] Gas optimizations applied
- [ ] Test coverage >90%
- [ ] Slither analysis passed
- [ ] solhint checks passed
- [ ] Professional audit for mainnet

### 4. Build and Deploy

**Build contracts:**

```bash
forge build --optimize --optimizer-runs 200
```

**Deploy using script:**

```solidity
// script/Deploy.s.sol
import {Script} from "forge-std/Script.sol";
import {MyContract} from "../src/MyContract.sol";

contract DeployScript is Script {
    function run() external {
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        vm.startBroadcast(deployerPrivateKey);

        MyContract myContract = new MyContract();
        console.log("Deployed at:", address(myContract));

        vm.stopBroadcast();
    }
}
```

**Execute deployment:**

```bash
# Load environment variables
source .env

# Simulate deployment
forge script script/Deploy.s.sol --rpc-url $SEPOLIA_RPC_URL

# Deploy to testnet
forge script script/Deploy.s.sol \
    --rpc-url $SEPOLIA_RPC_URL \
    --broadcast \
    --verify

# Deploy to mainnet (after audits!)
forge script script/Deploy.s.sol \
    --rpc-url $MAINNET_RPC_URL \
    --broadcast \
    --verify
```

## Advanced Testing Patterns

### Mainnet Forking

Test against real deployed contracts:

```solidity
contract ForkTest is Test {
    IERC20 constant USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);

    function setUp() public {
        vm.createSelectFork("mainnet", 18_000_000);
    }

    function test_InteractWithRealProtocol() public {
        // Test with actual mainnet state
    }
}
```

```bash
forge test --fork-url $MAINNET_RPC_URL
```

### Invariant Testing

Test properties that must always hold:

```solidity
function invariant_SumOfBalancesEqualsTotalSupply() public {
    assertEq(token.totalSupply(), handler.sumOfBalances());
}
```

### Fuzz Testing

Test with randomized inputs:

```solidity
function testFuzz_Transfer(address to, uint256 amount) public {
    vm.assume(to != address(0));
    amount = bound(amount, 1, 1000 ether);
    // Test with random inputs
}
```

## Gas Optimization

Key strategies from `references/solidity-security.md`:

1. **Storage packing** - Group uint8/uint16/etc in single slots
2. **uint256 for counters** - Native EVM word size
3. **calldata over memory** - For function parameters
4. **Events over storage** - Log data instead of storing
5. **Custom errors** - More gas-efficient than strings
6. **Immutable/constant** - For unchanging values

## Contract Verification

```bash
# Verify on Etherscan
forge verify-contract $CONTRACT_ADDRESS \
    src/MyContract.sol:MyContract \
    --chain-id 1 \
    --etherscan-api-key $ETHERSCAN_KEY

# With constructor args
forge verify-contrac

Related in General