Skip to content

Commit f963276

Browse files
committed
Introduce secure vs. managed tasks
1 parent 1ca0d96 commit f963276

File tree

2 files changed

+329
-163
lines changed

2 files changed

+329
-163
lines changed

contracts/extensions/Tasks.sol

+83-37
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ contract Tasks is DSMath {
3333
/// @param taskId The newly added task id
3434
event TaskAdded(uint256 taskId);
3535

36+
/// @notice Event logged when a task's security status changes (secure vs. managed)
37+
/// @param taskId Id of the task
38+
/// @param secure Boolean of security status (true: secure, false: managed)
39+
event TaskSecuritySet(uint256 indexed taskId, bool secure);
40+
3641
/// @notice Event logged when a task's specification hash changes
3742
/// @param taskId Id of the task
3843
/// @param specificationHash New specification hash of the task
@@ -69,6 +74,7 @@ contract Tasks is DSMath {
6974
uint256 dueDate;
7075
uint256 completionTimestamp;
7176
uint256 changeNonce;
77+
bool secure;
7278
}
7379

7480
struct Role {
@@ -103,6 +109,7 @@ contract Tasks is DSMath {
103109
roleAssignmentSigs[bytes4(keccak256("setTaskWorkerRole(uint256,address)"))] = true;
104110

105111
// Initialise the task update reviewers
112+
reviewers[bytes4(keccak256("setTaskSecurity(uint256,bool)"))] = [TaskRole.Manager, TaskRole.Worker];
106113
reviewers[bytes4(keccak256("setTaskBrief(uint256,bytes32)"))] = [TaskRole.Manager, TaskRole.Worker];
107114
reviewers[bytes4(keccak256("setTaskDueDate(uint256,uint256)"))] = [TaskRole.Manager, TaskRole.Worker];
108115
reviewers[bytes4(keccak256("setTaskSkill(uint256,uint256)"))] = [TaskRole.Manager, TaskRole.Worker];
@@ -115,8 +122,8 @@ contract Tasks is DSMath {
115122
reviewers[bytes4(keccak256("cancelTask(uint256)"))] = [TaskRole.Manager, TaskRole.Worker];
116123
}
117124

118-
modifier self() {
119-
require(address(this) == msg.sender, "task-not-self");
125+
modifier self(uint256 _id) {
126+
require(managerCanCall(_id) || address(this) == msg.sender, "task-not-self");
120127
_;
121128
}
122129

@@ -131,6 +138,16 @@ contract Tasks is DSMath {
131138
_;
132139
}
133140

141+
modifier taskSecure(uint256 _id) {
142+
require(isTaskSecure(_id), "task-not-secure");
143+
_;
144+
}
145+
146+
modifier taskManaged(uint256 _id) {
147+
require(!isTaskSecure(_id), "task-not-managed");
148+
_;
149+
}
150+
134151
modifier taskComplete(uint256 _id) {
135152
require(isTaskComplete(_id), "task-not-complete");
136153
_;
@@ -162,12 +179,10 @@ contract Tasks is DSMath {
162179
bytes4 sig;
163180
uint256 taskId;
164181
(sig, taskId) = deconstructCall(_data);
165-
require(taskId > 0 && taskId <= taskCount, "task-does-not-exist");
182+
require(doesTaskExist(taskId), "task-does-not-exist");
183+
require(!isTaskComplete(taskId), "task-complete");
166184
require(!roleAssignmentSigs[sig], "task-change-is-role-assign");
167185

168-
ColonyDataTypes.ExpenditureStatus status = colony.getExpenditure(tasks[taskId].expenditureId).status;
169-
require(status != ColonyDataTypes.ExpenditureStatus.Finalized, "task-finalized");
170-
171186
uint8 nSignaturesRequired;
172187
address taskRole1User = getTaskRoleUser(taskId, TaskRole(reviewers[sig][0]));
173188
address taskRole2User = getTaskRoleUser(taskId, TaskRole(reviewers[sig][1]));
@@ -219,12 +234,10 @@ contract Tasks is DSMath {
219234
uint256 taskId;
220235
address userAddress;
221236
(sig, taskId, userAddress) = deconstructRoleChangeCall(_data);
222-
require(taskId > 0 && taskId <= taskCount, "task-does-not-exist");
237+
require(doesTaskExist(taskId), "task-does-not-exist");
238+
require(!isTaskComplete(taskId), "task-complete");
223239
require(roleAssignmentSigs[sig], "task-change-is-not-role-assign");
224240

225-
ColonyDataTypes.ExpenditureStatus status = colony.getExpenditure(tasks[taskId].expenditureId).status;
226-
require(status != ColonyDataTypes.ExpenditureStatus.Finalized, "task-finalized");
227-
228241
uint8 nSignaturesRequired;
229242
address manager = getTaskRoleUser(taskId, TaskRole.Manager);
230243
// If manager wants to set himself to a role
@@ -274,7 +287,8 @@ contract Tasks is DSMath {
274287
bytes32 _specificationHash,
275288
uint256 _domainId,
276289
uint256 _skillId,
277-
uint256 _dueDate
290+
uint256 _dueDate,
291+
bool _secure
278292
)
279293
public
280294
isAdmin(msg.sender, _callerPermissionDomainId, _callerChildSkillIndex, _domainId)
@@ -285,9 +299,13 @@ contract Tasks is DSMath {
285299
tasks[taskCount].expenditureId = expenditureId;
286300
tasks[taskCount].specificationHash = _specificationHash;
287301
tasks[taskCount].dueDate = (_dueDate > 0) ? _dueDate : now + 90 days; // Note: can set dueDate in past?
302+
tasks[taskCount].secure = _secure;
288303

289304
setTaskRoleUser(taskCount, TaskRole.Manager, msg.sender);
290-
setTaskRoleUser(taskCount, TaskRole.Evaluator, msg.sender);
305+
306+
if (_secure) {
307+
setTaskRoleUser(taskCount, TaskRole.Evaluator, msg.sender);
308+
}
291309

292310
if (_skillId > 0) {
293311
this.setTaskSkill(taskCount, _skillId);
@@ -299,6 +317,8 @@ contract Tasks is DSMath {
299317

300318
function submitTaskWorkRating(uint256 _id, TaskRole _role, bytes32 _secret)
301319
public
320+
taskExists(_id)
321+
taskSecure(_id)
302322
taskComplete(_id)
303323
{
304324
if (_role == TaskRole.Manager) { // Manager rated by worker
@@ -355,46 +375,56 @@ contract Tasks is DSMath {
355375
return ratingSecrets[_id].secret[_role];
356376
}
357377

378+
function setTaskSecurity(uint256 _id, bool _secure) public self(_id) {
379+
tasks[_id].secure = _secure;
380+
381+
if (!_secure) {
382+
removeTaskEvaluatorRole(_id);
383+
}
384+
385+
emit TaskSecuritySet(_id, _secure);
386+
}
387+
358388
// Note: the domain permissions arguments are placed at the end for consistency with the other role change functions
359389
function setTaskManagerRole(uint256 _id, address payable _user, uint256 _permissionDomainId, uint256 _childSkillIndex)
360390
public
361-
self
391+
self(_id)
362392
isAdmin(_user, _permissionDomainId, _childSkillIndex, colony.getExpenditure(tasks[_id].expenditureId).domainId)
363393
{
364394
setTaskRoleUser(_id, TaskRole.Manager, _user);
365395
}
366396

367-
function setTaskEvaluatorRole(uint256 _id, address payable _user) public self {
397+
function setTaskEvaluatorRole(uint256 _id, address payable _user) public self(_id) {
368398
// Can only assign role if no one is currently assigned to it
369399
require(getTaskRoleUser(_id, TaskRole.Evaluator) == address(0x0), "task-evaluator-role-assigned");
370400
setTaskRoleUser(_id, TaskRole.Evaluator, _user);
371401
}
372402

373-
function setTaskWorkerRole(uint256 _id, address payable _user) public self {
403+
function setTaskWorkerRole(uint256 _id, address payable _user) public self(_id) {
374404
// Can only assign role if no one is currently assigned to it
375405
require(getTaskRoleUser(_id, TaskRole.Worker) == address(0x0), "task-worker-role-assigned");
376406
uint256[] memory skills = colony.getExpenditureSlot(tasks[_id].expenditureId, uint256(TaskRole.Worker)).skills;
377407
require(skills.length > 0 && skills[0] > 0, "task-skill-not-set"); // ignore-swc-110
378408
setTaskRoleUser(_id, TaskRole.Worker, _user);
379409
}
380410

381-
function removeTaskEvaluatorRole(uint256 _id) public self {
411+
function removeTaskEvaluatorRole(uint256 _id) public self(_id) {
382412
setTaskRoleUser(_id, TaskRole.Evaluator, address(0x0));
383413
}
384414

385-
function removeTaskWorkerRole(uint256 _id) public self {
415+
function removeTaskWorkerRole(uint256 _id) public self(_id) {
386416
setTaskRoleUser(_id, TaskRole.Worker, address(0x0));
387417
}
388418

389-
function setTaskManagerPayout(uint256 _id, address _token, uint256 _amount) public self {
419+
function setTaskManagerPayout(uint256 _id, address _token, uint256 _amount) public self(_id) {
390420
colony.setExpenditurePayout(_id, uint256(TaskRole.Manager), _token, _amount);
391421
}
392422

393-
function setTaskEvaluatorPayout(uint256 _id, address _token, uint256 _amount) public self {
423+
function setTaskEvaluatorPayout(uint256 _id, address _token, uint256 _amount) public self(_id) {
394424
colony.setExpenditurePayout(_id, uint256(TaskRole.Evaluator), _token, _amount);
395425
}
396426

397-
function setTaskWorkerPayout(uint256 _id, address _token, uint256 _amount) public self {
427+
function setTaskWorkerPayout(uint256 _id, address _token, uint256 _amount) public self(_id) {
398428
colony.setExpenditurePayout(_id, uint256(TaskRole.Worker), _token, _amount);
399429
}
400430

@@ -421,15 +451,14 @@ contract Tasks is DSMath {
421451
this.setTaskWorkerPayout(_id, _token, _workerAmount);
422452
}
423453

424-
function setTaskSkill(uint256 _id, uint256 _skillId) public self {
454+
function setTaskSkill(uint256 _id, uint256 _skillId) public self(_id) {
425455
colony.setExpenditureSkill(tasks[_id].expenditureId, uint256(TaskRole.Worker), _skillId);
426456
}
427457

428458
function setTaskBrief(uint256 _id, bytes32 _specificationHash)
429459
public
430-
self
460+
self(_id)
431461
taskExists(_id)
432-
taskNotComplete(_id)
433462
{
434463
tasks[_id].specificationHash = _specificationHash;
435464

@@ -438,9 +467,8 @@ contract Tasks is DSMath {
438467

439468
function setTaskDueDate(uint256 _id, uint256 _dueDate)
440469
public
441-
self
470+
self(_id)
442471
taskExists(_id)
443-
taskNotComplete(_id)
444472
{
445473
tasks[_id].dueDate = _dueDate;
446474

@@ -450,6 +478,7 @@ contract Tasks is DSMath {
450478
function submitTaskDeliverable(uint256 _id, bytes32 _deliverableHash)
451479
public
452480
taskExists(_id)
481+
taskSecure(_id)
453482
taskNotComplete(_id)
454483
confirmTaskRoleIdentity(_id, msg.sender, TaskRole.Worker)
455484
{
@@ -468,6 +497,7 @@ contract Tasks is DSMath {
468497
function completeTask(uint256 _id)
469498
public
470499
taskExists(_id)
500+
taskSecure(_id)
471501
taskNotComplete(_id)
472502
confirmTaskRoleIdentity(_id, msg.sender, TaskRole.Manager)
473503
{
@@ -479,19 +509,21 @@ contract Tasks is DSMath {
479509

480510
function cancelTask(uint256 _id)
481511
public
482-
self
512+
self(_id)
483513
taskExists(_id)
484-
taskNotComplete(_id)
485514
{
486515
colony.cancelExpenditure(tasks[_id].expenditureId);
487516
}
488517

489518
// Permissions pertain to the Arbitration role here
490-
function finalizeTask(uint256 _permissionDomainId, uint256 _childSkillIndex, uint256 _id)
519+
function finalizeSecureTask(uint256 _permissionDomainId, uint256 _childSkillIndex, uint256 _id)
491520
public
492521
taskExists(_id)
522+
taskSecure(_id)
493523
taskComplete(_id)
494524
{
525+
require(tasks[_id].secure, "task-not-secure");
526+
495527
colony.finalizeExpenditure(tasks[_id].expenditureId);
496528

497529
assignWorkRatings(_id);
@@ -510,6 +542,17 @@ contract Tasks is DSMath {
510542
}
511543
}
512544

545+
function finalizeManagedTask(uint256 _id)
546+
public
547+
taskExists(_id)
548+
taskManaged(_id)
549+
confirmTaskRoleIdentity(_id, msg.sender, TaskRole.Manager)
550+
{
551+
require(!tasks[_id].secure, "task-not-managed");
552+
553+
colony.finalizeExpenditure(tasks[_id].expenditureId);
554+
}
555+
513556
function getTaskCount() public view returns (uint256) {
514557
return taskCount;
515558
}
@@ -629,12 +672,14 @@ contract Tasks is DSMath {
629672
function taskWorkRatingsAssigned(uint256 _id) internal view returns (bool) {
630673
Role storage workerRole = taskRoles[_id][uint8(TaskRole.Worker)];
631674
Role storage managerRole = taskRoles[_id][uint8(TaskRole.Manager)];
675+
632676
return (workerRole.rating != TaskRatings.None) && (managerRole.rating != TaskRatings.None);
633677
}
634678

635679
function taskWorkRatingsClosed(uint256 _id) internal view returns (bool) {
636680
assert(tasks[_id].completionTimestamp > 0);
637681
assert(ratingSecrets[_id].count <= 2);
682+
638683
if (ratingSecrets[_id].count == 2) {
639684
return sub(now, ratingSecrets[_id].timestamp) > RATING_REVEAL_TIMEOUT;
640685
} else {
@@ -667,15 +712,8 @@ contract Tasks is DSMath {
667712
}
668713
}
669714

670-
function setTaskRoleUser(uint256 _id, TaskRole _role, address payable _user)
671-
internal
672-
taskExists(_id)
673-
taskNotComplete(_id)
674-
{
675-
taskRoles[_id][uint8(_role)] = Role({
676-
rateFail: false,
677-
rating: TaskRatings.None
678-
});
715+
function setTaskRoleUser(uint256 _id, TaskRole _role, address payable _user) internal {
716+
taskRoles[_id][uint8(_role)] = Role({ rateFail: false, rating: TaskRatings.None });
679717

680718
colony.setExpenditureRecipient(tasks[_id].expenditureId, uint256(_role), _user);
681719
}
@@ -684,7 +722,15 @@ contract Tasks is DSMath {
684722
return _id > 0 && _id <= taskCount;
685723
}
686724

725+
function isTaskSecure(uint256 _id) internal view returns (bool) {
726+
return tasks[_id].secure;
727+
}
728+
687729
function isTaskComplete(uint256 _id) internal view returns (bool) {
688730
return tasks[_id].completionTimestamp > 0;
689731
}
732+
733+
function managerCanCall(uint256 _id) internal view returns (bool) {
734+
return !tasks[_id].secure && getTaskRoleUser(_id, TaskRole.Manager) == msg.sender;
735+
}
690736
}

0 commit comments

Comments
 (0)