Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions contracts/MetaTxExample.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,15 @@ contract MetaTxExample is ERC2771Context, EIP712 {
bytes32 digest = _hashTypedDataV4(structHash);

// Check for replay
require(!usedSignatures[digest], "Signature already used");
bytes32 sigHash = keccak256(signature);
require(!usedSignatures[sigHash], "Signature already used");

// Recover signer from signature
address signer = digest.recover(signature);
require(signer == from, "Invalid signature");

// Mark signature as used
usedSignatures[digest] = true;
usedSignatures[sigHash] = true;

// Increment nonce
nonces[from]++;
Expand Down
21 changes: 18 additions & 3 deletions contracts/TruthBounty.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./utils/ResolverRoleTimelock.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
Expand Down Expand Up @@ -60,10 +61,23 @@ contract TruthBountyToken is ERC20, ResolverRoleTimelock, Initializable, UUPSUpg
}

function setSettlementContract(address _settlement) external onlyRole(ADMIN_ROLE) {
require(_settlement != address(0), "Invalid settlement contract");
if (settlementContract != address(0)) {
if (hasRole(RESOLVER_ROLE, settlementContract)) {
_scheduleResolverRoleRevoke(settlementContract);
} else {
bytes32 pendingGrant = resolverRoleChangeId(settlementContract, true);
if (resolverRoleChangeReadyAt[pendingGrant] != 0) {
delete resolverRoleChangeReadyAt[pendingGrant];
emit ResolverRoleChangeCancelled(pendingGrant, settlementContract, true);
}
}
}
address oldSettlement = settlementContract;
settlementContract = _settlement;
// Automatically grant RESOLVER_ROLE to the settlement contract
_grantRole(RESOLVER_ROLE, _settlement);
if (!hasRole(RESOLVER_ROLE, _settlement)) {
_scheduleResolverRoleGrant(_settlement);
}
emit SettlementContractUpdated(oldSettlement, _settlement);
}

Expand Down Expand Up @@ -201,6 +215,7 @@ contract TruthBounty is AccessControl, ReentrancyGuard, Pausable, GovernanceOwna
mapping(address => uint256) public verifierRewards;

uint256 public verificationWindowDuration = 7 days;
uint256 public confirmationDelay = 1 hours;
uint256 public minStakeAmount = 100 * 10**18;
uint256 public settlementThresholdPercent = 60;
uint256 public rewardPercent = 80;
Expand Down Expand Up @@ -332,7 +347,7 @@ contract TruthBounty is AccessControl, ReentrancyGuard, Pausable, GovernanceOwna
function settleClaim(uint256 claimId) external nonReentrant whenNotPaused {
Claim storage claim = claims[claimId];
require(claim.submitter != address(0), "Claim does not exist");
require(block.timestamp >= claim.verificationWindowEnd, "Verification window not closed");
require(block.timestamp >= claim.verificationWindowEnd + confirmationDelay, "Confirmation delay pending");
require(!claim.settled, "Claim already settled");
require(claim.totalStakeAmount > 0, "No votes cast");

Expand Down
21 changes: 12 additions & 9 deletions contracts/TruthBountyWeighted.sol
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,13 @@ contract TruthBountyWeighted is ResolverRoleTimelock, ReentrancyGuard, Pausable,

verifierStakes[msg.sender].totalStaked += amount;

if (reputationSnapshots[msg.sender].timestamp == 0) {
reputationSnapshots[msg.sender] = ReputationSnapshot({
reputationScore: _getReputationScore(msg.sender),
timestamp: block.timestamp
});
}

emit StakeDeposited(msg.sender, amount);
}

Expand Down Expand Up @@ -724,13 +731,6 @@ contract TruthBountyWeighted is ResolverRoleTimelock, ReentrancyGuard, Pausable,
uint256 expectedReputation,
uint256 maxDrift
) internal {
ReputationSnapshot memory lastSnapshot = reputationSnapshots[user];

// If no previous snapshot, this is the first preview - allow it
if (lastSnapshot.timestamp == 0) {
return;
}

// Check if reputation has changed more than the allowed drift
if (maxDrift > 0) {
// Calculate percentage change: (|current - expected| / expected) * 10000
Expand All @@ -743,8 +743,11 @@ contract TruthBountyWeighted is ResolverRoleTimelock, ReentrancyGuard, Pausable,
}

// Check if reputation is too stale (timestamp-based)
uint256 timeSinceSnapshot = block.timestamp - lastSnapshot.timestamp;
require(timeSinceSnapshot <= MAX_REPUTATION_STALENESS, "Reputation too stale");
ReputationSnapshot memory lastSnapshot = reputationSnapshots[user];
if (lastSnapshot.timestamp > 0) {
uint256 timeSinceSnapshot = block.timestamp - lastSnapshot.timestamp;
require(timeSinceSnapshot <= MAX_REPUTATION_STALENESS, "Reputation too stale");
}

// Emit validation event
emit ReputationStalenessValidated(user, expectedReputation, currentReputation, maxDrift);
Expand Down
Loading