ShitToken — satirical 2017 ICO parody with 151 supply (like the original Pokémon), zero pre-mine, and a deployer named ShitCoinGod.
Historical Significance
ShitToken is a deliberate anti-ICO statement deployed at the peak of the 2017 token-sale bubble. While contemporaries raised millions through opaque pre-sales, lock-ups, and team allocations, ShitToken inverts every one of those mechanics: the entire 151-token supply (a direct nod to the original 151 Pokémon) is unclaimed at deployment, there is no founder allocation, and the only way to acquire SHIT is to send ETH to the contract’s payable fallback at a fixed 10:1 rate. The deployer’s on-chain name — stored publicly as ShitCoinGod — is itself the joke. The deployer’s only privilege is claimMoney(), which simply forwards the contract’s ETH balance to itself; there is no admin mint, pause, blacklist, or upgrade path. Mechanically, this is a fixed-supply, no-pre-mine, fair-launch ERC-20 — a structure that did not become standard until YFI in July 2020. ShitToken predates DeFi fair launches by almost exactly three years, packaged as a joke about the very ICOs that were raising tens of millions of dollars on weaker structures the same week.
Context
Deployed on 2017-07-23 at 07:52:59 UTC (block 4,061,425) by ShitCoinGod (0xc952b2016f059483b8e365f3e53636ef0fe6fe6d), in the middle of the 2017 ICO bubble — the same month as Tezos’ $232M raise and Bancor’s $153M raise. ShitCoinGod shipped two versions of the contract within nine minutes: this contract (0x337b…), the first draft using a mint-on-send fallback, and 0xdbd9837… (block 4,061,483, ~9 minutes later) which used a sell-from-owner pattern and was the version linked from the project website. The project was announced on BitcoinTalk and accompanied by a static website at shitcoingod.github.io/shittoken/ that documented the joke, the supply cap, and the fact that there was no pre-mine. Both contracts went unverified on Etherscan for over eight years; this proof is the first published source reconstruction. Compiled with native solc 0.4.11 (Darwin/appleclang build), optimizer ON, runs=1, using SafeMath as a separate library with the using SafeMath for uint256; pattern — an early instance of the library/using-for idiom that later became standard in OpenZeppelin.
Token Information
Key Facts
Source Verified
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Spurious Dragon Era
Continued DoS protection. State trie clearing.
Bytecode Overview
Verified Source Available
Source verified through compiler archaeology and exact bytecode matching.
Show source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
pragma solidity ^0.4.11;
library SafeMath {
function safeMul(uint256 a, uint256 b) internal returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeSub(uint256 a, uint256 b) internal returns (uint256) {
assert(b <= a);
return a - b;
}
function safeAdd(uint256 a, uint256 b) internal returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
contract ShitToken {
using SafeMath for uint256;
uint256 public totalSupply;
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
string public name;
string public symbol;
uint256 public decimals;
uint256 public INITIAL_SUPPLY;
address public ShitCoinGod;
uint256 public unclaimedSupply;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
function ShitToken() {
name = "ShitToken";
symbol = "SHIT";
decimals = 18;
INITIAL_SUPPLY = 151 * 10**18;
totalSupply = INITIAL_SUPPLY;
unclaimedSupply = INITIAL_SUPPLY;
ShitCoinGod = msg.sender;
}
function () payable {
require(msg.value > 0);
uint256 amount = msg.value;
uint256 tokens = amount.safeMul(10);
require(tokens <= unclaimedSupply);
unclaimedSupply = unclaimedSupply.safeSub(tokens);
balances[msg.sender] = balances[msg.sender].safeAdd(tokens);
}
function approve(address _spender, uint256 _value) returns (bool success) {
require((_value == 0) || (allowed[msg.sender][_spender] == 0));
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
uint256 _allowance = allowed[_from][msg.sender];
balances[_to] = balances[_to].safeAdd(_value);
balances[_from] = balances[_from].safeSub(_value);
allowed[_from][msg.sender] = _allowance.safeSub(_value);
Transfer(_from, _to, _value);
return true;
}
function claimMoney() {
require(msg.sender == ShitCoinGod);
ShitCoinGod.transfer(this.balance);
}
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}
function transfer(address _to, uint256 _value) returns (bool success) {
balances[msg.sender] = balances[msg.sender].safeSub(_value);
balances[_to] = balances[_to].safeAdd(_value);
Transfer(msg.sender, _to, _value);
return true;
}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
}