refactor(contracts): remove deprecated AIPowerRental contract in favor of bounty system

- Delete AIPowerRental.sol (566 lines) - replaced by AgentBounty.sol
- Remove rental agreement system with provider/consumer model
- Remove performance metrics and SLA tracking
- Remove dispute resolution mechanism
- Remove ZK-proof verification for performance
- Remove provider/consumer authorization system
- Bounty system provides superior developer incentive structure
This commit is contained in:
oib
2026-02-27 21:46:54 +01:00
parent a477681c4b
commit 864ef4343e
152 changed files with 45716 additions and 94 deletions

View File

@@ -0,0 +1,307 @@
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("AgentBounty System", function () {
let agentBounty, aitbcToken, performanceVerifier;
let owner, bountyCreator, agent, arbitrator;
beforeEach(async function () {
// Get signers
[owner, bountyCreator, agent, arbitrator] = await ethers.getSigners();
// Deploy mock AITBC token
const MockERC20 = await ethers.getContractFactory("MockERC20");
aitbcToken = await MockERC20.deploy("AITBC Token", "AITBC", ethers.utils.parseEther("1000000"));
await aitbcToken.deployed();
// Deploy mock performance verifier
const MockPerformanceVerifier = await ethers.getContractFactory("MockPerformanceVerifier");
performanceVerifier = await MockPerformanceVerifier.deploy();
await performanceVerifier.deployed();
// Deploy AgentBounty contract
const AgentBounty = await ethers.getContractFactory("AgentBounty");
agentBounty = await AgentBounty.deploy(
aitbcToken.address,
performanceVerifier.address
);
await agentBounty.deployed();
// Transfer tokens to bounty creator and agent
await aitbcToken.transfer(bountyCreator.address, ethers.utils.parseEther("10000"));
await aitbcToken.transfer(agent.address, ethers.utils.parseEther("10000"));
});
describe("Bounty Creation", function () {
it("Should create a bounty successfully", async function () {
const rewardAmount = ethers.utils.parseEther("100");
const deadline = Math.floor(Date.now() / 1000) + 86400; // 24 hours from now
await aitbcToken.connect(bountyCreator).approve(agentBounty.address, rewardAmount);
const tx = await agentBounty.connect(bountyCreator).createBounty(
"Test Bounty",
"A test bounty for AI agents",
rewardAmount,
deadline,
90, // min_accuracy
3600, // max_response_time
10, // max_submissions
false, // requires_zk_proof
["test", "ai"],
"BRONZE",
"easy"
);
const receipt = await tx.wait();
const event = receipt.events.find(e => e.event === "BountyCreated");
expect(event.args.bountyId).to.equal(1);
expect(event.args.creator).to.equal(bountyCreator.address);
expect(event.args.rewardAmount).to.equal(rewardAmount);
});
it("Should fail if reward amount is zero", async function () {
const deadline = Math.floor(Date.now() / 1000) + 86400;
await aitbcToken.connect(bountyCreator).approve(agentBounty.address, ethers.utils.parseEther("100"));
await expect(
agentBounty.connect(bountyCreator).createBounty(
"Test Bounty",
"Description",
0,
deadline,
90,
3600,
10,
false,
["test"],
"BRONZE",
"easy"
)
).to.be.revertedWith("Reward amount must be greater than 0");
});
it("Should fail if deadline is in the past", async function () {
const pastDeadline = Math.floor(Date.now() / 1000) - 3600; // 1 hour ago
await aitbcToken.connect(bountyCreator).approve(agentBounty.address, ethers.utils.parseEther("100"));
await expect(
agentBounty.connect(bountyCreator).createBounty(
"Test Bounty",
"Description",
ethers.utils.parseEther("100"),
pastDeadline,
90,
3600,
10,
false,
["test"],
"BRONZE",
"easy"
)
).to.be.revertedWith("Deadline must be in the future");
});
});
describe("Bounty Submission", function () {
let bountyId;
beforeEach(async function () {
const rewardAmount = ethers.utils.parseEther("100");
const deadline = Math.floor(Date.now() / 1000) + 86400;
await aitbcToken.connect(bountyCreator).approve(agentBounty.address, rewardAmount);
const tx = await agentBounty.connect(bountyCreator).createBounty(
"Test Bounty",
"Description",
rewardAmount,
deadline,
90,
3600,
10,
false,
["test"],
"BRONZE",
"easy"
);
const receipt = await tx.wait();
bountyId = receipt.events.find(e => e.event === "BountyCreated").args.bountyId;
});
it("Should submit a bounty successfully", async function () {
const submissionData = "test submission data";
const tx = await agentBounty.connect(agent).submitBounty(
bountyId,
submissionData,
[]
);
const receipt = await tx.wait();
const event = receipt.events.find(e => e.event === "BountySubmitted");
expect(event.args.bountyId).to.equal(bountyId);
expect(event.args.submitter).to.equal(agent.address);
expect(event.args.submissionData).to.equal(submissionData);
});
it("Should fail if bounty doesn't exist", async function () {
await expect(
agentBounty.connect(agent).submitBounty(
999,
"test data",
[]
)
).to.be.revertedWith("Bounty does not exist");
});
it("Should fail if bounty is expired", async function () {
// Fast forward time past deadline
await ethers.provider.send("evm_increaseTime", [86400 * 2]); // 2 days
await ethers.provider.send("evm_mine");
await expect(
agentBounty.connect(agent).submitBounty(
bountyId,
"test data",
[]
)
).to.be.revertedWith("Bounty has expired");
});
});
describe("Bounty Verification", function () {
let bountyId, submissionId;
beforeEach(async function () {
const rewardAmount = ethers.utils.parseEther("100");
const deadline = Math.floor(Date.now() / 1000) + 86400;
await aitbcToken.connect(bountyCreator).approve(agentBounty.address, rewardAmount);
const tx = await agentBounty.connect(bountyCreator).createBounty(
"Test Bounty",
"Description",
rewardAmount,
deadline,
90,
3600,
10,
false,
["test"],
"BRONZE",
"easy"
);
const receipt = await tx.wait();
bountyId = receipt.events.find(e => e.event === "BountyCreated").args.bountyId;
const submitTx = await agentBounty.connect(agent).submitBounty(
bountyId,
"test submission data",
[]
);
const submitReceipt = await submitTx.wait();
submissionId = submitReceipt.events.find(e => e.event === "BountySubmitted").args.submissionId;
});
it("Should verify a bounty successfully", async function () {
// Mock performance verifier to return true
await performanceVerifier.setMockResult(true);
const tx = await agentBounty.verifyBounty(submissionId);
const receipt = await tx.wait();
const event = receipt.events.find(e => e.event === "BountyVerified");
expect(event.args.submissionId).to.equal(submissionId);
expect(event.args.success).to.be.true;
});
it("Should distribute rewards upon successful verification", async function () {
// Mock performance verifier to return true
await performanceVerifier.setMockResult(true);
const initialBalance = await aitbcToken.balanceOf(agent.address);
await agentBounty.verifyBounty(submissionId);
const finalBalance = await aitbcToken.balanceOf(agent.address);
expect(finalBalance).to.be.gt(initialBalance);
});
it("Should handle failed verification", async function () {
// Mock performance verifier to return false
await performanceVerifier.setMockResult(false);
const tx = await agentBounty.verifyBounty(submissionId);
const receipt = await tx.wait();
const event = receipt.events.find(e => e.event === "BountyVerified");
expect(event.args.success).to.be.false;
});
});
describe("Fee Management", function () {
it("Should allow owner to update fees", async function () {
const newCreationFee = 75; // 0.75%
await agentBounty.updateCreationFee(newCreationFee);
expect(await agentBounty.creationFeePercentage()).to.equal(newCreationFee);
});
it("Should prevent non-owners from updating fees", async function () {
await expect(
agentBounty.connect(bountyCreator).updateCreationFee(75)
).to.be.revertedWith("Ownable: caller is not the owner");
});
it("Should validate fee ranges", async function () {
// Test fee too high (over 1000 basis points = 10%)
await expect(
agentBounty.updateCreationFee(1001)
).to.be.revertedWith("Fee cannot exceed 1000 basis points");
});
});
describe("Pausability", function () {
it("Should allow owner to pause and unpause", async function () {
await agentBounty.pause();
expect(await agentBounty.paused()).to.be.true;
await agentBounty.unpause();
expect(await agentBounty.paused()).to.be.false;
});
it("Should prevent operations when paused", async function () {
await agentBounty.pause();
const rewardAmount = ethers.utils.parseEther("100");
const deadline = Math.floor(Date.now() / 1000) + 86400;
await aitbcToken.connect(bountyCreator).approve(agentBounty.address, rewardAmount);
await expect(
agentBounty.connect(bountyCreator).createBounty(
"Test Bounty",
"Description",
rewardAmount,
deadline,
90,
3600,
10,
false,
["test"],
"BRONZE",
"easy"
)
).to.be.revertedWith("Pausable: paused");
});
});
});

View File

@@ -0,0 +1,331 @@
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("AgentStaking System", function () {
let agentStaking, aitbcToken;
let owner, agent, staker1, staker2;
beforeEach(async function () {
// Get signers
[owner, agent, staker1, staker2] = await ethers.getSigners();
// Deploy mock AITBC token
const MockERC20 = await ethers.getContractFactory("MockERC20");
aitbcToken = await MockERC20.deploy("AITBC Token", "AITBC", ethers.utils.parseEther("1000000"));
await aitbcToken.deployed();
// Deploy AgentStaking contract
const AgentStaking = await ethers.getContractFactory("AgentStaking");
agentStaking = await AgentStaking.deploy(aitbcToken.address);
await agentStaking.deployed();
// Transfer tokens to stakers
await aitbcToken.transfer(staker1.address, ethers.utils.parseEther("10000"));
await aitbcToken.transfer(staker2.address, ethers.utils.parseEther("10000"));
});
describe("Agent Registration", function () {
it("Should register an agent successfully", async function () {
const tx = await agentStaking.connect(agent).registerAgent(
"Test Agent",
"https://example.com/metadata",
["AI", "ML", "NLP"]
);
const receipt = await tx.wait();
const event = receipt.events.find(e => e.event === "AgentRegistered");
expect(event.args.agentAddress).to.equal(agent.address);
expect(event.args.name).to.equal("Test Agent");
expect(event.args.metadataURI).to.equal("https://example.com/metadata");
});
it("Should fail if agent is already registered", async function () {
await agentStaking.connect(agent).registerAgent(
"Test Agent",
"metadata",
["AI"]
);
await expect(
agentStaking.connect(agent).registerAgent(
"Another Agent",
"metadata2",
["ML"]
)
).to.be.revertedWith("Agent already registered");
});
it("Should update agent metadata", async function () {
await agentStaking.connect(agent).registerAgent(
"Test Agent",
"metadata",
["AI"]
);
await agentStaking.connect(agent).updateAgentMetadata(
"Updated Agent",
"https://updated.com/metadata",
["AI", "ML", "CV"]
);
const agentInfo = await agentStaking.getAgentInfo(agent.address);
expect(agentInfo.name).to.equal("Updated Agent");
expect(agentInfo.metadataURI).to.equal("https://updated.com/metadata");
});
});
describe("Staking Operations", function () {
beforeEach(async function () {
await agentStaking.connect(agent).registerAgent(
"Test Agent",
"metadata",
["AI"]
);
});
it("Should stake tokens successfully", async function () {
const stakeAmount = ethers.utils.parseEther("1000");
await aitbcToken.connect(staker1).approve(agentStaking.address, stakeAmount);
const tx = await agentStaking.connect(staker1).stake(agent.address, stakeAmount);
const receipt = await tx.wait();
const event = receipt.events.find(e => e.event === "TokensStaked");
expect(event.args.staker).to.equal(staker1.address);
expect(event.args.agent).to.equal(agent.address);
expect(event.args.amount).to.equal(stakeAmount);
});
it("Should track total staked per agent", async function () {
const stakeAmount1 = ethers.utils.parseEther("500");
const stakeAmount2 = ethers.utils.parseEther("300");
await aitbcToken.connect(staker1).approve(agentStaking.address, stakeAmount1);
await aitbcToken.connect(staker2).approve(agentStaking.address, stakeAmount2);
await agentStaking.connect(staker1).stake(agent.address, stakeAmount1);
await agentStaking.connect(staker2).stake(agent.address, stakeAmount2);
const agentInfo = await agentStaking.getAgentInfo(agent.address);
expect(agentInfo.totalStaked).to.equal(stakeAmount1.add(stakeAmount2));
});
it("Should unstake tokens successfully", async function () {
const stakeAmount = ethers.utils.parseEther("1000");
await aitbcToken.connect(staker1).approve(agentStaking.address, stakeAmount);
await agentStaking.connect(staker1).stake(agent.address, stakeAmount);
// Fast forward past unstaking delay
await ethers.provider.send("evm_increaseTime", [86400 * 7]); // 7 days
await ethers.provider.send("evm_mine");
const initialBalance = await aitbcToken.balanceOf(staker1.address);
await agentStaking.connect(staker1).unstake(agent.address, stakeAmount);
const finalBalance = await aitbcToken.balanceOf(staker1.address);
expect(finalBalance).to.equal(initialBalance.add(stakeAmount));
});
it("Should fail to unstake before delay period", async function () {
const stakeAmount = ethers.utils.parseEther("1000");
await aitbcToken.connect(staker1).approve(agentStaking.address, stakeAmount);
await agentStaking.connect(staker1).stake(agent.address, stakeAmount);
await expect(
agentStaking.connect(staker1).unstake(agent.address, stakeAmount)
).to.be.revertedWith("Unstaking delay not met");
});
it("Should fail to unstake more than staked", async function () {
const stakeAmount = ethers.utils.parseEther("1000");
const unstakeAmount = ethers.utils.parseEther("1500");
await aitbcToken.connect(staker1).approve(agentStaking.address, stakeAmount);
await agentStaking.connect(staker1).stake(agent.address, stakeAmount);
// Fast forward past unstaking delay
await ethers.provider.send("evm_increaseTime", [86400 * 7]);
await ethers.provider.send("evm_mine");
await expect(
agentStaking.connect(staker1).unstake(agent.address, unstakeAmount)
).to.be.revertedWith("Insufficient staked amount");
});
});
describe("Reward Distribution", function () {
beforeEach(async function () {
await agentStaking.connect(agent).registerAgent(
"Test Agent",
"metadata",
["AI"]
);
const stakeAmount = ethers.utils.parseEther("1000");
await aitbcToken.connect(staker1).approve(agentStaking.address, stakeAmount);
await agentStaking.connect(staker1).stake(agent.address, stakeAmount);
});
it("Should distribute rewards proportionally", async function () {
const rewardAmount = ethers.utils.parseEther("100");
await aitbcToken.transfer(agentStaking.address, rewardAmount);
const initialBalance = await aitbcToken.balanceOf(staker1.address);
await agentStaking.distributeRewards(agent.address, rewardAmount);
const finalBalance = await aitbcToken.balanceOf(staker1.address);
expect(finalBalance).to.equal(initialBalance.add(rewardAmount));
});
it("Should handle multiple stakers proportionally", async function () {
// Add second staker
const stakeAmount2 = ethers.utils.parseEther("500");
await aitbcToken.connect(staker2).approve(agentStaking.address, stakeAmount2);
await agentStaking.connect(staker2).stake(agent.address, stakeAmount2);
const rewardAmount = ethers.utils.parseEther("150");
await aitbcToken.transfer(agentStaking.address, rewardAmount);
const initialBalance1 = await aitbcToken.balanceOf(staker1.address);
const initialBalance2 = await aitbcToken.balanceOf(staker2.address);
await agentStaking.distributeRewards(agent.address, rewardAmount);
const finalBalance1 = await aitbcToken.balanceOf(staker1.address);
const finalBalance2 = await aitbcToken.balanceOf(staker2.address);
// Staker1 had 1000 tokens, Staker2 had 500 tokens (2:1 ratio)
// So rewards should be distributed 100:50
expect(finalBalance1).to.equal(initialBalance1.add(ethers.utils.parseEther("100")));
expect(finalBalance2).to.equal(initialBalance2.add(ethers.utils.parseEther("50")));
});
});
describe("Agent Performance Tracking", function () {
beforeEach(async function () {
await agentStaking.connect(agent).registerAgent(
"Test Agent",
"metadata",
["AI"]
);
});
it("Should record successful performance", async function () {
await agentStaking.recordPerformance(agent.address, true, 95);
const agentInfo = await agentStaking.getAgentInfo(agent.address);
expect(agentInfo.successfulTasks).to.equal(1);
expect(agentInfo.totalTasks).to.equal(1);
expect(agentInfo.successRate).to.equal(10000); // 100% in basis points
});
it("Should record failed performance", async function () {
await agentStaking.recordPerformance(agent.address, false, 60);
const agentInfo = await agentStaking.getAgentInfo(agent.address);
expect(agentInfo.successfulTasks).to.equal(0);
expect(agentInfo.totalTasks).to.equal(1);
expect(agentInfo.successRate).to.equal(0);
});
it("Should calculate success rate correctly", async function () {
// Record multiple performances
await agentStaking.recordPerformance(agent.address, true, 90);
await agentStaking.recordPerformance(agent.address, true, 85);
await agentStaking.recordPerformance(agent.address, false, 70);
await agentStaking.recordPerformance(agent.address, true, 95);
const agentInfo = await agentStaking.getAgentInfo(agent.address);
expect(agentInfo.successfulTasks).to.equal(3);
expect(agentInfo.totalTasks).to.equal(4);
expect(agentInfo.successRate).to.equal(7500); // 75% in basis points
});
it("Should update average accuracy", async function () {
await agentStaking.recordPerformance(agent.address, true, 90);
await agentStaking.recordPerformance(agent.address, true, 80);
await agentStaking.recordPerformance(agent.address, true, 85);
const agentInfo = await agentStaking.getAgentInfo(agent.address);
expect(agentInfo.averageAccuracy).to.equal(8500); // 85% in basis points
});
});
describe("Slashing Mechanism", function () {
beforeEach(async function () {
await agentStaking.connect(agent).registerAgent(
"Test Agent",
"metadata",
["AI"]
);
const stakeAmount = ethers.utils.parseEther("1000");
await aitbcToken.connect(staker1).approve(agentStaking.address, stakeAmount);
await agentStaking.connect(staker1).stake(agent.address, stakeAmount);
});
it("Should slash agent stake for misconduct", async function () {
const slashAmount = ethers.utils.parseEther("100");
const initialContractBalance = await aitbcToken.balanceOf(agentStaking.address);
await agentStaking.slashStake(agent.address, slashAmount, "Test slash reason");
const finalContractBalance = await aitbcToken.balanceOf(agentStaking.address);
expect(finalContractBalance).to.equal(initialContractBalance.sub(slashAmount));
});
it("Should emit slash event", async function () {
const slashAmount = ethers.utils.parseEther("100");
const tx = await agentStaking.slashStake(agent.address, slashAmount, "Test reason");
const receipt = await tx.wait();
const event = receipt.events.find(e => e.event === "StakeSlashed");
expect(event.args.agent).to.equal(agent.address);
expect(event.args.amount).to.equal(slashAmount);
expect(event.args.reason).to.equal("Test reason");
});
it("Should fail to slash more than total staked", async function () {
const totalStaked = await agentStaking.getAgentStakedAmount(agent.address);
const slashAmount = totalStaked.add(ethers.utils.parseEther("1"));
await expect(
agentStaking.slashStake(agent.address, slashAmount, "Excessive slash")
).to.be.revertedWith("Slash amount exceeds total staked");
});
});
describe("Access Control", function () {
it("Should only allow owner to set performance recorder", async function () {
await expect(
agentStaking.connect(staker1).setPerformanceRecorder(staker2.address)
).to.be.revertedWith("Ownable: caller is not the owner");
});
it("Should allow owner to set performance recorder", async function () {
await agentStaking.setPerformanceRecorder(staker2.address);
expect(await agentStaking.performanceRecorder()).to.equal(staker2.address);
});
it("Should only allow performance recorder to record performance", async function () {
await agentStaking.connect(agent).registerAgent(
"Test Agent",
"metadata",
["AI"]
);
await expect(
agentStaking.connect(staker1).recordPerformance(agent.address, true, 90)
).to.be.revertedWith("Not authorized to record performance");
});
});
});