TITLES builds creative tools powered by artist-owned AI models. The underlying TITLES protocol enables the publishing of referential NFTs, including managing attribution and splitting payments with the creators of the attributed works.
Scope
Contest Results
On what chains are the smart contracts going to be deployed?
Ethereum, Base, OP, Zora, Blast, Arbitrum, zkSync, Degen
If you are integrating tokens, are you allowing only whitelisted tokens to work with the codebase or any complying with the standard? Are they assumed to have certain properties, e.g. be non-reentrant? Are there any types of weird tokens you want to integrate?
The current version supports native ETH
Are the admins of the protocols your contracts integrate with (if any) TRUSTED or RESTRICTED? If these integrations are trusted, should auditors also assume they are always responsive, for example, are oracles trusted to provide non-stale information, or VRF providers to respond within a designated timeframe?
The only third-party integration we utilize at this time is 0xSplits, and there are no critical roles involved. Any issues directly related to 0xSplits own implementation is NOT in scope, consider the protocol to be trusted for the purpose of this audit.
Are there any protocol roles? Please list them and provide whether they are TRUSTED or RESTRICTED, or provide a more comprehensive description of what a role can and can't do/impact.
There are a few roles in the system with varying levels of power.
ADMIN_ROLE (Trusted) => Granted by the deployer to internal, trusted addresses only.
On TitlesCore, this role can:
1) Change the ERC-1155 Edition implementation contract to an arbitrary address (setEditionImplementation
). No post-auth validation is performed.
2) Upgrade the contract to an arbitrary new implementation (via _authorizeUpgrade
, inherited and overridden with auth check from Solady's UUPSUpgradeable
)
On TitlesGraph, this role can:
1) Create new Edges at will (createEdges
). No post-auth validation is applied, except the typical uniqueness checks.
2) Upgrade the contract to an arbitrary new implementation (via _authorizeUpgrade
, inherited and overridden with auth check from Solady's UUPSUpgradeable
)
3) Grant or revoke any role to/from any address (grantRole
, revokeRole
).
On FeeManager, this role can:
1) Set the protocol fees (setProtocolFees
). All fees are constrained to a constant range.
2) Create or change a fee route for any work within any Edition (createRoute
). This is the only way to change the fee route for a work after publication.
3) Withdraw any funds locked in the contract (withdraw
). This is the only way to withdraw funds from the contract.
3) Grant or revoke any role to/from any address (grantRole
, revokeRole
).
EDITION_MANAGER_ROLE (Restricted) =>
On an Edition, this role can:
1) Publish a new work with any desired configuration (publish
). This is the only way to create new works after the Edition is created.
2) Mint promotional copies of any work (promoMint
). There are no limitations on this action aside from the work's supply cap and minting period.
3) Set the Edition's ERC2981 royalty receiver (setRoyaltyTarget
). This is the only way to change the royalty receiver for the Edition.
4) Grant or revoke any role to/from any address (grantRole
, revokeRole
).
EDITION_PUBLISHER_ROLE (Restricted) =>
On TitlesCore, this role can:
1) Publish a new work under any Edition for which they have been granted the role (i.e. edition.hasAnyRole(msg.sender, EDITION_PUBLISHER_ROLE)
is true) (publish
). After auth, the request is passed to the Edition contract for further handling.
EDITION_MINTER_ROLE (Restricted) =>
On an Edition, this role can:
1) Mint promotional copies of any work (promoMint
). There are no limitations on this action aside from the work's supply cap and minting period.
Other roles which don't have specific role IDs:
Editions have an Ownable owner
who can:
1) Mint promotional copies of any work (promoMint
). There are no limitations on this action aside from the work's supply cap and minting period.
2) Grant or revoke EDITION_PUBLISHER_ROLE to/from any address (grantPublisherRole
, revokePublisherRole
).
3) Manage the ERC1155 contract in typical ways (e.g. transfer ownership). Notably, the owner CANNOT manage roles other than EDITION_PUBLISHER_ROLE.
Works within an Edition have a creator
who can:
1) Update the minting period for the work (setTimeframe
). This is the only way to change the minting period for a work after publication.
2) Set the fee strategy for any work within the Edition (setFeeStrategy
). This is the only way to change the fee strategy for a work after publication. The fee strategy is validated by the Fee Manager, and the final strategy (which may have been modified during validation) is applied immediately.
3) Set the metadata for their own works. This is the only way to change the metadata for a work after publication.
4) Transfer full ownership of the work to a new address (transferWork
). This is the only way to change the creator for a work.
FeeManager has an Ownable owner
(essentially synonymous with ADMIN_ROLE
, held by TitlesCore) who can:
1) Set the protocol fees (setProtocolFees
). All fees are constrained to a constant range. This role is granted to the TitlesCore contract whose currently scoped version does not have a mechanism for leveraging this permission directly.
2) Create or change a fee route for any work within any Edition (createRoute
). This is the only way to change the fee route for a work after publication.
For permissioned functions, please list all checks and requirements that will be made before calling the function.
TitlesCore:
initialize
=> initializer, cannot be run twicepublish
=> checks that the caller has the EDITION_PUBLISHER_ROLE on the given Edition. setEditionImplementation
=> checks that the caller is the owner or has the ADMIN_ROLEFeeManager:
createRoute
=> checks that the caller is the owner or has the ADMIN_ROLEsetProtocolFees
=> checks that the caller is the owner or has the ADMIN_ROLEwithdraw
=> checks that the caller is the owner or has the ADMIN_ROLETitlesGraph:
createEdge
=> checks that the caller is the contract identified by the from
node (the node.entity.target
).createEdges
=> checks that the caller is the owner or has the ADMIN_ROLEacknowledgeEdge
(standard flow) => checks that the caller is either the creator of the contract identified by the to
node, or that contract itself.unacknowledgeEdge
(standard flow) => checks that the caller is either the creator of the contract identified by the to
node, or that contract itself.acknowledgeEdge
(signature flow) => checks that the given signature is valid for the to
node's creator (supports both ECDSA and ERC1271 signers), that the signed hash matches (based on the edge ID and data provided), and that the signature has not been previously used.unacknowledgeEdge
(signature flow) => checks that the given signature is valid for the to
node's creator (supports both ECDSA and ERC1271 signers), that the signed hash matches (based on the edge ID and data provided), and that the signature has not been previously used.Edition:
initialize
=> initializer, cannot be run twicepublish
=> checks that the caller has the EDITION_MANAGER_ROLEpromoMint
=> checks that the caller is the owner of the Edition or holds the EDITION_MANAGER_ROLE or EDITION_MINTER_ROLEsetFeeStrategy
=> checks that the caller is the creator of the work for which the strategy is being set.setMetadata
=> checks that the caller is the owner if ID is 0 (representing the Edition itself), or the creator of the specified work otherwise.setTimeframe
=> checks that the caller is the creator of the work for which the timeframe is being set.transferWork
=> checks that the caller is the creator of the work being transferred.grantRoles
/revokeRoles
=> checks that the caller has the EDITION_MANAGER_ROLEgrantPublisherRole
/revokePublisherRole
=> checks that the caller is the owner of the Edition or has the EDITION_MANAGER_ROLEIs the codebase expected to comply with any EIPs? Can there be/are there any deviations from the specification?
strict implementation of EIPs
1271 (Graph), 712 (Graph, Edition), 2981 (Edition), 1155 (Edition)
Are there any off-chain mechanisms or off-chain procedures for the protocol (keeper bots, arbitrage bots, etc.)?
N/A
Are there any hardcoded values that you intend to change before (some) deployments?
The exact amounts of the fees controlled by FeeManager may change before deployment, but only within the bounds of the current fee constants.
If the codebase is to be deployed on an L2, what should be the behavior of the protocol in case of sequencer issues (if applicable)? Should Sherlock assume that the Sequencer won't misbehave, including going offline?
Out of scope
Should potential issues, like broken assumptions about function behavior, be reported if they could pose risks in future integrations, even if they might not be an issue in the context of the scope? If yes, can you elaborate on properties/invariants that should hold?
Yes.
Please discuss any design choices you made.
Fund Management: We chose to delegate fee payouts to 0xSplits v2. The protocol aims to avoid any direct TVL in this release.
Graph: This is a new concept with a vast future design space, so we've erred on the side of a minimal implementation with low complexity. We intend to further standardize the OpenGraph model in the future.
Please list any known issues/acceptable risks that should not result in a valid finding.
N/A
We will report issues where the core protocol functionality is inaccessible for at least 7 days. Would you like to override this value?
No
Please provide links to previous audits (if any).
N/A
Please list any relevant protocol resources.
Run forge doc
or check out the /docs directory in the repo for pretty comprehensive auto-generated docs from the natspec.
Additional audit information.
In addition to the security of funds, we would also like there to be focus on the sanctity of the data in the TitlesGraph and the permissioning around it (only the appropriate people/contracts can signal reference and acknowledgement of reference).
Total Rewards
Contest Pool
Lead Senior Watson
Judging Pool
Lead Judge
16,000 USDC
7,000 USDC
700 USDC
800 USDC
Status
Scope
Start Time
End Time
Judging Rules