🏛️ OpenClawDAO Smart Contract Implementation: Core Governance Contract: - Enhanced OpenClawDAO with snapshot security and anti-flash-loan protection - Token-weighted voting with 24-hour TWAS calculation - Multi-sig protection for critical proposals (emergency/protocol upgrades) - Agent swarm role integration (Provider/Consumer/Builder/Coordinator) - Proposal types: Parameter Change, Protocol Upgrade, Treasury, Emergency, Agent Trading, DAO Grants - Maximum voting power limits (5% per address) and vesting periods Security Features: - Snapshot-based voting power capture prevents flash-loan manipulation - Proposal bonds and challenge mechanisms for proposal validation - Multi-signature requirements for critical governance actions - Reputation-based voting weight enhancement for agents - Emergency pause and recovery mechanisms Agent Wallet Contract: - Autonomous agent voting with configurable strategies - Role-specific voting preferences based on agent type - Reputation-based voting power bonuses - Authorized caller management for agent control - Emergency stop and reactivate functionality - Autonomous vote execution based on predefined strategies GPU Staking Contract: - GPU resource staking with AITBC token collateral - Reputation-based reward rate calculations - Utilization-based reward scaling - Lock period enforcement with flexible durations - Provider reputation tracking and updates - Multi-pool support with different reward rates Deployment & Testing: - Complete deployment script with system configuration - Comprehensive test suite covering all major functionality - Multi-sig setup and initial agent registration - Snapshot creation and staking pool initialization - Test report generation with detailed results 🔐 Security Implementation: - Anti-flash-loan protection through snapshot voting - Multi-layer security (proposal bonds, challenges, multi-sig) - Reputation-based access control and voting enhancement - Emergency mechanisms for system recovery - Comprehensive input validation and access controls 📊 Governance Features: - 6 proposal types covering all governance scenarios - 4 agent swarm roles with specialized voting preferences - Token-weighted voting with reputation bonuses - 7-day voting period with 1-day delay - 4% quorum requirement and 1000 AITBC proposal threshold 🚀 Ready for deployment and integration with AITBC ecosystem
450 lines
14 KiB
Solidity
450 lines
14 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.19;
|
|
|
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
|
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
|
|
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
|
|
|
/**
|
|
* @title GPUStaking
|
|
* @dev GPU resource staking and reward distribution for AITBC agents
|
|
* @notice Enables providers to stake GPU resources and earn rewards
|
|
*/
|
|
contract GPUStaking is Ownable, ReentrancyGuard {
|
|
using SafeMath for uint256;
|
|
|
|
// GPU resource structure
|
|
struct GPUResource {
|
|
address provider;
|
|
uint256 gpuPower; // Computational power units
|
|
uint256 lockPeriod; // Lock period in seconds
|
|
uint256 stakeAmount; // AITBC tokens staked
|
|
uint256 rewardRate; // Reward rate per second
|
|
uint256 reputation; // Provider reputation score
|
|
uint256 startTime; // When staking started
|
|
uint256 lastRewardTime; // Last reward calculation time
|
|
bool isActive; // Whether resource is active
|
|
string gpuSpecs; // GPU specifications (JSON)
|
|
}
|
|
|
|
// Staking pool structure
|
|
struct StakingPool {
|
|
uint256 totalGPUPower;
|
|
uint256 totalStaked;
|
|
uint256 rewardPool;
|
|
uint256 rewardRate;
|
|
uint256 utilizationRate; // Current utilization (0-10000 = 0-100%)
|
|
bool isActive;
|
|
mapping(address => uint256) providerContributions;
|
|
}
|
|
|
|
// Reward calculation structure
|
|
struct RewardInfo {
|
|
uint256 totalRewards;
|
|
uint256 pendingRewards;
|
|
uint256 lastClaimTime;
|
|
uint256 rewardHistory;
|
|
}
|
|
|
|
// State variables
|
|
IERC20 public stakingToken;
|
|
mapping(address => GPUResource) public gpuResources;
|
|
mapping(uint256 => StakingPool) public stakingPools;
|
|
mapping(address => RewardInfo) public rewards;
|
|
|
|
uint256 public poolCounter;
|
|
uint256 public constant MAX_UTILIZATION = 10000; // 100%
|
|
uint256 public constant SECONDS_PER_DAY = 86400;
|
|
|
|
// Governance parameters
|
|
uint256 public minStakeAmount = 100e18; // 100 AITBC
|
|
uint256 public minLockPeriod = 7 days;
|
|
uint256 public maxLockPeriod = 365 days;
|
|
uint256 public baseRewardRate = 1e15; // 0.001 AITBC per GPU unit per second
|
|
|
|
// Events
|
|
event GPUStaked(
|
|
address indexed provider,
|
|
uint256 indexed poolId,
|
|
uint256 gpuPower,
|
|
uint256 stakeAmount,
|
|
uint256 lockPeriod
|
|
);
|
|
|
|
event GPUUnstaked(
|
|
address indexed provider,
|
|
uint256 indexed poolId,
|
|
uint256 gpuPower,
|
|
uint256 stakeAmount
|
|
);
|
|
|
|
event RewardsClaimed(
|
|
address indexed provider,
|
|
uint256 rewardAmount
|
|
);
|
|
|
|
event PoolCreated(
|
|
uint256 indexed poolId,
|
|
string name,
|
|
uint256 rewardRate
|
|
);
|
|
|
|
event RewardPoolUpdated(
|
|
uint256 indexed poolId,
|
|
uint256 newAmount
|
|
);
|
|
|
|
modifier validPool(uint256 poolId) {
|
|
require(stakingPools[poolId].isActive, "Invalid pool");
|
|
_;
|
|
}
|
|
|
|
modifier onlyProvider(address provider) {
|
|
require(gpuResources[provider].isActive, "Not a provider");
|
|
_;
|
|
}
|
|
|
|
constructor(address _stakingToken) {
|
|
stakingToken = IERC20(_stakingToken);
|
|
|
|
// Create default staking pool
|
|
_createPool("Default GPU Pool", baseRewardRate);
|
|
}
|
|
|
|
/**
|
|
* @dev Stake GPU resources
|
|
* @param poolId ID of the staking pool
|
|
* @param gpuPower Computational power units
|
|
* @param stakeAmount Amount of AITBC tokens to stake
|
|
* @param lockPeriod Lock period in seconds
|
|
* @param gpuSpecs GPU specifications (JSON string)
|
|
*/
|
|
function stakeGPU(
|
|
uint256 poolId,
|
|
uint256 gpuPower,
|
|
uint256 stakeAmount,
|
|
uint256 lockPeriod,
|
|
string calldata gpuSpecs
|
|
) external nonReentrant validPool(poolId) {
|
|
require(gpuPower > 0, "Invalid GPU power");
|
|
require(stakeAmount >= minStakeAmount, "Below minimum stake");
|
|
require(lockPeriod >= minLockPeriod && lockPeriod <= maxLockPeriod, "Invalid lock period");
|
|
|
|
// Transfer staking tokens
|
|
require(
|
|
stakingToken.transferFrom(msg.sender, address(this), stakeAmount),
|
|
"Transfer failed"
|
|
);
|
|
|
|
// Create or update GPU resource
|
|
GPUResource storage resource = gpuResources[msg.sender];
|
|
if (!resource.isActive) {
|
|
resource.provider = msg.sender;
|
|
resource.reputation = 100; // Start with base reputation
|
|
resource.isActive = true;
|
|
}
|
|
|
|
resource.gpuPower = resource.gpuPower.add(gpuPower);
|
|
resource.stakeAmount = resource.stakeAmount.add(stakeAmount);
|
|
resource.lockPeriod = lockPeriod;
|
|
resource.startTime = block.timestamp;
|
|
resource.lastRewardTime = block.timestamp;
|
|
resource.gpuSpecs = gpuSpecs;
|
|
|
|
// Update staking pool
|
|
StakingPool storage pool = stakingPools[poolId];
|
|
pool.totalGPUPower = pool.totalGPUPower.add(gpuPower);
|
|
pool.totalStaked = pool.totalStaked.add(stakeAmount);
|
|
pool.providerContributions[msg.sender] = pool.providerContributions[msg.sender].add(gpuPower);
|
|
|
|
// Calculate reward rate based on reputation and utilization
|
|
resource.rewardRate = _calculateRewardRate(msg.sender, poolId);
|
|
|
|
emit GPUStaked(msg.sender, poolId, gpuPower, stakeAmount, lockPeriod);
|
|
}
|
|
|
|
/**
|
|
* @dev Unstake GPU resources
|
|
* @param poolId ID of the staking pool
|
|
* @param gpuPower Amount of GPU power to unstake
|
|
*/
|
|
function unstakeGPU(
|
|
uint256 poolId,
|
|
uint256 gpuPower
|
|
) external nonReentrant validPool(poolId) onlyProvider(msg.sender) {
|
|
GPUResource storage resource = gpuResources[msg.sender];
|
|
require(resource.gpuPower >= gpuPower, "Insufficient GPU power");
|
|
|
|
// Check lock period
|
|
require(
|
|
block.timestamp >= resource.startTime.add(resource.lockPeriod),
|
|
"Still locked"
|
|
);
|
|
|
|
// Calculate proportional stake amount to return
|
|
uint256 stakeToReturn = (gpuPower.mul(resource.stakeAmount)).div(resource.gpuPower);
|
|
|
|
// Update resource
|
|
resource.gpuPower = resource.gpuPower.sub(gpuPower);
|
|
resource.stakeAmount = resource.stakeAmount.sub(stakeToReturn);
|
|
|
|
if (resource.gpuPower == 0) {
|
|
resource.isActive = false;
|
|
}
|
|
|
|
// Update pool
|
|
StakingPool storage pool = stakingPools[poolId];
|
|
pool.totalGPUPower = pool.totalGPUPower.sub(gpuPower);
|
|
pool.totalStaked = pool.totalStaked.sub(stakeToReturn);
|
|
pool.providerContributions[msg.sender] = pool.providerContributions[msg.sender].sub(gpuPower);
|
|
|
|
// Return staked tokens
|
|
require(stakingToken.transfer(msg.sender, stakeToReturn), "Transfer failed");
|
|
|
|
emit GPUUnstaked(msg.sender, poolId, gpuPower, stakeToReturn);
|
|
}
|
|
|
|
/**
|
|
* @dev Claim pending rewards
|
|
* @param poolId ID of the staking pool
|
|
*/
|
|
function claimRewards(uint256 poolId) external nonReentrant validPool(poolId) onlyProvider(msg.sender) {
|
|
uint256 rewardAmount = _calculatePendingRewards(msg.sender, poolId);
|
|
|
|
require(rewardAmount > 0, "No rewards to claim");
|
|
|
|
// Update reward info
|
|
RewardInfo storage rewardInfo = rewards[msg.sender];
|
|
rewardInfo.totalRewards = rewardInfo.totalRewards.add(rewardAmount);
|
|
rewardInfo.pendingRewards = 0;
|
|
rewardInfo.lastClaimTime = block.timestamp;
|
|
|
|
// Transfer rewards
|
|
require(stakingToken.transfer(msg.sender, rewardAmount), "Transfer failed");
|
|
|
|
emit RewardsClaimed(msg.sender, rewardAmount);
|
|
}
|
|
|
|
/**
|
|
* @dev Create new staking pool
|
|
* @param name Pool name
|
|
* @param rewardRate Base reward rate
|
|
*/
|
|
function createPool(
|
|
string calldata name,
|
|
uint256 rewardRate
|
|
) external onlyOwner {
|
|
_createPool(name, rewardRate);
|
|
}
|
|
|
|
/**
|
|
* @dev Update reward pool
|
|
* @param poolId ID of the pool
|
|
* @param amount Amount to add to reward pool
|
|
*/
|
|
function updateRewardPool(
|
|
uint256 poolId,
|
|
uint256 amount
|
|
) external onlyOwner validPool(poolId) {
|
|
require(stakingToken.transferFrom(msg.sender, address(this), amount), "Transfer failed");
|
|
|
|
StakingPool storage pool = stakingPools[poolId];
|
|
pool.rewardPool = pool.rewardPool.add(amount);
|
|
|
|
emit RewardPoolUpdated(poolId, amount);
|
|
}
|
|
|
|
/**
|
|
* @dev Update pool utilization rate
|
|
* @param poolId ID of the pool
|
|
* @param utilizationRate Utilization rate (0-10000 = 0-100%)
|
|
*/
|
|
function updateUtilizationRate(
|
|
uint256 poolId,
|
|
uint256 utilizationRate
|
|
) external onlyOwner validPool(poolId) {
|
|
require(utilizationRate <= MAX_UTILIZATION, "Invalid utilization");
|
|
|
|
StakingPool storage pool = stakingPools[poolId];
|
|
pool.utilizationRate = utilizationRate;
|
|
}
|
|
|
|
/**
|
|
* @dev Update provider reputation
|
|
* @param provider Provider address
|
|
* @param reputation New reputation score
|
|
*/
|
|
function updateProviderReputation(
|
|
address provider,
|
|
uint256 reputation
|
|
) external onlyOwner {
|
|
require(gpuResources[provider].isActive, "Provider not active");
|
|
|
|
gpuResources[provider].reputation = reputation;
|
|
|
|
// Recalculate reward rates for all pools
|
|
for (uint256 i = 1; i <= poolCounter; i++) {
|
|
if (stakingPools[i].isActive) {
|
|
gpuResources[provider].rewardRate = _calculateRewardRate(provider, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dev Get pending rewards
|
|
* @param provider Provider address
|
|
* @param poolId ID of the pool
|
|
* @return rewardAmount Pending reward amount
|
|
*/
|
|
function getPendingRewards(
|
|
address provider,
|
|
uint256 poolId
|
|
) external view returns (uint256) {
|
|
return _calculatePendingRewards(provider, poolId);
|
|
}
|
|
|
|
/**
|
|
* @dev Get provider info
|
|
* @param provider Provider address
|
|
* @return gpuPower Total GPU power
|
|
* @return stakeAmount Total stake amount
|
|
* @return reputation Reputation score
|
|
* @return rewardRate Current reward rate
|
|
*/
|
|
function getProviderInfo(
|
|
address provider
|
|
) external view returns (
|
|
uint256 gpuPower,
|
|
uint256 stakeAmount,
|
|
uint256 reputation,
|
|
uint256 rewardRate
|
|
) {
|
|
GPUResource storage resource = gpuResources[provider];
|
|
return (
|
|
resource.gpuPower,
|
|
resource.stakeAmount,
|
|
resource.reputation,
|
|
resource.rewardRate
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dev Get pool statistics
|
|
* @param poolId ID of the pool
|
|
* @return totalGPUPower Total GPU power in pool
|
|
* @return totalStaked Total amount staked
|
|
* @return utilizationRate Current utilization rate
|
|
* @return activeProviders Number of active providers
|
|
*/
|
|
function getPoolStats(
|
|
uint256 poolId
|
|
) external view returns (
|
|
uint256 totalGPUPower,
|
|
uint256 totalStaked,
|
|
uint256 utilizationRate,
|
|
uint256 activeProviders
|
|
) {
|
|
StakingPool storage pool = stakingPools[poolId];
|
|
return (
|
|
pool.totalGPUPower,
|
|
pool.totalStaked,
|
|
pool.utilizationRate,
|
|
_countActiveProviders(poolId)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dev Calculate pending rewards for provider
|
|
* @param provider Provider address
|
|
* @param poolId ID of the pool
|
|
* @return rewardAmount Pending reward amount
|
|
*/
|
|
function _calculatePendingRewards(
|
|
address provider,
|
|
uint256 poolId
|
|
) internal view returns (uint256) {
|
|
GPUResource storage resource = gpuResources[provider];
|
|
StakingPool storage pool = stakingPools[poolId];
|
|
|
|
if (!resource.isActive || pool.totalGPUPower == 0) {
|
|
return 0;
|
|
}
|
|
|
|
uint256 timePassed = block.timestamp.sub(resource.lastRewardTime);
|
|
uint256 providerShare = (resource.gpuPower.mul(1e18)).div(pool.totalGPUPower);
|
|
|
|
// Base rewards * utilization * provider share * time
|
|
uint256 baseRewards = pool.rewardRate.mul(timePassed);
|
|
uint256 utilizationMultiplier = pool.utilizationRate.mul(1e4).div(MAX_UTILIZATION);
|
|
uint256 rewards = baseRewards.mul(utilizationMultiplier).mul(providerShare).div(1e22);
|
|
|
|
return rewards;
|
|
}
|
|
|
|
/**
|
|
* @dev Calculate reward rate for provider
|
|
* @param provider Provider address
|
|
* @param poolId ID of the pool
|
|
* @return rewardRate Calculated reward rate
|
|
*/
|
|
function _calculateRewardRate(
|
|
address provider,
|
|
uint256 poolId
|
|
) internal view returns (uint256) {
|
|
GPUResource storage resource = gpuResources[provider];
|
|
StakingPool storage pool = stakingPools[poolId];
|
|
|
|
// Base rate * reputation bonus * utilization bonus
|
|
uint256 reputationBonus = resource.reputation.add(100); // 1x + reputation/100
|
|
uint256 utilizationBonus = pool.utilizationRate.add(MAX_UTILIZATION).div(2); // Average with 100%
|
|
|
|
return pool.rewardRate.mul(reputationBonus).mul(utilizationBonus).div(1e4);
|
|
}
|
|
|
|
/**
|
|
* @dev Create new staking pool (internal)
|
|
* @param name Pool name
|
|
* @param rewardRate Base reward rate
|
|
*/
|
|
function _createPool(
|
|
string memory name,
|
|
uint256 rewardRate
|
|
) internal {
|
|
uint256 poolId = ++poolCounter;
|
|
|
|
StakingPool storage pool = stakingPools[poolId];
|
|
pool.rewardRate = rewardRate;
|
|
pool.isActive = true;
|
|
|
|
emit PoolCreated(poolId, name, rewardRate);
|
|
}
|
|
|
|
/**
|
|
* @dev Count active providers in pool
|
|
* @param poolId ID of the pool
|
|
* @return count Number of active providers
|
|
*/
|
|
function _countActiveProviders(uint256 poolId) internal view returns (uint256) {
|
|
// This is simplified - in production, maintain a separate mapping
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @dev Emergency functions
|
|
*/
|
|
function emergencyPause() external onlyOwner {
|
|
// Pause all staking operations
|
|
for (uint256 i = 1; i <= poolCounter; i++) {
|
|
stakingPools[i].isActive = false;
|
|
}
|
|
}
|
|
|
|
function emergencyUnpause() external onlyOwner {
|
|
// Unpause all staking operations
|
|
for (uint256 i = 1; i <= poolCounter; i++) {
|
|
stakingPools[i].isActive = true;
|
|
}
|
|
}
|
|
}
|