Created
November 1, 2020 19:26
-
-
Save 0xAnonymous/5d2b6764a08a6231cbc03dd744c6bd05 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
contract Polytopia { | |
uint constant public period = 4 weeks; | |
uint constant public genesis = 1604127600; | |
uint constant public randomize = 2 weeks; | |
uint constant public premeet = 3 weeks; | |
uint public hour; | |
function schedule() public view returns (uint) { return genesis + ((block.timestamp - genesis) / period) * period; } | |
uint entropy; | |
enum Rank { Court, Pair } | |
enum Token { Personhood, Registration, Immigration, Verified } | |
struct Reg { | |
Rank rank; | |
uint id; | |
bool verified; | |
} | |
mapping (uint => mapping (address => Reg)) public registry; | |
mapping (uint => mapping (Rank => mapping (uint => address))) public registryIndex; | |
mapping (uint => mapping (Rank => uint)) public registered; | |
mapping (uint => uint) public shuffled; | |
mapping (uint => mapping (address => bool)) public committed; | |
mapping (uint => mapping (Rank => mapping (uint => bool[2]))) public judgement; | |
mapping (uint => mapping (uint => bool)) public disputed; | |
mapping (uint => uint) public population; | |
mapping (uint => mapping (address => uint)) public proofOfPersonhood; | |
mapping (uint => mapping (uint => address)) public personhoodIndex; | |
mapping (uint => mapping (Token => mapping (address => uint))) public balanceOf; | |
mapping (uint => mapping (Token => mapping (address => mapping (address => uint)))) public allowed; | |
function inState(uint _prev, uint _next, uint _t) internal view returns (bool) { | |
if(_prev != 0) return (block.timestamp > _t + _prev); | |
if(_next != 0) return (block.timestamp < _t + _next); | |
} | |
constructor() public { | |
address genesisAccount; | |
uint genesisPopulation; | |
balanceOf[schedule()][Token.Registration][genesisAccount] = genesisPopulation; | |
} | |
function initializeRandomization() internal { | |
entropy = uint(blockhash(block.number-1)); | |
hour = (entropy%24)*1 hours; | |
} | |
function _shuffle(uint _t) internal { | |
if(shuffled[_t] == 0) initializeRandomization(); | |
shuffled[_t]++; | |
uint _shuffled = shuffled[_t]; | |
uint randomNumber = _shuffled + entropy%(registered[_t][Rank.Pair] + 1 - _shuffled); | |
entropy = uint(keccak256(abi.encodePacked(entropy, registryIndex[_t][Rank.Pair][randomNumber]))); | |
(registryIndex[_t][Rank.Pair][_shuffled], registryIndex[_t][Rank.Pair][randomNumber]) = (registryIndex[_t][Rank.Pair][randomNumber], registryIndex[_t][Rank.Pair][_shuffled]); | |
registry[_t][registryIndex[_t][Rank.Pair][_shuffled]].id = _shuffled; | |
} | |
function shuffle() external { | |
uint t = schedule(); | |
require(inState(randomize, premeet, t)); | |
require(registry[t][msg.sender].rank == Rank.Pair && committed[t][msg.sender] == false); | |
committed[t][msg.sender] = true; | |
_shuffle(t); | |
} | |
function lateShuffle(uint _iterations) external { | |
uint t = schedule(); | |
require(inState(premeet, 0, t)); | |
for (uint i = 0; i < _iterations; i++) _shuffle(t); | |
} | |
function _register(Rank _rank) internal { | |
uint t = schedule(); | |
require(inState(0, randomize, t)); | |
require(registry[t][msg.sender].id == 0 && registry[t][msg.sender].rank != Rank.Pair); | |
Token _token = Token(2-uint(_rank)); | |
require(balanceOf[t][_token][msg.sender] >= 1); | |
balanceOf[t][_token][msg.sender]--; | |
registered[t][_rank]++; | |
registryIndex[t][_rank][registered[t][_rank]] = msg.sender; | |
registry[t][msg.sender].rank = _rank; | |
if(_rank != Rank.Pair) registry[t][msg.sender].id = registered[t][Rank.Court]; | |
} | |
function register() external { _register(Rank.Pair); } | |
function immigrate() external { _register(Rank.Court); } | |
function isVerified(Rank _rank, uint _unit, uint t) public view returns (bool) { | |
return (judgement[t][_rank][_unit][0] == true && judgement[t][_rank][_unit][1] == true); | |
} | |
function dispute(bool _premeet) external { | |
uint t = schedule(); | |
if(_premeet != true) t -= period; | |
uint id = registry[t][msg.sender].id; | |
require(registry[t][msg.sender].rank == Rank.Pair && id != 0); | |
uint pair = (id+1)/2; | |
if(_premeet == false) require(!isVerified(Rank.Pair, pair, t)); | |
disputed[t][pair] = true; | |
} | |
function reassign(bool _premeet) external { | |
uint t = schedule(); | |
if(_premeet != true) t -= period; | |
uint id = registry[t][msg.sender].id; | |
require(id != 0); | |
uint countPairs = registered[t][Rank.Pair]/2; | |
uint pair; | |
if(registry[t][msg.sender].rank == Rank.Pair) { | |
pair = (id + 1)/2; | |
registry[t][msg.sender].rank = Rank.Court; | |
} | |
else pair = 1 + (id - 1)%countPairs; | |
require(disputed[t][pair] == true); | |
uint court = 1 + uint(keccak256(abi.encodePacked(msg.sender, pair)))%countPairs; | |
while(registryIndex[t][Rank.Court][court] != address(0)) court += countPairs; | |
registry[t][msg.sender].id = court; | |
registryIndex[t][Rank.Court][court] = msg.sender; | |
} | |
function _verify(address _account, address _signer, uint _t) internal { | |
require(inState(hour, 0, _t)); | |
require(_account != _signer); | |
require(registry[_t][_signer].rank == Rank.Pair && committed[_t][_signer] == true); | |
uint id = registry[_t][_account].id; | |
require(id != 0); | |
Rank rank = registry[_t][_account].rank; | |
uint unit; | |
uint pair; | |
if(rank == Rank.Pair) { | |
pair = (id + 1)/2; | |
unit = pair; | |
} | |
else { | |
unit = id; | |
pair = 1 + (unit - 1)%(registered[_t][Rank.Pair]/2); | |
} | |
require(disputed[_t][pair] == false); | |
uint peer = registry[_t][_signer].id; | |
require(peer != 0 && pair == (peer+1)/2); | |
judgement[_t][rank][unit][peer%2] = true; | |
} | |
function verify(address _account) external { _verify(_account, msg.sender, schedule()-period); } | |
function uploadSignature(address[] calldata _account, bytes32[] calldata r, bytes32[] calldata s, uint8[] calldata v) external { | |
uint t = schedule()-period; | |
for(uint i = 0; i < _account.length; i++) { | |
bytes32 _msgHash = keccak256(abi.encodePacked(_account[i], t)); | |
_verify(_account[i], ecrecover(_msgHash, v[i], r[i], s[i]), t); | |
} | |
} | |
function completeVerification() external { | |
uint t = schedule()-period; | |
require(registry[t][msg.sender].verified == false); | |
uint id = registry[t][msg.sender].id; | |
uint pair; | |
if(registry[t][msg.sender].rank == Rank.Court) { | |
require(isVerified(Rank.Court, id, t)); | |
pair = 1 + (id - 1)%(registered[t][Rank.Pair]/2); | |
} | |
else pair = (id + 1) /2; | |
require(isVerified(Rank.Pair, pair, t)); | |
balanceOf[t+period][Token.Verified][msg.sender]++; | |
registry[t][msg.sender].verified = true; | |
} | |
function collectTokens() external { | |
uint t = schedule(); | |
require(balanceOf[t][Token.Verified][msg.sender] >= 1); | |
balanceOf[t][Token.Verified][msg.sender]--; | |
balanceOf[t][Token.Personhood][msg.sender]++; | |
balanceOf[t][Token.Registration][msg.sender]++; | |
balanceOf[t][Token.Immigration][msg.sender]++; | |
} | |
function claimPersonhood() external { | |
uint t = schedule(); | |
require(proofOfPersonhood[t][msg.sender] == 0 && balanceOf[t][Token.Personhood][msg.sender] >= 1); | |
balanceOf[t][Token.Personhood][msg.sender]--; | |
population[t]++; | |
proofOfPersonhood[t][msg.sender] = population[t]; | |
personhoodIndex[t][population[t]] = msg.sender; | |
} | |
function _transfer(uint _t, address _from, address _to, uint _value, Token _token) internal { | |
require(balanceOf[_t][_token][_from] >= _value); | |
balanceOf[_t][_token][_from] -= _value; | |
balanceOf[_t][_token][_to] += _value; | |
} | |
function transfer(address _to, uint _value, Token _token) external { | |
_transfer(schedule(), msg.sender, _to, _value, _token); | |
} | |
function approve(address _spender, uint _value, Token _token) external { | |
allowed[schedule()][_token][msg.sender][_spender] = _value; | |
} | |
function transferFrom(address _from, address _to, uint _value, Token _token) external { | |
uint t = schedule(); | |
require(allowed[t][_token][_from][msg.sender] >= _value); | |
_transfer(t, _from, _to, _value, _token); | |
allowed[t][_token][_from][msg.sender] -= _value; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment