Skip to content

Instantly share code, notes, and snippets.

@RossPfeiffer
Created August 9, 2020 09:18
Show Gist options
  • Save RossPfeiffer/d19d754e6867c871e302a967acf8e53d to your computer and use it in GitHub Desktop.
Save RossPfeiffer/d19d754e6867c871e302a967acf8e53d to your computer and use it in GitHub Desktop.
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