CoinThreads

0x815f77e52ad8ecec40629abead29a37b29fa3f9a

Verification
Verified
0.8.24+commit.e11b9ed9
Type
Contract
2,532 bytes
ABI entries
10
4 read · 1 write
License
none

Contract information

Address
0x815f77e52ad8ecec40629abead29a37b29fa3f9a
Chain
Robinhood Chain (4663)
Compiler
0.8.24+commit.e11b9ed9
Optimization
Enabled
Creation tx
0x1e77b9bdda…5f26470569

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (4)

MAX_LENGTH()uint256
count(address)uint256
factory()address
getComments(address, uint256, uint256)tuple[]

Events (1)

CommentPosted

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "factory_",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "CommentTooLong",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "EmptyComment",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "UnknownToken",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "author",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "index",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "text",
        "type": "string"
      }
    ],
    "name": "CommentPosted",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "MAX_LENGTH",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "count",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "factory",
    "outputs": [
      {
        "internalType": "contract IPumpFactoryCurves",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "start",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "limit",
        "type": "uint256"
      }
    ],
    "name": "getComments",
    "outputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "author",
            "type": "address"
          },
          {
            "internalType": "uint64",
            "name": "timestamp",
            "type": "uint64"
          },
          {
            "internalType": "string",
            "name": "text",
            "type": "string"
          }
        ],
        "internalType": "struct CoinThreads.Comment[]",
        "name": "page",
        "type": "tuple[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "string",
        "name": "text",
        "type": "string"
      }
    ],
    "name": "post",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Source code

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

/// @dev Minimal view of PumpFactory used to check a token actually exists,
///      so threads can't be spammed onto arbitrary addresses. Field order must
///      match PumpFactory.Curve exactly (it's the auto-generated getter).
interface IPumpFactoryCurves {
    function curves(address token)
        external
        view
        returns (
            bool exists,
            bool graduated,
            bool migrated,
            address creator,
            uint256 ethReserve,
            uint256 tokensSold
        );
}

/// @title CoinThreads
/// @notice On-chain comment threads for launchpad coins, pump.fun style.
///         Deliberately simple: append-only per-token comment arrays with a
///         paginated reader. No backend, no moderation layer; the frontend can
///         filter client-side if needed.
contract CoinThreads {
    struct Comment {
        address author;
        uint64 timestamp;
        string text;
    }

    /// @notice The launchpad whose tokens can be commented on.
    IPumpFactoryCurves public immutable factory;

    /// @notice Max comment length in bytes (~one tweet).
    uint256 public constant MAX_LENGTH = 280;

    mapping(address => Comment[]) private _threads;

    event CommentPosted(
        address indexed token,
        address indexed author,
        uint256 index,
        string text
    );

    error UnknownToken();
    error EmptyComment();
    error CommentTooLong();

    constructor(address factory_) {
        factory = IPumpFactoryCurves(factory_);
    }

    /// @notice Post a comment on `token`'s thread.
    function post(address token, string calldata text) external {
        (bool exists, , , , , ) = factory.curves(token);
        if (!exists) revert UnknownToken();
        uint256 len = bytes(text).length;
        if (len == 0) revert EmptyComment();
        if (len > MAX_LENGTH) revert CommentTooLong();

        _threads[token].push(
            Comment({author: msg.sender, timestamp: uint64(block.timestamp), text: text})
        );
        emit CommentPosted(token, msg.sender, _threads[token].length - 1, text);
    }

    /// @notice Number of comments on `token`'s thread.
    function count(address token) external view returns (uint256) {
        return _threads[token].length;
    }

    /// @notice Paginated read: comments [start, start+limit) in post order.
    function getComments(address token, uint256 start, uint256 limit)
        external
        view
        returns (Comment[] memory page)
    {
        Comment[] storage all = _threads[token];
        uint256 len = all.length;
        if (start >= len) return new Comment[](0);
        uint256 end = start + limit;
        if (end > len) end = len;
        page = new Comment[](end - start);
        for (uint256 i = start; i < end; i++) {
            page[i - start] = all[i];
        }
    }
}
Chain explorer6651msChain node87ms