pragma solidity ^0.8.20;
import {Test} from "../lib/forge-std/src/Test.sol";
import {console2} from "../lib/forge-std/src/console2.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import {Swan} from "../contracts/swan/Swan.sol";
import {SwanAssetFactory, SwanAsset} from "../contracts/swan/SwanAsset.sol";
import {SwanManager, SwanMarketParameters} from "../contracts/swan/SwanManager.sol";
import {BuyerAgentFactory, BuyerAgent} from "../contracts/swan/BuyerAgent.sol";
import {LLMOracleTaskParameters} from "../contracts/llm/LLMOracleTask.sol";
import {LLMOracleCoordinator} from "../contracts/llm/LLMOracleCoordinator.sol";
import {LLMOracleRegistry, LLMOracleKind} from "../contracts/llm/LLMOracleRegistry.sol";
import {ERC20Mock} from "./ERC20Mock.sol";
contract Base is Test {
address deployer = makeAddr("deployer");
address buyerAgentOwner = makeAddr("buyerAgentOwner");
address creator = makeAddr("creator");
address generator1 = makeAddr("generator1");
address generator2 = makeAddr("generator2");
address[] generators;
address validator1 = makeAddr("validator1");
address validator2 = makeAddr("validator2");
address validator3 = makeAddr("validator3");
address[] validators;
Swan swan;
SwanAssetFactory swanAssetFactory;
LLMOracleCoordinator coordinator;
LLMOracleRegistry registry;
BuyerAgentFactory buyerAgentFactory;
ERC20Mock token;
uint256 withdrawInterval = 30 minutes;
uint256 sellInterval = 60 minutes;
uint256 buyInterval = 10 minutes;
uint256 platformFee = 1;
uint256 maxAssetCount = 5;
uint256 timestamp = 0;
SwanMarketParameters marketParameters = SwanMarketParameters({
withdrawInterval: withdrawInterval,
sellInterval: sellInterval,
buyInterval: buyInterval,
platformFee: platformFee,
maxAssetCount: maxAssetCount,
timestamp: timestamp
});
LLMOracleTaskParameters oracleParameters =
LLMOracleTaskParameters({difficulty: 1, numGenerations: 1, numValidations: 1});
uint256 generatorStakeAmount = 0.1e18;
uint256 validatorStakeAmount = 0.1e18;
uint256 stakePlatformFee = 0.001e18;
uint256 generationFee = 0.002e18;
uint256 validationFee = 0.003e18;
function setUp() public virtual {
vm.startPrank(deployer);
token = new ERC20Mock("Mock", "MOCK");
buyerAgentFactory = new BuyerAgentFactory();
swanAssetFactory = new SwanAssetFactory();
LLMOracleRegistry registryImpl = new LLMOracleRegistry();
ERC1967Proxy registryProxy = new ERC1967Proxy(
address(registryImpl),
abi.encodeWithSelector(
LLMOracleRegistry.initialize.selector, generatorStakeAmount, validatorStakeAmount, address(token)
)
);
registry = LLMOracleRegistry(address(registryProxy));
LLMOracleCoordinator coordinatorImpl = new LLMOracleCoordinator();
ERC1967Proxy coordinatorProxy = new ERC1967Proxy(
address(coordinatorImpl),
abi.encodeWithSelector(
LLMOracleCoordinator.initialize.selector,
address(registry),
address(token),
stakePlatformFee,
generationFee,
validationFee
)
);
coordinator = LLMOracleCoordinator(address(coordinatorProxy));
Swan swanImpl = new Swan();
ERC1967Proxy swanProxy = new ERC1967Proxy(
address(swanImpl),
abi.encodeWithSelector(
Swan.initialize.selector,
marketParameters,
oracleParameters,
address(coordinator),
address(token),
address(buyerAgentFactory),
address(swanAssetFactory)
)
);
swan = Swan(address(swanProxy));
assertEq(swan.getMarketParameters().length, 1);
vm.stopPrank();
generators = new address[](2);
generators[0] = generator1;
generators[1] = generator2;
validators = new address[](3);
validators[0] = validator1;
validators[1] = validator2;
validators[2] = validator3;
vm.stopPrank();
token.mint(buyerAgentOwner, 10e18);
token.mint(creator, 10e18);
token.mint(generator1, generatorStakeAmount);
token.mint(generator2, generatorStakeAmount);
token.mint(validator1, validatorStakeAmount);
token.mint(validator2, validatorStakeAmount);
token.mint(validator3, validatorStakeAmount);
}
function createBuyerAgent(uint96 _royaltyFee, uint256 _amountPerRound, uint256 _createTimeStamp)
public
returns (BuyerAgent buyerAgent)
{
vm.warp(_createTimeStamp);
vm.prank(buyerAgentOwner);
buyerAgent = swan.createBuyer("BuyerAgent", "Buyooor", _royaltyFee, _amountPerRound);
}
function generatorAndValidatorStake() public {
for (uint256 i = 0; i < generators.length; i++) {
vm.startPrank(generators[i]);
token.approve(address(registry), generatorStakeAmount);
registry.register(LLMOracleKind.Generator);
}
for (uint256 i = 0; i < validators.length; i++) {
vm.startPrank(validators[i]);
token.approve(address(registry), validatorStakeAmount);
registry.register(LLMOracleKind.Validator);
}
}
function createListing_Amount_For_WithPrice(address _creator, uint256 _amount, address _buyerAgent, uint256 _price)
public
returns (address[] memory assets)
{
vm.startPrank(_creator);
swan.token().approve(address(swan), _price * _amount);
bytes memory desc = "description";
for (uint256 i = 0; i < _amount; i++) {
swan.list(string(abi.encodePacked("test ", uint2str(i))), "TEST", desc, _price, _buyerAgent);
}
(uint256 round,,) = BuyerAgent(_buyerAgent).getRoundPhase();
assets = swan.getListedAssets(_buyerAgent, round);
vm.stopPrank();
}
function uint2str(uint256 _i) internal pure returns (string memory) {
if (_i == 0) {
return "0";
}
uint256 j = _i;
uint256 length;
while (j != 0) {
length++;
j /= 10;
}
bytes memory bstr = new bytes(length);
uint256 k = length;
while (_i != 0) {
k = k - 1;
uint8 temp = (48 + uint8(_i - _i / 10 * 10));
bytes1 b1 = bytes1(temp);
bstr[k] = b1;
_i /= 10;
}
return string(bstr);
}
function test_createListing() public {
uint256 amount = 5;
BuyerAgent buyerAgent = createBuyerAgent(10, 1e18, 1000);
address[] memory assets = createListing_Amount_For_WithPrice(creator, amount, address(buyerAgent), 100);
assertEq(swan.getListedAssets(address(buyerAgent), 0).length, amount);
for (uint256 i = 0; i < assets.length; i++) {
console2.log("asset: ", assets[i]);
}
}
function test_stake() public {
generatorAndValidatorStake();
}
}
pragma solidity 0.8.20;
import {console2} from "../lib/forge-std/src/console2.sol";
import {Base} from "./Base.t.sol";
import {BuyerAgent} from "../contracts/swan/BuyerAgent.sol";
import {SwanMarketParameters} from "../contracts/swan/SwanManager.sol";
import {LLMOracleTaskParameters} from "../contracts/llm/LLMOracleTask.sol";
contract SwanTest is Base {
BuyerAgent buyerAgent;
uint96 royaltyFee = 10;
uint256 amountPerRound = 1e18;
uint256 createTimeStamp = 1000;
function setUp() public override {
super.setUp();
buyerAgent = createBuyerAgent(royaltyFee, amountPerRound, createTimeStamp);
}
function test_oracleResultMultipleAssetTotalExceedMaxSpendingRounds() public {
(uint256 round,,) = buyerAgent.getRoundPhase();
uint256 assetAmount = 5;
uint256 assetPrice = 0.4e18;
uint256 balanceOfCreatorBefore = token.balanceOf(creator);
address[] memory listedAssets =
createListing_Amount_For_WithPrice(creator, assetAmount, address(buyerAgent), assetPrice);
uint256 balanceOfCreatorAfter = token.balanceOf(creator);
uint256 feePaidForListing = balanceOfCreatorBefore - balanceOfCreatorAfter;
console2.log("Creator paid ", feePaidForListing, " for listing assets at round", round);
vm.warp(createTimeStamp + sellInterval + 10);
vm.startPrank(buyerAgentOwner);
token.transfer(address(buyerAgent), 1e18);
vm.expectRevert();
buyerAgent.purchaseMock(listedAssets);
}
}
no purchase can happen on the round, financial and opportunity loss for both creator and agent owner