Created
August 9, 2020 09:18
-
-
Save RossPfeiffer/d19d754e6867c871e302a967acf8e53d to your computer and use it in GitHub Desktop.
This file contains 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
pragma solidity ^ 0.6.8; | |
pragma experimental ABIEncoderV2; | |
contract Oracle{ | |
address payable ORACLE = address(0); | |
address address0 = address(0); | |
//oracle configs | |
/* | |
uint constant 0 = 0; | |
uint constant 1 = 1; | |
uint constant 2 = 2; | |
uint constant 3 = 3; | |
uint constant 4 = 4; | |
uint constant 5 = 5; | |
uint constant 6 = 6; | |
uint constant 7 = 7; | |
uint constant 8 = 8;*/ | |
uint[] oracleConfigurations = new uint[](8); | |
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[] public 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 public 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[3]; | |
uint ers = oracleConfigurations[4]; | |
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<1/*8*/; config+=1){ | |
option = individualsSelectedOption[config][from]; | |
totalVotes_forEach_configOption[config][option] += value; | |
assertOption(config, option); | |
} | |
emit StakeResolves(from, value, _data); | |
address backImmediately = Common.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<8; 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<8; 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 ( 6*activeWatchers, oracleConfigurations[7] ); | |
} | |
//------------------------------ Request Ticket Life Cycle | |
event FileRequestTicket(address sender, RequestTicket requestTicket, string query, uint timeRequested, uint8 dataType, uint feePaid); | |
function fileRequestTicket(string memory query, uint8 returnType, bool needsResponse, uint additionalTime, bool subjective) public payable returns(RequestTicket ticketID){ | |
uint ETH = msg.value; | |
(uint txCoverageFee, uint serviceFee) = getFee(); | |
if(ETH == txCoverageFee + serviceFee ){ | |
RequestTicket requestTicket = new RequestTicket(query, returnType, now, requestTickets.length, msg.sender, needsResponse, subjective, additionalTime, txCoverageFee, serviceFee); | |
requestTickets.push( requestTicket ); | |
emit FileRequestTicket(msg.sender, requestTicket, query, now, returnType, ETH); | |
return requestTicket; | |
}else{ | |
revert(); | |
} | |
} | |
event CommitVote(address sender, bytes hash); | |
function commitVote(uint[] memory tickets, bytes[] memory voteHashes) public{ | |
address sender = msg.sender; | |
RequestTicket ticket; | |
for(uint R; R<tickets.length; R+=1 ){ | |
ticket = requestTickets[ tickets[R] ]; | |
if(now <= ticket.timeRequested() + oracleConfigurations[1] ){ | |
ticket._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 ticket; | |
bytes memory abiEncodePacked; | |
for(uint R; R<tickets.length; R+=1 ){ | |
ticket = requestTickets[ tickets[R] ]; | |
if(now > ticket.timeRequested() + oracleConfigurations[1] && now <= ticket.timeRequested() + oracleConfigurations[1] + oracleConfigurations[2] ){ | |
if(ticket.dataType() == 0){ | |
abiEncodePacked = abi.encodePacked( rejected[R], stringVotes[R], passwords[R] ); | |
}else if(ticket.dataType() == 1){ | |
abiEncodePacked = abi.encodePacked( rejected[R], uintVotes[R], passwords[R] ); | |
}else if(ticket.dataType() == 2){ | |
abiEncodePacked = abi.encodePacked( rejected[R], boolVotes[R], passwords[R] ); | |
}else if(ticket.dataType() == 3){ | |
abiEncodePacked = abi.encodePacked( rejected[R], addressVotes[R], passwords[R] ); | |
} | |
if( Common.compareBytes( abiEncodePacked, ticket.commitHash(sender)) ){ | |
bool isRejected; | |
bool voted; | |
if(rejected[R]){ | |
isRejected = true; | |
}else{ | |
voted = true; | |
} | |
ticket._reveal(sender, isRejected, voted, stringVotes[R], uintVotes[R], boolVotes[R], 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 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.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.dataType() == 0 && Common.compareStrings(stringOptions[opt], ticket.stringVotes(watcher)) ) || | |
(ticket.dataType() == 1 && uintOptions[opt] == ticket.uintVotes(watcher)) || | |
(ticket.dataType() == 2 && boolOptions[opt] == ticket.boolVotes(watcher)) || | |
(ticket.dataType() == 3 && addressOptions[opt] == ticket.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.dataType() == 0){ | |
stringOptions[OPT[0]] = ticket.stringVotes(watcher); | |
}else if(ticket.dataType() == 1){ | |
uintOptions[OPT[0]] = ticket.uintVotes(watcher); | |
}else if(ticket.dataType() == 2){ | |
boolOptions[OPT[0]] = ticket.boolVotes(watcher); | |
}else if(ticket.dataType() == 3){ | |
addressOptions[OPT[0]] = ticket.addressVotes(watcher); | |
} | |
optionWeights[OPT[0]] = totalShares[watcher]; | |
OPT[0]+=1; | |
} | |
}else if(ticket.rejected(watcher)){ | |
WEIGHTS[1] += totalShares[watcher]; | |
} | |
} | |
} | |
if( totalEligibleWeight == (WEIGHTS[1] + WEIGHTS[0]) || now > ticket.timeRequested()+oracleConfigurations[2]+oracleConfigurations[1] ){ | |
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 | |
ticket._resolve(rejected, stringOptions[OPT[1]], uintOptions[OPT[1]], boolOptions[OPT[1]], addressOptions[OPT[1]] ); | |
ticket._finalize(); | |
emit FinalizedRequestOptions( stringOptions, uintOptions, boolOptions, addressOptions, watchers); | |
//return results to requestor | |
if( Common.isContract(ticket.sender()) && ticket.needsResponse()){ | |
sendOracleResponse(ticket); | |
} | |
}else{ | |
revert(); | |
} | |
} | |
} | |
function sendOracleResponse(RequestTicket 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] ].committed( watchers[i] ) && | |
now > requestTickets[ tickets[i] ].timeRequested() + oracleConfigurations[1] && | |
now <= requestTickets[ tickets[i] ].timeRequested() + oracleConfigurations[1] + oracleConfigurations[2] | |
){ | |
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] ].committed( watchers[i] ) && | |
!requestTickets[ tickets[i] ].revealed( watchers[i] ) && | |
now > requestTickets[ tickets[i] ].timeRequested() + oracleConfigurations[1] + oracleConfigurations[2] | |
){ | |
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 ].dataType() == 0 && !Common.compareStrings(requestTickets[ ticket ].resolvedString(), requestTickets[ ticket ].stringVotes(watcher) ))|| | |
(requestTickets[ ticket ].dataType() == 1 && requestTickets[ ticket ].resolvedUint() != requestTickets[ ticket ].uintVotes(watcher) )|| | |
(requestTickets[ ticket ].dataType() == 2 && requestTickets[ ticket ].resolvedBool() != requestTickets[ ticket ].boolVotes(watcher) )|| | |
(requestTickets[ ticket ].dataType() == 3 && requestTickets[ ticket ].resolvedAddress() != requestTickets[ ticket ].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[5]; | |
}else{ | |
timeWhenThawedOut[watcher] = now + oracleConfigurations[5]; | |
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[0] > hotSeats ){ | |
candidate = chairsCandidate[hotSeats]; | |
if(candidate == address0){ | |
break; | |
}else{ | |
// | |
addShares(ORACLE, candidate, totalShares[candidate]); | |
hotSeats += 1; | |
} | |
} | |
if( oracleConfigurations[0] < hotSeats ){ | |
candidate = chairsCandidate[hotSeats-1]; | |
// | |
removeShares(ORACLE, candidate, totalShares[candidate]); | |
hotSeats -= 1; | |
} | |
if( oracleConfigurations[0] == 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].isRejected(); | |
resolvedString[t] = requestTickets[t].resolvedString(); | |
resolvedUint[t] = requestTickets[t].resolvedUint(); | |
resolvedBool[t] = requestTickets[t].resolvedBool(); | |
resolvedAddress[t] = requestTickets[t].resolvedAddress(); | |
dataType[t] = requestTickets[t].dataType(); | |
} | |
//return (ticket.sender, ticket.query,ticket.timeRequested,ticket.finalized,ticket.ETH,ticket.rejected,ticket.resolvedString,ticket.resolvedUint,ticket.resolvedBool,ticket.resolvedAddress,ticket.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 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; | |
} | |
} | |
library Common{ | |
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) public pure returns (address addr){ | |
assembly { | |
addr := mload(add(bys,20)) | |
} | |
} | |
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); | |
} | |
contract RequestTicket{ | |
uint public ID; | |
address public sender; | |
string public query; | |
uint public timeRequested; | |
bool public finalized; | |
uint public additionalTime; | |
bool public subjective; | |
uint public txCoverageFee; | |
uint public serviceFee; | |
bool public needsResponse; | |
bool public isRejected; | |
string public resolvedString; | |
uint public resolvedUint; | |
bool public resolvedBool; | |
address public resolvedAddress; | |
uint8 public dataType; // string, uint, bool, address | |
//commit | |
mapping(address => bool) public committed; | |
mapping(address => bytes) public commitHash; | |
//reveal | |
mapping(address => bool) public revealed; | |
mapping(address => bool) public rejected; | |
mapping(address => bool) public voted; | |
mapping(address => string) public stringVotes; | |
mapping(address => uint) public uintVotes; | |
mapping(address => bool) public boolVotes; | |
mapping(address => address) public addressVotes; | |
mapping(address => bool) public punished; | |
address oracle; | |
constructor(string memory _query, uint8 _dataType, uint _timeRequested, uint _ID, address _sender, bool _needsResponse, bool _subjective, uint _additionalTime, uint _txCoverageFee, uint _serviceFee) public{ | |
oracle = msg.sender; | |
query = _query; | |
dataType = _dataType; | |
timeRequested = _timeRequested; | |
ID = _ID; | |
sender = _sender; | |
needsResponse = _needsResponse; | |
subjective = _subjective; | |
additionalTime = _additionalTime; | |
txCoverageFee = _txCoverageFee; | |
serviceFee = _serviceFee; | |
} | |
modifier oracleOnly{ | |
require( msg.sender == oracle ); | |
_; | |
} | |
function _commitHash(address _sender, bytes memory voteHash) external oracleOnly(){ | |
committed[_sender] = true; | |
commitHash[_sender] = voteHash; | |
} | |
function _reveal(address _sender, bool _rejected, bool _voted, string memory stringVote, uint uintVote, bool boolVote, address addressVote) external oracleOnly(){ | |
revealed[_sender] = true; | |
rejected[_sender] = _rejected; | |
voted[_sender] = _voted; | |
stringVotes[_sender] = stringVote; | |
uintVotes[_sender] = uintVote; | |
boolVotes[_sender] = boolVote; | |
addressVotes[_sender] = addressVote; | |
} | |
function _reject() external oracleOnly(){ | |
} | |
function _resolve(bool _isRejected, string memory resolvedStringOption, uint resolvedUintOption, bool resolvedBoolOption, address resolvedAddressOption ) external oracleOnly(){ | |
if(_isRejected){ | |
isRejected = true; | |
}else{ | |
if(dataType == 0){ | |
resolvedString = resolvedStringOption; | |
}else if(dataType == 1){ | |
resolvedUint = resolvedUintOption; | |
}else if(dataType == 2){ | |
resolvedBool = resolvedBoolOption; | |
}else if(dataType == 3){ | |
resolvedAddress = resolvedAddressOption; | |
} | |
} | |
} | |
event FinalizedRequestTicketData(uint ticketID, string query, uint8 dataType, bool rejected, string resolvedString, uint resolvedUint, bool resolvedBool, address resolvedAddress); | |
function _finalize() external oracleOnly(){ | |
finalized = true; | |
emit FinalizedRequestTicketData(ID, query, dataType, isRejected, resolvedString, resolvedUint, resolvedBool, resolvedAddress); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment