Robinhood MainnetChain ID: 4663
Contract detail

EtchMarket

EtchMarket is a verified Robinhood Chain smart contract at 0x5a752b6f…3d4039ec with 0 indexed transactions.

Address type
Smart contract
Transactions
0
History coverage
No indexed activity found
Verification
Verified
Compiler
v0.8.26+commit.8a97fa7a
Verification match
partial
Creation transaction
0x29dab4ce…f51f2e62
Created at block
#28577501
Language
solidity
EVM version
cancun
License
mit
Compiler optimization
Enabled · 44444444 runs
Verified contract

Contract source code

// SPDX-License-Identifier: MIT
//
//  ██████╗  ██████╗ ██████╗ ██╗███╗   ██╗███████╗████████╗ ██████╗██╗  ██╗
//  ██╔══██╗██╔═══██╗██╔══██╗██║████╗  ██║██╔════╝╚══██╔══╝██╔════╝██║  ██║
//  ██████╔╝██║   ██║██████╔╝██║██╔██╗ ██║█████╗     ██║   ██║     ███████║
//  ██╔══██╗██║   ██║██╔══██╗██║██║╚██╗██║██╔══╝     ██║   ██║     ██╔══██║
//  ██║  ██║╚██████╔╝██████╔╝██║██║ ╚████║███████╗   ██║   ╚██████╗██║  ██║
//  ╚═╝  ╚═╝ ╚═════╝ ╚═════╝ ╚═╝╚═╝  ╚═══╝╚══════╝   ╚═╝    ╚═════╝╚═╝  ╚═╝
//
//  RobinEtch — the first inscriptions + token protocol using Uniswap V4 hooks
//  on Robinhood Chain.
//
//  Web: https://robinetch.app
//  X:   https://x.com/robinetchapp
//
pragma solidity 0.8.26;

import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

/// @title EtchMarket
/// @notice Minimal escrow marketplace for RobinEtch Inscriptions, priced in native ETH.
///         2% marketplace fee, matching the protocol's 2/2 swap tax.
contract EtchMarket is ReentrancyGuard {
    uint256 public constant FEE_BPS = 200;
    uint256 public constant BPS_DENOMINATOR = 10_000;

    IERC721 public immutable inscriptions;
    address public immutable treasury;

    struct Listing {
        address seller;
        uint96 price;
    }

    mapping(uint256 => Listing) public listings;
    uint256[] private _listedIds;
    mapping(uint256 => uint256) private _idxPlusOne;

    event Listed(uint256 indexed id, address indexed seller, uint256 price);
    event Cancelled(uint256 indexed id, address indexed seller);
    event Purchased(uint256 indexed id, address indexed buyer, address indexed seller, uint256 price);

    error NotListed();
    error NotSeller();
    error BadPrice();
    error WrongPayment();

    constructor(IERC721 inscriptions_, address treasury_) {
        inscriptions = inscriptions_;
        treasury = treasury_;
    }

    /// @notice Escrow-list an inscription for a fixed ETH price (requires prior approval).
    function list(uint256 id, uint96 price) external nonReentrant {
        if (price == 0) revert BadPrice();
        inscriptions.transferFrom(msg.sender, address(this), id);
        listings[id] = Listing(msg.sender, price);
        _idxPlusOne[id] = _listedIds.length + 1;
        _listedIds.push(id);
        emit Listed(id, msg.sender, price);
    }

    function cancel(uint256 id) external nonReentrant {
        Listing memory l = listings[id];
        if (l.seller == address(0)) revert NotListed();
        if (l.seller != msg.sender) revert NotSeller();
        _remove(id);
        inscriptions.transferFrom(address(this), msg.sender, id);
        emit Cancelled(id, msg.sender);
    }

    function buy(uint256 id) external payable nonReentrant {
        Listing memory l = listings[id];
        if (l.seller == address(0)) revert NotListed();
        if (msg.value != l.price) revert WrongPayment();
        _remove(id);

        uint256 fee = (uint256(l.price) * FEE_BPS) / BPS_DENOMINATOR;
        (bool okSeller,) = l.seller.call{value: msg.value - fee}("");
        require(okSeller, "seller payment failed");
        if (fee > 0) {
            (bool okFee,) = treasury.call{value: fee}("");
            require(okFee, "fee payment failed");
        }
        inscriptions.transferFrom(address(this), msg.sender, id);
        emit Purchased(id, msg.sender, l.seller, l.price);
    }

    function _remove(uint256 id) private {
        uint256 idx = _idxPlusOne[id] - 1;
        uint256 last = _listedIds.length - 1;
        if (idx != last) {
            uint256 moved = _listedIds[last];
            _listedIds[idx] = moved;
            _idxPlusOne[moved] = idx + 1;
        }
        _listedIds.pop();
        delete _idxPlusOne[id];
        delete listings[id];
    }

    /// @notice All active listings (small-scale friendly, one call for the frontend).
    function listed() external view returns (uint256[] memory ids, address[] memory sellers, uint256[] memory prices) {
        uint256 n = _listedIds.length;
        ids = new uint256[](n);
        sellers = new address[](n);
        prices = new uint256[](n);
        for (uint256 i = 0; i < n; i++) {
            uint256 id = _listedIds[i];
            ids[i] = id;
            sellers[i] = listings[id].seller;
            prices[i] = listings[id].price;
        }
    }

    function listedCount() external view returns (uint256) {
        return _listedIds.length;
    }
}