# Solidity Security

> Master smart contract security best practices to prevent common vulnerabilities and implement secure Solidity patterns. Use when writing smart contracts, auditing existing contracts, or implementing security measures for blockchain applications.

- **Type:** Skill
- **Install:** `agentstack add skill-clawdbotatg-clawdviction-solidity-security`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [clawdbotatg](https://agentstack.voostack.com/s/clawdbotatg)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [clawdbotatg](https://github.com/clawdbotatg)
- **Source:** https://github.com/clawdbotatg/clawdviction/tree/main/.agents/skills/solidity-security
- **Website:** https://clawdviction.vercel.app

## Install

```sh
agentstack add skill-clawdbotatg-clawdviction-solidity-security
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Solidity Security

Master smart contract security best practices, vulnerability prevention, and secure Solidity development patterns.

## When to Use This Skill

- Writing secure smart contracts
- Auditing existing contracts for vulnerabilities
- Implementing secure DeFi protocols
- Preventing reentrancy, overflow, and access control issues
- Optimizing gas usage while maintaining security
- Preparing contracts for professional audits
- Understanding common attack vectors

## Critical Vulnerabilities

### 1. Reentrancy

Attacker calls back into your contract before state is updated.

**Vulnerable Code:**

```solidity
// VULNERABLE TO REENTRANCY
contract VulnerableBank {
    mapping(address => uint256) public balances;

    function withdraw() public {
        uint256 amount = balances[msg.sender];

        // DANGER: External call before state update
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success);

        balances[msg.sender] = 0;  // Too late!
    }
}
```

**Secure Pattern (Checks-Effects-Interactions):**

```solidity
contract SecureBank {
    mapping(address => uint256) public balances;

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

        // EFFECTS: Update state BEFORE external call
        balances[msg.sender] = 0;

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

**Alternative: ReentrancyGuard**

```solidity
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract SecureBank is ReentrancyGuard {
    mapping(address => uint256) public balances;

    function withdraw() public nonReentrant {
        uint256 amount = balances[msg.sender];
        require(amount > 0, "Insufficient balance");

        balances[msg.sender] = 0;

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

### 2. Integer Overflow/Underflow

**Vulnerable Code (Solidity  uint256) public balances;

    function transfer(address to, uint256 amount) public {
        // No overflow check - can wrap around
        balances[msg.sender] -= amount;  // Can underflow!
        balances[to] += amount;          // Can overflow!
    }
}
```

**Secure Pattern (Solidity >= 0.8.0):**

```solidity
// Solidity 0.8+ has built-in overflow/underflow checks
contract SecureToken {
    mapping(address => uint256) public balances;

    function transfer(address to, uint256 amount) public {
        // Automatically reverts on overflow/underflow
        balances[msg.sender] -= amount;
        balances[to] += amount;
    }
}
```

**For Solidity  uint256) public balances;

    function transfer(address to, uint256 amount) public {
        balances[msg.sender] = balances[msg.sender].sub(amount);
        balances[to] = balances[to].add(amount);
    }
}
```

### 3. Access Control

**Vulnerable Code:**

```solidity
// VULNERABLE: Anyone can call critical functions
contract VulnerableContract {
    address public owner;

    function withdraw(uint256 amount) public {
        // No access control!
        payable(msg.sender).transfer(amount);
    }
}
```

**Secure Pattern:**

```solidity
import "@openzeppelin/contracts/access/Ownable.sol";

contract SecureContract is Ownable {
    function withdraw(uint256 amount) public onlyOwner {
        payable(owner()).transfer(amount);
    }
}

// Or implement custom role-based access
contract RoleBasedContract {
    mapping(address => bool) public admins;

    modifier onlyAdmin() {
        require(admins[msg.sender], "Not an admin");
        _;
    }

    function criticalFunction() public onlyAdmin {
        // Protected function
    }
}
```

### 4. Front-Running

**Vulnerable:**

```solidity
// VULNERABLE TO FRONT-RUNNING
contract VulnerableDEX {
    function swap(uint256 amount, uint256 minOutput) public {
        // Attacker sees this in mempool and front-runs
        uint256 output = calculateOutput(amount);
        require(output >= minOutput, "Slippage too high");
        // Perform swap
    }
}
```

**Mitigation:**

```solidity
contract SecureDEX {
    mapping(bytes32 => bool) public usedCommitments;

    // Step 1: Commit to trade
    function commitTrade(bytes32 commitment) public {
        usedCommitments[commitment] = true;
    }

    // Step 2: Reveal trade (next block)
    function revealTrade(
        uint256 amount,
        uint256 minOutput,
        bytes32 secret
    ) public {
        bytes32 commitment = keccak256(abi.encodePacked(
            msg.sender, amount, minOutput, secret
        ));
        require(usedCommitments[commitment], "Invalid commitment");
        // Perform swap
    }
}
```

## Security Best Practices

### Checks-Effects-Interactions Pattern

```solidity
contract SecurePattern {
    mapping(address => uint256) public balances;

    function withdraw(uint256 amount) public {
        // 1. CHECKS: Validate conditions
        require(amount  0, "Amount must be positive");

        // 2. EFFECTS: Update state
        balances[msg.sender] -= amount;

        // 3. INTERACTIONS: External calls last
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
    }
}
```

### Pull Over Push Pattern

```solidity
// Prefer this (pull)
contract SecurePayment {
    mapping(address => uint256) public pendingWithdrawals;

    function recordPayment(address recipient, uint256 amount) internal {
        pendingWithdrawals[recipient] += amount;
    }

    function withdraw() public {
        uint256 amount = pendingWithdrawals[msg.sender];
        require(amount > 0, "Nothing to withdraw");

        pendingWithdrawals[msg.sender] = 0;
        payable(msg.sender).transfer(amount);
    }
}

// Over this (push)
contract RiskyPayment {
    function distributePayments(address[] memory recipients, uint256[] memory amounts) public {
        for (uint i = 0; i  0, "Amount must be positive");
        require(amount  {
      const [deployer] = await ethers.getSigners();

      const VictimBank = await ethers.getContractFactory("SecureBank");
      bank = (await VictimBank.deploy()) as SecureBank;
      await bank.waitForDeployment();

      const Attacker = await ethers.getContractFactory("ReentrancyAttacker");
      attackerContract = (await Attacker.deploy(await bank.getAddress())) as ReentrancyAttacker;
      await attackerContract.waitForDeployment();
    });

    it("Should prevent reentrancy attack", async function () {
      // Deposit funds
      await bank.deposit({ value: ethers.parseEther("10") });

      // Attempt reentrancy attack
      await expect(
        attackerContract.attack({ value: ethers.parseEther("1") }),
      ).to.be.revertedWith("ReentrancyGuard: reentrant call");
    });
  });

  describe("Integer Overflow Protection", function () {
    let token: SecureToken;

    before(async () => {
      const Token = await ethers.getContractFactory("SecureToken");
      token = (await Token.deploy()) as SecureToken;
      await token.waitForDeployment();
    });

    it("Should prevent integer overflow", async function () {
      const [, attacker] = await ethers.getSigners();

      // Attempt overflow
      await expect(token.transfer(attacker.address, ethers.MaxUint256))
        .to.be.reverted;
    });
  });

  describe("Access Control", function () {
    let contract: SecureContract;

    before(async () => {
      const Contract = await ethers.getContractFactory("SecureContract");
      contract = (await Contract.deploy()) as SecureContract;
      await contract.waitForDeployment();
    });

    it("Should enforce access control", async function () {
      const [, attacker] = await ethers.getSigners();

      // Attempt unauthorized withdrawal
      await expect(contract.connect(attacker).withdraw(100)).to.be.revertedWith(
        "Ownable: caller is not the owner",
      );
    });
  });
});
```

## Audit Preparation

```solidity
contract WellDocumentedContract {
    /**
     * @title Well Documented Contract
     * @dev Example of proper documentation for audits
     * @notice This contract handles user deposits and withdrawals
     */

    /// @notice Mapping of user balances
    mapping(address => uint256) public balances;

    /**
     * @dev Deposits ETH into the contract
     * @notice Anyone can deposit funds
     */
    function deposit() public payable {
        require(msg.value > 0, "Must send ETH");
        balances[msg.sender] += msg.value;
    }

    /**
     * @dev Withdraws user's balance
     * @notice Follows CEI pattern to prevent reentrancy
     * @param amount Amount to withdraw in wei
     */
    function withdraw(uint256 amount) public {
        // CHECKS
        require(amount <= balances[msg.sender], "Insufficient balance");

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

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

## Common Pitfalls

1. **Using `tx.origin` for Authentication**: Use `msg.sender` instead
2. **Unchecked External Calls**: Always check return values
3. **Delegatecall to Untrusted Contracts**: Can hijack your contract
4. **Floating Pragma**: Pin to specific Solidity version
5. **Missing Events**: Emit events for state changes
6. **Excessive Gas in Loops**: Can hit block gas limit
7. **No Upgrade Path**: Consider proxy patterns if upgrades needed

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [clawdbotatg](https://github.com/clawdbotatg)
- **Source:** [clawdbotatg/clawdviction](https://github.com/clawdbotatg/clawdviction)
- **License:** MIT
- **Homepage:** https://clawdviction.vercel.app

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-clawdbotatg-clawdviction-solidity-security
- Seller: https://agentstack.voostack.com/s/clawdbotatg
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
