Spaces:
Restarting
Restarting
File size: 7,377 Bytes
6aa52e4 fab9c06 6aa52e4 fab9c06 6aa52e4 fab9c06 6aa52e4 | 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 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | // SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract PureVersation {
// --- 0. BRANDING ---
string public constant name = "PureVersation Research Registry";
string public constant symbol = "VERSATION";
// --- 1. IDENTITY & REPUTATION ---
struct Researcher {
bool isRegistered;
uint256 reputationScore;
string role; // Dynamic: "Initiate", "Scout", "Linguist", "Archivist", "Oracle", or "Admin"
}
mapping(address => Researcher) public researchers;
address public labAdmin;
// --- 2. REGISTRY & LICENSING ---
struct DialectEntry {
uint256 id;
string phrase;
string dialect;
string ipfsCid;
address contributor;
string licenseType;
uint256 verificationCount;
bool isVerified;
}
uint256 public entryCounter;
mapping(uint256 => DialectEntry) public entries;
// --- 3. BACKUP SYSTEM ---
struct DataSnapshot {
uint256 timestamp;
string dataType; // "Database_CSV" or "Persona_JSON"
string ipfsCid;
string description;
address uploader;
}
mapping(string => DataSnapshot[]) public backups;
// 🟢 NEW MAPPINGS FOR SECURITY
mapping(uint256 => mapping(address => bool)) public hasVerified;
mapping(uint256 => mapping(address => bool)) public hasRejected;
mapping(uint256 => uint256) public rejectionCounts;
// --- 4. EVENTS ---
event EntryProposed(uint256 indexed id, string phrase, address indexed proposer);
event EntryVerified(uint256 indexed id, address indexed verifier);
event EntryRejected(uint256 indexed id, address indexed rejector); // 🟢 NEW EVENT
event ReputationMinted(address indexed researcher, uint256 amount);
event RankUpgraded(address indexed researcher, string newRole);
event BackupCreated(string indexed dataKey, string ipfsCid, uint256 timestamp);
constructor() {
labAdmin = msg.sender;
researchers[msg.sender] = Researcher(true, 100, "Admin");
}
// --- MODIFIERS ---
modifier onlyAdmin() {
require(msg.sender == labAdmin, "Only Lab Admin can do this");
_;
}
modifier onlyRegistered() {
require(researchers[msg.sender].isRegistered, "Must be registered researcher");
_;
}
// --- CORE FUNCTIONS ---
function registerResearcher(address _user, string memory _initialRole) public onlyAdmin {
researchers[_user] = Researcher(true, 10, _initialRole);
_updateRank(_user);
}
function proposeEntry(string memory _phrase, string memory _dialect, string memory _ipfsCid, string memory _license, address _contributor) public onlyRegistered {
entryCounter++;
entries[entryCounter] = DialectEntry(entryCounter, _phrase, _dialect, _ipfsCid, _contributor, _license, 0, false);
emit EntryProposed(entryCounter, _phrase, _contributor);
if (!researchers[_contributor].isRegistered) {
researchers[_contributor] = Researcher(true, 0, "Initiate");
}
}
function verifyEntry(uint256 _id) public onlyRegistered {
require(entries[_id].contributor != msg.sender, "Cannot verify own entry");
require(!entries[_id].isVerified, "Already verified");
if (msg.sender == labAdmin) {
// Admin can verify instantly
_applyVerification(_id);
} else {
// Peer consensus
require(!hasVerified[_id][msg.sender], "Already verified by you");
hasVerified[_id][msg.sender] = true;
entries[_id].verificationCount++;
if (entries[_id].verificationCount >= 2) {
_applyVerification(_id);
}
}
// Reward the verifier
_mintReputation(msg.sender, 10);
}
// 🟢 Helper for verification
function _applyVerification(uint256 _id) internal {
entries[_id].isVerified = true;
_mintReputation(entries[_id].contributor, 50);
emit EntryVerified(_id, msg.sender);
}
// 🟢 FIX 2: Admin or Peer consensus rejection
function rejectEntry(uint256 _id) public onlyRegistered {
require(!entries[_id].isVerified, "Cannot reject an already verified entry");
if (msg.sender == labAdmin) {
// Admin can reject instantly
_applyRejection(_id);
} else {
// Peer consensus (3 out of 5 typical)
require(!hasRejected[_id][msg.sender], "Already rejected by you");
hasRejected[_id][msg.sender] = true;
rejectionCounts[_id]++;
if (rejectionCounts[_id] >= 3) {
_applyRejection(_id);
}
}
}
// 🟢 Helper for rejection
function _applyRejection(uint256 _id) internal {
address badActor = entries[_id].contributor;
_burnReputation(badActor, 10);
emit EntryRejected(_id, msg.sender);
}
function createBackup(string memory _dataKey, string memory _dataType, string memory _ipfsCid, string memory _description) public onlyRegistered {
DataSnapshot memory newSnap = DataSnapshot(block.timestamp, _dataType, _ipfsCid, _description, msg.sender);
backups[_dataKey].push(newSnap);
emit BackupCreated(_dataKey, _ipfsCid, block.timestamp);
}
// --- HELPER & VIEW FUNCTIONS ---
function getLatestBackup(string memory _dataKey) public view returns (string memory ipfsCid, uint256 timestamp) {
require(backups[_dataKey].length > 0, "No backups found");
DataSnapshot memory snap = backups[_dataKey][backups[_dataKey].length - 1];
return (snap.ipfsCid, snap.timestamp);
}
function getLicenseInfo(uint256 _id) public view returns (string memory license, address contributor) {
return (entries[_id].licenseType, entries[_id].contributor);
}
// --- INTERNAL REPUTATION & RANKING LOGIC ---
function _mintReputation(address _user, uint256 _amount) internal {
researchers[_user].reputationScore += _amount;
emit ReputationMinted(_user, _amount);
_updateRank(_user);
}
function _burnReputation(address _user, uint256 _amount) internal {
if (researchers[_user].reputationScore >= _amount) {
researchers[_user].reputationScore -= _amount;
} else {
researchers[_user].reputationScore = 0;
}
_updateRank(_user);
}
function _updateRank(address _user) internal {
Researcher storage r = researchers[_user];
if (keccak256(abi.encodePacked(r.role)) == keccak256(abi.encodePacked("Admin"))) {
return;
}
uint256 score = r.reputationScore;
string memory newRole;
if (score >= 1500) {
newRole = "Oracle";
} else if (score >= 800) {
newRole = "Archivist";
} else if (score >= 300) {
newRole = "Linguist";
} else if (score >= 100) {
newRole = "Scout";
} else {
newRole = "Initiate";
}
if (keccak256(abi.encodePacked(r.role)) != keccak256(abi.encodePacked(newRole))) {
r.role = newRole;
emit RankUpgraded(_user, newRole);
}
}
}
|