Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions contracts/src/AttestationRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,29 @@ contract AttestationRegistry is OwnableUpgradeable {
/**
* @notice Registers attestations to the AttestationRegistry
* @param attestationsPayloads the attestations payloads to create attestations and register them
* @param attester the account address issuing the attestations
*/
function bulkAttest(AttestationPayload[] calldata attestationsPayloads, address attester) public {
for (uint256 i = 0; i < attestationsPayloads.length; i = uncheckedInc256(i)) {
attest(attestationsPayloads[i], attester);
}
}

/**
* @notice Registers attestations to the AttestationRegistry with individual attesters for each attestation
* @param attestationsPayloads the attestations payloads to create attestations and register them
* @param attesters the account addresses issuing each attestation (must match length of attestationsPayloads)
*/
function bulkAttestWithAttesters(
AttestationPayload[] calldata attestationsPayloads,
address[] calldata attesters
) public {
if (attestationsPayloads.length != attesters.length) revert ArrayLengthMismatch();
for (uint256 i = 0; i < attestationsPayloads.length; i = uncheckedInc256(i)) {
attest(attestationsPayloads[i], attesters[i]);
}
}

function massImport(AttestationPayload[] calldata attestationsPayloads, address portal) public onlyOwner {
for (uint256 i = 0; i < attestationsPayloads.length; i = uncheckedInc256(i)) {
// Auto increment attestation counter
Expand Down Expand Up @@ -204,6 +220,25 @@ contract AttestationRegistry is OwnableUpgradeable {
}
}

/**
* @notice Replaces attestations for given identifiers and replaces them with new attestations,
* with individual attesters for each attestation
* @param attestationIds the list of IDs of the attestations to replace
* @param attestationPayloads the list of attestation payloads to create the new attestations and register them
* @param attesters the account addresses issuing each attestation (must match length of attestationPayloads)
*/
function bulkReplaceWithAttesters(
bytes32[] calldata attestationIds,
AttestationPayload[] calldata attestationPayloads,
address[] calldata attesters
) public {
if (attestationIds.length != attestationPayloads.length) revert ArrayLengthMismatch();
if (attestationPayloads.length != attesters.length) revert ArrayLengthMismatch();
for (uint256 i = 0; i < attestationIds.length; i = uncheckedInc256(i)) {
replace(attestationIds[i], attestationPayloads[i], attesters[i]);
}
}

/**
* @notice Revokes an attestation for a given identifier
* @param attestationId the ID of the attestation to revoke
Expand Down
42 changes: 42 additions & 0 deletions contracts/src/ModuleRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ contract ModuleRegistry is OwnableUpgradeable {
error ModuleNotRegistered();
/// @notice Error thrown when module addresses and validation payload length mismatch
error ModuleValidationPayloadMismatch();
/// @notice Error thrown when array lengths don't match
error ArrayLengthMismatch();
/// @notice Error thrown when the router address is the zero address
error RouterAddressInvalid();

Expand Down Expand Up @@ -207,6 +209,9 @@ contract ModuleRegistry is OwnableUpgradeable {
* @param modulesAddresses the addresses of the registered modules
* @param attestationPayloads the payloads to attest
* @param validationPayloads the payloads to check for each module
* @param initialCaller the address of the initial caller (transaction sender)
* @param attester the address defined by the Portal as the attester for all payloads
* @param operationType the type of operation being performed
* @dev NOTE: Currently the bulk run modules does not handle payable modules
* a default value of 0 is used.
* @dev DISCLAIMER: This method may have unexpected behavior if one of the checks is done on the attestation ID
Expand Down Expand Up @@ -234,6 +239,43 @@ contract ModuleRegistry is OwnableUpgradeable {
}
}

/**
* @notice Executes the V2 modules validation for all attestations payloads with individual attesters for each payload
* @param modulesAddresses the addresses of the registered modules
* @param attestationPayloads the payloads to attest
* @param validationPayloads the payloads to check for each module
* @param initialCaller the address of the initial caller (transaction sender)
* @param attesters the addresses defined by the Portal as the attester for each payload
* (must match length of attestationPayloads)
* @param operationType the type of operation being performed
* @dev NOTE: Currently the bulk run modules does not handle payable modules
* a default value of 0 is used.
* @dev DISCLAIMER: This method may have unexpected behavior if one of the checks is done on the attestation ID
* as this ID won't be incremented before the end of the transaction.
* If you need to check the attestation ID, please use the `attestV2` method.
*/
function bulkRunModulesV2WithAttesters(
address[] calldata modulesAddresses,
AttestationPayload[] calldata attestationPayloads,
bytes[][] calldata validationPayloads,
address initialCaller,
address[] calldata attesters,
OperationType operationType
) public {
if (attestationPayloads.length != attesters.length) revert ArrayLengthMismatch();
for (uint32 i = 0; i < attestationPayloads.length; i = uncheckedInc32(i)) {
runModulesV2(
modulesAddresses,
attestationPayloads[i],
validationPayloads[i],
0,
initialCaller,
attesters[i],
operationType
);
}
}

/**
* @notice Checks that a module is registered in the module registry
* @param moduleAddress The address of the Module to check
Expand Down
45 changes: 33 additions & 12 deletions contracts/src/abstracts/AbstractPortalV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AttestationPayload } from "../types/Structs.sol";
import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { IRouter } from "../interfaces/IRouter.sol";
import { IPortal } from "../interfaces/IPortal.sol";
import { uncheckedInc256 } from "../Common.sol";

/**
* @title Abstract Portal V2
Expand Down Expand Up @@ -72,19 +73,20 @@ abstract contract AbstractPortalV2 is IPortal, ERC165 {
* as the total `msg.value` is forwarded to all modules.
*/
function attest(AttestationPayload memory attestationPayload, bytes[] memory validationPayloads) public payable {
address attester = getAttester(attestationPayload, validationPayloads);
moduleRegistry.runModulesV2(
modules,
attestationPayload,
validationPayloads,
msg.value,
msg.sender,
getAttester(),
attester,
OperationType.Attest
);

_onAttest(attestationPayload, validationPayloads, msg.value);

attestationRegistry.attest(attestationPayload, getAttester());
attestationRegistry.attest(attestationPayload, attester);
}

/**
Expand All @@ -96,18 +98,24 @@ abstract contract AbstractPortalV2 is IPortal, ERC165 {
* If you need to check the attestation ID, please use the `attestV2` method.
*/
function bulkAttest(AttestationPayload[] memory attestationPayloads, bytes[][] memory validationPayloads) public {
moduleRegistry.bulkRunModulesV2(
// Get attester for each payload
address[] memory attesters = new address[](attestationPayloads.length);
for (uint256 i = 0; i < attestationPayloads.length; i = uncheckedInc256(i)) {
attesters[i] = getAttester(attestationPayloads[i], validationPayloads[i]);
}

moduleRegistry.bulkRunModulesV2WithAttesters(
modules,
attestationPayloads,
validationPayloads,
msg.sender,
getAttester(),
attesters,
OperationType.BulkAttest
);

_onBulkAttest(attestationPayloads, validationPayloads);

attestationRegistry.bulkAttest(attestationPayloads, getAttester());
attestationRegistry.bulkAttestWithAttesters(attestationPayloads, attesters);
}

/**
Expand All @@ -122,19 +130,20 @@ abstract contract AbstractPortalV2 is IPortal, ERC165 {
AttestationPayload memory attestationPayload,
bytes[] memory validationPayloads
) public payable onlyPortalOwner {
address attester = getAttester(attestationPayload, validationPayloads);
moduleRegistry.runModulesV2(
modules,
attestationPayload,
validationPayloads,
msg.value,
msg.sender,
getAttester(),
attester,
OperationType.Replace
);

_onReplace(attestationId, attestationPayload, getAttester(), msg.value);
_onReplace(attestationId, attestationPayload, attester, msg.value);

attestationRegistry.replace(attestationId, attestationPayload, getAttester());
attestationRegistry.replace(attestationId, attestationPayload, attester);
}

/**
Expand All @@ -151,18 +160,24 @@ abstract contract AbstractPortalV2 is IPortal, ERC165 {
AttestationPayload[] memory attestationsPayloads,
bytes[][] memory validationPayloads
) public onlyPortalOwner {
moduleRegistry.bulkRunModulesV2(
// Get attester for each payload
address[] memory attesters = new address[](attestationsPayloads.length);
for (uint256 i = 0; i < attestationsPayloads.length; i = uncheckedInc256(i)) {
attesters[i] = getAttester(attestationsPayloads[i], validationPayloads[i]);
}

moduleRegistry.bulkRunModulesV2WithAttesters(
modules,
attestationsPayloads,
validationPayloads,
msg.sender,
getAttester(),
attesters,
OperationType.BulkReplace
);

_onBulkReplace(attestationIds, attestationsPayloads, validationPayloads);

attestationRegistry.bulkReplace(attestationIds, attestationsPayloads, getAttester());
attestationRegistry.bulkReplaceWithAttesters(attestationIds, attestationsPayloads, attesters);
}

/**
Expand Down Expand Up @@ -209,9 +224,15 @@ abstract contract AbstractPortalV2 is IPortal, ERC165 {

/**
* @notice Defines the address of the entity issuing attestations to the subject
* @param attestationPayload the attestation payload
* @param validationPayloads the validation payloads
* @return The address of the attester
* @dev We strongly encourage a reflection when overriding this rule: who should be set as the attester?
*/
function getAttester() internal view virtual returns (address) {
function getAttester(
AttestationPayload memory attestationPayload,
bytes[] memory validationPayloads
) internal view virtual returns (address) {
return msg.sender;
}

Expand Down
15 changes: 15 additions & 0 deletions contracts/test/mocks/AttestationRegistryMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ contract AttestationRegistryMock {
emit BulkAttestationsRegistered();
}

function bulkAttestWithAttesters(
AttestationPayload[] calldata /*attestationsPayloads*/,
address[] calldata /*attesters*/
) public {
emit BulkAttestationsRegistered();
}

function replace(
bytes32 /*attestationId*/,
AttestationPayload calldata /*attestationPayload*/,
Expand All @@ -60,6 +67,14 @@ contract AttestationRegistryMock {
emit BulkAttestationsReplaced();
}

function bulkReplaceWithAttesters(
bytes32[] calldata /*attestationId*/,
AttestationPayload[] calldata /*attestationPayload*/,
address[] calldata /*attesters*/
) public {
emit BulkAttestationsReplaced();
}

function revoke(bytes32 attestationId) public {
emit AttestationRevoked(attestationId);
}
Expand Down
11 changes: 11 additions & 0 deletions contracts/test/mocks/ModuleRegistryMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,15 @@ contract ModuleRegistryMock {
) public {
emit ModulesBulkRunForAttestationV2();
}

function bulkRunModulesV2WithAttesters(
address[] memory /*modulesAddresses*/,
AttestationPayload[] memory /*attestationPayloads*/,
bytes[][] memory /*validationPayloads*/,
address /*initialCaller*/,
address[] memory /*attesters*/,
OperationType /*operationType*/
) public {
emit ModulesBulkRunForAttestationV2();
}
}