SubEthaNomic (SEN), a Nomic on chain: each player holds one unit of citizenship, any player may propose a motion, and motions pass only unanimously. The only contract deployed while ERC-20 was being drafted that implements totalSupply().
Historical Significance
Across every contract created on Ethereum mainnet while ERC-20 was being drafted, from issue #20 being filed on 19 November 2015 to the specification settling in January 2016, this is the only one that implements totalSupply(). It carries balanceOf, totalSupply, transfer, name, symbol and the Transfer event, three of the six methods the standard would require, and no allowance machinery at all: no approve, no transferFrom, no allowance, no Approval event. Nothing deployed to mainnet in that window implemented approve or allowance either, which is the measure of how far the written standard ran ahead of practice. The token here is a side effect rather than the point. SubEthaNomic is a Nomic, a game whose rules are changed by playing it: citizenship is one indivisible unit per player, a motion passes only if every player votes for it, and a passed upgrade motion suicides the contract to its successor. Deployed in block 689,715 on 14 December 2015.
Context
December 2015 fell in the late Frontier era of Ethereum, a period of active experimentation in the five months between the July 30, 2015 mainnet launch and the Homestead upgrade on March 14, 2016. The ERC-20 token standard had just been formally submitted on November 19, 2015. Early token deployers were exploring both the technical capabilities and the cultural dimensions of issuing tokens on a public blockchain. The Hitchhiker's Guide to the Galaxy had a strong following in technical communities, and its Sub-Etha network concept of a galaxy-spanning information network resonated as a metaphor for decentralized communication.
Token Information
Key Facts
Description
Deployed 14 December 2015 as SubEthaNomic, ticker SEN. A Nomic is a game whose rules are changed by playing it, and this is one run on chain.
Citizenship is the token. Each player holds exactly one unit, balanceOf returns 1 or 0, totalSupply is the number of players, and transfer moves citizenship only when the amount is exactly 1, which hands your seat to someone else. While the contract is in setup mode the founder can add and remove players unilaterally; startGame() closes setup and from then on the founder has no special power.
Any player may file a motion with newProposal, carrying a description, an IPFS hash for text too long to inline, and a flag marking it an upgrade. Voting is unanimous or nothing: a single vote against sets proposalFailed and closes the motion permanently, and executeProposal refuses until the affirmative count reaches the full player list. A motion that passes and is flagged as an upgrade calls suicide to the nominated address, handing the game's balance to a successor contract, which is how the rules of the game change the game.
Source recovered by compiling against solc v0.1.7+commit.b4e666cc with the optimizer on, reproducing both the deployed runtime and the creation bytecode exactly. The author's own nomic.sol, committed to GitHub eighteen hours after the deployment, has the same code with the functions in a different order and does not compile to the deployed bytes; restoring the deployed order does.
Source Verified
Historian Categories
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Frontier Era
The initial release of Ethereum. A bare-bones implementation for technical users.
Bytecode Overview
Verified Source Available
Source verified through compiler archaeology and exact bytecode matching.
View Verification ProofShow source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
/*
This creates a basic nomic.
There is a list of addresses that are "players", holding 1 unit of citizenship.
Motions can be proposed by any player.
Motions can be rejected by any player, or passed unanimously.
*/
contract Nomic {
struct Proposal {
string description; /* What is the proposal? */
string ipfsHash; /* If the proposal is too long to include inline */
bool isUpgrade; /* Should the passage of this proposal replace this contract with a new one? */
address upgradeAddress; /* Address to suicide to. This becomes the new game contract. Game state should have been copied. */
bool proposalPassed; /* Has the proposal passed? */
bool proposalFailed; /* Has the proposal failed? */
uint32 numberOfVotes; /* Affirmative votes */
mapping (address => bool) voted; /* Who has voted? */
}
/* Public variables of the citizenship token */
string public name;
string public symbol;
/* How many citizenships does everyone have? */
mapping (address => bool) public isPlaying;
/* How many players are playing? */
uint32 public totalPlayers;
/* Is the contract in setup mode (founder can add players) */
bool public isSetup;
address public founder;
/* Keep all proposals ever */
Proposal[] public proposals;
/* This generates a public event on the blockchain that will notify clients */
event Transfer(address indexed from, address indexed to, uint256 value);
/* These are for proposals */
event ProposalAdded(uint proposalID, string description, string ipfsHash, bool isUpgrade, address upgradeAddress);
event Voted(uint proposalID, address voter, bool position);
event ProposalClosed(uint proposalID, bool passed);
/* modifier that allows only shareholders to vote and create new proposals */
modifier onlyPlayers {
if (isSetup) throw;
if (!isPlaying[msg.sender]) throw;
_
}
/* Initializes contract with initial supply tokens to the creator of the contract */
function Nomic(string _name, string _symbol) {
/* Set up the game */
name = _name;
symbol = _symbol;
/* Original set-up-er is the only player so far. */
isPlaying[msg.sender] = true;
totalPlayers = 1;
/* In setup mode, founder can add players unilaterally. */
founder = msg.sender;
isSetup = true;
}
function totalSupply() constant returns (uint256 supply) {
supply = totalPlayers;
}
function vote(uint proposalNumber, bool supportsProposal) onlyPlayers {
Proposal p = proposals[proposalNumber];
if (p.voted[msg.sender] == true) throw;
if (p.proposalPassed) throw;
if (p.proposalFailed) throw;
p.voted[msg.sender] = true;
Voted(proposalNumber, msg.sender, supportsProposal);
if(supportsProposal) {
p.numberOfVotes += 1;
} else {
p.proposalFailed = true;
ProposalClosed(proposalNumber, false);
}
}
function executeProposal(uint proposalNumber) onlyPlayers {
Proposal p = proposals[proposalNumber];
if (p.proposalFailed) throw;
if (p.proposalPassed) throw;
if (p.numberOfVotes < totalPlayers) throw;
p.proposalPassed = true;
/* Fire Events */
ProposalClosed(proposalNumber, true);
if(p.isUpgrade) {
/* Send any money we have to the upgrade contract. */
suicide(p.upgradeAddress);
}
}
function transfer(address _to, uint256 _value) returns (bool _success) {
if (!isPlaying[msg.sender] || _value != 1) {
_success = false;
} else {
isPlaying[msg.sender] = false;
isPlaying[_to] = true;
/* Notifiy anyone listening that this transfer took place */
Transfer(msg.sender, _to, _value);
_success = true;
}
}
function addPlayer(address _address) {
if(msg.sender != founder) throw;
if(!isSetup) throw;
totalPlayers += 1;
isPlaying[_address] = true;
}
function removePlayer(address _address) {
if(msg.sender != founder) throw;
if(!isSetup) throw;
if(!isPlaying[_address]) throw;
totalPlayers -= 1;
isPlaying[_address] = false;
}
function startGame() {
if(msg.sender != founder) throw;
if(!isSetup) throw;
isSetup = false;
}
function balanceOf(address _address) constant returns (uint256 balance) {
if(isPlaying[_address]) {
balance = 1;
} else {
balance = 0;
}
}
function newProposal(string _description, string _ipfsHash, bool _isUpgrade, address _upgradeAddress) onlyPlayers returns (uint proposalID) {
proposalID = proposals.length++;
Proposal p = proposals[proposalID];
p.description = _description;
p.ipfsHash = _ipfsHash;
p.isUpgrade = _isUpgrade;
p.upgradeAddress = _upgradeAddress;
p.proposalPassed = false;
p.proposalFailed = false;
p.numberOfVotes = 0;
ProposalAdded(proposalID, _description, _ipfsHash, _isUpgrade, _upgradeAddress);
}
}External Links
Related contracts
token
Same eraAn early ERC-20-like token deployed in Ethereum's first week, built directly from the example in the official Ethereum Frontier Guide documentation.
0x8374f5...46609aAugust 7, 2015token
Same eraA second deployment of the FirstCoin tutorial token by the same creator, 11 blocks after the original — both derived from the official Ethereum Frontier Guide e
0x3b4446...295f52August 7, 2015Contract 0xd958b5...ec4c9f
Same eraEthereum.org tutorial Coin contract deployed on Frontier day 1. Contains a bug: balance(address) ignores its argument and returns msg.sender balance.
0xd958b5...ec4c9fAugust 7, 2015token
Same eraEarly tutorial-derived coin contract compiled with Solidity v0.1.1, deployed 9 days after Ethereum Frontier launch.
0x3c401b...da1634August 8, 2015token
Same eraTutorial-derived coin contract (Solidity v0.1.1), one of multiple token instances deployed by the same address on Aug 8, 2015.
0x33e986...395d13August 8, 2015CoinStub
Same eraCoin tutorial stub — mapping getter + empty function returning default bool.
0x4fb5ac...3b08aeAugust 8, 2015