SatoToken
plain erc-20 with one privileged role: a mint authority that locks itself permanently after a single call.
SatoTokenis the erc-20 itself. it inherits from openzeppelin's standard ERC20 and adds exactly four things on top: an immutable deployer, an immutable genesis fingerprint pair, a single one-shot minter setter, and a marker constant denying any restriction primitives. nothing else.
the entire contract is < 80 lines of solidity. it does not run any custom logic during transfers, holds no eth, has no admin role beyond the one-time minter assignment, and offers no upgrade path.
state
minter- the only address allowed to call
mintorburn. starts asaddress(0); once set viasetMinter, never changes. DEPLOYERimmutable. set in the constructor frommsg.sender. only this address can callsetMinter.GENESIS_BLOCKimmutable. set toblock.numberat deployment.GENESIS_HASHimmutable. set toblockhash(block.number − 1)at deployment. the only way to fabricate one is to deploy at that block.RESTRICTIONS_FORBIDDENimmutable bool, set totrue. purely declarative — a self-evident on-chain assertion that this contract implements no pause, no blocklist, no allowlist, no transfer hooks beyond standard erc-20.
functions
setMinter(address)- callable exactly once, by
DEPLOYERonly. reverts withNotDeployer,MinterAlreadySet, orMinterIsZero. emitsMinterLocked(minter). mint(to, amount)- callable only by the locked-in
minter(the hook). reverts withNotMinter. used to credit buyers. burn(from, amount)- callable only by the locked-in
minter. reverts withNotMinter. used to retire sellers' tokens during sell settlement.
events and errors
event MinterLocked(address indexed minter)— fires exactly once, at the moment the minter is permanently assigned.error NotDeployer(),NotMinter(),MinterAlreadySet(),MinterIsZero()— the only four named errors. no other paths revert with custom errors.
what is not in this contract
- no
owner, noOwnable. - no
pause, noPausable. - no
blacklist, noblocklist, no allowlist. - no transfer fees, no rebasing, no reflection.
- no upgrade proxy, no fallback function, no
selfdestruct. - no signature-based meta transactions (no
permit).
the deployment sequence
the only privileged action the deployer ever takes is the single setMinter call. the canonical sequence is:
- 1. deploy
SatoToken. the deployer becomesDEPLOYER;minterremainsaddress(0). - 2. deploy
SatoHook, passing the token's address into its constructor. - 3. call
SatoToken.setMinter(hookAddress). this is the one and only privileged call.MinterLockedfires; from this moment, even the deployer has no special powers over the token.
after step 3, the DEPLOYERaddress still exists on the contract but every function it could call now reverts. it's a cryptographic vestige.
this page describes deployed code. nothing here is a promise — it is a description of what the contract does and what it doesn't.
