SatoToken
0x587a07f220b078bc59cbf90179491292261af862
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
2,474 bytes
ABI entries
31
11 read · 6 write
License
none
Contract information
- Address
- 0x587a07f220b078bc59cbf90179491292261af862
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0xd3a962DF31…B254c28a91
- Creation tx
- 0xc0df883dc2…5c166b0120
Token
- Name
- rato
- Symbol
- rato
- Decimals
- 18
- Holders
- 213
- Market
- View token page →
Read contract (11)
DEPLOYER() → address
GENESIS_BLOCK() → uint256
GENESIS_HASH() → bytes32
RESTRICTIONS_FORBIDDEN() → bool
allowance(address, address) → uint256
balanceOf(address) → uint256
decimals() → uint8
minter() → address
name() → string
symbol() → string
totalSupply() → uint256
Events (3)
ApprovalMinterLockedTransfer
ABI
[
{
"inputs": [],
"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": "MinterAlreadySet",
"type": "error"
},
{
"inputs": [],
"name": "MinterIsZero",
"type": "error"
},
{
"inputs": [],
"name": "NotDeployer",
"type": "error"
},
{
"inputs": [],
"name": "NotMinter",
"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": "minter",
"type": "address"
}
],
"name": "MinterLocked",
"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": "DEPLOYER",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "GENESIS_BLOCK",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "GENESIS_HASH",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "RESTRICTIONS_FORBIDDEN",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"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": "address",
"name": "from",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "mint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "minter",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newMinter",
"type": "address"
}
],
"name": "setMinter",
"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.26;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
/// @title SatoToken
/// @notice Plain ERC-20 with one designated minter that is locked in once and cannot be changed.
/// No owner. No pause. No blacklist. No fee logic. No upgrade path.
contract SatoToken is ERC20 {
/// @notice The designated minter (the SatoHook). Locked once `setMinter` is called.
address public minter;
/// @notice The address that deployed this contract (only entity allowed to set the minter once).
address public immutable DEPLOYER;
/// @notice Marker that asserts this contract makes no use of any restriction primitive.
bool public immutable RESTRICTIONS_FORBIDDEN = true;
/// @notice The block at which this contract was deployed.
uint256 public immutable GENESIS_BLOCK;
/// @notice The hash of the block immediately preceding deployment. Burned into bytecode.
bytes32 public immutable GENESIS_HASH;
/// @notice Reverts when a caller other than the deployer tries to set the minter.
error NotDeployer();
/// @notice Reverts when a caller other than the locked-in minter tries to mint.
error NotMinter();
/// @notice Reverts when `setMinter` is called more than once.
error MinterAlreadySet();
/// @notice Reverts when a zero-address minter is supplied.
error MinterIsZero();
/// @notice Emitted exactly once, the moment the minter is permanently locked in.
event MinterLocked(address indexed minter);
/// @notice Construct the token. No constructor arguments.
constructor() ERC20("rato", "rato") {
DEPLOYER = msg.sender;
GENESIS_BLOCK = block.number;
GENESIS_HASH = blockhash(block.number - 1);
}
/// @notice Set the minter exactly once, then lock forever.
/// @param newMinter The address (the SatoHook) that will be the sole entity allowed to mint.
function setMinter(address newMinter) external {
if (msg.sender != DEPLOYER) revert NotDeployer();
if (minter != address(0)) revert MinterAlreadySet();
if (newMinter == address(0)) revert MinterIsZero();
minter = newMinter;
emit MinterLocked(newMinter);
}
/// @notice Mint SATO. Callable only by the locked-in minter.
/// @param to Recipient of newly minted tokens.
/// @param amount Amount in 1e18-scaled units.
function mint(address to, uint256 amount) external {
if (msg.sender != minter) revert NotMinter();
_mint(to, amount);
}
/// @notice Burn SATO held by `from`. Callable only by the locked-in minter (the hook),
/// used to retire tokens during sells settled against the inverse curve.
/// @param from Account whose tokens are burned.
/// @param amount Amount in 1e18-scaled units.
function burn(address from, uint256 amount) external {
if (msg.sender != minter) revert NotMinter();
_burn(from, amount);
}
}
Chain explorer2576msChain node88ms