RPunksToken

0xb572419d06baff046f2a090687c3c3c5e758926e

Verification
Verified
v0.8.28+commit.7893614a
Type
Contract
3,463 bytes
ABI entries
37
11 read · 10 write
License
mit

Contract information

Address
0xb572419d06baff046f2a090687c3c3c5e758926e
Chain
Robinhood Chain (4663)
Compiler
v0.8.28+commit.7893614a
Optimization
Enabled
Creation tx
0x31b5076d83…fd689f2237

Token

Name
rPunks
Symbol
PUNKS
Decimals
18
Holders
99

Read contract (11)

MAX_SUPPLY()uint256
allowance(address, address)uint256
balanceOf(address)uint256
decimals()uint8
hook()address
mirror()address
mirrorExempt(address)bool
name()string
owner()address
symbol()string
totalSupply()uint256

Events (3)

ApprovalOwnershipTransferredTransfer

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "allowance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientAllowance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "balance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "approver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidApprover",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidReceiver",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSender",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSpender",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "HookAlreadySet",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "MirrorAlreadySet",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotHook",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotMirror",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "OwnableInvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "OwnableUnauthorizedAccount",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "MAX_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "hook",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "mirror",
    "outputs": [
      {
        "internalType": "contract IRPunksMirror",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "mirrorExempt",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "mirrorTransfer",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "setHook",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "m",
        "type": "address"
      }
    ],
    "name": "setMirror",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "exempt",
        "type": "bool"
      }
    ],
    "name": "setMirrorExempt",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "certBase",
        "type": "uint256"
      }
    ],
    "name": "stageCert",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
//
//    ▄▄▄▄▄▄▄▄
//   █▀▀▀▀▀▀▀▀█
//   █ ██  ██ █     r P U N K S
//   █   ▄▄   █     every punk is born from a trade
//   █  ▀▀▀▀  █
//   ▀▀▀▀▀▀▀▀▀▀
//
// website:  https://rpunks.xyz
// twitter:  https://x.com/rPunks_
// telegram: https://t.me/rpunksxyz
//
pragma solidity ^0.8.28;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

interface IRPunksMirror {
    function mintSynced(address to, uint256 count, uint256 certBase) external;

    function burnLIFO(address from, uint256 count) external;

    function balanceOf(address owner) external view returns (uint256);
}

contract RPunksToken is ERC20, Ownable {
    error MirrorAlreadySet();
    error HookAlreadySet();
    error NotMirror();
    error NotHook();

    uint256 public constant MAX_SUPPLY = 1000e18;

    IRPunksMirror public mirror;
    address public hook;
    mapping(address => bool) public mirrorExempt;
    bool private _noSync;

    address private transient _stagedTo;
    uint256 private transient _stagedCert;

    constructor(address recipient)
        ERC20("rPunks", "PUNKS")
        Ownable(msg.sender)
    {
        _mint(recipient, MAX_SUPPLY);
    }

    function setMirror(address m) external onlyOwner {
        if (address(mirror) != address(0)) revert MirrorAlreadySet();
        mirror = IRPunksMirror(m);
        mirrorExempt[m] = true;
    }

    function setMirrorExempt(address account, bool exempt) external onlyOwner {
        mirrorExempt[account] = exempt;
    }

    function setHook(address h) external onlyOwner {
        if (hook != address(0)) revert HookAlreadySet();
        hook = h;
    }

    /// @notice The hook stages the market cert for the swap recipient; the
    ///         mint itself only ever happens when tokens actually arrive.
    function stageCert(address to, uint256 certBase) external {
        if (msg.sender != hook) revert NotHook();
        _stagedTo = to;
        _stagedCert = certBase;
    }

    /// @notice NFT transfers carry one whole token; the mirror moves it here
    ///         without re-triggering the balance sync.
    function mirrorTransfer(address from, address to, uint256 value) external {
        if (msg.sender != address(mirror)) revert NotMirror();
        _noSync = true;
        _transfer(from, to, value);
        _noSync = false;
    }

    /// @dev punk count == floor(token balance) for every non-exempt wallet.
    function _update(address from, address to, uint256 value)
        internal override
    {
        super._update(from, to, value);
        IRPunksMirror m = mirror;
        if (_noSync || address(m) == address(0)) return;
        if (from != address(0) && !mirrorExempt[from]) {
            uint256 floorBal = balanceOf(from) / 1e18;
            uint256 punks = m.balanceOf(from);
            if (punks > floorBal) m.burnLIFO(from, punks - floorBal);
        }
        if (to != address(0) && !mirrorExempt[to]) {
            uint256 floorBal = balanceOf(to) / 1e18;
            uint256 punks = m.balanceOf(to);
            if (floorBal > punks) {
                uint256 certBase;
                if (to == _stagedTo) {
                    certBase = _stagedCert;
                    _stagedTo = address(0);
                }
                m.mintSynced(to, floorBal - punks, certBase);
            }
        }
    }
}
Chain explorer3793msChain node88ms