diff --git a/contracts/AgentFactory.sol b/contracts/AgentFactory.sol deleted file mode 100644 index 0b1f3dc..0000000 --- a/contracts/AgentFactory.sol +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.28; - -import {AgentMech} from "./AgentMech.sol"; -import {GenericManager} from "../lib/autonolas-registries/contracts/GenericManager.sol"; -import {IServiceRegistry} from "./interfaces/IServiceRegistry.sol"; - -interface IAgentRegistry { - /// @dev Creates a agent. - /// @param agentOwner Owner of the agent. - /// @param agentHash IPFS CID hash of the agent metadata. - /// @return agentId The id of a minted agent. - function create(address agentOwner, bytes32 agentHash) external returns (uint256 agentId); -} - -/// @title Agent Factory - Periphery smart contract for managing agent and mech creation -contract AgentFactory is GenericManager { - event CreateMech(address indexed mech, uint256 indexed agentId, uint256 indexed price); - - // Agent factory version number - string public constant VERSION = "1.1.0"; - - // Service registry address - address public immutable serviceRegistry; - - constructor(address _serviceRegistry) { - serviceRegistry = _serviceRegistry; - owner = msg.sender; - } - - /// @dev Registers service as a mech. - /// @param serviceId Service id. - /// @param price Minimum required payment the agent accepts. - /// @param mechMarketplace Mech marketplace address. - /// @return mech The created mech instance address. - function create( - uint256 serviceId, - uint256 price, - address mechMarketplace - ) external returns (address mech) - { - // Check if the creation is paused - if (paused) { - revert Paused(); - } - - // Get service multisig address - (, address multisig, , , , , ) = IServiceRegistry(serviceRegistry).mapServices(serviceId); - - bytes32 salt = keccak256(abi.encode(multisig, serviceId)); - // multisig is isOperator() for the mech - mech = address((new AgentMech){salt: salt}(serviceRegistry, serviceId, price, mechMarketplace)); - - emit CreateMech(mech, serviceId, price); - } -} diff --git a/contracts/AgentMech.sol b/contracts/AgentMech.sol index 85852ad..4203066 100644 --- a/contracts/AgentMech.sol +++ b/contracts/AgentMech.sol @@ -288,23 +288,6 @@ contract AgentMech is OlasMech { emit Deliver(msg.sender, requestId, requestData); } - /// @dev Registers a request without a marketplace. - /// @notice Interface provided for backwards compatibility only. - /// @param data Self-descriptive opaque data-blob. - /// @return requestId Request Id. - function request(bytes memory data) external payable returns (uint256 requestId) { - if (mechMarketplace != address(0)) { - revert MarketplaceExists(mechMarketplace); - } - - // Get the local request Id - requestId = getRequestId(msg.sender, data, mapNonces[msg.sender]); - mapNonces[msg.sender]++; - - // Perform a request - _request(msg.sender, data, requestId); - } - /// @dev Registers a request by a marketplace. /// @notice This function is called by the marketplace contract since this mech was specified as a priority one. /// @param account Requester account address. @@ -342,28 +325,6 @@ contract AgentMech is OlasMech { emit RevokeRequest(account, requestId); } - /// @dev Delivers a request without a marketplace. - /// @notice Interface provided for backwards compatibility only. - /// @param requestId Request id. - /// @param data Self-descriptive opaque data-blob. - function deliver(uint256 requestId, bytes memory data) external onlyOperator { - // Reentrancy guard - if (_locked > 1) { - revert ReentrancyGuard(); - } - _locked = 2; - - // Check for the marketplace existence - if (mechMarketplace != address(0)) { - revert MarketplaceExists(mechMarketplace); - } - - // Request delivery - _deliver(requestId, data); - - _locked = 1; - } - /// @dev Delivers a request by a marketplace. /// @notice This function ultimately calls mech marketplace contract to finalize the delivery. /// @param requestId Request id. diff --git a/contracts/MechFactoryBasic.sol b/contracts/MechFactoryBasic.sol new file mode 100644 index 0000000..b5b8cdf --- /dev/null +++ b/contracts/MechFactoryBasic.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import {AgentMech} from "./AgentMech.sol"; + +/// @title Mech Factory Basic - Periphery smart contract for managing basic mech creation +contract MechFactoryBasic { + event CreateBasicMech(address indexed mech, uint256 indexed serviceId, uint256 indexed price); + + // Agent factory version number + string public constant VERSION = "0.1.0"; + + /// @dev Registers service as a mech. + /// @param mechMarketplace Mech marketplace address. + /// @param serviceRegistry Service registry address. + /// @param serviceId Service id. + /// @param payload Mech creation payload. + /// @return mech The created mech instance address. + function createMech( + address mechMarketplace, + address serviceRegistry, + uint256 serviceId, + bytes memory payload + ) external returns (address mech) { + // Check payload length + if (payload.length != 32) { + revert(); + } + + // Decode price + uint256 price = abi.decode(payload, (uint256)); + + // Get salt + bytes32 salt = keccak256(abi.encode(block.timestamp, msg.sender, serviceId)); + + // Service multisig is isOperator() for the mech + mech = address((new AgentMech){salt: salt}(serviceRegistry, serviceId, price, mechMarketplace)); + + emit CreateBasicMech(mech, serviceId, price); + } +} diff --git a/contracts/MechMarketplace.sol b/contracts/MechMarketplace.sol index 474ed3d..312802a 100644 --- a/contracts/MechMarketplace.sol +++ b/contracts/MechMarketplace.sol @@ -7,6 +7,17 @@ import {IMech} from "./interfaces/IMech.sol"; import {IServiceRegistry} from "./interfaces/IServiceRegistry.sol"; import {IStaking, IStakingFactory} from "./interfaces/IStaking.sol"; +interface IMechFactory { + /// @dev Registers service as a mech. + /// @param mechMarketplace Mech marketplace address. + /// @param serviceRegistry Service registry address. + /// @param serviceId Service id. + /// @param payload Mech creation payload. + /// @return mech The created mech instance address. + function createMech(address mechMarketplace, address serviceRegistry, uint256 serviceId, bytes memory payload) + external returns (address mech); +} + // Mech delivery info struct struct MechDelivery { // Priority mech address @@ -21,10 +32,7 @@ struct MechDelivery { /// @title Mech Marketplace - Marketplace for posting and delivering requests served by agent mechs contract MechMarketplace is IErrorsMarketplace { - event OwnerUpdated(address indexed owner); - event FactoryUpdated(address indexed factory); - event MinMaxResponseTimeoutUpdated(uint256 minResponseTimeout, uint256 maxResponseTimeout); - event MechRegistrationStatusChanged(address indexed mech, bool status); + event CreateMech(address indexed mech, uint256 indexed serviceId); event MarketplaceRequest(address indexed requester, address indexed requestedMech, uint256 requestId, bytes data); event MarketplaceDeliver(address indexed priorityMech, address indexed actualMech, address indexed requester, uint256 requestId, bytes data); @@ -37,7 +45,7 @@ contract MechMarketplace is IErrorsMarketplace { } // Contract version number - string public constant VERSION = "1.0.0"; + string public constant VERSION = "1.1.0"; // Domain separator type hash bytes32 public constant DOMAIN_SEPARATOR_TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); @@ -133,6 +141,21 @@ contract MechMarketplace is IErrorsMarketplace { ); } + /// @dev Registers service as a mech. + /// @param serviceId Service id. + /// @param mechFactory Mech factory address. + /// @return mech The created mech instance address. + function create(uint256 serviceId, address mechFactory, bytes memory payload) external returns (address mech) { + mech = IMechFactory(mechFactory).createMech(address(this), serviceRegistry, serviceId, payload); + + // This should never be the case + if (mech == address(0)) { + revert ZeroAddress(); + } + + emit CreateMech(mech, serviceId); + } + /// @dev Registers a request. /// @notice The request is going to be registered for a specified priority agent mech. /// @param data Self-descriptive opaque data-blob. @@ -395,6 +418,12 @@ contract MechMarketplace is IErrorsMarketplace { revert ZeroValue(); } + // Check marketplace address + address checkMarketplace = IMech(mech).mechMarketplace(); + if (checkMarketplace != address(this)) { + revert UnauthorizedAccount(checkMarketplace); + } + // Check mech service Id and staking instance, if applicable multisig = checkServiceAndGetMultisig(mechStakingInstance, mechServiceId); diff --git a/contracts/integrations/nevermined/AgentFactorySubscription.sol b/contracts/integrations/nevermined/AgentFactorySubscription.sol deleted file mode 100644 index 4fb1f19..0000000 --- a/contracts/integrations/nevermined/AgentFactorySubscription.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.28; - -import {AgentMechSubscription} from "./AgentMechSubscription.sol"; -import {GenericManager} from "../../../lib/autonolas-registries/contracts/GenericManager.sol"; - -interface IAgentRegistry { - /// @dev Creates a agent. - /// @param agentOwner Owner of the agent. - /// @param agentHash IPFS CID hash of the agent metadata. - /// @return agentId The id of a minted agent. - function create(address agentOwner, bytes32 agentHash) external returns (uint256 agentId); -} - -/// @title Agent Factory Subscription - Periphery smart contract for managing agent and mech creation with subscription -contract AgentFactorySubscription is GenericManager { - event CreateMech( - address indexed mech, - uint256 indexed agentId, - uint256 minCreditsPerRequest, - address indexed subscriptionNFT, - uint256 subscriptionTokenId - ); - - // Agent factory version number - string public constant VERSION = "1.1.0"; - - // Agent registry address - address public immutable agentRegistry; - - constructor(address _agentRegistry) { - agentRegistry = _agentRegistry; - owner = msg.sender; - } - - /// @dev Creates agent. - /// @param agentOwner Owner of the agent. - /// @param agentHash IPFS CID hash of the agent metadata. - /// @param minCreditsPerRequest Minimum number of credits to pay for each request via a subscription. - /// @param subscriptionNFT Subscription address. - /// @param subscriptionTokenId Subscription token Id. - /// @param mechMarketplace Mech marketplace address. - /// @return agentId The id of a created agent. - /// @return mech The created mech instance address. - function create( - address agentOwner, - bytes32 agentHash, - uint256 minCreditsPerRequest, - address subscriptionNFT, - uint256 subscriptionTokenId, - address mechMarketplace - ) external returns (uint256 agentId, address mech) - { - // Check if the creation is paused - if (paused) { - revert Paused(); - } - - agentId = IAgentRegistry(agentRegistry).create(agentOwner, agentHash); - bytes32 salt = keccak256(abi.encode(agentOwner, agentId)); - // agentOwner is isOperator() for the mech - mech = address((new AgentMechSubscription){salt: salt}(agentRegistry, agentId, - minCreditsPerRequest, subscriptionNFT, subscriptionTokenId, mechMarketplace)); - - emit CreateMech(mech, agentId, minCreditsPerRequest, subscriptionNFT, subscriptionTokenId); - } -} diff --git a/contracts/integrations/nevermined/MechFactorySubscription.sol b/contracts/integrations/nevermined/MechFactorySubscription.sol new file mode 100644 index 0000000..454056b --- /dev/null +++ b/contracts/integrations/nevermined/MechFactorySubscription.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import {AgentMechSubscription} from "./AgentMechSubscription.sol"; + +/// @title Mech Factory Subscription - Periphery smart contract for managing subscription mech creation +contract MechFactorySubscription { + event CreateSubscriptionMech(address indexed mech, uint256 indexed serviceId, uint256 minCreditsPerRequest, + address indexed subscriptionNFT, uint256 subscriptionTokenId); + + // Agent factory version number + string public constant VERSION = "0.1.0"; + + /// @dev Registers service as a mech. + /// @param mechMarketplace Mech marketplace address. + /// @param serviceRegistry Service registry address. + /// @param serviceId Service id. + /// @param payload Mech creation payload. + /// @return mech The created mech instance address. + function createMech( + address mechMarketplace, + address serviceRegistry, + uint256 serviceId, + bytes memory payload + ) external returns (address mech) { + // Check payload length + if (payload.length != 96) { + revert(); + } + + // Decode subscription parameters + (uint256 minCreditsPerRequest, address subscriptionNFT, uint256 subscriptionTokenId) = + abi.decode(payload, (uint256, address, uint256)); + + // Get salt + bytes32 salt = keccak256(abi.encode(block.timestamp, msg.sender, serviceId)); + + // Service multisig is isOperator() for the mech + mech = address((new AgentMechSubscription){salt: salt}(serviceRegistry, serviceId, minCreditsPerRequest, + subscriptionNFT, subscriptionTokenId, mechMarketplace)); + + emit CreateSubscriptionMech(mech, serviceId, minCreditsPerRequest, subscriptionNFT, subscriptionTokenId); + } +} diff --git a/contracts/interfaces/IMech.sol b/contracts/interfaces/IMech.sol index 2b0e1ec..152ea1f 100644 --- a/contracts/interfaces/IMech.sol +++ b/contracts/interfaces/IMech.sol @@ -16,4 +16,8 @@ interface IMech { /// @notice Only marketplace can call this function if the request is not delivered by the chosen priority mech. /// @param requestId Request Id. function revokeRequest(uint256 requestId) external; + + /// @dev Gets mech marketplace address. + /// @return marketplace Mech Marketplace address. + function mechMarketplace() external view returns (address marketplace); } \ No newline at end of file