MemeFolioToken
0xc2217b52901763c6eaba87b20d13e91d18764ea6
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
3,683 bytes
ABI entries
29
13 read · 3 write
License
none
Contract information
- Address
- 0xc2217b52901763c6eaba87b20d13e91d18764ea6
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0x7861A13054…F58333520b
- Creation tx
- 0xb4259e0665…a6fa637c12
Token
- Name
- Meme ETF
- Symbol
- mETF
- Decimals
- 18
- Holders
- 182
- Market
- View token page →
Read contract (13)
allowance(address, address) → uint256
balanceOf(address) → uint256
decimals() → uint8
eligibleHolderCount() → uint256
eligibleSupply() → uint256
getPastBalance(address, uint256) → uint256
getPastEligibleHolderCount(uint256) → uint256
getPastEligibleSupply(uint256) → uint256
initialSupply() → uint256
minHolderBalance() → uint256
name() → string
symbol() → string
totalSupply() → uint256
Events (2)
ApprovalTransfer
ABI
[
{
"inputs": [
{
"internalType": "string",
"name": "name_",
"type": "string"
},
{
"internalType": "string",
"name": "symbol_",
"type": "string"
},
{
"internalType": "uint256",
"name": "supply_",
"type": "uint256"
},
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "minHolderBalance_",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "CheckpointUnorderedInsertion",
"type": "error"
},
{
"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": [
{
"internalType": "uint256",
"name": "blockNumber",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "currentBlock",
"type": "uint256"
}
],
"name": "FutureLookup",
"type": "error"
},
{
"inputs": [],
"name": "InvalidRecipient",
"type": "error"
},
{
"inputs": [],
"name": "InvalidSupply",
"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": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"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": "eligibleHolderCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "eligibleSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "blockNumber",
"type": "uint256"
}
],
"name": "getPastBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "blockNumber",
"type": "uint256"
}
],
"name": "getPastEligibleHolderCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "blockNumber",
"type": "uint256"
}
],
"name": "getPastEligibleSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "initialSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "minHolderBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"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"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { Checkpoints } from "@openzeppelin/contracts/utils/structs/Checkpoints.sol";
/// @title MemeFolioToken
/// @notice Fixed-supply launch token with immutable historical balance checkpoints.
/// @dev Balance, threshold-eligible supply and eligible-holder-count checkpoints let the distributor
/// verify an offchain-enumerated holder batch without trusting uploaded balances.
contract MemeFolioToken is ERC20 {
using Checkpoints for Checkpoints.Trace256;
uint256 public immutable initialSupply;
uint256 public immutable minHolderBalance;
uint256 public eligibleSupply;
uint256 public eligibleHolderCount;
mapping(address holder => Checkpoints.Trace256 trace) private _balanceCheckpoints;
Checkpoints.Trace256 private _eligibleSupplyCheckpoints;
Checkpoints.Trace256 private _eligibleHolderCountCheckpoints;
error InvalidRecipient();
error InvalidSupply();
error FutureLookup(uint256 blockNumber, uint256 currentBlock);
constructor(
string memory name_,
string memory symbol_,
uint256 supply_,
address recipient,
uint256 minHolderBalance_
) ERC20(name_, symbol_) {
if (recipient == address(0)) revert InvalidRecipient();
if (supply_ == 0 || minHolderBalance_ == 0 || minHolderBalance_ > supply_) {
revert InvalidSupply();
}
initialSupply = supply_;
minHolderBalance = minHolderBalance_;
_mint(recipient, supply_);
}
function getPastBalance(address account, uint256 blockNumber) external view returns (uint256) {
_validatePastBlock(blockNumber);
return _balanceCheckpoints[account].upperLookupRecent(blockNumber);
}
function getPastEligibleSupply(uint256 blockNumber) external view returns (uint256) {
_validatePastBlock(blockNumber);
return _eligibleSupplyCheckpoints.upperLookupRecent(blockNumber);
}
function getPastEligibleHolderCount(uint256 blockNumber) external view returns (uint256) {
_validatePastBlock(blockNumber);
return _eligibleHolderCountCheckpoints.upperLookupRecent(blockNumber);
}
function _update(address from, address to, uint256 value) internal override {
uint256 fromBefore = from == address(0) ? 0 : balanceOf(from);
uint256 toBefore = to == address(0) ? 0 : balanceOf(to);
super._update(from, to, value);
uint256 updatedEligibleSupply = eligibleSupply;
uint256 updatedEligibleHolderCount = eligibleHolderCount;
if (from != address(0)) {
uint256 fromAfter = balanceOf(from);
updatedEligibleSupply = updatedEligibleSupply - _eligibleContribution(fromBefore)
+ _eligibleContribution(fromAfter);
updatedEligibleHolderCount = updatedEligibleHolderCount
- _eligibleAccountContribution(fromBefore) + _eligibleAccountContribution(fromAfter);
_writeAccountCheckpoint(from, fromAfter);
}
if (to != address(0) && to != from) {
uint256 toAfter = balanceOf(to);
updatedEligibleSupply = updatedEligibleSupply - _eligibleContribution(toBefore)
+ _eligibleContribution(toAfter);
updatedEligibleHolderCount = updatedEligibleHolderCount
- _eligibleAccountContribution(toBefore) + _eligibleAccountContribution(toAfter);
_writeAccountCheckpoint(to, toAfter);
}
if (updatedEligibleSupply != eligibleSupply) {
eligibleSupply = updatedEligibleSupply;
_eligibleSupplyCheckpoints.push(block.number, updatedEligibleSupply);
}
if (updatedEligibleHolderCount != eligibleHolderCount) {
eligibleHolderCount = updatedEligibleHolderCount;
_eligibleHolderCountCheckpoints.push(block.number, updatedEligibleHolderCount);
}
}
function _writeAccountCheckpoint(address account, uint256 balance) private {
_balanceCheckpoints[account].push(block.number, balance);
}
function _eligibleContribution(uint256 balance) private view returns (uint256) {
return balance >= minHolderBalance ? balance : 0;
}
function _eligibleAccountContribution(uint256 balance) private view returns (uint256) {
return balance >= minHolderBalance ? 1 : 0;
}
function _validatePastBlock(uint256 blockNumber) private view {
if (blockNumber >= block.number) revert FutureLookup(blockNumber, block.number);
}
}
Chain explorer4562msChain node82ms