Skip to content

Instantly share code, notes, and snippets.

@RossPfeiffer
Created August 8, 2020 08:00
Show Gist options
  • Save RossPfeiffer/3179ecd93b8430257cafd6585508feae to your computer and use it in GitHub Desktop.
Save RossPfeiffer/3179ecd93b8430257cafd6585508feae to your computer and use it in GitHub Desktop.
pragma solidity ^ 0.6.6;
pragma experimental ABIEncoderV2;
contract Oracle{
address payable ORACLE = address(0);
address address0 = address(0);
struct Poll{
uint8 dataType; // string, uint, bool, address
//commit
mapping(address => bool) committed;
mapping(address => bytes) commitHash;
//reveal
mapping(address => bool) revealed;
mapping(address => bool) rejected;
mapping(address => bool) voted;
mapping(address => string) stringVotes;
mapping(address => uint) uintVotes;
mapping(address => bool) boolVotes;
mapping(address => address) addressVotes;
}
struct RequestTicket{
uint ID;
address sender;
string query;
uint timeRequested;
bool finalized;
Poll poll;
uint additionalTime;
bool subjective;
uint txCoverageFee;
uint serviceFee;
bool needsResponse;
bool rejected;
string resolvedString;
uint resolvedUint;
bool resolvedBool;
address resolvedAddress;
mapping(address => bool) punished;
}
//oracle configs
uint constant ROUNDTABLE_SEATS = 0;
uint constant COMMIT_TIME_WINDOW = 1;
uint constant REVEAL_TIME_WINDOW = 2;
uint constant DELEGATE_REWARDSHARE = 3;
uint constant ELECTORATE_REWARDSHARE = 4;
uint constant FREEZE_TIMEOUT = 5;
uint constant TX_FEE_PER = 6;
uint constant SERVICE_FEE = 7;
uint constant CONFIGS = 8;
uint[] oracleConfigurations = new uint[](CONFIGS);
mapping(uint/*configID*/ => mapping(uint => uint) ) public totalVotes_forEach_configOption;
mapping(uint/*configID*/ => mapping(address => uint) ) public individualsSelectedOption;
mapping(address => uint) resolveWeight;
mapping(address => uint) weightLocked;
RequestTicket[] requestTickets;
//ROUND TABLE & Candidates
mapping(uint => address) public chairsCandidate; // only looks at the first X indexes
mapping(address => uint) candidatesChair;
mapping(address => uint) timeSeated; // watchers aren't responsible for requestTickets that came in before them
mapping(address => bool) frozen;
mapping(address => uint) timeWhenThawedOut;
mapping(address => bool) paused; // self pause
mapping(address => bool) hasChair;
uint chairs;
uint public hotSeats;
uint256 constant scaleFactor = 0x10000000000000000;
//PAYROLL
mapping(address => uint) earnings;
mapping(address => uint) totalShares;
mapping(address => mapping(address => uint256)) public shares;
mapping(address => mapping(address => uint256)) payouts;
mapping(address => uint) earningsPerShare;
//Tx Coverage fee
uint earningsPerWatcher;
uint totalWatchers;
mapping(address => uint256) watcherPayouts;
//lazy UI data
mapping(address => address[]) public yourBacking;
mapping(address => mapping(address => bool)) public alreadyBacking;
ResolveToken resolveToken;
constructor(address _resolve) public{
resolveToken = ResolveToken(_resolve);
}
fallback () payable external {}
function addressPayable(address addr) public pure returns(address payable){
return address( uint160(addr) );
}
function addShares(address pool, address account, uint amount) internal{
update(pool, addressPayable(account));
totalShares[pool] += amount;
shares[pool][account] += amount;
if(pool == ORACLE){
updateWatcherTxEarnings(addressPayable(account));
totalWatchers += 1;
}
}
function removeShares(address pool, address account, uint amount) internal{
update(pool, addressPayable(account));
totalShares[pool] -= amount;
shares[pool][account] -= amount;
if(pool == ORACLE){
updateWatcherTxEarnings(addressPayable(account));
totalWatchers -= 1;
}
}
event Cashout(address account, uint amount);
event WatcherPayroll(address watcher, uint paidOut);
function update(address pool, address payable account) internal {
uint owedPerShare = earningsPerShare[pool] - payouts[pool][account];
uint newMoney = shares[pool][account] * owedPerShare;
payouts[pool][account] = earningsPerShare[pool];
if(pool == ORACLE){
uint drs = oracleConfigurations[DELEGATE_REWARDSHARE];
uint ers = oracleConfigurations[ELECTORATE_REWARDSHARE];
uint eth4Watcher = newMoney *drs/(drs+ers);
earnings[account] += eth4Watcher/scaleFactor;
earningsPerShare[account] += (newMoney - eth4Watcher)/totalShares[account];
emit Cashout(account, eth4Watcher/scaleFactor);
emit WatcherPayroll(account, (newMoney - eth4Watcher)/totalShares[account]);
}else{
earnings[account] += newMoney/scaleFactor;
emit Cashout(account, newMoney/scaleFactor);
}
}
event TxCashout(address watcher, uint amount);
function updateWatcherTxEarnings(address payable watcher) internal {
uint owed = earningsPerWatcher - watcherPayouts[watcher];
watcherPayouts[watcher] = earningsPerWatcher;
earnings[watcher] += owed;
emit TxCashout(watcher, owed);
}
event StakeResolves( address indexed addr, uint256 amountStaked, bytes _data );
function tokenFallback(address from, uint value, bytes calldata _data) external{
if( msg.sender == address(resolveToken) ){
resolveWeight[from] += value;
//update option totals
uint option;
for(uint8 config = 0; config<CONFIGS; config+=1){
option = individualsSelectedOption[config][from];
totalVotes_forEach_configOption[config][option] += value;
assertOption(config, option);
}
emit StakeResolves(from, value, _data);
address backImmediately = bytesToAddress( _data );
if( backImmediately != address0 ){
backCandidate(backImmediately,value, false);
}
}else{
revert();
}
}
event UnstakeResolves(address sender, uint amount);
function unstakeResolves(uint amount) public{
address sender = msg.sender;
if( amount <= ( resolveWeight[sender] - weightLocked[sender] ) ){
resolveWeight[sender] -= amount;
for(uint config = 0; config<CONFIGS; config+=1){
totalVotes_forEach_configOption[config][individualsSelectedOption[config][sender]] -= amount;
}
emit UnstakeResolves(sender, amount);
resolveToken.transfer(sender, amount);
}else{
revert();
}
}
event BackCandidate(address sender,address candidate, uint amount);
function backCandidate(address candidate, uint amount, bool _assert) public{
address sender = msg.sender;
require(candidate!=ORACLE);
if( amount <= ( resolveWeight[sender] - weightLocked[sender] ) && !isWatcher(candidate) ){
weightLocked[sender] += amount;
addShares(candidate, sender, amount);
//I guess candidates should be able to opt into pausing themselves instead of being cast as a delegate right away.
//Idk where else to write this comment
//If the candidate isn't seated, and freezing and pause isn't preventing them from being seated ... then assertCandidate()
if( candidatesChair[candidate] >= hotSeats && !frausted(candidate) && _assert){
assertCandidate(candidate);
}
emit BackCandidate(sender, candidate, amount);
//LAZY U.I.
if(!alreadyBacking[sender][candidate]){
yourBacking[sender].push(candidate);
alreadyBacking[sender][candidate] = true;
}
}else{
revert();
}
}
event WithdrawBacking(address sender,address candidate, uint amount);
function withdrawBacking(address candidate, uint amount) public{
address sender = msg.sender;
if( amount <= shares[candidate][sender] && !frozen[candidate] && ( !(candidatesChair[candidate]<hotSeats) || paused[candidate] ) ){
weightLocked[sender] -= amount;
removeShares(candidate, sender, amount);
emit WithdrawBacking(sender, candidate, amount);
}else{
revert();
}
}
function frausted(address candidate) public view returns(bool){
return paused[candidate] || frozen[candidate];
}
event AssertCandidate(address candidate, bool asserted, address replacedWatcher, uint newSeat);
function assertCandidate(address candidate) public returns(bool){
if(candidatesChair[candidate] >= hotSeats && candidate != ORACLE && !frausted(candidate) ){
address weakestLink = chairsCandidate[0];
bool thereIsAFraustedDelegate;
uint chairNumber;
address comparedDelegate;
for(uint i = 0; i<hotSeats; i+=1){
comparedDelegate = chairsCandidate[i];
if(thereIsAFraustedDelegate && frausted(comparedDelegate) ){
if( totalShares[comparedDelegate] < totalShares[weakestLink] ){
weakestLink = comparedDelegate;
chairNumber = i;
}
}else{
if( frausted(comparedDelegate) ){
thereIsAFraustedDelegate = true;
weakestLink = comparedDelegate;
chairNumber = i;
}else if( totalShares[comparedDelegate] < totalShares[weakestLink] ){
weakestLink = comparedDelegate;
chairNumber = i;
}
}
}
//check if we can swap out seated watcher & then swap 'em
if( totalShares[candidate] > totalShares[weakestLink] || thereIsAFraustedDelegate ){
uint theChairForTheLoser;
if(hasChair[candidate]){
theChairForTheLoser = candidatesChair[candidate];
}else{
hasChair[candidate] = true;
theChairForTheLoser = chairs;
chairs += 1;
}
//
//old candidate getting bumped
removeShares(ORACLE, weakestLink, totalShares[weakestLink]);
candidatesChair[ weakestLink ] = theChairForTheLoser;
chairsCandidate[theChairForTheLoser] = weakestLink;
//new candidate sitting at the round table
addShares(ORACLE, candidate, totalShares[candidate]);
chairsCandidate[chairNumber] = candidate;
candidatesChair[candidate] = chairNumber;
emit AssertCandidate(candidate, true, weakestLink, chairNumber);
return true;
}else{
if(!hasChair[candidate]){
hasChair[candidate] = true;
candidatesChair[candidate] = chairs;
chairsCandidate[chairs] = candidate;
emit AssertCandidate(candidate, false, address0, chairs);
chairs+=1;
return false;
}else{
revert();
}
}
}else{
revert();
}
}
event OptionVote(address sender, uint8 config, uint option, uint weight);
function optionVote(bool[] memory isModifying, uint[] memory modifiedOptions) public{
address sender = msg.sender;
for(uint8 config = 0; config<CONFIGS; config+=1){
if(isModifying[config]){
uint selectedOption = individualsSelectedOption[config][sender];
totalVotes_forEach_configOption[config][ selectedOption ] -= resolveWeight[sender];
individualsSelectedOption[config][sender] = modifiedOptions[config];
totalVotes_forEach_configOption[config][ modifiedOptions[config] ] += resolveWeight[sender];
emit OptionVote(sender, config, modifiedOptions[config], resolveWeight[sender]);
assertOption( config, modifiedOptions[config] );
}
}
}
event AssertOption(uint8 config, uint option);
function assertOption(uint8 config, uint option) public{
if( totalVotes_forEach_configOption[config][option] > totalVotes_forEach_configOption[config][ oracleConfigurations[config] ] ){
oracleConfigurations[config] = option;
emit AssertOption(config, option);
}
}
function isWatcher(address candidate) public view returns(bool){
return candidatesChair[candidate]<hotSeats && !frausted(candidate);
}
function getFee() public view returns(uint txCoverageFee, uint serviceFee){
uint activeWatchers;
for(uint chair = 0; chair<hotSeats; chair+=1){
if( !frausted(chairsCandidate[chair]) ){
activeWatchers += 1;
}
}
return ( TX_FEE_PER*activeWatchers, oracleConfigurations[SERVICE_FEE] );
}
//------------------------------ Request Ticket Life Cycle
event FileRequestTicket(address sender, uint ticketID, string query, uint timeRequested, uint8 dataType, uint feePaid);
function fileRequestTicket(string memory query, uint8 returnType, bool needsResponse, uint additionalTime, bool subjective) public payable returns(uint ticketID){
uint ETH = msg.value;
(uint txCoverageFee, uint serviceFee) = getFee();
if(ETH == txCoverageFee + serviceFee ){
RequestTicket memory ticket;
ticket.query = query;
ticket.timeRequested = now;
ticket.ID = requestTickets.length;
ticket.sender = msg.sender;
ticket.needsResponse = needsResponse;
ticket.subjective = subjective;
ticket.additionalTime = additionalTime;
Poll memory poll;
if(returnType>3)
returnType = 3;
poll.dataType = returnType;
ticket.poll = poll;
requestTickets.push(ticket);
ticket.txCoverageFee = txCoverageFee;
ticket.serviceFee = serviceFee;
emit FileRequestTicket(msg.sender, ticketID, query, now, returnType, ETH);
return ticket.ID;
}else{
revert();
}
}
event CommitVote(address sender, bytes hash);
function commitVote(uint[] memory tickets, bytes[] memory voteHashes) public{
address sender = msg.sender;
//RequestTicket storage ticket;
for(uint R; R<tickets.length; R+=1 ){
//ticket = requestTickets[ tickets[R] ];
if(now <= requestTickets[ tickets[R] ].timeRequested + requestTickets[ tickets[R] ].additionalTime + oracleConfigurations[COMMIT_TIME_WINDOW] ){
requestTickets[ tickets[R] ].poll.committed[sender] = true;
requestTickets[ tickets[R] ].poll.commitHash[sender] = voteHashes[R];
emit CommitVote(sender, voteHashes[R]);
}
}
}
event RevealVote(address voter, uint ticketID, bool rejected, /*suba*/ string stringVote, uint uintVote, bool boolVote, address addressVote);
function revealVote(uint[] memory tickets, bool[] memory rejected, string[] memory stringVotes, uint[] memory uintVotes, bool[] memory boolVotes, address[] memory addressVotes, string[] memory passwords) public{
address sender = msg.sender;
RequestTicket memory ticket;
bytes memory abiEncodePacked;
for(uint R; R<tickets.length; R+=1 ){
ticket = requestTickets[ tickets[R] ];
if(now > ticket.timeRequested + ticket.additionalTime + oracleConfigurations[COMMIT_TIME_WINDOW] && now <= ticket.timeRequested + ticket.additionalTime + oracleConfigurations[COMMIT_TIME_WINDOW] + oracleConfigurations[REVEAL_TIME_WINDOW] ){
if(ticket.poll.dataType == 0){
abiEncodePacked = abi.encodePacked( rejected[R], stringVotes[R], passwords[R] );
}else if(ticket.poll.dataType == 1){
abiEncodePacked = abi.encodePacked( rejected[R], uintVotes[R], passwords[R] );
}else if(ticket.poll.dataType == 2){
abiEncodePacked = abi.encodePacked( rejected[R], boolVotes[R], passwords[R] );
}else if(ticket.poll.dataType == 3){
abiEncodePacked = abi.encodePacked( rejected[R], addressVotes[R], passwords[R] );
}
if( compareBytes( abiEncodePacked, requestTickets[ tickets[R] ].poll.commitHash[sender]) ){
requestTickets[ tickets[R] ].poll.revealed[sender] = true;
if(rejected[R]){
requestTickets[ tickets[R] ].poll.rejected[sender] = true;
}else{
requestTickets[ tickets[R] ].poll.voted[sender] = true;
if(ticket.poll.dataType == 0){
requestTickets[ tickets[R] ].poll.stringVotes[sender] = stringVotes[R];
}else if(ticket.poll.dataType == 1){
requestTickets[ tickets[R] ].poll.uintVotes[sender] = uintVotes[R];
}else if(ticket.poll.dataType == 2){
requestTickets[ tickets[R] ].poll.boolVotes[sender] = boolVotes[R];
}else if(ticket.poll.dataType == 3){
requestTickets[ tickets[R] ].poll.addressVotes[sender] = addressVotes[R];
}
}
emit RevealVote(sender, tickets[R], rejected[R], stringVotes[R], uintVotes[R], boolVotes[R], addressVotes[R]);
}
}
}
}
event FinalizedRequestOptions(string[] stringOptions, uint[] uintOptions, bool[] boolOptions, address[] addressOptions, address[] watchers);
function finalizeRequest(uint ticketID) public{
// if response time window is over or all delegates have voted,
// anyone can finalize the request to trigger the event
RequestTicket storage ticket = requestTickets[ticketID];
if(!ticket.finalized){
uint totalEligibleWeight;
address watcher;
//uint WEIGHTS[0];
//uint WEIGHTS[1];
uint[] memory WEIGHTS = new uint[](2);//0 weight of votes | 1 weight of rejections
string[] memory stringOptions = new string[](hotSeats);
uint[] memory uintOptions = new uint[](hotSeats);
bool[] memory boolOptions = new bool[](hotSeats);
address[] memory addressOptions = new address[](hotSeats);
uint[] memory optionWeights = new uint[](hotSeats);
address[] memory watchers = new address[](hotSeats);// LAZY UI data
//uint options;
uint[] memory OPT = new uint[](2);//0= number of options, 1=top Option
//uint weight;
//uint topOption;
uint opt;
for(uint chair = 0; chair < hotSeats; chair+=1){
watcher = chairsCandidate[chair];
watchers[chair] = watcher;
//weight = totalShares[watcher];
if( !frausted(watcher) && timeSeated[watcher] <= ticket.timeRequested ){
totalEligibleWeight += totalShares[watcher];
if(ticket.poll.voted[watcher]){
WEIGHTS[0] += totalShares[watcher];
//check to see if chosen option already is accounted for, if so, add weight to it.
for(opt = 0; opt<OPT[0]; opt+=1){
if( (ticket.poll.dataType == 0 && compareStrings(stringOptions[opt],ticket.poll.stringVotes[watcher]) ) ||
(ticket.poll.dataType == 1 && uintOptions[opt] == ticket.poll.uintVotes[watcher]) ||
(ticket.poll.dataType == 2 && boolOptions[opt] == ticket.poll.boolVotes[watcher]) ||
(ticket.poll.dataType == 3 && addressOptions[opt] == ticket.poll.addressVotes[watcher])
){
optionWeights[opt] += totalShares[watcher];
if(optionWeights[opt] > optionWeights[OPT[1]]){
OPT[1] = opt;
}
break;
}
}
//add new unique option
if(opt == OPT[0]){
if(ticket.poll.dataType == 0){
stringOptions[OPT[0]] = ticket.poll.stringVotes[watcher];
}else if(ticket.poll.dataType == 1){
uintOptions[OPT[0]] = ticket.poll.uintVotes[watcher];
}else if(ticket.poll.dataType == 2){
boolOptions[OPT[0]] = ticket.poll.boolVotes[watcher];
}else if(ticket.poll.dataType == 3){
addressOptions[OPT[0]] = ticket.poll.addressVotes[watcher];
}
optionWeights[OPT[0]] = totalShares[watcher];
OPT[0]+=1;
}
}else if(ticket.poll.rejected[watcher]){
WEIGHTS[1] += totalShares[watcher];
}
}
}
if( totalEligibleWeight == (WEIGHTS[1] + WEIGHTS[0]) || now > ticket.timeRequested + ticket.additionalTime+oracleConfigurations[REVEAL_TIME_WINDOW]+oracleConfigurations[COMMIT_TIME_WINDOW] ){
bool rejected;
if( WEIGHTS[1] > optionWeights[OPT[1]] ){
rejected = true;
}
//dish out the rewards
earningsPerShare[ORACLE] += ticket.serviceFee * scaleFactor / totalShares[ORACLE];
earningsPerWatcher += ticket.txCoverageFee / totalWatchers;
//write results in stone
if(rejected){
ticket.rejected = true;
}else{
uint8 dataType = ticket.poll.dataType;
if(dataType == 0){
ticket.resolvedString = stringOptions[OPT[1]];
}else if(dataType == 1){
ticket.resolvedUint = uintOptions[OPT[1]];
}else if(dataType == 2){
ticket.resolvedBool = boolOptions[OPT[1]];
}else if(dataType == 3){
ticket.resolvedAddress = addressOptions[OPT[1]];
}
}
ticket.finalized = true;
EMIT_FinalizeRequestData(ticket);
emit FinalizedRequestOptions( stringOptions, uintOptions, boolOptions, addressOptions, watchers);
//return results to requestor
if( isContract(ticket.sender) && ticket.needsResponse){
sendOracleResponse(ticket);
}
}else{
revert();
}
}
}
event FinalizedRequestTicketData(uint ticketID, string query, uint8 dataType, bool rejected, string resolvedString, uint resolvedUint, bool resolvedBool, address resolvedAddress);
function EMIT_FinalizeRequestData(RequestTicket storage ticket) internal{
FinalizedRequestTicketData(ticket.ID, ticket.query, ticket.poll.dataType, ticket.rejected, ticket.resolvedString, ticket.resolvedUint, ticket.resolvedBool, ticket.resolvedAddress);
}
function sendOracleResponse(RequestTicket memory ticket) internal{
address(ticket.sender).call(abi.encodeWithSignature("receiveOracleResponse(bool,string,uint,bool,address)",ticket.rejected, ticket.resolvedString,ticket.resolvedUint,ticket.resolvedBool,ticket.resolvedAddress ) );
}
function cashout(address[] memory pools) public{
address payable sender = msg.sender;
for(uint p; p < pools.length; p+=1){
update(pools[p], sender);
}
uint ETH = earnings[sender];
earnings[sender] = 0;
sender.transfer( ETH );
}
function runWatcherPayroll(address watcher) public{
update(ORACLE, addressPayable(watcher) );
updateWatcherTxEarnings(addressPayable(watcher) );
}
function tryToPunish(uint[] memory tickets, address[] memory watchers) public{
freezeNoncommits(tickets, watchers);
freezeUnrevealedCommits(tickets, watchers);
freezeWrongWatchers(tickets, watchers);
}
event FreezeNoncommits(uint ticketID, address watcher);
function freezeNoncommits(uint[] memory tickets, address[] memory watchers) public{
// get them while they're still at the round table and we're in the reveal phase of a ticket
for(uint i; i<watchers.length; i+=1){
if( candidatesChair[watchers[i]] < hotSeats &&
!requestTickets[ tickets[i] ].poll.committed[ watchers[i] ] &&
now > requestTickets[ tickets[i] ].timeRequested + requestTickets[ tickets[i] ].additionalTime + oracleConfigurations[COMMIT_TIME_WINDOW] &&
now <= requestTickets[ tickets[i] ].timeRequested + requestTickets[ tickets[i] ].additionalTime + oracleConfigurations[COMMIT_TIME_WINDOW] + oracleConfigurations[REVEAL_TIME_WINDOW]
){
if(punish(tickets[i] , watchers[i]) ){
emit FreezeNoncommits(tickets[i] , watchers[i]);
}
}
}
}
event FreezeUnrevealedCommits(uint ticketID, address watcher);
function freezeUnrevealedCommits(uint[] memory tickets, address[] memory watchers) public{
// get them if they made a commit, but did not reveal it after the reveal window is over
for(uint i; i<watchers.length; i+=1){
if( requestTickets[ tickets[i] ].poll.committed[ watchers[i] ] &&
!requestTickets[ tickets[i] ].poll.revealed[ watchers[i] ] &&
now > requestTickets[ tickets[i] ].timeRequested + requestTickets[ tickets[i] ].additionalTime + oracleConfigurations[COMMIT_TIME_WINDOW] + oracleConfigurations[REVEAL_TIME_WINDOW]
){
if(punish(tickets[i] , watchers[i]) ){
emit FreezeUnrevealedCommits(tickets[i] , watchers[i]);
}
}
}
}
event FreezeWrongWatchers(uint ticketID, address watcher);
function freezeWrongWatchers(uint[] memory tickets, address[] memory watchers) public{
// get them if the ticket is finalized and their vote doesn't match the resolved answer
uint ticket;
address watcher;
for(uint i; i<watchers.length; i+=1){
ticket = tickets[i];
watcher = watchers[i];
if( requestTickets[ ticket ].finalized &&
(
(requestTickets[ ticket ].poll.dataType == 0 && !compareStrings(requestTickets[ ticket ].resolvedString, requestTickets[ ticket ].poll.stringVotes[ watcher ] ))||
(requestTickets[ ticket ].poll.dataType == 1 && requestTickets[ ticket ].resolvedUint != requestTickets[ ticket ].poll.uintVotes[ watcher ] )||
(requestTickets[ ticket ].poll.dataType == 2 && requestTickets[ ticket ].resolvedBool != requestTickets[ ticket ].poll.boolVotes[ watcher ] )||
(requestTickets[ ticket ].poll.dataType == 3 && requestTickets[ ticket ].resolvedAddress != requestTickets[ ticket ].poll.addressVotes[ watcher ] )
)
){
if(punish(ticket , watcher)){
emit FreezeWrongWatchers(ticket , watcher);
}
}
}
}
event Punish(uint thatOutTime, bool freshFreeze, bool knockOff);
function punish(uint ticketID, address watcher) internal returns(bool punished){
if(!requestTickets[ticketID].punished[watcher] && timeSeated[watcher] <= requestTickets[ ticketID ].timeRequested ){
frozen[watcher] = true;
bool freshFreeze;
bool knockOff;
if(timeWhenThawedOut[watcher] > now){
timeWhenThawedOut[watcher] += oracleConfigurations[FREEZE_TIMEOUT];
}else{
timeWhenThawedOut[watcher] = now + oracleConfigurations[FREEZE_TIMEOUT];
freshFreeze = true;
if(isWatcher(watcher)){
//
removeShares(ORACLE, watcher, totalShares[watcher]);
knockOff = true;
}
}
emit Punish(timeWhenThawedOut[watcher], freshFreeze, knockOff);
return true;
}
return false;
}
event Thaw(address candidate, bool seated);
function thaw(address candidate, bool _assert) public{
if( now >= timeWhenThawedOut[candidate] ){
bool seated;
frozen[candidate] = false;
if( candidatesChair[candidate] < hotSeats && !paused[candidate]){
//
addShares(ORACLE, candidate, totalShares[candidate]);
seated = true;
}else if( _assert ){
seated = assertCandidate(candidate);
}
emit Thaw(candidate, seated);
}else{
revert();
}
}
event PauseOut(address sender, bool wasWatcher);
function pauseOut() public{
address sender = msg.sender;
bool wasWatcher;
if(isWatcher(sender)){
wasWatcher = true;
//
removeShares(ORACLE, sender, totalShares[sender]);
}
paused[sender] = true;
emit PauseOut(sender, wasWatcher);
}
event Unpause(address sender, bool seated);
function unpause(bool _assert) public{
address sender = msg.sender;
paused[sender] = false;
bool seated;
if( candidatesChair[sender] < hotSeats && !frozen[sender]){
//
addShares(ORACLE, sender, totalShares[sender]);
seated = true;
}else if( _assert ){
seated = assertCandidate(sender);
}
emit Unpause(sender, seated);
}
event UpdateRoundTable(uint newTotalHotSeats);
function updateRoundTable(uint seats) public{
// update hotSeats up and down.
address candidate;
for(uint s; s<seats; s+=1){
if( oracleConfigurations[ROUNDTABLE_SEATS] > hotSeats ){
candidate = chairsCandidate[hotSeats];
if(candidate == address0){
break;
}else{
//
addShares(ORACLE, candidate, totalShares[candidate]);
hotSeats += 1;
}
}
if( oracleConfigurations[ROUNDTABLE_SEATS] < hotSeats ){
candidate = chairsCandidate[hotSeats-1];
//
removeShares(ORACLE, candidate, totalShares[candidate]);
hotSeats -= 1;
}
if( oracleConfigurations[ROUNDTABLE_SEATS] == hotSeats ){break;}
}
emit UpdateRoundTable(hotSeats);
}
function viewRequestTickets(uint[] memory ticketIDs) public view returns(
address[] memory sender,
string[] memory query,
uint[] memory timeRequested,
bool[] memory finalized,
uint[] memory txCoverageFeePaid,
uint[] memory serviceFeePaid,
bool[] memory rejected,
string[] memory resolvedString,
uint[] memory resolvedUint,
bool[] memory resolvedBool,
address[] memory resolvedAddress,
uint8[] memory dataType){
uint L = ticketIDs.length;
sender = new address[](L);
query = new string[](L);
timeRequested = new uint[](L);
finalized = new bool[](L);
txCoverageFeePaid = new uint[](L);
serviceFeePaid = new uint[](L);
rejected = new bool[](L);
resolvedString = new string[](L);
resolvedUint = new uint[](L);
resolvedBool = new bool[](L);
resolvedAddress = new address[](L);
dataType = new uint8[](L);
for(uint t; t<L;t+=1){
sender[t] = requestTickets[t].sender;
query[t] = requestTickets[t].query;
timeRequested[t] = requestTickets[t].timeRequested;
finalized[t] = requestTickets[t].finalized;
txCoverageFeePaid[t] = requestTickets[t].txCoverageFee;
serviceFeePaid[t] = requestTickets[t].serviceFee;
rejected[t] = requestTickets[t].rejected;
resolvedString[t] = requestTickets[t].resolvedString;
resolvedUint[t] = requestTickets[t].resolvedUint;
resolvedBool[t] = requestTickets[t].resolvedBool;
resolvedAddress[t] = requestTickets[t].resolvedAddress;
dataType[t] = requestTickets[t].poll.dataType;
}
//return (ticket.sender, ticket.query,ticket.timeRequested,ticket.finalized,ticket.ETH,ticket.rejected,ticket.resolvedString,ticket.resolvedUint,ticket.resolvedBool,ticket.resolvedAddress,ticket.poll.dataType);
}
function viewYourCandidates(address you)public view returns(uint[] memory dividends, uint[] memory seat, bool[] memory isFrozen, bool[] memory isPaused){
uint L = yourBacking[you].length;
dividends = new uint[](L);
seat = new uint[](L);
isFrozen = new bool[](L);
isPaused = new bool[](L);
uint owedPerShare;// = earningsPerShare[pool] - payouts[pool][account];
uint newMoney;// = shares[pool][account] * owedPerShare;
address candidate;
for(uint c;c<L;c+=1){
candidate = yourBacking[you][c];
owedPerShare = earningsPerShare[candidate] - payouts[candidate][you];
newMoney = shares[candidate][you] * owedPerShare;
dividends[c] = newMoney;
seat[c] = candidatesChair[candidate];
isFrozen[c] = frozen[candidate];
isPaused[c] = paused[candidate];
}
}
function compareStrings(string memory a, string memory b) public pure returns (bool) {
return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))) );
}
function compareBytes(bytes memory a, bytes memory b) public pure returns (bool) {
return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))) );
}
function bytesToAddress(bytes memory bys) private pure returns (address addr){
assembly {
addr := mload(add(bys,20))
}
}
function accountData(address account) public view returns(
uint _resolveWeight,
uint _weightLocked,
uint _candidatesChair,
uint _timeSeated,
bool _frozen,
uint _timeWhenThawedOut,
bool _paused,
bool _hasChair,
uint _earnings,
uint _totalShares,
uint _txCoverageFeeEarnings
){
_resolveWeight = resolveWeight[account];
_weightLocked = weightLocked[account];
_candidatesChair = candidatesChair[account];
_timeSeated = timeSeated[account];
_frozen = frozen[account];
_timeWhenThawedOut = timeWhenThawedOut[account];
_paused = paused[account];
_hasChair = hasChair[account];
_earnings = earnings[account];
_totalShares = totalShares[account];
uint txCoverageFeeEarnings;
if( !isWatcher(account) ){
txCoverageFeeEarnings = earningsPerWatcher - watcherPayouts[account];
}
_txCoverageFeeEarnings = txCoverageFeeEarnings;
}
function isContract(address _addr) public view returns (bool is_contract) {
uint length;
assembly {
//retrieve the size of the code on target address, this needs assembly
length := extcodesize(_addr)
}
if(length>0) {
return true;
}else {
return false;
}
}
}
abstract contract OracleInterfacingContract{
function receiveOracleResponse(bool rejected, string calldata STRING, uint UINT, bool BOOL, address ADDRESS) external virtual returns(bool);
}
abstract contract ResolveToken{
function transfer(address _to, uint256 _value) public virtual returns (bool);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment