Skip to content

Commit

Permalink
Evaluator reputation update (#158)
Browse files Browse the repository at this point in the history
* Added separate payout function for every role
* Added constant for initial funding
  • Loading branch information
Filip Lazovic authored and elenadimitrova committed Feb 19, 2018
1 parent f03ed9c commit 0f2bd75
Show file tree
Hide file tree
Showing 13 changed files with 188 additions and 140 deletions.
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

0 comments on commit 0f2bd75

Please sign in to comment.