Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save elenadimitrova/4967a3509d31e76d89dc72902643a218 to your computer and use it in GitHub Desktop.
Save elenadimitrova/4967a3509d31e76d89dc72902643a218 to your computer and use it in GitHub Desktop.
pragma solidity ^0.4.23;
contract ReviewableTaskCollection {
function addTask() {
}
struct Task {
bytes32 specificationHash;
uint256 dueDate;
// Role Ids mapping to user addresses, using role Ids:
// 0 - task manager, 1 - task evaluator, 2 - task work
mapping (uint8 => address) roles;
// Maps task role ids (0,1,2) to payment amount
mapping (uint8 => uint256) payouts;
}
mapping (uint256 => Task) tasks;
uint256 taskCount;
uint8 constant MANAGER = 0;
uint8 constant EVALUATOR = 1;
uint8 constant WORKER = 2;
// Mapping task id to current "active" nonce for executing task changes
mapping (uint256 => uint256) taskChangeNonces;
// Mapping function signature to 2 task roles whose approval is needed to execute
mapping (bytes4 => uint8[2]) reviewers;
modifier self() {
require(address(this) == msg.sender);
_;
}
constructor() {
setFunctionReviewers(bytes4(keccak256("setTaskBrief(uint256,bytes32)")), MANAGER, WORKER);
setFunctionReviewers(bytes4(keccak256("setTaskDueDate(uint256,uint256)")), MANAGER, WORKER);
setFunctionReviewers(bytes4(keccak256("setTaskEvaluatorPayout(uint256,uint256)")), MANAGER, EVALUATOR);
setFunctionReviewers(bytes4(keccak256("setTaskWorkerPayout(uint256,uint256)")), MANAGER, WORKER);
}
function setFunctionReviewers(bytes4 _sig, uint8 _firstReviewer, uint8 _secondReviewer)
private
{
uint8[2] memory _reviewers = [_firstReviewer, _secondReviewer];
reviewers[_sig] = _reviewers;
}
function setTaskBrief(uint256 _id, bytes32 _specificationHash) public self {
tasks[_id].specificationHash = _specificationHash;
}
function setTaskDueDate(uint256 _id, uint256 _dueDate) public self {
tasks[_id].dueDate = _dueDate;
}
function setTaskEvaluatorPayout(uint256 _id, uint256 _amount) public self {
tasks[_id].payouts[EVALUATOR] = _amount;
}
function setTaskWorkerPayout(uint256 _id, uint256 _amount) public self {
tasks[_id].payouts[WORKER] = _amount;
}
function executeTaskChange(uint8[] _sigV, bytes32[] _sigR, bytes32[] _sigS, uint256 _value, bytes _data) public {
require(_sigR.length == 2);
bytes4 sig;
uint256 taskId;
(sig, taskId) = deconstructCall(_data);
bytes32 msgHash = keccak256(abi.encodePacked(address(this), address(this), _value, _data, taskChangeNonces[taskId]));
address[] memory reviewerAddresses = new address[](2);
for (uint i = 0; i < 2; i++) {
bytes32 txHash;
txHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", msgHash));
reviewerAddresses[i] = ecrecover(txHash, _sigV[i], _sigR[i], _sigS[i]);
}
require(reviewerAddresses[0] != reviewerAddresses[1]);
require(
reviewerAddresses[0] == tasks[taskId].roles[reviewers[sig][0]] ||
reviewerAddresses[0] == tasks[taskId].roles[reviewers[sig][1]]
);
require(
reviewerAddresses[1] == tasks[taskId].roles[reviewers[sig][0]] ||
reviewerAddresses[1] == tasks[taskId].roles[reviewers[sig][1]]
);
taskChangeNonces[taskId] += 1;
require(executeCall(address(this), _value, _data));
}
// The address.call() syntax is no longer recommended, see:
// https://github.com/ethereum/solidity/issues/2884
function executeCall(address to, uint256 value, bytes data) internal returns (bool success) {
assembly {
success := call(gas, to, value, add(data, 0x20), mload(data), 0, 0)
}
}
// Get the function signature and task id from the transaction bytes data
// Note: Relies on the encoded function's first parameter to be the uint256 taskId
function deconstructCall(bytes _data) internal pure returns (bytes4 sig, uint256 taskId) {
assembly {
sig := mload(add(_data, 0x20))
taskId := mload(add(_data, 0x24))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment