1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | 10× 4× 1× 1× 1× 1× 1× 1× 1× 1× 1× 70× 55× 27× 25× 25× 25× 25× 125× 125× 5× 5× 3× 3× 3× 15× 15× 15× 3× 2× 10× 10× 5× 5× 5× 5× 5× 5× 140× 70× 25× 955× 953× 48× 44× 44× 42× 42× 42× 1× 1× 1× 1× 1× 1× 1× 1× 1× 1× 1× 1× 1× 1× 1× 11× 11× 11× 36× 36× | pragma solidity ^0.4.23; import "./FathomToken.sol"; import "./ConceptRegistry.sol"; import "./Assessment.sol"; import "./AssessmentData.sol"; import "./Math.sol"; import "./ConceptData.sol"; //@purpose: To store concept data and create and manage assessments and members contract Concept is ConceptData { modifier onlyOwner() { require(msg.sender == owner, 'Owner access only'); _; } function transferOwnership(address _newOwner) public onlyOwner() { owner = _newOwner; } function changeParents(address[] _newParents, uint[] _newPropagationRates) public onlyOwner() { for (uint j = 0; j < _newParents.length; j++) { Erequire(_newParents[j] != address(this), 'Concept cannot be parent to itself'); Erequire(conceptRegistry.conceptExists(_newParents[j]), 'Parent concept does not exist'); Erequire(_newPropagationRates[j] < 1000, 'Propagation rates must be < 1000'); } parents = _newParents; propagationRates = _newPropagationRates; } function changeData(bytes _data) public onlyOwner() { data = _data; } function changeLifetime(uint _newLifetime) public onlyOwner() { lifetime = _newLifetime; } function getAvailableMemberLength() public view returns(uint) { return buckets[activeBucket()].length; } function getParentsLength() public view returns(uint) { return parents.length; } /* @purpose: To add the firstUser to Mew */ function addInitialMember(address _user, uint _weight) public { require(msg.sender == conceptRegistry.distributorAddress(), 'Distributor access only'); Eif (conceptRegistry.distributorAddress() == msg.sender) { addWeight(_user, _weight); uint startBucket = startBucketNumber(_user); for(uint i; i < NofBUCKETS; i++) { buckets[startBucket + i].push(_user); memberData[_user].bucketIndices[startBucket + i] = buckets[startBucket + i].length; } } } /* @purpose: add the caller of this function to the arrays of potential assessors if they still have a weight in the concept @returns true if they are available as assessor */ function toggleAvailability(bool available) public { // startBucket: the msg.senders first bucket they are available in uint startBucketNumber = (memberData[msg.sender].date - CREATION_DATE - lifetime) / (lifetime / NofBUCKETS); if (available) { Erequire(memberData[msg.sender].weight > 0, 'Must have a weight to toggle available'); Erequire(memberData[msg.sender].date > now, 'Weight must not be expired to toggle available'); for (uint i; i < NofBUCKETS; i++) { Eif (memberData[msg.sender].bucketIndices[startBucketNumber + i] == 0) { buckets[startBucketNumber + i].push(msg.sender); memberData[msg.sender].bucketIndices[startBucketNumber + i] = buckets[startBucketNumber + i].length; } } return; } // Else set unavailable for (uint bi; bi < NofBUCKETS; bi++) { uint index = memberData[msg.sender].bucketIndices[startBucketNumber + bi]; if (index > 0) { address[] storage bucket = buckets[startBucketNumber + bi]; address lastMember = bucket[bucket.length -1]; bucket[index - 1] = lastMember; memberData[lastMember].bucketIndices[startBucketNumber + bi] = index; memberData[msg.sender].bucketIndices[startBucketNumber + bi] = 0; bucket.length--; } } } function activeBucket () public view returns(uint) { return (now - CREATION_DATE) / (lifetime / NofBUCKETS); // existence / bucketLength } function getActiveBucket () public view returns(address[]) { return buckets[activeBucket()]; } function startBucketNumber(address _user) internal view returns(uint) { return (memberData[_user].date - CREATION_DATE - lifetime) / (lifetime / NofBUCKETS); } /* @purpose: get the weight of a given member */ function getWeight(address _member) public view returns(uint weight) { if (memberData[_member].date > now) { weight = memberData[_member].weight; } } /* @purpose: To make a new assessment NOTE: While there are less than 200 members in network, all members of mew will be called as assessors for any concept @param: uint cost = the cost per assessor @param: uint size = the number of assessors */ function makeAssessment(uint cost, uint size, uint _waitTime, uint _timeLimit) public { require(size >= 5, 'Assessment size must be >= five'); Erequire(fathomToken.balanceOf(msg.sender) >= cost*size, 'Token balance too low'); Assessment newAssessment = conceptRegistry.proxyFactory().createAssessment( msg.sender, cost, size, _waitTime, _timeLimit ); assessmentExists[address(newAssessment)] = true; fathomToken.takeBalance(msg.sender, address(newAssessment), cost*size, address(this)); newAssessment.setAssessorPool(uint(blockhash(block.number)), address(this), size); } /* integrates the caller into the new concept IFF they have an assessment in the original concept that - is not expired by the definition of the this concept (aka the clone) - and has ended before this concept has been created */ function integrateMember() public { Concept original = Concept(cloneOf); address recentAssessment; uint weight; uint date; (recentAssessment, weight, date) = original.memberData(msg.sender); Erequire(weight > 0, 'Must have a non-zero weight in original concept'); uint adjustedExpirationDate = date - original.lifetime() + lifetime; Erequire(adjustedExpirationDate > now, 'Expiration date must be in the future'); Erequire(Assessment(recentAssessment).endTime() < creationDate, 'Assessment must be before clone creation'); // Initial Members can't migratedd memberData[msg.sender].weight = weight; memberData[msg.sender].date = adjustedExpirationDate; original.migrateMember(msg.sender); // if (available) toggleAvailable(true); // by default, members are available in the new concept } function migrateMember(address _member) public { Erequire(conceptRegistry.conceptExists(msg.sender), 'Concept access only'); toggleAvailability(false); delete memberData[_member]; } /* @purpose: To add a member to a concept @param: address assessee = the address of the assessee @param: uint weight = the weight for the member @returns: nothing */ function addMember(address _assessee, uint _weight) external { Eif (assessmentExists[msg.sender]) { memberData[_assessee].recentAssessment = msg.sender; addWeight(_assessee, _weight); } } function addWeight(address _assessee, uint _weight) internal { memberData[_assessee].weight = _weight; memberData[_assessee].date = now + lifetime > now ? now + lifetime : 2**255; } } |