Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evaluator reputation update #158

Merged
merged 21 commits into from Feb 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions contracts/Colony.sol
Expand Up @@ -48,7 +48,8 @@ contract Colony is ColonyStorage {
// Initialise the task update reviewers
IColony(this).setFunctionReviewers(0xda4db249, 0, 2); // setTaskBrief => manager, worker
IColony(this).setFunctionReviewers(0xcae960fe, 0, 2); // setTaskDueDate => manager, worker
IColony(this).setFunctionReviewers(0xbe2320af, 0, 2); // setTaskPayout => manager, worker
IColony(this).setFunctionReviewers(0x6fb0794f, 0, 1); // setTaskEvaluatorPayout => manager, evaluator
IColony(this).setFunctionReviewers(0x2cf62b39, 0, 2); // setTaskWorkerPayout => manager, worker

// Initialise the root domain
domainCount += 1;
Expand All @@ -74,7 +75,7 @@ contract Colony is ColonyStorage {
return colonyNetwork.addSkill(_parentSkillId, true);
}

function addDomain(uint256 _parentSkillId) public
function addDomain(uint256 _parentSkillId) public
localSkill(_parentSkillId)
{
// Note: remove that when we start allowing more domain hierarchy levels
Expand All @@ -86,7 +87,7 @@ contract Colony is ColonyStorage {
// Setup new local skill
IColonyNetwork colonyNetwork = IColonyNetwork(colonyNetworkAddress);
uint256 newLocalSkill = colonyNetwork.addSkill(_parentSkillId, false);

// Add domain to local mapping
domainCount += 1;
potCount += 1;
Expand Down
33 changes: 22 additions & 11 deletions contracts/ColonyFunding.sol
Expand Up @@ -40,18 +40,16 @@ contract ColonyFunding is ColonyStorage, DSMath {
return 100;
}

function setTaskPayout(uint256 _id, uint256 _role, address _token, uint256 _amount) public
self()
taskExists(_id)
taskNotFinalized(_id)
{
Task storage task = tasks[_id];
uint currentAmount = task.payouts[_role][_token];
task.payouts[_role][_token] = _amount;
function setTaskManagerPayout(uint256 _id, address _token, uint256 _amount) public isManager(_id) {
setTaskPayout(_id, 0, _token, _amount);
}

uint currentTotalAmount = task.totalPayouts[_token];
task.totalPayouts[_token] = add(sub(currentTotalAmount, currentAmount), _amount);
updateTaskPayoutsWeCannotMakeAfterBudgetChange(_id, _token, currentTotalAmount);
function setTaskEvaluatorPayout(uint256 _id, address _token, uint256 _amount) public self {
setTaskPayout(_id, 1, _token, _amount);
}

function setTaskWorkerPayout(uint256 _id, address _token, uint256 _amount) public self {
setTaskPayout(_id, 2, _token, _amount);
}

// To get all payouts for a task iterate over roles.length
Expand Down Expand Up @@ -175,4 +173,17 @@ contract ColonyFunding is ColonyStorage, DSMath {
}
}
}

function setTaskPayout(uint256 _id, uint256 _role, address _token, uint256 _amount) private
taskExists(_id)
taskNotFinalized(_id)
{
Task storage task = tasks[_id];
uint currentAmount = task.payouts[_role][_token];
task.payouts[_role][_token] = _amount;

uint currentTotalAmount = task.totalPayouts[_token];
task.totalPayouts[_token] = add(sub(currentTotalAmount, currentAmount), _amount);
updateTaskPayoutsWeCannotMakeAfterBudgetChange(_id, _token, currentTotalAmount);
}
}
6 changes: 6 additions & 0 deletions contracts/ColonyStorage.sol
Expand Up @@ -112,6 +112,12 @@ contract ColonyStorage is DSAuth {
uint256 potId;
}

modifier isManager(uint256 _id) {
Task storage task = tasks[_id];
require(task.roles[0].user == msg.sender);
_;
}

modifier taskExists(uint256 _id) {
require(_id <= taskCount);
_;
Expand Down
48 changes: 21 additions & 27 deletions contracts/ColonyTask.sol
Expand Up @@ -52,7 +52,7 @@ contract ColonyTask is ColonyStorage, DSMath {
} else {
revert();
}
_;
_;
}

modifier ratingSecretDoesNotExist(uint256 _id, uint8 _role) {
Expand Down Expand Up @@ -86,7 +86,7 @@ contract ColonyTask is ColonyStorage, DSMath {
modifier taskWorkRatingRevealOpen(uint256 _id) {
RatingSecrets storage ratingSecrets = taskWorkRatings[_id];
require(ratingSecrets.count <= 2);

// If both ratings have been received, start the reveal period from the time of the last rating commit
// Otherwise start the reveal period after the commit period has expired
// In both cases, keep reveal period open for 5 days
Expand Down Expand Up @@ -130,10 +130,10 @@ contract ColonyTask is ColonyStorage, DSMath {
rated: false,
rating: 0
});

pots[potCount].taskId = taskCount;
setTaskDomain(taskCount, _domainId);

TaskAdded(taskCount);
}

Expand Down Expand Up @@ -171,7 +171,7 @@ contract ColonyTask is ColonyStorage, DSMath {
IColony(this).confirmTransaction(_transactionId, _role);
}

function submitTaskWorkRating(uint256 _id, uint8 _role, bytes32 _ratingSecret) public
function submitTaskWorkRating(uint256 _id, uint8 _role, bytes32 _ratingSecret) public
userCanRateRole(_id, _role)
ratingSecretDoesNotExist(_id, _role)
taskWorkRatingCommitOpen(_id)
Expand All @@ -182,19 +182,19 @@ contract ColonyTask is ColonyStorage, DSMath {
ratingSecrets.secret[_role] = _ratingSecret;
}

function revealTaskWorkRating(uint256 _id, uint8 _role, uint8 _rating, bytes32 _salt) public
function revealTaskWorkRating(uint256 _id, uint8 _role, uint8 _rating, bytes32 _salt) public
taskWorkRatingRevealOpen(_id)
{
bytes32 ratingSecret = generateSecret(_salt, _rating);
require(ratingSecret == taskWorkRatings[_id].secret[_role]);

Role storage role = tasks[_id].roles[_role];
role.rated = true;
role.rating = _rating;
}

// In the event of a user not committing or revealing within the 10 day rating window,
// their rating of their counterpart is assumed to be the highest possible
// In the event of a user not committing or revealing within the 10 day rating window,
// their rating of their counterpart is assumed to be the highest possible
// and their own rating is decreased by 5 (e.g. 0.5 points)
function assignWorkRating(uint256 _id) public
taskWorkRatingsClosed(_id)
Expand Down Expand Up @@ -292,27 +292,21 @@ contract ColonyTask is ColonyStorage, DSMath {
taskNotFinalized(_id)
{
Task storage task = tasks[_id];
Role storage managerRole = task.roles[MANAGER];
Role storage workerRole = task.roles[WORKER];

task.finalized = true;

IColonyNetwork colonyNetworkContract = IColonyNetwork(colonyNetworkAddress);
uint skillId = task.skills[0];

uint managerPayout = task.payouts[MANAGER][token];
uint workerPayout = task.payouts[WORKER][token];

// NOTE: Ratings are already 10 multiplied because of the requirement to support 0.5 subtraction of rating values
// NOTE: reputation change amount is hereby limited to MAXINT/50
int managerReputation = SafeMath.mulInt(int(managerPayout), (int(managerRole.rating)*2 - 50)) / 50;
//TODO: Change the skillId to represent the task domain
colonyNetworkContract.appendReputationUpdateLog(managerRole.user, managerReputation, skillId);
for (uint8 roleId = 0; roleId <= 2; roleId++) {
uint payout = task.payouts[roleId][token];
Role storage role = task.roles[roleId];
uint8 rating = (roleId == EVALUATOR) ? 50 : role.rating;
int divider = (roleId == WORKER) ? 30 : 50;
int reputation = SafeMath.mulInt(int(payout), (int(rating)*2 - 50)) / divider;
if (roleId == WORKER) {
colonyNetworkContract.appendReputationUpdateLog(role.user, reputation, task.skills[0]);
}
colonyNetworkContract.appendReputationUpdateLog(role.user, reputation, task.domains[0]);
}

// NOTE: reputation change amount is hereby limited to MAXINT/30
int workerReputation = SafeMath.mulInt(int(workerPayout), (int(workerRole.rating)*2 - 50)) / 30;
colonyNetworkContract.appendReputationUpdateLog(workerRole.user, workerReputation, skillId);
// TODO Reputation changes for other relevant roles, domains.
task.finalized = true;
}

function cancelTask(uint256 _id) public
Expand Down
8 changes: 5 additions & 3 deletions contracts/IColony.sol
Expand Up @@ -46,7 +46,7 @@ contract IColony {
function assignWorkRating(uint256 _id) public;
function generateSecret(bytes32 _salt, uint256 _value) public pure returns (bytes32);
function getTaskWorkRatings(uint256 _id) public view returns (uint256, uint256);
function getTaskWorkRatingSecret(uint256 _id, uint8 _role) public view returns (bytes32);
function getTaskWorkRatingSecret(uint256 _id, uint8 _role) public view returns (bytes32);
function setTaskRoleUser(uint256 _id, uint8 _role, address _user) public;
function setTaskSkill(uint256 _id, uint256 _skillId) public;
function setTaskDomain(uint256 _id, uint256 _domainId) public;
Expand All @@ -59,12 +59,14 @@ contract IColony {
function getTaskRole(uint256 _id, uint8 _idx) public view returns (address, bool, uint8);
function getTaskSkill(uint256 _id, uint256 _idx) public view returns (uint256);
function getTaskDomain(uint256 _id, uint256 _idx) public view returns (uint256);

// ColonyFunding.sol
function getFeeInverse() public pure returns (uint256);
function getRewardInverse() public pure returns (uint256);
function setTaskPayout(uint256 _id, uint256 _role, address _token, uint256 _amount) public;
function getTaskPayout(uint256 _id, uint256 _role, address _token) public view returns (uint256);
function setTaskManagerPayout(uint256 _id, address _token, uint256 _amount) public;
function setTaskEvaluatorPayout(uint256 _id, address _token, uint256 _amount) public;
function setTaskWorkerPayout(uint256 _id, address _token, uint256 _amount) public;
function claimPayout(uint256 _id, uint256 _role, address _token) public;
function getPotBalance(uint256 _potId, address _token) public view returns (uint256);
function moveFundsBetweenPots(uint256 _fromPot, uint256 _toPot, uint256 _amount, address _token) public;
Expand Down
24 changes: 18 additions & 6 deletions gasCosts/gasCosts.js
Expand Up @@ -50,6 +50,7 @@ contract("all", () => {
let proposeTaskChangeCost;
let approveTaskChangeCost;
let moveFundsBetweenPotsCost;
let setTaskManagerPayoutCost;
let submitTaskDeliverableCost;
let submitTaskWorkRatingCost;
let revealTaskWorkRatingCost;
Expand Down Expand Up @@ -177,12 +178,21 @@ contract("all", () => {
moveFundsBetweenPotsCost = tx.receipt.gasUsed;
console.log("moveFundsBetweenPots actual cost :", moveFundsBetweenPotsCost);

// setTaskPayout
txData = await colony.contract.setTaskPayout.getData(1, MANAGER_ROLE, tokenAddress, 50);
// setTaskManagerPayout
estimate = await colony.setTaskManagerPayout.estimateGas(1, tokenAddress, 50);
console.log("setTaskManagerPayout estimate : ", estimate);
tx = await colony.setTaskManagerPayout(1, tokenAddress, 50);
setTaskManagerPayoutCost = tx.receipt.gasUsed;
console.log("setTaskManagerPayout actual cost :", setTaskManagerPayoutCost);

// setTaskEvaluatorPayout
txData = await colony.contract.setTaskEvaluatorPayout.getData(1, tokenAddress, 40);
await colony.proposeTaskChange(txData, 0, MANAGER_ROLE);
transactionId = await colony.getTransactionCount.call();
await colony.approveTaskChange(transactionId, WORKER_ROLE, { from: WORKER });
txData = await colony.contract.setTaskPayout.getData(1, WORKER_ROLE, tokenAddress, 100);
await colony.approveTaskChange(transactionId, EVALUATOR_ROLE, { from: EVALUATOR });

// setTaskWorkerPayout
txData = await colony.contract.setTaskWorkerPayout.getData(1, tokenAddress, 100);
await colony.proposeTaskChange(txData, 0, MANAGER_ROLE);
transactionId = await colony.getTransactionCount.call();
await colony.approveTaskChange(transactionId, WORKER_ROLE, { from: WORKER });
Expand Down Expand Up @@ -225,9 +235,11 @@ contract("all", () => {
makeTaskCost +
setTaskSkillCost +
setTaskRoleUserCost * 2 +
proposeTaskChangeCost * 3 +
approveTaskChangeCost * 3 +
// setTaskBrief, setTaskDueDate, setTaskEvaluatorPayout, setTaskWorkerPayout
proposeTaskChangeCost * 4 +
approveTaskChangeCost * 4 +
submitTaskDeliverableCost +
setTaskManagerPayoutCost +
submitTaskWorkRatingCost * 2 +
revealTaskWorkRatingCost * 2 +
finalizeTaskCost;
Expand Down
4 changes: 4 additions & 0 deletions helpers/constants.js
Expand Up @@ -12,7 +12,9 @@ const WORKER_ROLE = 2;
const SPECIFICATION_HASH = "9bb76d8e6c89b524d34a454b3140df28";
const SPECIFICATION_HASH_UPDATED = "9bb76d8e6c89b524d34a454b3140df29";
const DELIVERABLE_HASH = "9cc89e3e3d12a672d67a424b3640ce34";
const INITIAL_FUNDING = 360 * 1e18;
const MANAGER_PAYOUT = web3Utils.toBN(100 * 1e18);
const EVALUATOR_PAYOUT = web3Utils.toBN(50 * 1e18);
const WORKER_PAYOUT = web3Utils.toBN(200 * 1e18);
const MANAGER_RATING = 30;
const WORKER_RATING = 40;
Expand All @@ -34,7 +36,9 @@ module.exports = {
SPECIFICATION_HASH_UPDATED,
DELIVERABLE_HASH,
SECONDS_PER_DAY,
INITIAL_FUNDING,
MANAGER_PAYOUT,
EVALUATOR_PAYOUT,
WORKER_PAYOUT,
MANAGER_RATING,
WORKER_RATING,
Expand Down
30 changes: 25 additions & 5 deletions helpers/test-data-generator.js
Expand Up @@ -5,6 +5,7 @@ import {
EVALUATOR,
WORKER,
MANAGER_PAYOUT,
EVALUATOR_PAYOUT,
WORKER_PAYOUT,
MANAGER_RATING,
WORKER_RATING,
Expand Down Expand Up @@ -56,6 +57,7 @@ module.exports = {
evaluator = EVALUATOR,
worker = WORKER,
manager_payout = MANAGER_PAYOUT,
evaluator_payout = EVALUATOR_PAYOUT,
worker_payout = WORKER_PAYOUT
) {
let tokenAddress;
Expand All @@ -70,17 +72,22 @@ module.exports = {
const potId = task[6].toNumber();
const managerPayout = new BN(manager_payout);
const workerPayout = new BN(worker_payout);
const totalPayouts = managerPayout.add(workerPayout);
const evaluatorPayout = new BN(evaluator_payout);
const totalPayouts = managerPayout.add(workerPayout).add(evaluatorPayout);
await colony.moveFundsBetweenPots(1, potId, totalPayouts.toString(), tokenAddress);
let txData = await colony.contract.setTaskPayout.getData(taskId, MANAGER_ROLE, tokenAddress, managerPayout.toString());

await colony.setTaskManagerPayout(taskId, tokenAddress, managerPayout.toString());

let txData = await colony.contract.setTaskEvaluatorPayout.getData(taskId, tokenAddress, evaluatorPayout.toString());
await colony.proposeTaskChange(txData, 0, MANAGER_ROLE);
let transactionId = await colony.getTransactionCount.call();
await colony.approveTaskChange(transactionId, WORKER_ROLE, { from: worker });
await colony.approveTaskChange(transactionId, EVALUATOR_ROLE, { from: evaluator });

txData = await colony.contract.setTaskPayout.getData(taskId, WORKER_ROLE, tokenAddress, workerPayout.toString());
txData = await colony.contract.setTaskWorkerPayout.getData(taskId, tokenAddress, workerPayout.toString());
await colony.proposeTaskChange(txData, 0, MANAGER_ROLE);
transactionId = await colony.getTransactionCount.call();
await colony.approveTaskChange(transactionId, WORKER_ROLE, { from: worker });

return taskId;
},
async setupRatedTask(
Expand All @@ -93,13 +100,26 @@ module.exports = {
evaluator = EVALUATOR,
worker = WORKER,
manager_payout = MANAGER_PAYOUT,
evaluator_payout = EVALUATOR_PAYOUT,
worker_payout = WORKER_PAYOUT,
manager_rating = MANAGER_RATING,
manager_rating_salt = RATING_1_SALT,
worker_rating = WORKER_RATING,
worker_rating_salt = RATING_2_SALT
) {
const taskId = await this.setupFundedTask(colonyNetwork, colony, token, dueDate, domain, skill, evaluator, worker, manager_payout, worker_payout);
const taskId = await this.setupFundedTask(
colonyNetwork,
colony,
token,
dueDate,
domain,
skill,
evaluator,
worker,
manager_payout,
evaluator_payout,
worker_payout
);
const WORKER_RATING_SECRET = web3Utils.soliditySha3(worker_rating_salt, worker_rating);
const MANAGER_RATING_SECRET = web3Utils.soliditySha3(manager_rating_salt, manager_rating);
await colony.submitTaskWorkRating(taskId, WORKER_ROLE, WORKER_RATING_SECRET, { from: evaluator });
Expand Down