diff --git a/contracts/Colony.sol b/contracts/Colony.sol index 9bfc36ed76..58bf13004d 100755 --- a/contracts/Colony.sol +++ b/contracts/Colony.sol @@ -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; @@ -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 @@ -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; diff --git a/contracts/ColonyFunding.sol b/contracts/ColonyFunding.sol index bda59cc343..d374ff57b7 100755 --- a/contracts/ColonyFunding.sol +++ b/contracts/ColonyFunding.sol @@ -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 @@ -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); + } } diff --git a/contracts/ColonyStorage.sol b/contracts/ColonyStorage.sol index ab39840321..15c8afe34c 100755 --- a/contracts/ColonyStorage.sol +++ b/contracts/ColonyStorage.sol @@ -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); _; diff --git a/contracts/ColonyTask.sol b/contracts/ColonyTask.sol index bed141e9f1..cfb8d866fb 100755 --- a/contracts/ColonyTask.sol +++ b/contracts/ColonyTask.sol @@ -52,7 +52,7 @@ contract ColonyTask is ColonyStorage, DSMath { } else { revert(); } - _; + _; } modifier ratingSecretDoesNotExist(uint256 _id, uint8 _role) { @@ -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 @@ -130,10 +130,10 @@ contract ColonyTask is ColonyStorage, DSMath { rated: false, rating: 0 }); - + pots[potCount].taskId = taskCount; setTaskDomain(taskCount, _domainId); - + TaskAdded(taskCount); } @@ -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) @@ -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) @@ -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 diff --git a/contracts/IColony.sol b/contracts/IColony.sol index 1226def8e4..c5de80766a 100644 --- a/contracts/IColony.sol +++ b/contracts/IColony.sol @@ -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; @@ -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; diff --git a/gasCosts/gasCosts.js b/gasCosts/gasCosts.js index ab234d82bb..b4c9449163 100644 --- a/gasCosts/gasCosts.js +++ b/gasCosts/gasCosts.js @@ -50,6 +50,7 @@ contract("all", () => { let proposeTaskChangeCost; let approveTaskChangeCost; let moveFundsBetweenPotsCost; + let setTaskManagerPayoutCost; let submitTaskDeliverableCost; let submitTaskWorkRatingCost; let revealTaskWorkRatingCost; @@ -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 }); @@ -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; diff --git a/helpers/constants.js b/helpers/constants.js index b7eaee87f8..914eb9adf7 100644 --- a/helpers/constants.js +++ b/helpers/constants.js @@ -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; @@ -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, diff --git a/helpers/test-data-generator.js b/helpers/test-data-generator.js index 10e8dde7d7..0934f66a2c 100644 --- a/helpers/test-data-generator.js +++ b/helpers/test-data-generator.js @@ -5,6 +5,7 @@ import { EVALUATOR, WORKER, MANAGER_PAYOUT, + EVALUATOR_PAYOUT, WORKER_PAYOUT, MANAGER_RATING, WORKER_RATING, @@ -56,6 +57,7 @@ module.exports = { evaluator = EVALUATOR, worker = WORKER, manager_payout = MANAGER_PAYOUT, + evaluator_payout = EVALUATOR_PAYOUT, worker_payout = WORKER_PAYOUT ) { let tokenAddress; @@ -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( @@ -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 }); diff --git a/test/colony-funding.js b/test/colony-funding.js index 8b3fd680bb..e79e75a7b4 100755 --- a/test/colony-funding.js +++ b/test/colony-funding.js @@ -1,5 +1,5 @@ /* globals artifacts */ -import { EVALUATOR, WORKER, MANAGER_ROLE, WORKER_ROLE, SPECIFICATION_HASH } from "../helpers/constants"; +import { EVALUATOR, WORKER, MANAGER_ROLE, EVALUATOR_ROLE, WORKER_ROLE, SPECIFICATION_HASH, INITIAL_FUNDING } from "../helpers/constants"; import testHelper from "../helpers/test-helper"; import testDataGenerator from "../helpers/test-data-generator"; @@ -141,9 +141,7 @@ contract("Colony Funding", () => { await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); // Pot 0, Payout 0 // Pot was equal to payout, transition to pot being equal by changing payout (18) - const txData1 = await colony.contract.setTaskPayout.getData(1, 0, otherToken.address, 0); - await colony.proposeTaskChange(txData1, 0, 0); - await colony.approveTaskChange(1, WORKER_ROLE, { from: WORKER }); + await colony.setTaskManagerPayout(1, otherToken.address, 0); let task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 0); // Pot 0, Payout 0 @@ -153,9 +151,7 @@ contract("Colony Funding", () => { assert.equal(task[5].toNumber(), 0); // Pot 0, Payout 0 // Pot was equal to payout, transition to pot being lower by increasing payout (8) - const txData2 = await colony.contract.setTaskPayout.getData(1, 0, otherToken.address, 40); - await colony.proposeTaskChange(txData2, 0, 0); - await colony.approveTaskChange(2, WORKER_ROLE, { from: WORKER }); + await colony.setTaskManagerPayout(1, otherToken.address, 40); task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 1); // Pot 0, Payout 40 @@ -170,17 +166,13 @@ contract("Colony Funding", () => { assert.equal(task[5].toNumber(), 0); // Pot 80, Payout 40 // Pot was above payout, transition to being equal by increasing payout (12) - const txData3 = await colony.contract.setTaskPayout.getData(1, 0, otherToken.address, 80); - await colony.proposeTaskChange(txData3, 0, 0); - await colony.approveTaskChange(3, WORKER_ROLE, { from: WORKER }); + await colony.setTaskManagerPayout(1, otherToken.address, 80); task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 0); // Pot 80, Payout 80 // Pot was equal to payout, transition to being above by decreasing payout (6) - const txData4 = await colony.contract.setTaskPayout.getData(1, 0, otherToken.address, 40); - await colony.proposeTaskChange(txData4, 0, 0); - await colony.approveTaskChange(4, WORKER_ROLE, { from: WORKER }); + await colony.setTaskManagerPayout(1, otherToken.address, 40); task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 0); @@ -206,16 +198,12 @@ contract("Colony Funding", () => { assert.equal(task[5].toNumber(), 1); // Pot 20, Payout 40 // Pot was below payout, change to being above by changing payout (4) - const txData5 = await colony.contract.setTaskPayout.getData(1, 0, otherToken.address, 10); - await colony.proposeTaskChange(txData5, 0, 0); - await colony.approveTaskChange(5, WORKER_ROLE, { from: WORKER }); + await colony.setTaskManagerPayout(1, otherToken.address, 10); task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 0); // Pot 20, Payout 10 // Pot was above, change to being above by changing payout (16) - const txData6 = await colony.contract.setTaskPayout.getData(1, 0, otherToken.address, 5); - await colony.proposeTaskChange(txData6, 0, 0); - await colony.approveTaskChange(6, WORKER_ROLE, { from: WORKER }); + await colony.setTaskManagerPayout(1, otherToken.address, 5); task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 0); // Pot 20, Payout 5 @@ -225,16 +213,12 @@ contract("Colony Funding", () => { assert.equal(task[5].toNumber(), 0); // Pot 10, Payout 5 // Pot was above payout, change to being below by changing payout (10) - const txData7 = await colony.contract.setTaskPayout.getData(1, 0, otherToken.address, 40); - await colony.proposeTaskChange(txData7, 0, 0); - await colony.approveTaskChange(7, WORKER_ROLE, { from: WORKER }); + await colony.setTaskManagerPayout(1, otherToken.address, 40); task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 1); // Pot 10, Payout 40 // Pot was below payout, change to being below by changing payout (14) - const txData8 = await colony.contract.setTaskPayout.getData(1, 0, otherToken.address, 30); - await colony.proposeTaskChange(txData8, 0, 0); - await colony.approveTaskChange(8, WORKER_ROLE, { from: WORKER }); + await colony.setTaskManagerPayout(1, otherToken.address, 30); task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 1); // Pot 10, Payout 30 @@ -244,9 +228,7 @@ contract("Colony Funding", () => { assert.equal(task[5].toNumber(), 1); // Pot 5, Payout 30 // Pot was below payout, change to being equal by changing payout (2) - const txData9 = await colony.contract.setTaskPayout.getData(1, 0, otherToken.address, 5); - await colony.proposeTaskChange(txData9, 0, 0); - await colony.approveTaskChange(9, WORKER_ROLE, { from: WORKER }); + await colony.setTaskManagerPayout(1, otherToken.address, 5); task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 0); // Pot 5, Payout 5 @@ -271,21 +253,22 @@ contract("Colony Funding", () => { }); it("should not allow funds to be removed from a task with payouts to go", async () => { - await testDataGenerator.fundColonyWithTokens(colony, otherToken, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, otherToken, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, otherToken); await colony.finalizeTask(taskId); await testHelper.checkErrorRevert(colony.moveFundsBetweenPots(2, 1, 40, otherToken.address)); const colonyPotBalance = await colony.getPotBalance.call(2, otherToken.address); - assert.equal(colonyPotBalance.toNumber(), 300 * 1e18); + assert.equal(colonyPotBalance.toNumber(), 350 * 1e18); }); it("should allow funds to be removed from a task if there are no more payouts of that token to be claimed", async () => { - await testDataGenerator.fundColonyWithTokens(colony, otherToken, 313 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, otherToken, 363 * 1e18); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, otherToken); await colony.moveFundsBetweenPots(1, 2, 10, otherToken.address); await colony.finalizeTask(taskId); await colony.claimPayout(taskId, MANAGER_ROLE, otherToken.address); await colony.claimPayout(taskId, WORKER_ROLE, otherToken.address, { from: WORKER }); + await colony.claimPayout(taskId, EVALUATOR_ROLE, otherToken.address, { from: EVALUATOR }); await colony.moveFundsBetweenPots(2, 1, 10, otherToken.address); const colonyPotBalance = await colony.getPotBalance.call(2, otherToken.address); @@ -347,9 +330,7 @@ contract("Colony Funding", () => { await colony.makeTask(SPECIFICATION_HASH, 1); await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); - const txData1 = await colony.contract.setTaskPayout.getData(1, 0, 0x0, 40); - await colony.proposeTaskChange(txData1, 0, 0); - await colony.approveTaskChange(1, WORKER_ROLE, { from: WORKER }); + await colony.setTaskManagerPayout(1, 0x0, 40); let task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 1); @@ -360,9 +341,7 @@ contract("Colony Funding", () => { task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 1); - const txData2 = await colony.contract.setTaskPayout.getData(1, 0, 0x0, 10); - await colony.proposeTaskChange(txData2, 0, 0); - await colony.approveTaskChange(2, WORKER_ROLE, { from: WORKER }); + await colony.setTaskManagerPayout(1, 0x0, 10); task = await colony.getTask.call(1); assert.equal(task[5].toNumber(), 0); diff --git a/test/colony-task-work-rating.js b/test/colony-task-work-rating.js index 326651aea7..2eca3a1573 100644 --- a/test/colony-task-work-rating.js +++ b/test/colony-task-work-rating.js @@ -15,6 +15,7 @@ import { EVALUATOR_ROLE, WORKER_ROLE, DELIVERABLE_HASH, + INITIAL_FUNDING, SECONDS_PER_DAY } from "../helpers/constants"; import testHelper from "../helpers/test-helper"; @@ -133,7 +134,7 @@ contract("Colony Task Work Rating", () => { describe("when revealing a task work rating", () => { it("should allow revealing a rating by evaluator and worker", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); const roleManager = await colony.getTaskRole.call(taskId, MANAGER_ROLE); assert.isTrue(roleManager[1]); diff --git a/test/colony.js b/test/colony.js index 39ea99723a..9cf9cad705 100755 --- a/test/colony.js +++ b/test/colony.js @@ -10,6 +10,7 @@ import { SPECIFICATION_HASH, SPECIFICATION_HASH_UPDATED, DELIVERABLE_HASH, + INITIAL_FUNDING, SECONDS_PER_DAY, MANAGER_RATING, WORKER_RATING, @@ -260,7 +261,7 @@ contract("Colony", () => { }); it("should fail to submit update of task brief, if the task was already finalized", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); await colony.finalizeTask(taskId); @@ -304,7 +305,7 @@ contract("Colony", () => { }); it("should fail if I try to submit work for a task that is finalized", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); await colony.finalizeTask(taskId); await testHelper.checkErrorRevert(colony.submitTaskDeliverable(taskId, DELIVERABLE_HASH)); @@ -342,7 +343,7 @@ contract("Colony", () => { describe("when finalizing a task", () => { it('should set the task "finalized" property to "true"', async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); await colony.finalizeTask(taskId); const task = await colony.getTask.call(taskId); @@ -350,26 +351,26 @@ contract("Colony", () => { }); it("should fail if the task work ratings have not been assigned", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupFundedTask(colonyNetwork, colony, token); await testHelper.checkErrorRevert(colony.finalizeTask(taskId)); }); it("should fail if a non-admin tries to accept the task", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); await testHelper.checkErrorRevert(colony.finalizeTask(taskId, { from: OTHER })); }); it("should fail if I try to accept a task that was finalized before", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); await colony.finalizeTask(taskId); await testHelper.checkErrorRevert(colony.finalizeTask(taskId)); }); it("should fail if I try to accept a task using an invalid id", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); await testHelper.checkErrorRevert(colony.finalizeTask(10)); }); @@ -377,7 +378,7 @@ contract("Colony", () => { describe("when cancelling a task", () => { it('should set the task "cancelled" property to "true"', async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); await colony.cancelTask(taskId); @@ -386,7 +387,7 @@ contract("Colony", () => { }); it("should be possible to return funds back to the domain", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupFundedTask(colonyNetwork, colony, token); const task = await colony.getTask.call(taskId); const domainId = await colony.getTaskDomain.call(taskId, 0); @@ -443,7 +444,7 @@ contract("Colony", () => { }); it("should fail if manager tries to cancel a task that was finalized", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); await colony.finalizeTask(taskId); await testHelper.checkErrorRevert(colony.cancelTask(taskId)); @@ -458,35 +459,40 @@ contract("Colony", () => { it("should be able to set the task payouts for different roles", async () => { await colony.makeTask(SPECIFICATION_HASH, 1); await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + await colony.setTaskRoleUser(1, EVALUATOR_ROLE, EVALUATOR); await colony.mintTokens(100); // Set the manager payout as 5000 wei and 100 colony tokens - const txData1 = await colony.contract.setTaskPayout.getData(1, MANAGER_ROLE, 0x0, 5000); - await colony.proposeTaskChange(txData1, 0, 0); - await colony.approveTaskChange(1, WORKER_ROLE, { from: WORKER }); - const txData2 = await colony.contract.setTaskPayout.getData(1, MANAGER_ROLE, token.address, 100); - await colony.proposeTaskChange(txData2, 0, 0); - await colony.approveTaskChange(2, WORKER_ROLE, { from: WORKER }); - - // Set the evaluator payout as 40 colony tokens - const txData3 = await colony.contract.setTaskPayout.getData(1, EVALUATOR_ROLE, token.address, 40); - await colony.proposeTaskChange(txData3, 0, 0); + await colony.setTaskManagerPayout(1, 0x0, 5000); + await colony.setTaskManagerPayout(1, token.address, 100); + + // // Set the evaluator payout as 1000 ethers + const txData1 = await colony.contract.setTaskEvaluatorPayout.getData(1, 0x0, 1000); + await colony.proposeTaskChange(txData1, 0, MANAGER_ROLE); + await colony.approveTaskChange(1, EVALUATOR_ROLE, { from: EVALUATOR }); + + // // Set the evaluator payout as 40 colony tokens + const txData2 = await colony.contract.setTaskEvaluatorPayout.getData(1, token.address, 40); + await colony.proposeTaskChange(txData2, 0, MANAGER_ROLE); + await colony.approveTaskChange(2, EVALUATOR_ROLE, { from: EVALUATOR }); + + // // Set the worker payout as 98000 wei and 200 colony tokens + const txData3 = await colony.contract.setTaskWorkerPayout.getData(1, 0x0, 98000); + await colony.proposeTaskChange(txData3, 0, MANAGER_ROLE); await colony.approveTaskChange(3, WORKER_ROLE, { from: WORKER }); - // Set the worker payout as 98000 wei and 200 colony tokens - const txData4 = await colony.contract.setTaskPayout.getData(1, 2, 0x0, 98000); - await colony.proposeTaskChange(txData4, 0, 0); + const txData4 = await colony.contract.setTaskWorkerPayout.getData(1, token.address, 200); + await colony.proposeTaskChange(txData4, 0, MANAGER_ROLE); await colony.approveTaskChange(4, WORKER_ROLE, { from: WORKER }); - const txData5 = await colony.contract.setTaskPayout.getData(1, WORKER_ROLE, token.address, 200); - await colony.proposeTaskChange(txData5, 0, 0); - await colony.approveTaskChange(5, WORKER_ROLE, { from: WORKER }); const taskPayoutManager1 = await colony.getTaskPayout.call(1, MANAGER_ROLE, 0x0); assert.equal(taskPayoutManager1.toNumber(), 5000); const taskPayoutManager2 = await colony.getTaskPayout.call(1, MANAGER_ROLE, token.address); assert.equal(taskPayoutManager2.toNumber(), 100); - const taskPayoutEvaluator = await colony.getTaskPayout.call(1, EVALUATOR_ROLE, token.address); - assert.equal(taskPayoutEvaluator.toNumber(), 40); + const taskPayoutEvaluator1 = await colony.getTaskPayout.call(1, EVALUATOR_ROLE, 0x0); + assert.equal(taskPayoutEvaluator1.toNumber(), 1000); + const taskPayoutEvaluator2 = await colony.getTaskPayout.call(1, EVALUATOR_ROLE, token.address); + assert.equal(taskPayoutEvaluator2.toNumber(), 40); const taskPayoutWorker1 = await colony.getTaskPayout.call(1, WORKER_ROLE, 0x0); assert.equal(taskPayoutWorker1.toNumber(), 98000); @@ -497,7 +503,7 @@ contract("Colony", () => { describe("when claiming payout for a task", () => { it("should payout agreed tokens for a task", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); await colony.finalizeTask(taskId); const networkBalanceBefore = await token.balanceOf.call(colonyNetwork.address); @@ -507,11 +513,11 @@ contract("Colony", () => { const balance = await token.balanceOf.call(MANAGER); assert.equal(balance.toNumber(), 99 * 1e18); const potBalance = await colony.getPotBalance.call(2, token.address); - assert.equal(potBalance.toNumber(), 200 * 1e18); + assert.equal(potBalance.toNumber(), 250 * 1e18); }); it("should payout agreed ether for a task", async () => { - await colony.send(303); + await colony.send(353); await colony.claimColonyFunds(0x0); const dueDate = testHelper.currentBlockTime() - 1; const taskId = await testDataGenerator.setupRatedTask( @@ -524,6 +530,7 @@ contract("Colony", () => { undefined, undefined, 100, + 50, 200 ); await colony.finalizeTask(taskId); @@ -536,17 +543,17 @@ contract("Colony", () => { assert.equal(balanceAfter.minus(balanceBefore).toNumber(), 99); assert.equal(commonBalanceAfter.minus(commonBalanceBefore).toNumber(), 1); const potBalance = await colony.getPotBalance.call(2, 0x0); - assert.equal(potBalance.toNumber(), 200); + assert.equal(potBalance.toNumber(), 250); }); it("should return error when task is not finalized", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); await testHelper.checkErrorRevert(colony.claimPayout(taskId, MANAGER_ROLE, token.address)); }); it("should return error when called by account that doesn't match the role", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony, token); await colony.finalizeTask(taskId); diff --git a/test/common-colony.js b/test/common-colony.js index 48c3db712d..89b3f562a8 100644 --- a/test/common-colony.js +++ b/test/common-colony.js @@ -1,5 +1,5 @@ /* globals artifacts */ -import { SPECIFICATION_HASH } from "../helpers/constants"; +import { SPECIFICATION_HASH, INITIAL_FUNDING } from "../helpers/constants"; import testHelper from "../helpers/test-helper"; import testDataGenerator from "../helpers/test-data-generator"; @@ -408,7 +408,7 @@ contract("Common Colony", () => { }); it("should NOT be able to set a domain on finalized task", async () => { - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony); await colony.finalizeTask(taskId); await testHelper.checkError(colony.setTaskDomain(taskId, 1)); @@ -431,7 +431,7 @@ contract("Common Colony", () => { it("should NOT be able to set global skill on finalized task", async () => { await commonColony.addGlobalSkill(1); await commonColony.addGlobalSkill(4); - await testDataGenerator.fundColonyWithTokens(colony, token, 310 * 1e18); + await testDataGenerator.fundColonyWithTokens(colony, token, INITIAL_FUNDING); const taskId = await testDataGenerator.setupRatedTask(colonyNetwork, colony); await colony.finalizeTask(taskId); await testHelper.checkError(colony.setTaskSkill(taskId, 5)); diff --git a/test/reputation-update.js b/test/reputation-update.js index bb40813e53..06a53d6d12 100755 --- a/test/reputation-update.js +++ b/test/reputation-update.js @@ -2,7 +2,7 @@ import web3Utils from "web3-utils"; import { BN } from "bn.js"; -import { MANAGER, WORKER, OTHER, MANAGER_PAYOUT, WORKER_PAYOUT } from "../helpers/constants"; +import { MANAGER, WORKER, EVALUATOR, OTHER, MANAGER_PAYOUT, WORKER_PAYOUT } from "../helpers/constants"; import testHelper from "../helpers/test-helper"; import testDataGenerator from "../helpers/test-data-generator"; @@ -46,7 +46,7 @@ contract("Colony Reputation Updates", () => { colonyToken = await Token.at(tokenAddress); const amount = new BN(10) .pow(new BN(18)) - .mul(new BN(600)) + .mul(new BN(1000)) .toString(); await testDataGenerator.fundColonyWithTokens(commonColony, colonyToken, amount); }); @@ -63,13 +63,21 @@ contract("Colony Reputation Updates", () => { assert.equal(repLogEntryManager[4].toNumber(), 2); assert.equal(repLogEntryManager[5].toNumber(), 0); - const repLogEntryWorker = await colonyNetwork.getReputationUpdateLogEntry.call(1); + const repLogEntryEvaluator = await colonyNetwork.getReputationUpdateLogEntry.call(1); + assert.equal(repLogEntryEvaluator[0], EVALUATOR); + assert.equal(repLogEntryEvaluator[1].toNumber(), 50 * 1e18); + assert.equal(repLogEntryEvaluator[2].toNumber(), 1); + assert.equal(repLogEntryEvaluator[3], commonColony.address); + assert.equal(repLogEntryEvaluator[4].toNumber(), 2); + assert.equal(repLogEntryEvaluator[5].toNumber(), 2); + + const repLogEntryWorker = await colonyNetwork.getReputationUpdateLogEntry.call(2); assert.equal(repLogEntryWorker[0], WORKER); assert.equal(repLogEntryWorker[1].toNumber(), 200 * 1e18); assert.equal(repLogEntryWorker[2].toNumber(), 1); assert.equal(repLogEntryWorker[3], commonColony.address); assert.equal(repLogEntryWorker[4].toNumber(), 2); - assert.equal(repLogEntryWorker[5].toNumber(), 2); + assert.equal(repLogEntryWorker[5].toNumber(), 4); }); const ratings = [ @@ -142,6 +150,7 @@ contract("Colony Reputation Updates", () => { undefined, undefined, undefined, + undefined, rating.manager, undefined, rating.worker, @@ -157,13 +166,13 @@ contract("Colony Reputation Updates", () => { assert.equal(repLogEntryManager[4].toNumber(), 2); assert.equal(repLogEntryManager[5].toNumber(), 0); - const repLogEntryWorker = await colonyNetwork.getReputationUpdateLogEntry.call(1); + const repLogEntryWorker = await colonyNetwork.getReputationUpdateLogEntry.call(2); assert.equal(repLogEntryWorker[0], WORKER); assert.equal(repLogEntryWorker[1].toString(), rating.reputationChangeWorker.toString()); assert.equal(repLogEntryWorker[2].toNumber(), 1); assert.equal(repLogEntryWorker[3], commonColony.address); assert.equal(repLogEntryWorker[4].toNumber(), 2); - assert.equal(repLogEntryWorker[5].toNumber(), 2); + assert.equal(repLogEntryWorker[5].toNumber(), 4); }); }); @@ -198,14 +207,14 @@ contract("Colony Reputation Updates", () => { const taskId1 = await testDataGenerator.setupRatedTask(colonyNetwork, commonColony, undefined, undefined, undefined, 4); await commonColony.finalizeTask(taskId1); - let repLogEntryWorker = await colonyNetwork.getReputationUpdateLogEntry.call(1); + let repLogEntryWorker = await colonyNetwork.getReputationUpdateLogEntry.call(2); const result = web3Utils.toBN("1").mul(WORKER_PAYOUT); assert.equal(repLogEntryWorker[1].toString(), result.toString()); assert.equal(repLogEntryWorker[4].toNumber(), 6); const taskId2 = await testDataGenerator.setupRatedTask(colonyNetwork, commonColony, undefined, undefined, undefined, 5); await commonColony.finalizeTask(taskId2); - repLogEntryWorker = await colonyNetwork.getReputationUpdateLogEntry.call(3); + repLogEntryWorker = await colonyNetwork.getReputationUpdateLogEntry.call(6); assert.equal(repLogEntryWorker[1].toString(), result.toString()); assert.equal(repLogEntryWorker[4].toNumber(), 8); // Negative reputation change means children change as well. }); @@ -218,8 +227,9 @@ contract("Colony Reputation Updates", () => { .toString(10); await testDataGenerator.fundColonyWithTokens(commonColony, colonyToken, maxUIntNumber); // Split the tokens as payouts between the manager and worker - const managerPayout = new BN("1"); - const workerPayout = new BN(maxUIntNumber).sub(managerPayout); + const managerPayout = new BN("2"); + const evaluatorPayout = new BN("1"); + const workerPayout = new BN(maxUIntNumber).sub(managerPayout).sub(evaluatorPayout); const taskId = await testDataGenerator.setupRatedTask( colonyNetwork, commonColony, @@ -230,6 +240,7 @@ contract("Colony Reputation Updates", () => { undefined, undefined, managerPayout, + evaluatorPayout, workerPayout, undefined, undefined,