EquifoldRestrictedTokenV4
0x82c6fe1082dcc6e71e9411cef2846a0a107c34ab
Verification
Verified
v0.8.24+commit.e11b9ed9
Type
Contract
4,909 bytes
ABI entries
49
23 read · 6 write
License
none
Contract information
- Address
- 0x82c6fe1082dcc6e71e9411cef2846a0a107c34ab
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.24+commit.e11b9ed9
- Optimization
- Enabled
- Creator
- 0x120cAef934…6B0282736E
- Creation tx
- 0xd1cfd1b539…39ce34a603
Token
- Name
- MemeSoft
- Symbol
- MSFT
- Decimals
- 18
- Holders
- 72
- Market
- View token page →
Read contract (23)
MAX_DECIMALS() → uint8
MIN_DECIMALS() → uint8
TOKEN_VERSION() → uint32
allowance(address, address) → uint256
balanceOf(address) → uint256
creator() → address
decimals() → uint8
factory() → address
isBurnable() → bool
launchBlock() → uint256
launchContract() → address
launchTimestamp() → uint48
maxBuysLimit() → uint256
maxTxBps() → uint16
maxWalletBps() → uint16
maxWalletLimit() → uint256
metadataURI() → string
name() → string
poolManager() → address
projectNumber() → uint256
restrictionEndBlock() → uint256
symbol() → string
totalSupply() → uint256
Events (2)
ApprovalTransfer
ABI
[
{
"inputs": [
{
"components": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "uint8",
"name": "decimals",
"type": "uint8"
},
{
"internalType": "uint256",
"name": "initialSupply",
"type": "uint256"
},
{
"internalType": "bool",
"name": "burnable",
"type": "bool"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "uint256",
"name": "projectNumber",
"type": "uint256"
},
{
"internalType": "string",
"name": "metadataURI",
"type": "string"
},
{
"internalType": "address",
"name": "launchContract",
"type": "address"
}
],
"internalType": "struct EquifoldToken.Initialization",
"name": "initial",
"type": "tuple"
},
{
"components": [
{
"internalType": "address",
"name": "poolManager",
"type": "address"
},
{
"internalType": "uint16",
"name": "maxWalletBps",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "maxTxBps",
"type": "uint16"
},
{
"internalType": "uint32",
"name": "restrictionBlocks",
"type": "uint32"
}
],
"internalType": "struct EquifoldRestrictedTokenV4.RestrictionConfigV4",
"name": "restriction",
"type": "tuple"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "BurningDisabled",
"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": [],
"name": "InvalidAddress",
"type": "error"
},
{
"inputs": [],
"name": "InvalidDecimals",
"type": "error"
},
{
"inputs": [],
"name": "InvalidMetadata",
"type": "error"
},
{
"inputs": [],
"name": "InvalidProject",
"type": "error"
},
{
"inputs": [],
"name": "InvalidRestrictionConfig",
"type": "error"
},
{
"inputs": [],
"name": "InvalidSupply",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
}
],
"name": "LaunchBlockBuyBlocked",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "cumulative",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "limit",
"type": "uint256"
}
],
"name": "MaxBuysExceeded",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "resultingBalance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "limit",
"type": "uint256"
}
],
"name": "MaxWalletExceeded",
"type": "error"
},
{
"inputs": [],
"name": "NotLaunchContract",
"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": [],
"name": "MAX_DECIMALS",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MIN_DECIMALS",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "TOKEN_VERSION",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"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": [
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "burnFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "creator",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "factory",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "isBurnable",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "launchBlock",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "launchContract",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "launchTimestamp",
"outputs": [
{
"internalType": "uint48",
"name": "",
"type": "uint48"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxBuysLimit",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxTxBps",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxWalletBps",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxWalletLimit",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "metadataURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "poolManager",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "projectNumber",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "restrictionEndBlock",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
}
],
"name": "setInitialBuyRecipient",
"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"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import { EquifoldToken } from "./EquifoldToken.sol";
/// @title Equifold restricted launch token (stock-paired v4 v2)
/// @notice EquifoldToken whose v4 pool BUYS are limited during a fixed launch window. In
/// Uniswap v4 every pool's balances are custodied by the singleton PoolManager, so a
/// "pool buy" is any transfer with `from == poolManager` — one check covers every v4
/// pool of this token, with no per-fee-tier probing. Launch-block buys are blocked
/// (except the module's atomic creator dev buy), then each recipient is capped at
/// {maxWalletBps} balance and {maxTxBps} cumulative buys until {restrictionEndBlock}.
/// Sells and wallet-to-wallet transfers are never restricted; after the window the
/// token behaves as a plain EquifoldToken. External routers can therefore trade the
/// pool from block launchBlock+1 — only cap-breaking buys revert.
contract EquifoldRestrictedTokenV4 is EquifoldToken {
error InvalidRestrictionConfig();
error LaunchBlockBuyBlocked(address recipient);
error MaxBuysExceeded(address recipient, uint256 cumulative, uint256 limit);
error MaxWalletExceeded(address recipient, uint256 resultingBalance, uint256 limit);
error NotLaunchContract();
struct RestrictionConfigV4 {
address poolManager;
uint16 maxWalletBps;
uint16 maxTxBps;
uint32 restrictionBlocks;
}
uint16 private constant BPS_DENOMINATOR = 10_000;
address public immutable poolManager;
uint16 public immutable maxWalletBps;
uint16 public immutable maxTxBps;
uint256 public immutable launchBlock;
uint256 public immutable restrictionEndBlock;
address private _initialBuyRecipient;
mapping(address recipient => uint256 bought) private _restrictedPoolBuys;
constructor(
Initialization memory initial,
RestrictionConfigV4 memory restriction
) EquifoldToken(initial) {
if (
restriction.poolManager == address(0) || restriction.poolManager.code.length == 0
|| restriction.maxWalletBps == 0 || restriction.maxWalletBps > BPS_DENOMINATOR
|| restriction.maxTxBps < restriction.maxWalletBps
|| restriction.maxTxBps > BPS_DENOMINATOR || restriction.restrictionBlocks == 0
) revert InvalidRestrictionConfig();
poolManager = restriction.poolManager;
maxWalletBps = restriction.maxWalletBps;
maxTxBps = restriction.maxTxBps;
launchBlock = block.number;
restrictionEndBlock = block.number + restriction.restrictionBlocks;
}
function maxWalletLimit() public view returns (uint256) {
return (totalSupply() * maxWalletBps) / BPS_DENOMINATOR;
}
function maxBuysLimit() public view returns (uint256) {
return (totalSupply() * maxTxBps) / BPS_DENOMINATOR;
}
function setInitialBuyRecipient(
address recipient
) external {
if (msg.sender != launchContract) revert NotLaunchContract();
_initialBuyRecipient = recipient;
}
function _update(
address from,
address to,
uint256 value
) internal override {
if (
from != address(0) && to != address(0) && block.number <= restrictionEndBlock
&& from == poolManager
) {
bool exemptBuy = block.number == launchBlock && _initialBuyRecipient != address(0)
&& to == _initialBuyRecipient;
if (!exemptBuy) {
if (block.number == launchBlock) revert LaunchBlockBuyBlocked(to);
uint256 resultingBalance = balanceOf(to) + value;
uint256 walletLimit = maxWalletLimit();
if (resultingBalance > walletLimit) {
revert MaxWalletExceeded(to, resultingBalance, walletLimit);
}
uint256 cumulative = _restrictedPoolBuys[to] + value;
uint256 buysLimit = maxBuysLimit();
if (cumulative > buysLimit) {
revert MaxBuysExceeded(to, cumulative, buysLimit);
}
_restrictedPoolBuys[to] = cumulative;
}
}
super._update(from, to, value);
}
}
Chain explorer4128msChain node89ms