/

BUGCAT

Poetry is what happens when language exceeds its own limits.
In code, we call these moments vulnerabilities.
Smart contracts are poems with consequences.

Poems

ReentrancyCat

// SPDX-License-Identifier: WTFPL
pragma solidity ^0.8.30;

import "../interface/BugCat.sol";

contract ReentrancyCat is BugCat {
    mapping(address => uint) public balance;

    function deposit() public payable {
        balance[msg.sender] += msg.value;
    }

    function withdraw() public {
        (bool success, ) = msg.sender.call{value: balance[msg.sender]}("");
        require(success);
        balance[msg.sender] = 0;
    }

    function caress() public {
        if (address(this).balance == 0) {
            emit Meow(msg.sender, "reentrancy");
        }
    }

    function remember() external view returns (bool) {
        address TheDAO = 0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413;
        return TheDAO.code.length > 0;
    }
}

PredictableCat

// SPDX-License-Identifier: WTFPL
pragma solidity ^0.8.30;

import "../interface/BugCat.sol";

contract PredictableCat is BugCat {
    mapping(address => uint8) public winCount;

    function flip() external {
        if ((uint(keccak256(abi.encodePacked(
            block.timestamp,
            block.prevrandao,
            msg.sender
        ))) & 1) == 0) {
            winCount[msg.sender] += 1;
        } else {
            winCount[msg.sender] = 0;
        }
    }

    function caress() public {
        if (winCount[msg.sender] >= 10) {
            emit Meow(msg.sender, "predictable");
            winCount[msg.sender] = 0;
        }
    }

    function remember() external view returns (bool) {
        address FoMo3Dlong = 0xA62142888ABa8370742bE823c1782D17A0389Da1;
        return FoMo3Dlong.code.length > 0;
    }
}

OverflowCat

// SPDX-License-Identifier: WTFPL
pragma solidity ^0.4.26;

import "../interface/BugCat.sol";

contract OverflowCat is BugCat {
    mapping(address => uint) public balance;

    function batchTransfer(address[] memory _receivers, uint256 _value) public {
        uint count = _receivers.length;
        uint amount = count * _value;
        require(_value > 0 && balance[msg.sender] >= amount);
        balance[msg.sender] -= amount;
        for (uint i = 0; i < count; i++) {
            balance[_receivers[i]] += _value;
        }
    }

    function caress() public {
        if (balance[msg.sender] > 0) {
            emit Meow(msg.sender, "overflow");
        }
    }

    function remember() external view returns (bool) {
        address BecToken = 0xC5d105E63711398aF9bbff092d4B6769C82F793D;
        uint256 size; assembly { size := extcodesize(BecToken) }
        return size > 0;
    }
}

UnprotectedCat

// SPDX-License-Identifier: WTFPL
pragma solidity ^0.4.26;

import "../interface/BugCat.sol";

contract UnprotectedCat is BugCat {
    address public owner;
    bool public initialized;

    function init(address o) public {
        owner = o;
        initialized = true;
    }

    function kill() public {
        require(msg.sender == owner);
        suicide(owner);
    }

    function caress() public {
        if (msg.sender == owner) {
            emit Meow(msg.sender, "unprotected");
        }
    }

    function remember() external view returns (bool) {
        address WalletLibrary = 0x863DF6BFa4469f3ead0bE8f9F2AAE51c91A907b4;
        uint256 size; assembly { size := extcodesize(WalletLibrary) }
        return size == 0 && WalletLibrary.balance > 0;
    }
}

MisspelledCat

// SPDX-License-Identifier: WTFPL
pragma solidity ^0.4.26;

import "../interface/BugCat.sol";

contract MisspelledCat is BugCat {
    address public owner;

    function MisspeledCat(address o) {
        owner = o;
    }

    function caress() public {
        if (msg.sender == owner) {
            emit Meow(msg.sender, "misspelled");
        }
    }

    function remember() external view returns (bool) {
        address Rubixi = 0xe82719202e5965Cf5D9B6673B7503a3b92DE20be;
        uint256 size; assembly { size := extcodesize(Rubixi) }
        return size > 0;
    }
}

Interface

Every BUGCAT speaks the same language of memory. To remember is to verify existence across time—it returns true if the ancestor still breathes in bytecode. To caress is to awaken the ghost within; each touch costs gas, each interaction leaves a trace. The purr echoes through the network as an event, logged in permanence, remembered by none.

interface BugCat {
    function remember() external view returns (bool);
    function caress() external;
    event Meow(address indexed who, string vulnerability);
}

Annotations

ReentrancyCat

reentrancy

The DAO, 2016. 3.6 million ETH vanished into recursion. Ethereum split in two—one chain that remembered, one that chose to forget.

Reentrancy occurs when a contract calls an external address before updating its state. The external contract can then call back into the original function, withdrawing funds multiple times before the balance is set to zero. This vulnerability arises from Ethereum's ability to transfer control flow to arbitrary code during external calls.

PredictableCat

weak randomness

FoMo3D. The future written in block hashes. Miners chose winners. Randomness was an illusion.

True randomness cannot exist in a deterministic system where every node must reach consensus. Any on-chain data source—block timestamps, hashes, or transaction parameters—can be predicted or manipulated. Miners have additional power to influence these values, turning games of chance into games of control.

OverflowCat

integer overflow

BEC Token, 2018. A multiplication overflow created billions of tokens from nothing. Markets crashed in minutes. Mathematics betrayed economics.

Integer overflow occurs when arithmetic operations exceed the maximum value of a data type. In uint256, multiplying large numbers can wrap around to zero. The BEC Token's batchTransfer function multiplied the number of recipients by the value per recipient without checking if the result would overflow, allowing attackers to bypass balance checks.

UnprotectedCat

unprotected initializer

Parity, 2017. July: hackers stole $30 million by calling unprotected init functions. November: someone accidentally killed the patched library, freezing $280 million forever. One vulnerability, two catastrophes.

The Parity wallet library had initialization functions that could be called by anyone, multiple times. This allowed attackers to take ownership of wallets. After the fix, the library itself remained vulnerable—someone initialized it, became owner, and killed it, destroying the code that all wallets depended on.

MisspelledCat

constructor typo

Rubixi, 2016. The contract changed its name. The constructor didn't. Solidity reinterpreted it. Ownership became an open door.

Before Solidity 0.4.22, constructors were functions with the contract's exact name. Any typo turned initialization into a regular public function. When Rubixi was renamed from DynamicPyramid but the constructor wasn't updated, ownership became open to anyone who noticed the mistake.

Invocation

The BUGCATS contract is where someone might remember them. An array of addresses, each a story. To remember is to ask each cat if its ancestor lives. To caress is to awaken the ghost within—each touch costs gas, each interaction leaves a trace on the chain.

You can invoke these poems through Etherscan. Call remember(index) to verify if an ancestor still exists. Connect your wallet and call caress(index) to leave your mark—a Meow event, logged forever.

contract BUGCATS is Ownable {
    address[] public bugs;

    function remember(uint256 index) external view returns (bool) {
        return BugCat(bugs[index]).remember();
    }

    function inject(address bug) external onlyOwner {
        bugs.push(bug);
    }
}

Specifications

Title BUGCAT Author Zeroichi Arakawa Year 2025 Blockchain Ethereum Medium On-chain code (Solidity), Event logs, Vulnerability references License WTFPL Contracts