diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml new file mode 100644 index 00000000..cda2e14a --- /dev/null +++ b/.github/workflows/gh-pages.yml @@ -0,0 +1,30 @@ +name: github pages + +on: + push: + branches: + - main + pull_request: + +jobs: + deploy: + runs-on: ubuntu-20.04 + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + steps: + - uses: actions/checkout@v2 + + - name: Setup mdBook + uses: peaceiris/actions-mdbook@v1 + with: + mdbook-version: "0.4.10" + # mdbook-version: 'latest' + + - run: cd docs; mdbook build + + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + if: ${{ github.ref == 'refs/heads/main' }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/book diff --git a/.gitignore b/.gitignore index cd56cb3b..259c9313 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ cache/ out/ .DS_Store +docs/ # Ignores development broadcast logs /broadcast diff --git a/foundry.toml b/foundry.toml index 32072b05..31df114b 100644 --- a/foundry.toml +++ b/foundry.toml @@ -13,6 +13,7 @@ number_underscore="thousands" [doc] title = "Rhinestone Registry" +ignore = ["src/DataTypes.sol", "src/Common.sol", "src/external"] [invariant] # fail_on_revert = true diff --git a/package.json b/package.json index f03faec7..1227cd90 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "prepack": "pnpm install", "test": "forge test", "test:lite": "FOUNDRY_PROFILE=lite forge test", - "test:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge test" + "test:optimized": "pnpm run build:optimized && FOUNDRY_PROFILE=test-optimized forge test", + "build:docs": "forge doc && cd ./docs && rm -rf ./src/src/DataTypes.sol; mdbook build && cd .." } } diff --git a/src/DataTypes.sol b/src/DataTypes.sol index d5e95e07..4813f234 100644 --- a/src/DataTypes.sol +++ b/src/DataTypes.sol @@ -8,7 +8,6 @@ import { IExternalResolver } from "./external/IExternalResolver.sol"; /* Storage Structs */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ -// Struct that represents an attestation. struct AttestationRecord { uint48 time; // The time when the attestation was created (Unix timestamp). uint48 expirationTime; // The time when the attestation expires (Unix timestamp). @@ -20,7 +19,6 @@ struct AttestationRecord { SchemaUID schemaUID; // The unique identifier of the schema. } -// Struct that represents Module artefact. struct ModuleRecord { ResolverUID resolverUID; // The unique identifier of the resolver. address sender; // The address of the sender who deployed the contract diff --git a/src/IRegistry.sol b/src/IRegistry.sol index fcda55ed..c53162b9 100644 --- a/src/IRegistry.sol +++ b/src/IRegistry.sol @@ -42,6 +42,17 @@ interface IERC7484 { function checkN(address module, ModuleType moduleType, address[] calldata attesters, uint256 threshold) external view; } +/** + * Interface definition of all features of the registry: + * - Register Schemas + * - Register External Resolvers + * - Register Modules + * - Make Attestations + * - Make Revocations + * - Delegate Trust to Attester(s) + * + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) + */ interface IRegistry is IERC7484 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* Smart Account - Trust Management */ @@ -60,9 +71,9 @@ interface IRegistry is IERC7484 { error InsufficientAttestations(); /** - * Allows smartaccounts - the end users of the registry - to appoint + * Allows Smart Accounts - the end users of the registry - to appoint * one or many attesters as trusted. - * @notice this function reverts, if address(0), or duplicates are provided in attesters[] + * @dev this function reverts, if address(0), or duplicates are provided in attesters[] * * @param threshold The minimum number of attestations required for a module * to be considered secure. @@ -71,8 +82,8 @@ interface IRegistry is IERC7484 { function trustAttesters(uint8 threshold, address[] calldata attesters) external; /** - * Get trusted attester for a specific smartAccount - * @param smartAccount The address of the smartAccount + * Get trusted attester for a specific Smart Account + * @param smartAccount The address of the Smart Account */ function findTrustedAttesters(address smartAccount) external view returns (address[] memory attesters); @@ -93,8 +104,8 @@ interface IRegistry is IERC7484 { error InvalidModuleTypes(); /** - * Allows msg.sender to attest to multiple modules' security status. - * The AttestationRequest.Data provided should match the attestation + * Allows `msg.sender` to attest to multiple modules' security status. + * The `AttestationRequest.Data` provided should match the attestation * schema defined by the Schema corresponding to the SchemaUID * * @dev This function will revert if the same module is attested twice by the same attester. @@ -106,8 +117,8 @@ interface IRegistry is IERC7484 { function attest(SchemaUID schemaUID, AttestationRequest calldata request) external; /** - * Allows msg.sender to attest to multiple modules' security status. - * The AttestationRequest.Data provided should match the attestation + * Allows `msg.sender` to attest to multiple modules' security status. + * The `AttestationRequest.Data` provided should match the attestation * schema defined by the Schema corresponding to the SchemaUID * * @dev This function will revert if the same module is attested twice by the same attester. @@ -119,8 +130,8 @@ interface IRegistry is IERC7484 { function attest(SchemaUID schemaUID, AttestationRequest[] calldata requests) external; /** - * Allows attester to attest by signing an AttestationRequest (ECDSA or ERC1271) - * The AttestationRequest.Data provided should match the attestation + * Allows attester to attest by signing an `AttestationRequest` (`ECDSA` or `ERC1271`) + * The `AttestationRequest.Data` provided should match the attestation * schema defined by the Schema corresponding to the SchemaUID * * @dev This function will revert if the same module is attested twice by the same attester. @@ -134,8 +145,8 @@ interface IRegistry is IERC7484 { function attest(SchemaUID schemaUID, address attester, AttestationRequest calldata request, bytes calldata signature) external; /** - * Allows attester to attest by signing an AttestationRequest (ECDSA or ERC1271) - * The AttestationRequest.Data provided should match the attestation + * Allows attester to attest by signing an `AttestationRequest` (`ECDSA` or `ERC1271`) + * The `AttestationRequest.Data` provided should match the attestation * schema defined by the Schema corresponding to the SchemaUID * * @dev This function will revert if the same module is attested twice by the same attester. @@ -169,17 +180,17 @@ interface IRegistry is IERC7484 { /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** - * Allows msg.sender to revoke an attstation made by the same msg.sender + * Allows `msg.sender` to revoke an attestation made by the same `msg.sender` * * @dev this function will revert if the attestation is not found * @dev this function will revert if the attestation is already revoked * - * @param request the RevocationRequest + * @param request single RevocationRequest */ function revoke(RevocationRequest calldata request) external; /** - * Allows msg.sender to revoke multiple attstations made by the same msg.sender + * Allows msg.sender to revoke multiple attestation made by the same msg.sender * * @dev this function will revert if the attestation is not found * @dev this function will revert if the attestation is already revoked @@ -189,16 +200,16 @@ interface IRegistry is IERC7484 { function revoke(RevocationRequest[] calldata requests) external; /** - * Allows attester to revoke an attestation by signing an RevocationRequest (ECDSA or ERC1271) + * Allows attester to revoke an attestation by signing an `RevocationRequest` (`ECDSA` or `ERC1271`) * * @param attester the signer / revoker - * @param request the RevocationRequest + * @param request single RevocationRequest * @param signature ECDSA or ERC1271 signature */ function revoke(address attester, RevocationRequest calldata request, bytes calldata signature) external; /** - * Allows attester to revoke an attestation by signing an RevocationRequest (ECDSA or ERC1271) + * Allows attester to revoke an attestation by signing an `RevocationRequest` (`ECDSA` or `ERC1271`) * @dev if you want to revoke multiple attestations, but from different attesters, call this function multiple times * * @param attester the signer / revoker @@ -219,12 +230,12 @@ interface IRegistry is IERC7484 { error FactoryCallFailed(address factory); /** - * This registry implements a CREATE2 factory, that allows module developers to register and deploy module bytecode - * @param salt The salt to be used in the CREATE2 factory. This adheres to Pr000xy/Create2Factory.sol salt formatting. + * This registry implements a `CREATE2` factory, that allows module developers to register and deploy module bytecode + * @param salt The salt to be used in the `CREATE2` factory. This adheres to Pr000xy/Create2Factory.sol salt formatting. * The salt's first bytes20 should be the address of the sender * or bytes20(0) to bypass the check (this will lose replay protection) - * @param resolverUID The resolverUID to be used in the CREATE2 factory - * @param initCode The initCode to be used in the CREATE2 factory + * @param resolverUID The resolverUID to be used in the `CREATE2` factory + * @param initCode The initCode to be used in the `CREATE2` factory * @param metadata The metadata to be stored on the registry. * This field is optional, and might be used by the module developer to store additional * information about the module or facilitate business logic with the Resolver stub @@ -297,14 +308,14 @@ interface IRegistry is IERC7484 { error InvalidSchemaValidator(IExternalSchemaValidator validator); /** - * Register Schema and (optional) external IExternalSchemaValidator - * Schemas describe the structure of the data of attestations + * Register Schema and (optional) external `IExternalSchemaValidator` + * A Schema describe the structure of the data of attestations * every attestation made on this registry, will reference a SchemaUID to * make it possible to decode attestation data in human readable form * overrwriting a schema is not allowed, and will revert * @param schema ABI schema used to encode attestations that are made with this schema * @param validator (optional) external schema validator that will be used to validate attestations. - * use address(0), if you dont need an external validator + * use address(0), if you don't need an external validator * @return uid SchemaUID of the registered schema */ function registerSchema( @@ -315,7 +326,7 @@ interface IRegistry is IERC7484 { returns (SchemaUID uid); /** - * getter function to retrieve SchemaRecord + * Getter function to retrieve SchemaRecord */ function findSchema(SchemaUID uid) external view returns (SchemaRecord memory record); @@ -336,7 +347,7 @@ interface IRegistry is IERC7484 { function registerResolver(IExternalResolver resolver) external returns (ResolverUID uid); /** - * Entities that previously regsitered an external resolver, may update the implementation address. + * Entities that previously registered an external resolver, may update the implementation address. * @param uid The UID of the resolver. * @param resolver The new resolver implementation address. */ @@ -350,7 +361,7 @@ interface IRegistry is IERC7484 { function transferResolverOwnership(ResolverUID uid, address newOwner) external; /** - * Getter function to get the ResolverRecord of a registerd resolver + * Getter function to get the ResolverRecord of a registered resolver * @param uid The UID of the resolver. */ function findResolver(ResolverUID uid) external view returns (ResolverRecord memory record); diff --git a/src/Registry.sol b/src/Registry.sol index 59d1dae8..ba970301 100644 --- a/src/Registry.sol +++ b/src/Registry.sol @@ -3,8 +3,15 @@ pragma solidity ^0.8.24; import { SignedAttestation } from "./core/SignedAttestation.sol"; import { IRegistry } from "./IRegistry.sol"; + /** - * @author zeroknots + * Implementation of all features of the registry: + * - Register Schemas + * - Register External Resolvers + * - Register Modules + * - Make Attestations + * - Make Revocations + * - Delegate Trust to Attester(s) + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) */ - contract Registry is IRegistry, SignedAttestation { } diff --git a/src/core/Attestation.sol b/src/core/Attestation.sol index 034aedfb..a92fa08e 100644 --- a/src/core/Attestation.sol +++ b/src/core/Attestation.sol @@ -5,6 +5,11 @@ import { AttestationRecord, AttestationRequest, RevocationRequest, SchemaUID } f import { AttestationManager } from "./AttestationManager.sol"; import { IRegistry } from "../IRegistry.sol"; +/** + * Abstract contract that implements the `IRegistry` interface + * Allows `msg.sender` to make attestations / revocations directly + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) + */ abstract contract Attestation is IRegistry, AttestationManager { /** * @inheritdoc IRegistry diff --git a/src/core/AttestationManager.sol b/src/core/AttestationManager.sol index f1ae86e9..bce64499 100644 --- a/src/core/AttestationManager.sol +++ b/src/core/AttestationManager.sol @@ -22,7 +22,9 @@ import { EMPTY_ATTESTATION_REF, EMPTY_RESOLVER_UID, _time, ZERO_TIMESTAMP } from /** * AttestationManager handles the registry's internal storage of new attestations and revocation of attestation - * @dev This contract is abstract and provides utility functions to store attestations and revocations. + * @dev This contract is abstract and provides internal utility functions to store attestations and revocations. + * + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) */ abstract contract AttestationManager is IRegistry, ModuleManager, SchemaManager, TrustManagerExternalAttesterList { using StubLib for *; @@ -42,12 +44,12 @@ abstract contract AttestationManager is IRegistry, ModuleManager, SchemaManager, * Processes an attestation request and stores the attestation in the registry. * If the attestation was made for a module that was not registered, the function will revert. * function will get the external Schema Validator for the supplied SchemaUID - * and call it, if an external IExternalSchemaValidator was set - * function will get the external IExternalResolver for the module - that the attestation is for + * and call it, if an external `IExternalSchemaValidator` was set + * function will get the external `IExternalResolver` for the module - that the attestation is for * and call it, if an external Resolver was set * @param attester The address of the attesting account. * @param schemaUID the UID of the schema that the attestation is made for - * @param request AttestationRequest send by attester via calldata + * @param request AttestationRequest send by attester via `calldata` */ function _attest(address attester, SchemaUID schemaUID, AttestationRequest calldata request) internal { (AttestationRecord memory record, ResolverUID resolverUID) = @@ -88,11 +90,11 @@ abstract contract AttestationManager is IRegistry, ModuleManager, SchemaManager, /** * Stores an attestation in the registry storage. - * The bytes encoded AttestationRequest.Data is not stored directly into the registry storage, - * but rather stored with SSTORE2. SSTORE2/SLOAD2 is writing and reading contract storage + * The bytes encoded `AttestationRequest.Data` is not stored directly into the registry storage, + * but rather stored with `SSTORE2`. `SSTORE2/SLOAD2` is writing and reading contract storage * paying a fraction of the cost, it uses contract code as storage, writing data takes the - * form of contract creations and reading data uses EXTCODECOPY. - * since attestation data is supposed to be immutable, it is a good candidate for SSTORE2 + * form of contract creations and reading data uses `EXTCODECOPY`. + * since attestation data is supposed to be immutable, it is a good candidate for `SSTORE2` * * @dev This function will revert if the same module is attested twice by the same attester. * If you want to re-attest, you have to revoke your attestation first, and then attest again. @@ -128,7 +130,7 @@ abstract contract AttestationManager is IRegistry, ModuleManager, SchemaManager, } // use SSTORE2 to store the data in attestationRequest - // @dev this will revert, if in a batched attestation, + // this will revert, if in a batched attestation, // the same data is used twice by the same attester for the same module since the salt will be the same AttestationDataRef sstore2Pointer = request.sstore2({ salt: attester.sstore2Salt(module) }); @@ -155,8 +157,8 @@ abstract contract AttestationManager is IRegistry, ModuleManager, SchemaManager, /** * Revoke a single Revocation Request - * This function will write the RevocationRequest into storage, and get the stored RevocationRecord back, - * and pass the RevocationRecord to the resolver to check if the revocation is valid + * This function will write the `RevocationRequest` into storage, and get the stored `RevocationRecord` back, + * and pass the `RevocationRecord` to the resolver to check if the revocation is valid */ function _revoke(address attester, RevocationRequest calldata request) internal { (AttestationRecord memory record, ResolverUID resolverUID) = _storeRevocation(attester, request); @@ -165,8 +167,8 @@ abstract contract AttestationManager is IRegistry, ModuleManager, SchemaManager, /** * Revoke an array Revocation Request - * This function will write the RevocationRequest into storage, and get the stored RevocationRecord back, - * and pass the RevocationRecord to the resolver to check if the revocation is valid + * This function will write the `RevocationRequest` into storage, and get the stored `RevocationRecord` back, + * and pass the `RevocationRecord` to the resolver to check if the revocation is valid */ function _revoke(address attester, RevocationRequest[] calldata requests) internal { uint256 length = requests.length; @@ -182,7 +184,7 @@ abstract contract AttestationManager is IRegistry, ModuleManager, SchemaManager, else if (resolverUID_cache != resolverUID) revert DifferentResolvers(); } - // No schema validation required during revocation. the attestation data was already checked against + // No schema validation required during revocation. The attestation data was already checked against records.tryExternalResolverOnRevocation({ $resolver: $resolvers[resolverUID] }); } @@ -228,8 +230,8 @@ abstract contract AttestationManager is IRegistry, ModuleManager, SchemaManager, } /** - * Returns the attestation records for the given module and attesters. - * This function is expected to be used by TrustManager and TrustManagerExternalAttesterList + * Returns a storage reference to attestation records for the given module and attesters. + * This function is expected to be used by `TrustManager` and `TrustManagerExternalAttesterList` */ function $getAttestation(address module, address attester) internal view override returns (AttestationRecord storage $attestation) { $attestation = $moduleToAttesterToAttestations[module][attester]; diff --git a/src/core/ModuleManager.sol b/src/core/ModuleManager.sol index 4da58042..dfa69b99 100644 --- a/src/core/ModuleManager.sol +++ b/src/core/ModuleManager.sol @@ -10,21 +10,16 @@ import { ResolverManager } from "./ResolverManager.sol"; import { IRegistry } from "../IRegistry.sol"; /** - * @title Module - * - * @dev The Module contract is responsible for handling the registration, + * The ModuleManager contract is responsible for handling module the registration, * storage and retrieval of modules on the Registry. - * This contract inherits from the IModule interface - * - * @dev The primary responsibility of the Module is to deploy and manage modules. A module is a smart contract - * that has been deployed through the Module. The details of each module, such as its address, code hash, schema ID, + * This contract inherits from the `IModule` interface + * The primary responsibility of the Module is to deploy and manage modules. A module is a smart contract + * that has been deployed through the Module. The details of each module, such as its address, resolver UID * sender address, deploy parameters hash, and additional metadata are stored in * a struct and mapped to the module's address in * the `_modules` mapping for easy access and management. - * - * @dev In conclusion, the Module is a central part of a system to manage, - * deploy, and interact with a set of smart contracts - * in a structured and controlled manner. + * @dev The module developer select the resolver to be used for attestations and revocations made of the module. + * @dev Important: only module registrations made through the `deployModule()` function are frontrun protected. * * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) */ @@ -122,6 +117,17 @@ abstract contract ModuleManager is IRegistry, ResolverManager { record.requireExternalResolverOnModuleRegistration({ moduleAddress: moduleAddress, $resolver: $resolver }); } + /** + * Turns module registration artifacts to `ModuleRecord` to stores it in the registry storage + * @dev if a non-existent resolverUID is provided, this function reverts. + * @dev if moduleAddress is already registered, this function reverts. + * @dev if moduleAddress is not a contract, this function reverts. + * @param moduleAddress the address of the module to register + * @param sender the address of the sender who deployed the module + * @param resolverUID the unique identifier of the resolver + * @param metadata additional data related to the contract deployment. + * This parameter is optional and may be used to facilitate custom business logic on the external resolver + */ function _storeModuleRecord( address moduleAddress, address sender, diff --git a/src/core/ResolverManager.sol b/src/core/ResolverManager.sol index f4e4f065..2b380f34 100644 --- a/src/core/ResolverManager.sol +++ b/src/core/ResolverManager.sol @@ -7,6 +7,17 @@ import { IExternalResolver } from "../external/IExternalResolver.sol"; import { UIDLib } from "../lib/Helpers.sol"; import { IRegistry } from "../IRegistry.sol"; +/** + * The ResolverManager allows entities that operate modular marketplaces to register and + * manager custom `IExternalResolver` implementations. + * This feature may be used to extend the registry's security guarantees with custom business logic + * for example: + * - KYC of module devs / attesters + * - tokenomics of module devs / attestation + * @dev only `msg.sender` and the external `IExternalResolver` address are used to create a unique ID for the resolver + * This allows for a single resolver address to be possible across different chains + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) + */ abstract contract ResolverManager is IRegistry { using UIDLib for ResolverRecord; @@ -25,7 +36,7 @@ abstract contract ResolverManager is IRegistry { } /** - * If a resolver is not address(0), we check if it supports the IExternalResolver interface + * If a resolver is not address(0), we check if it supports the `IExternalResolver` interface */ modifier onlyResolver(IExternalResolver resolver) { if (address(resolver) == address(0) || !resolver.supportsInterface(type(IExternalResolver).interfaceId)) { diff --git a/src/core/SchemaManager.sol b/src/core/SchemaManager.sol index 6bafe409..5f1c771a 100644 --- a/src/core/SchemaManager.sol +++ b/src/core/SchemaManager.sol @@ -9,7 +9,6 @@ import { ZERO_TIMESTAMP, _time } from "../Common.sol"; import { IRegistry } from "../IRegistry.sol"; /** - * @title SchemaManager * Allows the creation registration and creation of schemas. * Schemas are used to describe attestation data. It is recommended to use ABI encoded data as schema. * An external schema validator contract may be provided, diff --git a/src/core/SignedAttestation.sol b/src/core/SignedAttestation.sol index 27b3f7cb..344b83df 100644 --- a/src/core/SignedAttestation.sol +++ b/src/core/SignedAttestation.sol @@ -8,6 +8,11 @@ import { EIP712 } from "solady/utils/EIP712.sol"; import { SignatureCheckerLib } from "solady/utils/SignatureCheckerLib.sol"; import { IRegistry } from "../IRegistry.sol"; +/** + * Implements similar functionality to Attestation.sol, but with the added feature of requiring a signature from the attester. + * Signatures may be provided as `ECDSA` or `ERC-1271` + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) + */ contract SignedAttestation is IRegistry, Attestation, EIP712 { using AttestationLib for AttestationRequest; using AttestationLib for RevocationRequest; diff --git a/src/core/TrustManager.sol b/src/core/TrustManager.sol index 07ed2d16..d357bf1c 100644 --- a/src/core/TrustManager.sol +++ b/src/core/TrustManager.sol @@ -10,14 +10,13 @@ import { TrustLib } from "../lib/TrustLib.sol"; import { LibSort } from "solady/utils/LibSort.sol"; /** - * @title TrustManager * Allows smart accounts to query the registry for the security status of modules. * Smart accounts may trust a list of attesters to attest to the security status of * modules and configure a minimum threshold of how many attestations have to be in place * to consider a module as "trust worthy" - * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) - * Implements EIP-7484 to query attestations stored in the registry. + * Implements `ERC-7484` to query attestations stored in the registry. * @dev This contract is abstract and provides utility functions to query attestations. + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) */ abstract contract TrustManager is IRegistry { using ModuleTypeLib for PackedModuleTypes; @@ -92,7 +91,7 @@ abstract contract TrustManager is IRegistry { } /** - * Internal helper function to check for module's security attestations on behalf of a SmartAccount + * Internal helper function to check for module's security attestations on behalf of a Smart Account * will use registy's storage to get the trusted attester(s) of a smart account, and check if the module was attested * @param smartAccount the smart account to check for * @param module address of the module to check diff --git a/src/core/TrustManagerExternalAttesterList.sol b/src/core/TrustManagerExternalAttesterList.sol index ea78c60c..caf7aca7 100644 --- a/src/core/TrustManagerExternalAttesterList.sol +++ b/src/core/TrustManagerExternalAttesterList.sol @@ -11,6 +11,8 @@ import { TrustLib } from "../lib/TrustLib.sol"; /** * If smart accounts want to query the registry, and supply a list of trusted attesters in calldata, this component can be used * @dev This contract is abstract and provides utility functions to query attestations with a calldata provided list of attesters + * + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) */ abstract contract TrustManagerExternalAttesterList is IRegistry, TrustManager { using TrustLib for AttestationRecord; diff --git a/src/lib/StubLib.sol b/src/lib/StubLib.sol index a79a6db7..16bd503a 100644 --- a/src/lib/StubLib.sol +++ b/src/lib/StubLib.sol @@ -8,14 +8,17 @@ import { ZERO_ADDRESS, ZERO_TIMESTAMP } from "../Common.sol"; import { IRegistry } from "../IRegistry.sol"; /** - * @title StubLib - * @dev A library that interacts with IExternalResolver and IExternalSchemaValidator + * Helper library for interacting with `IExternalResolver` and `IExternalSchemaValidator` + * @dev if a certain resolver or validator is not set, the function will return without reverting */ library StubLib { event ResolverRevocationError(IExternalResolver resolver); /** - * @notice if Schema Validator is set, it will call validateSchema() on the validator + * Calls an external schema validator contract to validate the schema for a single attestation + * @dev if Schema Validator is set, it will call `validateSchema()` on the `IExternalSchemaValidator` contract + * @param attestationRecord the data record that will be written into registry for this attestation + * @param $schema the storage reference of the schema record */ function requireExternalSchemaValidation(AttestationRecord memory attestationRecord, SchemaRecord storage $schema) internal { // only run this function if the selected schemaUID exists @@ -28,6 +31,12 @@ library StubLib { } } + /** + * Calls an external schema validator contract to validate the schema for multiple attestation + * @dev if Schema Validator is set, it will call `validateSchema()` on the `IExternalSchemaValidator` contract + * @param attestationRecords the data records that will be written into registry for the attestations + * @param $schema the storage reference of the schema record + */ function requireExternalSchemaValidation(AttestationRecord[] memory attestationRecords, SchemaRecord storage $schema) internal { // only run this function if the selected schemaUID exists if ($schema.registeredAt == ZERO_TIMESTAMP) revert IRegistry.InvalidSchema(); @@ -39,6 +48,12 @@ library StubLib { } } + /** + * Calls an external resolver contract to resolve a single attestation + * @dev if a resolver is set, it will call `resolveAttestation()` on the `IExternalResolver` contract + * @param attestationRecord the data record that will be written into registry for the attestation + * @param $resolver the storage reference of the resolver record used for this attestation + */ function requireExternalResolverOnAttestation(AttestationRecord memory attestationRecord, ResolverRecord storage $resolver) internal { IExternalResolver resolverContract = $resolver.resolver; @@ -48,6 +63,12 @@ library StubLib { } } + /** + * Calls an external resolver contract to resolve multiple attestations + * @dev if a resolver is set, it will call `resolveAttestation()` on the `IExternalResolver` contract + * @param attestationRecords the data records that will be written into registry for the attestation + * @param $resolver the storage reference of the resolver record used for this attestation + */ function requireExternalResolverOnAttestation( AttestationRecord[] memory attestationRecords, ResolverRecord storage $resolver @@ -63,6 +84,14 @@ library StubLib { } } + /** + * Calls an external resolver contract to resolve a single revocation + * @dev if a resolver is set, it will call `resolveRevocation()` on the `IExternalResolver` contract + * @dev if the resolver contract reverts, the function will return without reverting. + * This prevents Resolvers to stop DoS revocations + * @param attestationRecord the data records of the attestation that will be revoked + * @param $resolver the storage reference of the resolver record used for this attestation + */ function tryExternalResolverOnRevocation( AttestationRecord memory attestationRecord, ResolverRecord storage $resolver @@ -81,6 +110,14 @@ library StubLib { } } + /** + * Calls an external resolver contract to resolve multiple revocation + * @dev if a resolver is set, it will call `resolveRevocation()` on the `IExternalResolver` contract + * @dev if the resolver contract reverts, the function will return without reverting. + * This prevents Resolvers to stop DoS revocations + * @param attestationRecords the data records of the attestations that will be revoked + * @param $resolver the storage reference of the resolver record used for this attestation + */ function tryExternalResolverOnRevocation( AttestationRecord[] memory attestationRecords, ResolverRecord storage $resolver @@ -99,6 +136,14 @@ library StubLib { } } + /** + * Calls an external resolver contract to resolve a module registration + * @dev if a resolver is set, it will call `resolveModuleRegistration()` on the `IExternalResolver` contract + * @param moduleRecord the module record that will be written into registry for the module registration + * @param moduleAddress the address of the module to register. + * at the point of this call, the module MUST be already deployed (could be within the current transaction) + * @param $resolver the storage reference of the resolver record used for this module registration + */ function requireExternalResolverOnModuleRegistration( ModuleRecord memory moduleRecord, address moduleAddress, diff --git a/src/lib/TrustLib.sol b/src/lib/TrustLib.sol index d629aea1..aed6fba7 100644 --- a/src/lib/TrustLib.sol +++ b/src/lib/TrustLib.sol @@ -6,8 +6,13 @@ import { ZERO_TIMESTAMP, ZERO_MODULE_TYPE } from "../Common.sol"; import { IRegistry } from "../IRegistry.sol"; import { ModuleTypeLib } from "../lib/ModuleTypeLib.sol"; +/** + * Library implements checks to validat if a storage reference for an `AttestationRecord` is currently valid + * @author rhinestone | zeroknots.eth, Konrad Kopp (@kopy-kat) + */ library TrustLib { using ModuleTypeLib for PackedModuleTypes; + /** * Check that attestationRecord is valid: * - not revoked @@ -17,7 +22,6 @@ library TrustLib { * @param expectedType the expected module type. if this is ZERO_MODULE_TYPE, types specified in the attestation are ignored * @param $attestation the storage reference of the attestation record to check */ - function enforceValid(AttestationRecord storage $attestation, ModuleType expectedType) internal view { uint256 attestedAt; uint256 expirationTime; @@ -66,6 +70,15 @@ library TrustLib { } } + /** + * Check that attestationRecord is valid: + * - not revoked + * - not expired + * - correct module type (if not ZERO_MODULE_TYPE) + * @dev this function DOES NOT revert if the attestationRecord is not valid, but returns false + * @param expectedType the expected module type. if this is ZERO_MODULE_TYPE, types specified in the attestation are ignored + * @param $attestation the storage reference of the attestation record to check + */ function checkValid(AttestationRecord storage $attestation, ModuleType expectedType) internal view returns (bool) { uint256 attestedAt; uint256 expirationTime;