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
- Creator
- 0x1A0ed77C45…5C129B214c
- Creation tx
- 0x31b5076d83…fd689f2237
Token
- Name
- rPunks
- Symbol
- PUNKS
- Decimals
- 18
- Holders
- 99
- Market
- View token page →
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