Modules
Modules are reusable validation contracts that portals can execute before an attestation is written onchain.
They are the main way to keep issuance logic modular instead of hard-coding every rule into every portal.
Contract interface
Modules inherit AbstractModuleV2 and implement:
function run(
AttestationPayload calldata attestationPayload,
bytes calldata validationPayload,
address initialCaller,
uint256 value,
address attester,
address portal,
OperationType operationType
) public virtual;
Key inputs:
attestationPayload: the payload being issued or replaced;validationPayload: module-specific proof or extra data;initialCaller: original transaction sender;value:msg.valueforwarded by the portal;attester: account the portal records as attester;portal: issuing portal address;operationType:Attest,BulkAttest,Replace, orBulkReplace.
The module should revert when validation fails.
Registration model
Modules must be registered in ModuleRegistry before portals can run them. ModuleRegistry.runModulesV2(...) reverts
with ModuleNotRegistered for an unregistered module.
Registration stores:
- the module contract address;
- a human-readable name;
- a description string.
Because AbstractModuleV2 already inherits ERC165 and exposes supportsInterface, most custom modules do not need
extra ERC165 boilerplate beyond inheriting the abstract base.
Important caveat about msg.value
Every module in a portal chain receives the same forwarded value during attest and replace.
If more than one module tries to account for the same msg.value, your workflow can become inconsistent. In practice:
- only one module in a module chain should interpret
msg.value; - bulk module execution currently uses
0as value inModuleRegistry.bulkRunModulesV2(...).
That second point matters if you rely on payable logic for bulk attest or bulk replace.
If you use fee-like or payable validation logic, treat msg.value as a shared resource. More than one module trying to
account for it can make the workflow inconsistent.
Standard-library modules
The repository includes reusable modules such as:
ECDSAModuleV2ERC1271ModuleV2FeeModuleV2SchemaModuleV2SenderModuleV2IssuersModuleV2IndexerModuleV2
When to write a custom module
Use a custom module when you need logic like:
- signature verification with custom replay protection;
- external state checks;
- merkle proof verification;
- issuer-specific authorization rules;
- integration with another contract system.