Valory Agent Registries
Smart Contract Audit Report
Audit Summary
Valory Agent Registries is a series of smart contracts allowing developers to record off-chain code as NFTs on-chain.
For this audit, we reviewed the following contracts:
- ComponentRegistry contract at 0x15bd56669F57192a97dF41A2aa8f4403e9491776 on the Ethereum Mainnet.
- AgentRegistry contract at 0x2F1f7D38e4772884b88f3eCd8B6b9faCdC319112 on the Ethereum Mainnet.
- ServiceRegistry contract at 0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA on the Ethereum Mainnet.
- RegistriesManager contract at 0x9eC9156dEF5C613B2a7D4c46C383F9B58DfcD6fE on the Ethereum Mainnet.
- ServiceManager contract at 0x38b062d11CD7596Ab5aDFe4d0e9F0dC3218E5389 on the Ethereum Mainnet, at 0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE on the Polygon Mainnet, and at 0xE3607b00E75f6405248323A9417ff6b39B244b50 on the Gnosis Mainnet.
- ServiceManagerToken contract at 0x2EA682121f815FBcF86EA3F3CaFdd5d67F2dB143 on the Ethereum Mainnet.
- ServiceRegistryL2 contract at 0xE3607b00E75f6405248323A9417ff6b39B244b50 on the Polygon Mainnet and at 0x9338b5153AE39BB89f50468E608eD9d764B755fD on the Gnosis Mainnet.
- ServiceRegistryTokenUtility contract at the 0x3Fb926116D454b95c669B6Bf2E7c3bad8d19affA on the Ethereum Mainnet.
- GnosisSafeMultisig contract at 0x46C0D07F55d4F9B5Eed2Fc9680B5953e5fd7b461 on the Ethereum Mainnet, at 0x3d77596beb0f130a4415df3D2D8232B3d3D31e44 on the Polygon Mainnet, and at 0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE on the Gnosis Mainnet.
- GnosisSafeSameAddressMultisig contract at 0x26Ea2dC7ce1b41d0AD0E0521535655d7a94b684c on the Ethereum Mainnet, at 0x34C895f302D0b5cf52ec0Edd3945321EB0f83dd5 on the Polygon Mainnet, and at 0x3d77596beb0f130a4415df3D2D8232B3d3D31e44 on the Gnosis Mainnet.
- OperatorWhitelist contract at 0x42042799B0DE38AdD2a70dc996f69f98E1a85260 on the Ethereum Mainnet
Audit Findings
All findings have been resolved, with minimal centralized aspects present.
Date: July 15th, 2022.
Updated: July 19th, 2022 with changes from commit 1a3fbd065a91e7d85544c65476e458b917a22fcd to commit v0.3.0.
Updated: July 22nd, 2022 with commit v1.0.0 and Mainnet addresses.
Updated: September 22nd, 2023 with new ServiceManagerToken, ServiceRegistryL2, and ServiceRegistryTokenUtility contracts.Finding #1 - ServiceRegistry - Medium (Resolved)
Description: Slashed funds are removed from an Operator's Service balance and not returned when they are slashed. As the Operator's Service balance is decreased, slashed funds will also not be returned when unbonding.
Risk/Impact: Any slashed funds will remain within the contract.
Recommendation: The team should return funds as they are slashed or add functionality to allow slashed funds to be withdrawn.
Resolution: The team has implemented a Drainer address to allow them to withdraw slashed funds.
Finding #2 - UnitRegistry - Informational (Resolved)
Description: The subComponentIds.length is used multiple times, including in a loop, when adding a new subComponent Id.
Recommendation: The team should consider declaring a variable equal to subComponentIds.length to save gas on each use.
Resolution: The team has implemented the above recommendation.
Contracts Overview
AgentRegistry & ComponentRegistry:
- The contracts utilize ReentrancyGuard to prevent against reentrancy attacks in applicable functions.
- As the contracts are implemented with Solidity v0.8 or above, they are safe from any possible overflows/underflows.
- The team has optimized the contracts' gas usage through variable packing and efficient logic where possible.
ServiceRegistry:
- These contracts are used to create and manage Components and Agents (units).
- The Manager address may create a new unit for the Unit Owner.
- Each unit is associated with a hash.
- The unit's dependencies, or SubComponents, must be provided in ascending order by unit ID.
- The Unit Owner will be minted an NFT representing ownership of the unit.
- The onERC721Received function must be implemented if the Unit Owner is a contract.
- A Unit Owner may associate additional unused hashes with any of their units.
- The owner may transfer ownership at any time.
- The owner may update the Manager address at any time.
- The owner may update the base URI at any time.
- The contract is ERC721 compliant.
RegistriesManager:
- This contract is used to create and manage Services.
- Services may be in one of several states depending on the most recent action performed.
- The Manager address may create a new Service for the Service Owner.
- The hash associated with the service and the threshold for a successful MultiSig wallet call must be provided in addition to the number of Agents and their corresponding number of "slots" and "bond" cost in ETH.
- The threshold must be at least 2/3 of the total number of Agents.
- Each Agent's number of slots and bond cost are stored using a 2-part key consisting of the Service ID and the Agent ID.
- The Agent IDs associated with each Agent must be provided in ascending order.
- A newly created Service will be in the PreRegistration state.
- The Service Owner is minted an NFT representing ownership of the Service.
- The onERC721Received function must be implemented if the Service Owner is a contract.
- The Manager address may update any Services in the PreRegistration state.
- An update may remove existing Agents, add new Agents, modify an Agents slots or bond, update the MultiSig threshold, and add a new hash to a Service.
- An Agent is removed from the service if the Agent ID is provided with no corresponding slots in the Agent parameters.
- Similarly to creating a Service, the Agent IDs must be provided in ascending order when updating.
- The Manager address may activate the registration of any Services in the PreRegistration state.
- The Service Owner must pay the "security deposit" amount of ETH.
- The security deposit is equal to the largest bond of any of the Agents associated with the Service being activated.
- The Service will then be in the ActiveRegistration state.
- The Manager address may register Agents for any Service in the ActiveRegistration state for an Operator.
- Each Agent instance (the Agent's address and Agent ID) will be associated with the Operator for the corresponding Service being registered.
- The Agent instances are stored using a 2-part key consisting of the Service ID and the Operator ID.
- Services may have multiple Operators, but each Agent instance may only have one Operator.
- An Operator may not be an Agent instance.
- The Operator must pay the total bond of all Agents they are registering. The bond is stored in the Operator's balance for the Service.
- The Service will be in the FinishedRegistration state once all of the Agents for the Service have been registered.
- The Manager Address may deploy any Service in the FinishedRegistration state.
- Deploying a Service will create a MultiSig wallet from one of the approved implementations.
- The Agent instances provided in the creation process will serve as the signers for the MultiSig wallet.
- The Service will then be in the Deployed state.
- The MultiSig associated with a Service in the Deployed state may "slash" funds.
- Slashing will remove a specified amount of funds from the corresponding Agent's Operator's balance.
- The Drainer address may withdraw any slashed funds from the contract.
- The Manager Address may terminate any Service that is not in the PreRegistration or TerminatedBonded states.
- Terminating a Service will delete the Agent instances associated with the Service and refund the Service Owner their security deposit.
- The Service will be in the Terminated Bonded state if it had associated Agent Instances.
- The Service will be in the PreRegistration state if it did not have associated Agent Instances.
- The Manager address may unbond an Operator for any Service in the TerminatedBonded state.
- Unbonding will remove the association between the Operator's Agent instances and the Service, and the association with the Operator Service key.
- The Operator will be refunded the total bond amount of the unassociated Agent instances and the Operator's Service balance will be reset to 0.
- The Service will be in the PreRegistration state if it has no associated Agent instances after unbonding.
- The owner may add and remove an address as a valid MultiSig wallet implementation at any time.
- The owner may transfer ownership at any time.
- The owner may update the Manager and Drainer addresses at any time.
- The owner may update the base URI at any time.
- The contract is ERC721 compliant.
ServiceManager:
- This contract serves as a wrapper and the Manager address for the ComponentRegistry and AgentRegistry contracts.
- Any address may create a new Agent or Component (unit).
- The hash associated with the unit and the dependencies must be provided.
- The unit owner may add additional hashes to any of their units.
- The owner may update ownership at any time.
- The owner may pause the contract, preventing the creation of units, at any time.
ServiceManagerToken Contract:
- This contract serves as a wrapper and the Manager address for the ServiceRegistry contract.
- Any address may use this contract to create a Service.
- The user must provide the number of Agents associated with the Service, each Agents corresponding Agent ID, and the required "bond" that must be paid by each Agent.
- The Service Owner may update any of their Services while they are in the PreRegistration state.
- The Service Owner may activate the registration of any of their Services by providing the security deposit amount of ETH.
- A Service Operator may register Agents associated with any Services in the ActiveRegistration state; each Agent requires paying their corresponding bond amount in ETH.
- The Service Owner may deploy any of their Services that are in the ActiveRegistration state.
- The Service Owner may terminate any of their Services that are not in the PreRegistration or TerminatedBonded state.
- A Service Operator may unbond any of their Services that are in the TerminatedUnbonded state.
- The owner may update ownership at any time.
- The owner may pause the contract, preventing the creation of Services, at any time.
ServiceRegistryTokenUtility Contract:
- This contract is used to route ServiceRegistry requests to the appropriate contract based on whether the user is supplying ERC-20 or ETH.
- Any address may call the ServiceManagerToken functionality, though the functions are access restricted within the corresponding contracts.
- Any address may create a Service when the contract is not paused.
- This contract will forward the create request to the Service Registry if the token being used is ETH.
- The contract will first create the Service in the ServiceRegistry and then create a Token Service in the ServiceRegistryTokenUtility.
- Any address may update a Service.
- This contract will forward the update request to the ServiceRegistry for both ETH and ERC-20 tokens.
- The corresponding Token Service will be deleted if the Service's asset is changed from an ERC-20 token to ETH.
- A Token Service will be created if the Service's asset is changed from ETH to an ERC-20 token.
- Any address may activate a Service's registration. This contract will forward the correct format of activation request to the ServiceRegistry.
- Any address may register agents for a Service.
- The registering address must be whitelisted in the OperatorWhitelist if one has been set.
- This contract will forward the correct format of an agent registration request to the ServiceRegistry.
- Users may elect to register agents with a signature.
- Any address may deploy the multisig wallet for a specified Service.
- Any address may terminate a specified Service.
- The corresponding security deposit will be refunded from the ServiceRegistryTokenUtility if the Service's asset is an ERC-20 token.
- The Service will then be terminated in the ServiceRegistry.
- Any address may unbond a specified Service.
- This will unbond in the ServiceRegistryTokenUtility if applicable and unbond in the ServiceRegistry.
- Users may elect to unbond with a signature.
- The owner may set the Operator Whitelist address at any time.
GnosisSafeMultisig Contract:
- This contract is used to manage data associated with a Service whose asset is an ERC-20 token.
- The manager address may create a Token Service to be associated with a specified token in combination with the service ID and agent IDs in the ServiceRegistry contract.
- The token specified must implement the balanceOf() function.
- The total security deposit for the Token Service is calculated as the sum of the bonds for each agent.
- The manager address may activate the registration for a specified service ID at any time.
- This will transfer the security deposit of the Token Service's asset token from the Service owner to this contract.
- The manager address may register a token deposit for specified agent Ids at any time.
- This will transfer the total bond cost for the specified agents from the operator address to this contract.
- The manager address may terminate a token refund for a specified Service ID at any time. This will transfer the Service's security deposit back to the Service owner.
- The manager address may unbond a token refund for a specified service ID and operator address at any time.
- This will refund any tokens the operator has deposited as bonds for the Service.
- The MultiSig wallet associated with a Token Service may perform a slash when the token is in the deployed state.
- This will mark the specified amount of tokens from specified agents as slashed up to the Service's balance.
- The owner may drain a specified token from the contract at any time.
- This will transfer all slashed tokens from the contract to the drainer address.
- The manager address may remove the Token Service for a specified service ID at any time.
- The owner may transfer ownership to a new address at any time.
- The owner may set the manager address at any time.
- The owner may set the drainer address at any time.
GnosisSafeSameAddressMultisig Contract:
- This contract is used to create GnosisSafe proxies to be used as MultiSig implementations for Services.
- Any address may use this contract to create a GnosisSafe proxy.
- Users may provide data to be used as a payload during the proxy creation.
- The proxy will be created with the specified owners and proposal approval threshold.
OperatorWhitelist Contract:
- This contract is used when a MultiSig associated with a Service updates the owners or threshold to pass a proposed action.
- If the MultiSig values have not been updated the contract will attempt to perform the update through a signed transaction.
- The contract will verify the owners and threshold for the MultiSig based on the provided data after the update is performed or if the update was previously executed.
- This contract maintains a whitelist of Operators for each Service.
- A Service's owner may toggle whether an address' whitelist status should be checked for the Service.
- A Service's owner may add and remove an address from the whitelist for the Service at any time.
- Any address may query whether an address is whitelisted for a specified Service. Addresses are whitelisted by default.
- If the Service owner has enabled that the specified address should be checked the address' whitelist status is returned.
Audit Results
Vulnerability Category | Notes | Result |
---|---|---|
Arbitrary Jump/Storage Write | N/A | PASS |
Centralization of Control | The contracts contain minimal ownership controls. | PASS |
Compiler Issues | N/A | PASS |
Delegate Call to Untrusted Contract | N/A | PASS |
Dependence on Predictable Variables | N/A | PASS |
Ether/Token Theft | N/A | PASS |
Flash Loans | N/A | PASS |
Front Running | N/A | PASS |
Improper Events | N/A | PASS |
Improper Authorization Scheme | N/A | PASS |
Integer Over/Underflow | N/A | PASS |
Logical Issues | N/A | PASS |
Oracle Issues | N/A | PASS |
Outdated Compiler Version | N/A | PASS |
Race Conditions | N/A | PASS |
Reentrancy | N/A | PASS |
Signature Issues | N/A | PASS |
Unbounded Loops | N/A | PASS |
Unused Code | N/A | PASS |
Overall Contract Safety | PASS |
Name |
Address/Source Code |
Visualized |
AgentRegistry |
||
ComponentRegistry |
||
ServiceRegistry |
||
ServiceRegistryL2 |
||
RegistriesManager |
||
ServiceManager |
||
ServiceManagerToken |
||
ServiceRegistryTokenUtility |
||
GnosisSafeMultisig |
||
GnosisSafeSameAddressMultisig |
||
OperatorWhitelist |
About SourceHat
SourceHat has quickly grown to have one of the most experienced and well-equipped smart contract auditing teams in the industry. Our team has conducted 1800+ solidity smart contract audits covering all major project types and protocols, securing a total of over $50 billion U.S. dollars in on-chain value!
Our firm is well-reputed in the community and is trusted as a top smart contract auditing company for the review of solidity code, no matter how complex. Our team of experienced solidity smart contract auditors performs audits for tokens, NFTs, crowdsales, marketplaces, gambling games, financial protocols, and more!
Contact us today to get a free quote for a smart contract audit of your project!
What is a SourceHat Audit?
Typically, a smart contract audit is a comprehensive review process designed to discover logical errors, security vulnerabilities, and optimization opportunities within code. A SourceHat Audit takes this a step further by verifying economic logic to ensure the stability of smart contracts and highlighting privileged functionality to create a report that is easy to understand for developers and community members alike.
How Do I Interpret the Findings?
Each of our Findings will be labeled with a Severity level. We always recommend the team resolve High, Medium, and Low severity findings prior to deploying the code to the mainnet. Here is a breakdown on what each Severity level means for the project:
- High severity indicates that the issue puts a large number of users' funds at risk and has a high probability of exploitation, or the smart contract contains serious logical issues which can prevent the code from operating as intended.
- Medium severity issues are those which place at least some users' funds at risk and has a medium to high probability of exploitation.
- Low severity issues have a relatively minor risk association; these issues have a low probability of occurring or may have a minimal impact.
- Informational issues pose no immediate risk, but inform the project team of opportunities for gas optimizations and following smart contract security best practices.