-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Introduce Modules V2 with more flexibility
- Loading branch information
Showing
25 changed files
with
2,050 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,4 @@ | |
|
||
pnpm run prettier:write | ||
pnpm -r run lint | ||
pnpm -r run test | ||
pnpm --filter "{contracts}" run test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.21; | ||
|
||
import { AttestationPayload } from "../types/Structs.sol"; | ||
import { IERC165 } from "openzeppelin-contracts/contracts/utils/introspection/IERC165.sol"; | ||
|
||
/** | ||
* @title Abstract Module V2 | ||
* @author Consensys | ||
* @notice Defines the minimal Module V2 interface | ||
*/ | ||
abstract contract AbstractModuleV2 is IERC165 { | ||
/// @notice Error thrown when someone else than the portal's owner is trying to revoke | ||
error OnlyPortalOwner(); | ||
|
||
/** | ||
* @notice Executes the module's custom logic | ||
* @param attestationPayload The incoming attestation data | ||
* @param validationPayload Additional data required for verification | ||
* @param initialCaller The address of the initial caller (transaction sender) | ||
* @param value The value (ETH) optionally passed in the attesting transaction | ||
* @param attester The address defined by the Portal as the attester for this payload | ||
* @param portal The issuing Portal's address | ||
*/ | ||
function run( | ||
AttestationPayload memory attestationPayload, | ||
bytes memory validationPayload, | ||
address initialCaller, | ||
uint256 value, | ||
address attester, | ||
address portal | ||
) public virtual; | ||
|
||
/** | ||
* @notice Checks if the contract implements the Module interface. | ||
* @param interfaceID The ID of the interface to check. | ||
* @return A boolean indicating interface support. | ||
*/ | ||
function supportsInterface(bytes4 interfaceID) public pure virtual override returns (bool) { | ||
return interfaceID == type(AbstractModuleV2).interfaceId || interfaceID == type(IERC165).interfaceId; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.21; | ||
|
||
import { AbstractModuleV2 } from "../../abstracts/AbstractModuleV2.sol"; | ||
import { AttestationPayload } from "../../types/Structs.sol"; | ||
|
||
/** | ||
* @notice Definition of EIP-712 domain | ||
*/ | ||
struct EIP712Domain { | ||
string name; | ||
string version; | ||
uint256 chainId; | ||
address verifyingContract; | ||
} | ||
|
||
contract ERC712ModuleV2 is AbstractModuleV2 { | ||
EIP712Domain public domain; | ||
address public sender; | ||
address public receiver; | ||
|
||
error InvalidSignature(); | ||
|
||
constructor(EIP712Domain memory _domain, address _sender, address _receiver) { | ||
domain = _domain; | ||
sender = _sender; | ||
receiver = _receiver; | ||
} | ||
|
||
/** | ||
* @inheritdoc AbstractModuleV2 | ||
* @notice This method is used to run the module's validation logic | ||
* @param validationPayload - Payload containing the serialized hash. The last one is the 'Root'. | ||
* @param initialCaller - The initial transaction sender | ||
*/ | ||
function run( | ||
AttestationPayload memory /*attestationPayload*/, | ||
bytes memory validationPayload, | ||
address initialCaller, | ||
uint256 /*value*/, | ||
address /*attester*/, | ||
address /*portal*/ | ||
) public view override { | ||
(uint8 v, bytes32 r, bytes32 s) = abi.decode(validationPayload, (uint8, bytes32, bytes32)); | ||
|
||
bytes32 DOMAIN_TYPE_HASH = keccak256( | ||
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" | ||
); | ||
bytes32 domainHash = keccak256( | ||
abi.encode( | ||
DOMAIN_TYPE_HASH, | ||
keccak256(bytes(domain.name)), | ||
keccak256(bytes(domain.version)), | ||
domain.chainId, | ||
domain.verifyingContract | ||
) | ||
); | ||
bytes32 TXN_TYPE_HASH = keccak256("Transaction(address from,address to,uint256 value)"); | ||
bytes32 structHash = keccak256(abi.encode(TXN_TYPE_HASH, sender, receiver, uint256(1234))); | ||
bytes32 hash = keccak256(abi.encodePacked("\x19\x01", domainHash, structHash)); | ||
|
||
address signer = ecrecover(hash, v, r, s); | ||
if (signer != initialCaller) { | ||
revert InvalidSignature(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.21; | ||
|
||
import { AbstractModuleV2 } from "../../abstracts/AbstractModuleV2.sol"; | ||
import { AttestationPayload } from "../../types/Structs.sol"; | ||
import { uncheckedInc256 } from "../../Common.sol"; | ||
|
||
contract MerkleProofModuleV2 is AbstractModuleV2 { | ||
error MerkelProofVerifyFailed(); | ||
|
||
/** | ||
* @inheritdoc AbstractModuleV2 | ||
* @notice This method is used to run the module's validation logic | ||
* @param attestationPayload - AttestationPayload containing the user address as `subject` | ||
* and nonce as `attestationData` | ||
* @param validationPayload - validationPayload containing the serialized hash.The last one is the 'Root'. | ||
*/ | ||
function run( | ||
AttestationPayload memory attestationPayload, | ||
bytes memory validationPayload, | ||
address /*initialCaller*/, | ||
uint256 /*value*/, | ||
address /*attester*/, | ||
address /*portal*/ | ||
) public pure override { | ||
bytes32[] memory proof = abi.decode(validationPayload, (bytes32[])); | ||
bytes32 hash = bytes32(attestationPayload.attestationData); | ||
/* | ||
* @notice We send the hardcoded third leaf to verify. | ||
*/ | ||
uint256 index = 2; | ||
for (uint256 i = index + 1; i < proof.length; i = uncheckedInc256(i)) { | ||
bytes32 proofElement = proof[i]; | ||
|
||
if (index % 2 == 0) { | ||
hash = keccak256(abi.encodePacked(hash, proofElement)); | ||
} else { | ||
hash = keccak256(abi.encodePacked(proofElement, hash)); | ||
} | ||
index = index / 2; | ||
if (index == 0) { | ||
break; | ||
} | ||
} | ||
|
||
if (hash != proof[proof.length - 1]) { | ||
revert MerkelProofVerifyFailed(); | ||
} | ||
} | ||
} |
Oops, something went wrong.