Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: As a user, I want to have an example ERC-1271 module #314

Merged
merged 9 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from 6 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
72 changes: 72 additions & 0 deletions contracts/src/examples/modules/ERC1271Module.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import { AbstractModule } from "../../interface/AbstractModule.sol";
import { AttestationPayload } from "../../types/Structs.sol";

contract ERC1271Module is AbstractModule {
address public owner;

constructor(address _owner) {
owner = _owner;
}

/**
* @notice Recover the signer of hash, assuming it's an EOA account
* @dev Only for EthSign signatures
* @param _hash Hash of message that was signed
* @param _signature Signature encoded as (bytes32 r, bytes32 s, uint8 v)
*/
function recoverSigner(bytes32 _hash, bytes memory _signature) internal pure returns (address signer) {
require(_signature.length == 65, "Invalid signature length");
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(_signature, 0x20))
s := mload(add(_signature, 0x40))
v := byte(0, mload(add(_signature, 0x60)))
}
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
revert("SignatureValidator#recoverSigner: invalid signature 's' value");
}
if (v != 27 && v != 28) {
revert("SignatureValidator#recoverSigner: invalid signature 'v' value");
}

signer = ecrecover(_hash, v, r, s);
// Prevent signer from being 0x0
require(signer != address(0x0), "SignatureValidator#recoverSigner: INVALID_SIGNER");
return signer;
}

/**
* @notice Verifies that the signer is the owner of the signing contract.
*/
function isValidSignature(bytes32 _hash, bytes memory _signature) internal view returns (bytes4) {
// Validate signatures
address signer = recoverSigner(_hash, _signature);
if (signer == owner) {
return 0x1626ba7e;
} else {
return 0xffffffff;
}
}

function run(
AttestationPayload memory attestationPayload,
bytes memory validationPayload,
address txSender,
uint256 /*value*/
) public view override {
require(txSender == owner, "Invalid sender");
address signee = abi.decode(attestationPayload.subject, (address));
uint256 nonce = abi.decode(attestationPayload.attestationData, (uint256));
bytes memory message = abi.encodePacked(signee, nonce);
bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", message));
require(
isValidSignature(digest, validationPayload) == 0x1626ba7e,
"SignatureValidator#isValidSignature: INVALID_SIGNER"
);
}
}
44 changes: 44 additions & 0 deletions contracts/test/example/ERC1271Module.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import { Test } from "forge-std/Test.sol";
import { AbstractModule } from "../../src/interface/AbstractModule.sol";
import { ERC1271Module } from "../../src/examples/modules/ERC1271Module.sol";
import { AttestationPayload } from "../../src/types/Structs.sol";

contract ERC1271ModuleTest is Test {
ERC1271Module private erc1271Module;
uint256 internal signerPrivateKey;
address internal signerAddress;

event ModuleRegistered(string name, string description, address moduleAddress);

function setUp() public {
(signerAddress, signerPrivateKey) = makeAddrAndKey("veraxUser");
erc1271Module = new ERC1271Module(signerAddress);
vm.deal(signerAddress, 1 ether);
}

function test_ERC1271Module_verifySignature() public {
address user = makeAddr("user");
uint256 nonce = 1234567;
AttestationPayload memory attestationPayload = AttestationPayload(
bytes32(uint256(1234)),
0,
abi.encode(user),
abi.encode(nonce)
);

bytes32 hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", abi.encodePacked(user, nonce)));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(signerPrivateKey, hash);

bytes memory signature = abi.encodePacked(r, s, v);

erc1271Module.run(attestationPayload, signature, signerAddress, 0);
}

function test_EcRecoverModule_supportsInterface() public {
bool isAbstractModuleSupported = erc1271Module.supportsInterface(type(AbstractModule).interfaceId);
assertEq(isAbstractModuleSupported, true);
}
}
Loading