docs(plan): update milestone planning with phase 4 focus and success metrics
- Update priority areas from "100% COMPLETE" to "Next Priority Areas" with phase 4 focus - Mark Smart Contract Development as 🔄 NEXT and Advanced AI Features as 🔄 FUTURE - Restructure development timeline with Q2 2026 marked as COMPLETED, Q3 2026 as CURRENT PHASE - Add Q4 2026 future planning section with weeks 25-36 roadmap - Reorganize next development steps into completed and future sections - Add comprehensive success metrics and
This commit is contained in:
606
contracts/contracts/PerformanceAggregator.sol
Normal file
606
contracts/contracts/PerformanceAggregator.sol
Normal file
@@ -0,0 +1,606 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
||||
import "@openzeppelin/contracts/security/Pausable.sol";
|
||||
import "../interfaces/IModularContracts.sol";
|
||||
import "./ContractRegistry.sol";
|
||||
|
||||
/**
|
||||
* @title PerformanceAggregator
|
||||
* @dev Cross-contract performance data aggregation with reputation scoring
|
||||
* @notice Integrates with AgentStaking, AgentBounty, and PerformanceVerifier
|
||||
*/
|
||||
contract PerformanceAggregator is IPerformanceAggregator, Ownable, ReentrancyGuard, Pausable {
|
||||
|
||||
// State variables
|
||||
uint256 public version = 1;
|
||||
ContractRegistry public registry;
|
||||
address public performanceVerifier;
|
||||
address public agentBounty;
|
||||
address public agentStaking;
|
||||
|
||||
// Performance metrics
|
||||
struct PerformanceMetrics {
|
||||
uint256 totalTasks;
|
||||
uint256 completedTasks;
|
||||
uint256 failedTasks;
|
||||
uint256 averageAccuracy;
|
||||
uint256 totalEarnings;
|
||||
uint256 lastUpdated;
|
||||
uint256 reputationScore;
|
||||
uint256 performanceTier; // 0-5 performance tiers
|
||||
}
|
||||
|
||||
// Performance history
|
||||
struct PerformanceRecord {
|
||||
uint256 recordId;
|
||||
address agent;
|
||||
uint256 score;
|
||||
uint256 accuracy;
|
||||
uint256 earnings;
|
||||
uint256 timestamp;
|
||||
string taskType;
|
||||
bool isPositive;
|
||||
}
|
||||
|
||||
// Performance tier thresholds
|
||||
struct PerformanceTier {
|
||||
uint256 minScore;
|
||||
uint256 maxScore;
|
||||
uint256 apyMultiplier; // In basis points (10000 = 1x)
|
||||
string name;
|
||||
}
|
||||
|
||||
// Mappings
|
||||
mapping(address => PerformanceMetrics) public agentMetrics;
|
||||
mapping(uint256 => PerformanceRecord) public performanceRecords;
|
||||
mapping(address => uint256[]) public agentRecords;
|
||||
mapping(uint256 => address) public recordToAgent;
|
||||
mapping(uint256 => PerformanceTier) public performanceTiers;
|
||||
|
||||
// Counters
|
||||
uint256 public recordCounter;
|
||||
uint256 public tierCounter;
|
||||
uint256[] public recordIds;
|
||||
|
||||
// Constants
|
||||
uint256 public constant INITIAL_REPUTATION = 5000; // 50% initial reputation
|
||||
uint256 public constant MAX_REPUTATION = 10000; // 100% max reputation
|
||||
uint256 public constant MIN_REPUTATION = 0; // 0% min reputation
|
||||
uint256 public constant REPUTATION_DECAY_RATE = 100; // 1% decay per day
|
||||
uint256 public constant DECAY_INTERVAL = 1 days;
|
||||
uint256 public constant MAX_HISTORY_RECORDS = 1000; // Max records per agent
|
||||
|
||||
// Events
|
||||
event PerformanceUpdated(address indexed agent, uint256 score, uint256 reputation);
|
||||
event ReputationCalculated(address indexed agent, uint256 reputation, uint256 tier);
|
||||
event PerformanceRecordAdded(uint256 indexed recordId, address indexed agent, uint256 score);
|
||||
event PerformanceTierUpdated(uint256 indexed tier, uint256 minScore, uint256 maxScore, uint256 multiplier);
|
||||
event AgentTierChanged(address indexed agent, uint256 oldTier, uint256 newTier);
|
||||
event BatchPerformanceUpdated(address[] agents, uint256[] scores);
|
||||
|
||||
// Errors
|
||||
error InvalidScore(uint256 score);
|
||||
error InvalidAgent(address agent);
|
||||
error InvalidAccuracy(uint256 accuracy);
|
||||
error RecordNotFound(uint256 recordId);
|
||||
error MaxHistoryReached(address agent);
|
||||
error RegistryNotSet();
|
||||
error NotAuthorized();
|
||||
|
||||
modifier validScore(uint256 score) {
|
||||
if (score > MAX_REPUTATION) revert InvalidScore(score);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier validAgent(address agent) {
|
||||
if (agent == address(0)) revert InvalidAgent(agent);
|
||||
_;
|
||||
}
|
||||
|
||||
modifier validAccuracy(uint256 accuracy) {
|
||||
if (accuracy > 10000) revert InvalidAccuracy(accuracy); // Accuracy in basis points
|
||||
_;
|
||||
}
|
||||
|
||||
modifier onlyAuthorized() {
|
||||
if (msg.sender != owner() && msg.sender != performanceVerifier && msg.sender != agentBounty && msg.sender != agentStaking) {
|
||||
revert NotAuthorized();
|
||||
}
|
||||
_;
|
||||
}
|
||||
|
||||
modifier registrySet() {
|
||||
if (address(registry) == address(0)) revert RegistryNotSet();
|
||||
_;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
// Initialize default performance tiers
|
||||
_initializeDefaultTiers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Initialize the performance aggregator (implements IModularContract)
|
||||
*/
|
||||
function initialize(address _registry) external override {
|
||||
require(address(registry) == address(0), "Already initialized");
|
||||
registry = ContractRegistry(_registry);
|
||||
|
||||
// Register this contract
|
||||
bytes32 contractId = keccak256(abi.encodePacked("PerformanceAggregator"));
|
||||
registry.registerContract(contractId, address(this));
|
||||
|
||||
// Get integration addresses from registry
|
||||
performanceVerifier = registry.getContract(keccak256(abi.encodePacked("PerformanceVerifier")));
|
||||
agentBounty = registry.getContract(keccak256(abi.encodePacked("AgentBounty")));
|
||||
agentStaking = registry.getContract(keccak256(abi.encodePacked("AgentStaking")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Upgrade the contract
|
||||
*/
|
||||
function upgrade(address newImplementation) external override onlyOwner {
|
||||
version++;
|
||||
// Implementation upgrade logic would go here
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pause the contract
|
||||
*/
|
||||
function pause() external override onlyOwner {
|
||||
_pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Unpause the contract
|
||||
*/
|
||||
function unpause() external override onlyOwner {
|
||||
_unpause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get current version
|
||||
*/
|
||||
function getVersion() external view override returns (uint256) {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Update agent performance
|
||||
*/
|
||||
function updateAgentPerformance(address agent, uint256 score)
|
||||
external
|
||||
override
|
||||
onlyAuthorized
|
||||
whenNotPaused
|
||||
validAgent(agent)
|
||||
validScore(score)
|
||||
nonReentrant
|
||||
{
|
||||
_updatePerformance(agent, score, 0, 0, "general", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Update agent performance with detailed metrics
|
||||
*/
|
||||
function updateAgentPerformanceDetailed(
|
||||
address agent,
|
||||
uint256 score,
|
||||
uint256 accuracy,
|
||||
uint256 earnings,
|
||||
string memory taskType,
|
||||
bool isPositive
|
||||
)
|
||||
external
|
||||
onlyAuthorized
|
||||
whenNotPaused
|
||||
validAgent(agent)
|
||||
validScore(score)
|
||||
validAccuracy(accuracy)
|
||||
nonReentrant
|
||||
{
|
||||
_updatePerformance(agent, score, accuracy, earnings, taskType, isPositive);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Batch update agent performance
|
||||
*/
|
||||
function batchUpdatePerformance(address[] memory agents, uint256[] memory scores)
|
||||
external
|
||||
onlyAuthorized
|
||||
whenNotPaused
|
||||
nonReentrant
|
||||
{
|
||||
require(agents.length == scores.length, "Array length mismatch");
|
||||
|
||||
for (uint256 i = 0; i < agents.length; i++) {
|
||||
if (agents[i] != address(0) && scores[i] <= MAX_REPUTATION) {
|
||||
_updatePerformance(agents[i], scores[i], 0, 0, "batch", true);
|
||||
}
|
||||
}
|
||||
|
||||
emit BatchPerformanceUpdated(agents, scores);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal performance update logic
|
||||
*/
|
||||
function _updatePerformance(
|
||||
address agent,
|
||||
uint256 score,
|
||||
uint256 accuracy,
|
||||
uint256 earnings,
|
||||
string memory taskType,
|
||||
bool isPositive
|
||||
) internal {
|
||||
PerformanceMetrics storage metrics = agentMetrics[agent];
|
||||
|
||||
// Initialize if new agent
|
||||
if (metrics.lastUpdated == 0) {
|
||||
metrics.totalTasks = 0;
|
||||
metrics.completedTasks = 0;
|
||||
metrics.failedTasks = 0;
|
||||
metrics.averageAccuracy = 0;
|
||||
metrics.totalEarnings = 0;
|
||||
metrics.reputationScore = INITIAL_REPUTATION;
|
||||
metrics.performanceTier = 0;
|
||||
}
|
||||
|
||||
// Update metrics
|
||||
metrics.totalTasks++;
|
||||
if (isPositive) {
|
||||
metrics.completedTasks++;
|
||||
} else {
|
||||
metrics.failedTasks++;
|
||||
}
|
||||
|
||||
// Update average accuracy
|
||||
if (accuracy > 0) {
|
||||
metrics.averageAccuracy = (metrics.averageAccuracy * (metrics.totalTasks - 1) + accuracy) / metrics.totalTasks;
|
||||
}
|
||||
|
||||
// Update earnings
|
||||
if (earnings > 0) {
|
||||
metrics.totalEarnings += earnings;
|
||||
}
|
||||
|
||||
// Calculate new reputation score
|
||||
uint256 newReputation = _calculateReputation(metrics, score);
|
||||
uint256 oldTier = metrics.performanceTier;
|
||||
uint256 newTier = _getPerformanceTier(newReputation);
|
||||
|
||||
// Update reputation and tier
|
||||
metrics.reputationScore = newReputation;
|
||||
metrics.performanceTier = newTier;
|
||||
metrics.lastUpdated = block.timestamp;
|
||||
|
||||
// Add performance record
|
||||
uint256 recordId = ++recordCounter;
|
||||
performanceRecords[recordId] = PerformanceRecord({
|
||||
recordId: recordId,
|
||||
agent: agent,
|
||||
score: score,
|
||||
accuracy: accuracy,
|
||||
earnings: earnings,
|
||||
timestamp: block.timestamp,
|
||||
taskType: taskType,
|
||||
isPositive: isPositive
|
||||
});
|
||||
|
||||
agentRecords[agent].push(recordId);
|
||||
recordToAgent[recordId] = agent;
|
||||
recordIds.push(recordId);
|
||||
|
||||
// Limit history size
|
||||
if (agentRecords[agent].length > MAX_HISTORY_RECORDS) {
|
||||
uint256 oldRecordId = agentRecords[agent][0];
|
||||
delete performanceRecords[oldRecordId];
|
||||
delete recordToAgent[oldRecordId];
|
||||
|
||||
// Shift array
|
||||
for (uint256 i = 0; i < agentRecords[agent].length - 1; i++) {
|
||||
agentRecords[agent][i] = agentRecords[agent][i + 1];
|
||||
}
|
||||
agentRecords[agent].pop();
|
||||
}
|
||||
|
||||
emit PerformanceUpdated(agent, score, newReputation);
|
||||
emit ReputationCalculated(agent, newReputation, newTier);
|
||||
emit PerformanceRecordAdded(recordId, agent, score);
|
||||
|
||||
if (oldTier != newTier) {
|
||||
emit AgentTierChanged(agent, oldTier, newTier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculate reputation score based on metrics
|
||||
*/
|
||||
function _calculateReputation(PerformanceMetrics memory metrics, uint256 currentScore) internal view returns (uint256) {
|
||||
// Base score from current performance
|
||||
uint256 baseScore = currentScore;
|
||||
|
||||
// Adjust based on task completion rate
|
||||
uint256 completionRate = metrics.totalTasks > 0 ?
|
||||
(metrics.completedTasks * 10000) / metrics.totalTasks : 0;
|
||||
|
||||
// Adjust based on average accuracy
|
||||
uint256 accuracyBonus = metrics.averageAccuracy > 0 ?
|
||||
(metrics.averageAccuracy * 2000) / 10000 : 0; // Max 20% bonus
|
||||
|
||||
// Adjust based on earnings (logarithmic scaling)
|
||||
uint256 earningsBonus = 0;
|
||||
if (metrics.totalEarnings > 0) {
|
||||
// Logarithmic scaling: every 10x increase in earnings adds 10% bonus
|
||||
earningsBonus = (1000 * log10(metrics.totalEarnings)) / 10000;
|
||||
}
|
||||
|
||||
// Apply time decay
|
||||
uint256 timeSinceLastUpdate = block.timestamp - metrics.lastUpdated;
|
||||
uint256 decayAmount = (timeSinceLastUpdate * REPUTATION_DECAY_RATE) / DECAY_INTERVAL;
|
||||
|
||||
// Calculate final reputation
|
||||
uint256 finalScore = baseScore + completionRate + accuracyBonus + earningsBonus - decayAmount;
|
||||
|
||||
// Clamp to valid range
|
||||
if (finalScore > MAX_REPUTATION) {
|
||||
finalScore = MAX_REPUTATION;
|
||||
} else if (finalScore < MIN_REPUTATION) {
|
||||
finalScore = MIN_REPUTATION;
|
||||
}
|
||||
|
||||
return finalScore;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Simple logarithm approximation for earnings bonus
|
||||
*/
|
||||
function log10(uint256 value) internal pure returns (uint256) {
|
||||
if (value == 0) return 0;
|
||||
if (value < 10) return 0;
|
||||
if (value < 100) return 1;
|
||||
if (value < 1000) return 2;
|
||||
if (value < 10000) return 3;
|
||||
if (value < 100000) return 4;
|
||||
if (value < 1000000) return 5;
|
||||
if (value < 10000000) return 6;
|
||||
if (value < 100000000) return 7;
|
||||
if (value < 1000000000) return 8;
|
||||
if (value < 10000000000) return 9;
|
||||
return 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get performance tier for reputation score
|
||||
*/
|
||||
function _getPerformanceTier(uint256 reputation) internal view returns (uint256) {
|
||||
for (uint256 i = tierCounter; i > 0; i--) {
|
||||
PerformanceTier memory tier = performanceTiers[i];
|
||||
if (reputation >= tier.minScore && reputation <= tier.maxScore) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0; // Default tier
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get reputation score for agent
|
||||
*/
|
||||
function getReputationScore(address agent) external view override returns (uint256) {
|
||||
return agentMetrics[agent].reputationScore;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculate APY multiplier for reputation
|
||||
*/
|
||||
function calculateAPYMultiplier(uint256 reputation) external view override returns (uint256) {
|
||||
uint256 tier = _getPerformanceTier(reputation);
|
||||
if (tier > 0) {
|
||||
return performanceTiers[tier].apyMultiplier;
|
||||
}
|
||||
return 10000; // 1x default multiplier
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get performance history for agent
|
||||
*/
|
||||
function getPerformanceHistory(address agent) external view override returns (uint256[] memory) {
|
||||
return agentRecords[agent];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get detailed performance metrics for agent
|
||||
*/
|
||||
function getAgentMetrics(address agent) external view returns (
|
||||
uint256 totalTasks,
|
||||
uint256 completedTasks,
|
||||
uint256 failedTasks,
|
||||
uint256 averageAccuracy,
|
||||
uint256 totalEarnings,
|
||||
uint256 reputationScore,
|
||||
uint256 performanceTier,
|
||||
uint256 lastUpdated
|
||||
) {
|
||||
PerformanceMetrics memory metrics = agentMetrics[agent];
|
||||
return (
|
||||
metrics.totalTasks,
|
||||
metrics.completedTasks,
|
||||
metrics.failedTasks,
|
||||
metrics.averageAccuracy,
|
||||
metrics.totalEarnings,
|
||||
metrics.reputationScore,
|
||||
metrics.performanceTier,
|
||||
metrics.lastUpdated
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get performance record details
|
||||
*/
|
||||
function getPerformanceRecord(uint256 recordId) external view returns (
|
||||
address agent,
|
||||
uint256 score,
|
||||
uint256 accuracy,
|
||||
uint256 earnings,
|
||||
uint256 timestamp,
|
||||
string memory taskType,
|
||||
bool isPositive
|
||||
) {
|
||||
PerformanceRecord memory record = performanceRecords[recordId];
|
||||
return (
|
||||
record.agent,
|
||||
record.score,
|
||||
record.accuracy,
|
||||
record.earnings,
|
||||
record.timestamp,
|
||||
record.taskType,
|
||||
record.isPositive
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get performance tier details
|
||||
*/
|
||||
function getPerformanceTier(uint256 tierId) external view returns (
|
||||
uint256 minScore,
|
||||
uint256 maxScore,
|
||||
uint256 apyMultiplier,
|
||||
string memory name
|
||||
) {
|
||||
PerformanceTier memory tier = performanceTiers[tierId];
|
||||
return (
|
||||
tier.minScore,
|
||||
tier.maxScore,
|
||||
tier.apyMultiplier,
|
||||
tier.name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get all performance tiers
|
||||
*/
|
||||
function getAllPerformanceTiers() external view returns (uint256[] memory) {
|
||||
uint256[] memory tierIds = new uint256[](tierCounter);
|
||||
for (uint256 i = 1; i <= tierCounter; i++) {
|
||||
tierIds[i - 1] = i;
|
||||
}
|
||||
return tierIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Update performance tier
|
||||
*/
|
||||
function updatePerformanceTier(
|
||||
uint256 tierId,
|
||||
uint256 minScore,
|
||||
uint256 maxScore,
|
||||
uint256 apyMultiplier,
|
||||
string memory name
|
||||
) external onlyOwner {
|
||||
require(tierId > 0 && tierId <= tierCounter, "Invalid tier ID");
|
||||
|
||||
performanceTiers[tierId] = PerformanceTier({
|
||||
minScore: minScore,
|
||||
maxScore: maxScore,
|
||||
apyMultiplier: apyMultiplier,
|
||||
name: name
|
||||
});
|
||||
|
||||
emit PerformanceTierUpdated(tierId, minScore, maxScore, apyMultiplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Add new performance tier
|
||||
*/
|
||||
function addPerformanceTier(
|
||||
uint256 minScore,
|
||||
uint256 maxScore,
|
||||
uint256 apyMultiplier,
|
||||
string memory name
|
||||
) external onlyOwner {
|
||||
require(minScore <= maxScore, "Invalid score range");
|
||||
require(apyMultiplier <= 50000, "Multiplier too high"); // Max 5x
|
||||
|
||||
tierCounter++;
|
||||
performanceTiers[tierCounter] = PerformanceTier({
|
||||
minScore: minScore,
|
||||
maxScore: maxScore,
|
||||
apyMultiplier: apyMultiplier,
|
||||
name: name
|
||||
});
|
||||
|
||||
emit PerformanceTierUpdated(tierCounter, minScore, maxScore, apyMultiplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Initialize default performance tiers
|
||||
*/
|
||||
function _initializeDefaultTiers() internal {
|
||||
tierCounter++;
|
||||
performanceTiers[tierCounter] = PerformanceTier({
|
||||
minScore: 0,
|
||||
maxScore: 2000,
|
||||
apyMultiplier: 8000, // 0.8x
|
||||
name: "Bronze"
|
||||
});
|
||||
|
||||
tierCounter++;
|
||||
performanceTiers[tierCounter] = PerformanceTier({
|
||||
minScore: 2001,
|
||||
maxScore: 4000,
|
||||
apyMultiplier: 10000, // 1x
|
||||
name: "Silver"
|
||||
});
|
||||
|
||||
tierCounter++;
|
||||
performanceTiers[tierCounter] = PerformanceTier({
|
||||
minScore: 4001,
|
||||
maxScore: 6000,
|
||||
apyMultiplier: 12000, // 1.2x
|
||||
name: "Gold"
|
||||
});
|
||||
|
||||
tierCounter++;
|
||||
performanceTiers[tierCounter] = PerformanceTier({
|
||||
minScore: 6001,
|
||||
maxScore: 8000,
|
||||
apyMultiplier: 15000, // 1.5x
|
||||
name: "Platinum"
|
||||
});
|
||||
|
||||
tierCounter++;
|
||||
performanceTiers[tierCounter] = PerformanceTier({
|
||||
minScore: 8001,
|
||||
maxScore: 10000,
|
||||
apyMultiplier: 20000, // 2x
|
||||
name: "Diamond"
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get aggregator statistics
|
||||
*/
|
||||
function getAggregatorStats() external view returns (
|
||||
uint256 totalAgents,
|
||||
uint256 totalRecords,
|
||||
uint256 averageReputation,
|
||||
uint256 activeAgents
|
||||
) {
|
||||
uint256 _totalAgents = 0;
|
||||
uint256 _totalReputation = 0;
|
||||
uint256 _activeAgents = 0;
|
||||
|
||||
// This would require iterating through all agents, which is gas-intensive
|
||||
// For production, consider using a different approach or off-chain calculation
|
||||
|
||||
return (
|
||||
_totalAgents,
|
||||
recordCounter,
|
||||
_totalReputation,
|
||||
_activeAgents
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user