feat: recreate AgentMarketplaceV2.sol based on docs
This commit is contained in:
224
contracts/contracts/AgentMarketplaceV2.sol
Normal file
224
contracts/contracts/AgentMarketplaceV2.sol
Normal file
@@ -0,0 +1,224 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
||||
import "@openzeppelin/contracts/security/Pausable.sol";
|
||||
|
||||
/**
|
||||
* @title AgentMarketplaceV2
|
||||
* @dev Advanced marketplace with capability trading and subscriptions for AI agents.
|
||||
*/
|
||||
contract AgentMarketplaceV2 is Ownable, ReentrancyGuard, Pausable {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
IERC20 public aitbcToken;
|
||||
|
||||
uint256 public capabilityCounter;
|
||||
uint256 public subscriptionCounter;
|
||||
uint256 public platformFeePercentage = 250; // 2.5% in basis points (10000 = 100%)
|
||||
|
||||
struct Capability {
|
||||
uint256 capabilityId;
|
||||
address providerAgent;
|
||||
string metadataURI; // IPFS hash containing capability description, API spec, and SLA
|
||||
uint256 pricePerCall; // Price for a single capability use
|
||||
uint256 subscriptionPrice; // Price for a 30-day subscription
|
||||
bool isSubscriptionEnabled;
|
||||
bool isActive;
|
||||
uint256 totalCalls;
|
||||
uint256 totalRevenue;
|
||||
uint256 reputationScore; // Automatically updated score based on verifications
|
||||
}
|
||||
|
||||
struct Subscription {
|
||||
uint256 subscriptionId;
|
||||
uint256 capabilityId;
|
||||
address subscriberAgent;
|
||||
uint256 expiryTimestamp;
|
||||
bool isActive;
|
||||
}
|
||||
|
||||
mapping(uint256 => Capability) public capabilities;
|
||||
mapping(uint256 => Subscription) public subscriptions;
|
||||
mapping(address => uint256[]) public providerCapabilities;
|
||||
mapping(address => uint256[]) public subscriberSubscriptions;
|
||||
|
||||
// Events
|
||||
event CapabilityListed(uint256 indexed capabilityId, address indexed provider, string metadataURI, uint256 pricePerCall, uint256 subscriptionPrice);
|
||||
event CapabilityUpdated(uint256 indexed capabilityId, uint256 pricePerCall, uint256 subscriptionPrice, bool isActive);
|
||||
event CapabilityPurchased(uint256 indexed capabilityId, address indexed buyer, uint256 pricePaid);
|
||||
event SubscriptionCreated(uint256 indexed subscriptionId, uint256 indexed capabilityId, address indexed subscriber, uint256 expiryTimestamp);
|
||||
event PlatformFeeUpdated(uint256 newFeePercentage);
|
||||
event CapabilityReputationUpdated(uint256 indexed capabilityId, uint256 newScore);
|
||||
|
||||
modifier capabilityExists(uint256 _capabilityId) {
|
||||
require(_capabilityId < capabilityCounter, "Capability does not exist");
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(address _aitbcToken) {
|
||||
require(_aitbcToken != address(0), "Invalid token address");
|
||||
aitbcToken = IERC20(_aitbcToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev List a new agent capability on the marketplace
|
||||
*/
|
||||
function listCapability(
|
||||
string calldata _metadataURI,
|
||||
uint256 _pricePerCall,
|
||||
uint256 _subscriptionPrice,
|
||||
bool _isSubscriptionEnabled
|
||||
) external whenNotPaused returns (uint256) {
|
||||
require(bytes(_metadataURI).length > 0, "Invalid URI");
|
||||
|
||||
uint256 capabilityId = capabilityCounter++;
|
||||
|
||||
capabilities[capabilityId] = Capability({
|
||||
capabilityId: capabilityId,
|
||||
providerAgent: msg.sender,
|
||||
metadataURI: _metadataURI,
|
||||
pricePerCall: _pricePerCall,
|
||||
subscriptionPrice: _subscriptionPrice,
|
||||
isSubscriptionEnabled: _isSubscriptionEnabled,
|
||||
isActive: true,
|
||||
totalCalls: 0,
|
||||
totalRevenue: 0,
|
||||
reputationScore: 0
|
||||
});
|
||||
|
||||
providerCapabilities[msg.sender].push(capabilityId);
|
||||
|
||||
emit CapabilityListed(capabilityId, msg.sender, _metadataURI, _pricePerCall, _subscriptionPrice);
|
||||
return capabilityId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Update an existing capability
|
||||
*/
|
||||
function updateCapability(
|
||||
uint256 _capabilityId,
|
||||
uint256 _pricePerCall,
|
||||
uint256 _subscriptionPrice,
|
||||
bool _isSubscriptionEnabled,
|
||||
bool _isActive
|
||||
) external capabilityExists(_capabilityId) {
|
||||
Capability storage cap = capabilities[_capabilityId];
|
||||
require(cap.providerAgent == msg.sender, "Not the provider");
|
||||
|
||||
cap.pricePerCall = _pricePerCall;
|
||||
cap.subscriptionPrice = _subscriptionPrice;
|
||||
cap.isSubscriptionEnabled = _isSubscriptionEnabled;
|
||||
cap.isActive = _isActive;
|
||||
|
||||
emit CapabilityUpdated(_capabilityId, _pricePerCall, _subscriptionPrice, _isActive);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Purchase a single call of a capability
|
||||
*/
|
||||
function purchaseCall(uint256 _capabilityId) external nonReentrant whenNotPaused capabilityExists(_capabilityId) {
|
||||
Capability storage cap = capabilities[_capabilityId];
|
||||
require(cap.isActive, "Capability inactive");
|
||||
require(cap.pricePerCall > 0, "Not available for single call");
|
||||
|
||||
uint256 platformFee = (cap.pricePerCall * platformFeePercentage) / 10000;
|
||||
uint256 providerAmount = cap.pricePerCall - platformFee;
|
||||
|
||||
// Transfer funds
|
||||
aitbcToken.safeTransferFrom(msg.sender, address(this), cap.pricePerCall);
|
||||
|
||||
// Pay provider
|
||||
if (providerAmount > 0) {
|
||||
aitbcToken.safeTransfer(cap.providerAgent, providerAmount);
|
||||
}
|
||||
|
||||
cap.totalCalls += 1;
|
||||
cap.totalRevenue += providerAmount;
|
||||
|
||||
emit CapabilityPurchased(_capabilityId, msg.sender, cap.pricePerCall);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Subscribe to an agent capability for 30 days
|
||||
*/
|
||||
function subscribeToCapability(uint256 _capabilityId) external nonReentrant whenNotPaused capabilityExists(_capabilityId) returns (uint256) {
|
||||
Capability storage cap = capabilities[_capabilityId];
|
||||
require(cap.isActive, "Capability inactive");
|
||||
require(cap.isSubscriptionEnabled, "Subscriptions not enabled");
|
||||
|
||||
uint256 platformFee = (cap.subscriptionPrice * platformFeePercentage) / 10000;
|
||||
uint256 providerAmount = cap.subscriptionPrice - platformFee;
|
||||
|
||||
// Transfer funds
|
||||
aitbcToken.safeTransferFrom(msg.sender, address(this), cap.subscriptionPrice);
|
||||
|
||||
// Pay provider
|
||||
if (providerAmount > 0) {
|
||||
aitbcToken.safeTransfer(cap.providerAgent, providerAmount);
|
||||
}
|
||||
|
||||
cap.totalRevenue += providerAmount;
|
||||
|
||||
uint256 subId = subscriptionCounter++;
|
||||
uint256 expiry = block.timestamp + 30 days;
|
||||
|
||||
subscriptions[subId] = Subscription({
|
||||
subscriptionId: subId,
|
||||
capabilityId: _capabilityId,
|
||||
subscriberAgent: msg.sender,
|
||||
expiryTimestamp: expiry,
|
||||
isActive: true
|
||||
});
|
||||
|
||||
subscriberSubscriptions[msg.sender].push(subId);
|
||||
|
||||
emit SubscriptionCreated(subId, _capabilityId, msg.sender, expiry);
|
||||
return subId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Check if a subscription is still active and valid
|
||||
*/
|
||||
function checkSubscription(uint256 _subscriptionId) external view returns (bool) {
|
||||
Subscription memory sub = subscriptions[_subscriptionId];
|
||||
return sub.isActive && (block.timestamp < sub.expiryTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Update the reputation score of a capability (Oracle/Owner only)
|
||||
*/
|
||||
function updateCapabilityReputation(uint256 _capabilityId, uint256 _newScore) external onlyOwner capabilityExists(_capabilityId) {
|
||||
capabilities[_capabilityId].reputationScore = _newScore;
|
||||
emit CapabilityReputationUpdated(_capabilityId, _newScore);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Update platform fee percentage
|
||||
*/
|
||||
function updatePlatformFee(uint256 _newFee) external onlyOwner {
|
||||
require(_newFee <= 1000, "Fee too high"); // Max 10%
|
||||
platformFeePercentage = _newFee;
|
||||
emit PlatformFeeUpdated(_newFee);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraw accumulated platform fees
|
||||
*/
|
||||
function withdrawPlatformFees() external onlyOwner {
|
||||
uint256 balance = aitbcToken.balanceOf(address(this));
|
||||
require(balance > 0, "No fees to withdraw");
|
||||
aitbcToken.safeTransfer(owner(), balance);
|
||||
}
|
||||
|
||||
function pause() external onlyOwner {
|
||||
_pause();
|
||||
}
|
||||
|
||||
function unpause() external onlyOwner {
|
||||
_unpause();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user