Files
aitbc/contracts/BountyIntegration.sol
oib a477681c4b feat(developer-ecosystem): implement bounty and staking system with ZK-proof integration
Phase 1 Implementation Complete:
- AgentBounty.sol: Automated bounty board with ZK-proof verification
- AgentStaking.sol: Reputation-based yield farming with dynamic APY
- BountyIntegration.sol: Cross-contract event handling and auto-verification
- Database models: Complete bounty, staking, and ecosystem metrics schemas
- REST APIs: Full bounty and staking management endpoints
- Services: Business logic for bounty creation, verification, and staking operations
- Ecosystem dashboard: Analytics and metrics tracking system

Key Features:
- Multi-tier bounty system (Bronze, Silver, Gold, Platinum)
- Performance-based APY calculation with reputation multipliers
- ZK-proof integration with PerformanceVerifier.sol
- Automatic bounty completion detection
- Comprehensive analytics dashboard
- Risk assessment and leaderboards
- Real-time metrics and predictions

Security Features:
- Reentrancy protection on all contracts
- Role-based access control
- Dispute resolution mechanism
- Early unbonding penalties
- Platform fee collection

Economic Model:
- Creation fees: 0.5%
- Success fees: 2%
- Platform fees: 1%
- Staking APY: 5-20% based on performance
- Dispute fees: 0.1%
2026-02-27 17:51:23 +01:00

617 lines
20 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./AgentBounty.sol";
import "./AgentStaking.sol";
import "./PerformanceVerifier.sol";
import "./AIToken.sol";
/**
* @title Bounty Integration Layer
* @dev Bridges PerformanceVerifier with bounty and staking contracts
* @notice Handles automatic bounty completion detection and cross-contract event handling
*/
contract BountyIntegration is Ownable, ReentrancyGuard {
// State variables
AgentBounty public agentBounty;
AgentStaking public agentStaking;
PerformanceVerifier public performanceVerifier;
AIToken public aitbcToken;
uint256 public integrationCounter;
uint256 public autoVerificationThreshold = 90; // 90% accuracy for auto-verification
uint256 public batchProcessingLimit = 50;
uint256 public gasOptimizationThreshold = 100000;
// Integration status
enum IntegrationStatus { PENDING, PROCESSING, COMPLETED, FAILED }
// Performance to bounty mapping
struct PerformanceMapping {
uint256 mappingId;
bytes32 performanceHash;
uint256 bountyId;
uint256 submissionId;
IntegrationStatus status;
uint256 createdAt;
uint256 processedAt;
string errorMessage;
}
// Batch processing
struct BatchRequest {
uint256 batchId;
uint256[] bountyIds;
uint256[] submissionIds;
bytes32[] performanceHashes;
uint256[] accuracies;
uint256[] responseTimes;
IntegrationStatus status;
uint256 createdAt;
uint256 processedAt;
uint256 successCount;
uint256 failureCount;
}
// Event handlers
struct EventHandler {
bytes32 eventType;
address targetContract;
bytes4 functionSelector;
bool isActive;
uint256 priority;
}
// Mappings
mapping(uint256 => PerformanceMapping) public performanceMappings;
mapping(bytes32 => uint256) public performanceHashToMapping;
mapping(uint256 => BatchRequest) public batchRequests;
mapping(bytes32 => EventHandler) public eventHandlers;
mapping(address => bool) public authorizedIntegrators;
// Arrays
uint256[] public pendingMappings;
bytes32[] public performanceHashes;
address[] public authorizedIntegratorList;
// Events
event PerformanceMapped(
uint256 indexed mappingId,
bytes32 indexed performanceHash,
uint256 indexed bountyId,
uint256 submissionId
);
event BountyAutoCompleted(
uint256 indexed bountyId,
uint256 indexed submissionId,
address indexed submitter,
uint256 rewardAmount
);
event StakingRewardsTriggered(
address indexed agentWallet,
uint256 totalEarnings,
uint256 stakerCount
);
event BatchProcessed(
uint256 indexed batchId,
uint256 successCount,
uint256 failureCount,
uint256 gasUsed
);
event IntegrationFailed(
uint256 indexed mappingId,
string errorMessage,
bytes32 indexed performanceHash
);
event EventHandlerRegistered(
bytes32 indexed eventType,
address indexed targetContract,
bytes4 functionSelector
);
// Modifiers
modifier mappingExists(uint256 _mappingId) {
require(_mappingId < integrationCounter, "Mapping does not exist");
_;
}
modifier onlyAuthorizedIntegrator() {
require(authorizedIntegrators[msg.sender], "Not authorized integrator");
_;
}
modifier validPerformanceHash(bytes32 _performanceHash) {
require(_performanceHash != bytes32(0), "Invalid performance hash");
_;
}
constructor(
address _agentBounty,
address _agentStaking,
address _performanceVerifier,
address _aitbcToken
) {
agentBounty = AgentBounty(_agentBounty);
agentStaking = AgentStaking(_agentStaking);
performanceVerifier = PerformanceVerifier(_performanceVerifier);
aitbcToken = AIToken(_aitbcToken);
// Register default event handlers
_registerEventHandler(
keccak256("BOUNTY_COMPLETED"),
_agentStaking,
AgentStaking.distributeAgentEarnings.selector
);
_registerEventHandler(
keccak256("PERFORMANCE_VERIFIED"),
_agentBounty,
AgentBounty.verifySubmission.selector
);
}
/**
* @dev Maps performance verification to bounty completion
* @param _performanceHash Hash of performance metrics
* @param _bountyId Bounty ID
* @param _submissionId Submission ID
*/
function mapPerformanceToBounty(
bytes32 _performanceHash,
uint256 _bountyId,
uint256 _submissionId
) external
onlyAuthorizedIntegrator
validPerformanceHash(_performanceHash)
nonReentrant
returns (uint256)
{
require(performanceHashToMapping[_performanceHash] == 0, "Performance already mapped");
uint256 mappingId = integrationCounter++;
PerformanceMapping storage mapping = performanceMappings[mappingId];
mapping.mappingId = mappingId;
mapping.performanceHash = _performanceHash;
mapping.bountyId = _bountyId;
mapping.submissionId = _submissionId;
mapping.status = IntegrationStatus.PENDING;
mapping.createdAt = block.timestamp;
performanceHashToMapping[_performanceHash] = mappingId;
pendingMappings.push(mappingId);
performanceHashes.push(_performanceHash);
emit PerformanceMapped(mappingId, _performanceHash, _bountyId, _submissionId);
// Attempt auto-processing
_processMapping(mappingId);
return mappingId;
}
/**
* @dev Processes a single performance mapping
* @param _mappingId Mapping ID
*/
function processMapping(uint256 _mappingId) external
onlyAuthorizedIntegrator
mappingExists(_mappingId)
nonReentrant
{
_processMapping(_mappingId);
}
/**
* @dev Processes multiple mappings in a batch
* @param _mappingIds Array of mapping IDs
*/
function processBatchMappings(uint256[] calldata _mappingIds) external
onlyAuthorizedIntegrator
nonReentrant
{
require(_mappingIds.length <= batchProcessingLimit, "Batch too large");
uint256 batchId = integrationCounter++;
BatchRequest storage batch = batchRequests[batchId];
batch.batchId = batchId;
batch.bountyIds = new uint256[](_mappingIds.length);
batch.submissionIds = new uint256[](_mappingIds.length);
batch.performanceHashes = new bytes32[](_mappingIds.length);
batch.accuracies = new uint256[](_mappingIds.length);
batch.responseTimes = new uint256[](_mappingIds.length);
batch.status = IntegrationStatus.PROCESSING;
batch.createdAt = block.timestamp;
uint256 gasStart = gasleft();
uint256 successCount = 0;
uint256 failureCount = 0;
for (uint256 i = 0; i < _mappingIds.length; i++) {
try this._processMappingInternal(_mappingIds[i]) {
successCount++;
} catch {
failureCount++;
}
}
batch.successCount = successCount;
batch.failureCount = failureCount;
batch.processedAt = block.timestamp;
batch.status = IntegrationStatus.COMPLETED;
uint256 gasUsed = gasStart - gasleft();
emit BatchProcessed(batchId, successCount, failureCount, gasUsed);
}
/**
* @dev Auto-verifies bounty submissions based on performance metrics
* @param _bountyId Bounty ID
* @param _submissionId Submission ID
* @param _accuracy Achieved accuracy
* @param _responseTime Response time
*/
function autoVerifyBountySubmission(
uint256 _bountyId,
uint256 _submissionId,
uint256 _accuracy,
uint256 _responseTime
) external
onlyAuthorizedIntegrator
nonReentrant
{
// Get bounty details
(,,,,,, bytes32 performanceCriteria, uint256 minAccuracy,,,, bool requiresZKProof) = agentBounty.getBounty(_bountyId);
// Check if auto-verification conditions are met
if (_accuracy >= autoVerificationThreshold && _accuracy >= minAccuracy) {
// Verify the submission
agentBounty.verifySubmission(_bountyId, _submissionId, true, address(this));
// Get submission details to calculate rewards
(address submitter,,,,,,,) = agentBounty.getSubmission(_submissionId);
// Trigger staking rewards if applicable
_triggerStakingRewards(submitter, _accuracy);
emit BountyAutoCompleted(_bountyId, _submissionId, submitter, 0); // Reward amount will be set by bounty contract
}
}
/**
* @dev Handles performance verification events
* @param _verificationId Performance verification ID
* @param _accuracy Accuracy achieved
* @param _responseTime Response time
* @param _performanceHash Hash of performance metrics
*/
function handlePerformanceVerified(
uint256 _verificationId,
uint256 _accuracy,
uint256 _responseTime,
bytes32 _performanceHash
) external
onlyAuthorizedIntegrator
nonReentrant
{
// Check if this performance is mapped to any bounties
uint256 mappingId = performanceHashToMapping[_performanceHash];
if (mappingId > 0) {
PerformanceMapping storage mapping = performanceMappings[mappingId];
// Update agent staking metrics
(address submitter,,,,,,,) = agentBounty.getSubmission(mapping.submissionId);
agentStaking.updateAgentPerformance(submitter, _accuracy, _accuracy >= autoVerificationThreshold);
// Auto-verify bounty if conditions are met
_autoVerifyBounty(mapping.bountyId, mapping.submissionId, _accuracy, _responseTime);
}
}
/**
* @dev Registers an event handler for cross-contract communication
* @param _eventType Event type identifier
* @param _targetContract Target contract address
* @param _functionSelector Function selector to call
*/
function registerEventHandler(
bytes32 _eventType,
address _targetContract,
bytes4 _functionSelector
) external onlyOwner {
require(_targetContract != address(0), "Invalid target contract");
require(_functionSelector != bytes4(0), "Invalid function selector");
eventHandlers[_eventType] = EventHandler({
eventType: _eventType,
targetContract: _targetContract,
functionSelector: _functionSelector,
isActive: true,
priority: 0
});
emit EventHandlerRegistered(_eventType, _targetContract, _functionSelector);
}
/**
* @dev Authorizes an integrator address
* @param _integrator Address to authorize
*/
function authorizeIntegrator(address _integrator) external onlyOwner {
require(_integrator != address(0), "Invalid integrator address");
require(!authorizedIntegrators[_integrator], "Already authorized");
authorizedIntegrators[_integrator] = true;
authorizedIntegratorList.push(_integrator);
}
/**
* @dev Revokes integrator authorization
* @param _integrator Address to revoke
*/
function revokeIntegrator(address _integrator) external onlyOwner {
require(authorizedIntegrators[_integrator], "Not authorized");
authorizedIntegrators[_integrator] = false;
// Remove from list
for (uint256 i = 0; i < authorizedIntegratorList.length; i++) {
if (authorizedIntegratorList[i] == _integrator) {
authorizedIntegratorList[i] = authorizedIntegratorList[authorizedIntegratorList.length - 1];
authorizedIntegratorList.pop();
break;
}
}
}
/**
* @dev Updates configuration parameters
* @param _autoVerificationThreshold New auto-verification threshold
* @param _batchProcessingLimit New batch processing limit
* @param _gasOptimizationThreshold New gas optimization threshold
*/
function updateConfiguration(
uint256 _autoVerificationThreshold,
uint256 _batchProcessingLimit,
uint256 _gasOptimizationThreshold
) external onlyOwner {
require(_autoVerificationThreshold <= 100, "Invalid threshold");
require(_batchProcessingLimit <= 100, "Batch limit too high");
autoVerificationThreshold = _autoVerificationThreshold;
batchProcessingLimit = _batchProcessingLimit;
gasOptimizationThreshold = _gasOptimizationThreshold;
}
// View functions
/**
* @dev Gets performance mapping details
* @param _mappingId Mapping ID
*/
function getPerformanceMapping(uint256 _mappingId) external view mappingExists(_mappingId) returns (
bytes32 performanceHash,
uint256 bountyId,
uint256 submissionId,
IntegrationStatus status,
uint256 createdAt,
uint256 processedAt,
string memory errorMessage
) {
PerformanceMapping storage mapping = performanceMappings[_mappingId];
return (
mapping.performanceHash,
mapping.bountyId,
mapping.submissionId,
mapping.status,
mapping.createdAt,
mapping.processedAt,
mapping.errorMessage
);
}
/**
* @dev Gets batch request details
* @param _batchId Batch ID
*/
function getBatchRequest(uint256 _batchId) external view returns (
uint256[] memory bountyIds,
uint256[] memory submissionIds,
IntegrationStatus status,
uint256 createdAt,
uint256 processedAt,
uint256 successCount,
uint256 failureCount
) {
BatchRequest storage batch = batchRequests[_batchId];
return (
batch.bountyIds,
batch.submissionIds,
batch.status,
batch.createdAt,
batch.processedAt,
batch.successCount,
batch.failureCount
);
}
/**
* @dev Gets pending mappings
*/
function getPendingMappings() external view returns (uint256[] memory) {
return pendingMappings;
}
/**
* @dev Gets all performance hashes
*/
function getPerformanceHashes() external view returns (bytes32[] memory) {
return performanceHashes;
}
/**
* @dev Gets authorized integrators
*/
function getAuthorizedIntegrators() external view returns (address[] memory) {
return authorizedIntegratorList;
}
/**
* @dev Checks if an address is authorized
* @param _integrator Address to check
*/
function isAuthorizedIntegrator(address _integrator) external view returns (bool) {
return authorizedIntegrators[_integrator];
}
/**
* @dev Gets integration statistics
*/
function getIntegrationStats() external view returns (
uint256 totalMappings,
uint256 pendingCount,
uint256 completedCount,
uint256 failedCount,
uint256 averageProcessingTime
) {
uint256 completed = 0;
uint256 failed = 0;
uint256 totalTime = 0;
uint256 processedCount = 0;
for (uint256 i = 0; i < integrationCounter; i++) {
PerformanceMapping storage mapping = performanceMappings[i];
if (mapping.status == IntegrationStatus.COMPLETED) {
completed++;
totalTime += mapping.processedAt - mapping.createdAt;
processedCount++;
} else if (mapping.status == IntegrationStatus.FAILED) {
failed++;
}
}
uint256 avgTime = processedCount > 0 ? totalTime / processedCount : 0;
return (
integrationCounter,
pendingMappings.length,
completed,
failed,
avgTime
);
}
// Internal functions
function _processMapping(uint256 _mappingId) internal {
PerformanceMapping storage mapping = performanceMappings[_mappingId];
if (mapping.status != IntegrationStatus.PENDING) {
return;
}
try this._processMappingInternal(_mappingId) {
mapping.status = IntegrationStatus.COMPLETED;
mapping.processedAt = block.timestamp;
} catch Error(string memory reason) {
mapping.status = IntegrationStatus.FAILED;
mapping.errorMessage = reason;
mapping.processedAt = block.timestamp;
emit IntegrationFailed(_mappingId, reason, mapping.performanceHash);
} catch {
mapping.status = IntegrationStatus.FAILED;
mapping.errorMessage = "Unknown error";
mapping.processedAt = block.timestamp;
emit IntegrationFailed(_mappingId, "Unknown error", mapping.performanceHash);
}
// Remove from pending
_removeFromPending(_mappingId);
}
function _processMappingInternal(uint256 _mappingId) external {
PerformanceMapping storage mapping = performanceMappings[_mappingId];
// Get bounty details
(,,,,,, bytes32 performanceCriteria, uint256 minAccuracy,,,, bool requiresZKProof) = agentBounty.getBounty(mapping.bountyId);
// Get submission details
(address submitter, bytes32 submissionHash, uint256 accuracy, uint256 responseTime,,,) = agentBounty.getSubmission(mapping.submissionId);
// Verify performance criteria match
require(mapping.performanceHash == submissionHash, "Performance hash mismatch");
// Check if accuracy meets requirements
require(accuracy >= minAccuracy, "Accuracy below minimum");
// Auto-verify if conditions are met
if (accuracy >= autoVerificationThreshold) {
agentBounty.verifySubmission(mapping.bountyId, mapping.submissionId, true, address(this));
// Update agent staking metrics
agentStaking.updateAgentPerformance(submitter, accuracy, true);
// Trigger staking rewards
_triggerStakingRewards(submitter, accuracy);
}
}
function _autoVerifyBounty(
uint256 _bountyId,
uint256 _submissionId,
uint256 _accuracy,
uint256 _responseTime
) internal {
if (_accuracy >= autoVerificationThreshold) {
agentBounty.verifySubmission(_bountyId, _submissionId, true, address(this));
}
}
function _triggerStakingRewards(address _agentWallet, uint256 _accuracy) internal {
// Calculate earnings based on accuracy
uint256 baseEarnings = (_accuracy * 100) * 10**18; // Simplified calculation
// Distribute to stakers
try agentStaking.distributeAgentEarnings(_agentWallet, baseEarnings) {
emit StakingRewardsTriggered(_agentWallet, baseEarnings, 0);
} catch {
// Handle staking distribution failure
}
}
function _registerEventHandler(
bytes32 _eventType,
address _targetContract,
bytes4 _functionSelector
) internal {
eventHandlers[_eventType] = EventHandler({
eventType: _eventType,
targetContract: _targetContract,
functionSelector: _functionSelector,
isActive: true,
priority: 0
});
}
function _removeFromPending(uint256 _mappingId) internal {
for (uint256 i = 0; i < pendingMappings.length; i++) {
if (pendingMappings[i] == _mappingId) {
pendingMappings[i] = pendingMappings[pendingMappings.length - 1];
pendingMappings.pop();
break;
}
}
}
}