PureVersation / src /PureBi_Jun11.sol
github-actions[bot]
Automated deployment to Hugging Face
963d10b
Raw
History Blame Contribute Delete
7.71 kB
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract PureBi_Jun11 {
// --- 0. BRANDING ---
string public constant name = "PureBilingual Versation June 11, 2026 Research Registry";
string public constant symbol = "VERSATION";
// --- 1. IDENTITY & REPUTATION (PER DIALECT) ---
mapping(address => bool) public isRegistered;
// user -> dialect -> xp
mapping(address => mapping(string => uint256)) public userXP;
// user -> dialect -> role
mapping(address => mapping(string => string)) public userRole;
// Global admin checking
mapping(address => bool) public isAdmin;
address public labAdmin; // The Gasless Relayer (Python Backend)
// --- 2. REGISTRY & LICENSING ---
struct DialectEntry {
uint256 id;
string phrase;
string dialect;
string ipfsCid;
address contributor;
string licenseType;
uint256 verificationCount;
uint256 rejectionCount;
bool isVerified;
bool isBurned;
}
uint256 public entryCounter;
mapping(uint256 => DialectEntry) public entries;
// Consensus Tracking (entry_id -> user -> bool)
mapping(uint256 => mapping(address => bool)) public hasVoted;
// --- 3. BACKUP SYSTEM ---
struct DataSnapshot {
uint256 timestamp;
string dataType;
string ipfsCid;
string description;
}
mapping(string => DataSnapshot[]) public backups;
// --- 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);
event EntryBurned(uint256 indexed id, address indexed contributor);
event ReputationMinted(address indexed researcher, string dialect, uint256 amount);
event RankUpgraded(address indexed researcher, string dialect, string newRole);
event BackupCreated(string indexed dataKey, string ipfsCid, uint256 timestamp);
constructor() {
labAdmin = msg.sender; // The Python Backend Wallet
isAdmin[msg.sender] = true;
}
// --- MODIFIERS ---
modifier onlyRelayer() {
require(msg.sender == labAdmin, "Only the Python Relayer can execute transactions");
_;
}
// --- CORE FUNCTIONS ---
function proposeEntry(string memory _phrase, string memory _dialect, string memory _ipfsCid, string memory _license, address _contributor) public onlyRelayer returns (uint256) {
entryCounter++;
entries[entryCounter] = DialectEntry(entryCounter, _phrase, _dialect, _ipfsCid, _contributor, _license, 0, 0, false, false);
emit EntryProposed(entryCounter, _phrase, _contributor);
if (!isRegistered[_contributor]) {
isRegistered[_contributor] = true;
}
// Auto-register brand new React users as Initiates in this dialect if they have no role
if (bytes(userRole[_contributor][_dialect]).length == 0 && !isAdmin[_contributor]) {
userRole[_contributor][_dialect] = "Initiate";
}
return entryCounter;
}
function verifyEntry(uint256 _id, address _verifier) public onlyRelayer {
DialectEntry storage entry = entries[_id];
require(!entry.isVerified && !entry.isBurned, "Entry already resolved");
require(entry.contributor != _verifier, "Cannot verify own entry");
require(!hasVoted[_id][_verifier], "User already voted");
string memory role = userRole[_verifier][entry.dialect];
bool isGod = isAdmin[_verifier];
bool isOracle = keccak256(bytes(role)) == keccak256(bytes("Oracle"));
require(isGod || isOracle, "Only Admins or Oracles can verify");
hasVoted[_id][_verifier] = true;
_mintReputation(_verifier, entry.dialect, 10); // +10 XP for doing the audit
if (isGod) {
_applyVerification(_id);
} else {
entry.verificationCount++;
if (entry.verificationCount >= 3) {
_applyVerification(_id);
}
}
}
function _applyVerification(uint256 _id) internal {
entries[_id].isVerified = true;
_mintReputation(entries[_id].contributor, entries[_id].dialect, 50); // +50 XP to the original submitter
emit EntryVerified(_id, msg.sender);
}
function rejectEntry(uint256 _id, address _rejector) public onlyRelayer {
DialectEntry storage entry = entries[_id];
require(!entry.isVerified && !entry.isBurned, "Entry already resolved");
require(entry.contributor != _rejector, "Cannot reject own entry");
require(!hasVoted[_id][_rejector], "User already voted");
string memory role = userRole[_rejector][entry.dialect];
bool isGod = isAdmin[_rejector];
bool isOracle = keccak256(bytes(role)) == keccak256(bytes("Oracle"));
require(isGod || isOracle, "Only Admins or Oracles can reject");
hasVoted[_id][_rejector] = true;
_mintReputation(_rejector, entry.dialect, 10); // +10 XP for doing the audit
if (isGod) {
_applyBurn(_id);
} else {
entry.rejectionCount++;
if (entry.rejectionCount >= 3) {
_applyBurn(_id);
}
}
}
function _applyBurn(uint256 _id) internal {
entries[_id].isBurned = true;
address badActor = entries[_id].contributor;
string memory dialect = entries[_id].dialect;
// Burn -10 XP from the contributor
if (userXP[badActor][dialect] >= 10) {
userXP[badActor][dialect] -= 10;
} else {
userXP[badActor][dialect] = 0;
}
_updateRank(badActor, dialect);
emit EntryBurned(_id, badActor);
}
function createBackup(string memory _dataKey, string memory _dataType, string memory _ipfsCid, string memory _description) public onlyRelayer {
DataSnapshot memory newSnap = DataSnapshot(block.timestamp, _dataType, _ipfsCid, _description);
backups[_dataKey].push(newSnap);
emit BackupCreated(_dataKey, _ipfsCid, block.timestamp);
}
// --- INTERNAL REPUTATION & RANKING LOGIC ---
function _mintReputation(address _user, string memory _dialect, uint256 _amount) internal {
userXP[_user][_dialect] += _amount;
emit ReputationMinted(_user, _dialect, _amount);
_updateRank(_user, _dialect);
}
function _updateRank(address _user, string memory _dialect) internal {
if (isAdmin[_user]) return;
uint256 score = userXP[_user][_dialect];
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(userRole[_user][_dialect])) != keccak256(abi.encodePacked(newRole))) {
userRole[_user][_dialect] = newRole;
emit RankUpgraded(_user, _dialect, newRole);
}
}
// --- HELPER QUERIES ---
function getRole(address _user, string memory _dialect) public view returns (string memory) {
if (isAdmin[_user]) return "Admin";
if (bytes(userRole[_user][_dialect]).length == 0) return "Initiate";
return userRole[_user][_dialect];
}
function getXP(address _user, string memory _dialect) public view returns (uint256) {
return userXP[_user][_dialect];
}
}