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

test(eas): mock gatekeeper tests #1412

Merged
merged 1 commit into from
Apr 30, 2024
Merged
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
2 changes: 1 addition & 1 deletion contracts/contracts/gatekeepers/EASGatekeeper.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

Expand Down
104 changes: 104 additions & 0 deletions contracts/contracts/mocks/MockEAS.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { IEAS } from "../interfaces/IEAS.sol";

/// @title MockEAS
/// @notice A mock contract to test the EASGatekeeper
contract MockEAS is IEAS {
address public immutable attester;
bytes32 public immutable schema;

address public recipient;

constructor(address _attester, bytes32 _schema, address _recipient) {

Check notice

Code scanning / Slither

Missing zero address validation Low

Check notice

Code scanning / Slither

Missing zero address validation Low

attester = _attester;
schema = _schema;
recipient = _recipient;
}

/// @notice Set the attestation recipient (mock)
function setRecipient(address _recipient) public {

Check notice

Code scanning / Slither

Missing zero address validation Low

Check warning

Code scanning / Slither

Conformance to Solidity naming conventions Warning

Parameter MockEAS.setRecipient(address)._recipient is not in mixedCase
recipient = _recipient;
}

/// @inheritdoc IEAS
function getAttestation(bytes32 attestationId) external view override returns (Attestation memory) {
// revoked
if (attestationId == 0x0000000000000000000000000000000000000000000000000000000000000001) {
return
Attestation({
uid: "0x000000000000000000000000000001",
schema: schema,
time: 0,
expirationTime: 0,
revocationTime: 1,
refUID: "0x000000000000000000000000000001",
recipient: recipient,
attester: attester,
revocable: true,
data: ""
});
// invalid schema
} else if (attestationId == 0x0000000000000000000000000000000000000000000000000000000000000002) {
return
Attestation({
uid: "0x000000000000000000000000000001",
schema: "0x000000000000000000000000000001",
time: 0,
expirationTime: 0,
revocationTime: 0,
refUID: "0x000000000000000000000000000001",
recipient: recipient,
attester: attester,
revocable: false,
data: ""
});
// invalid recipient
} else if (attestationId == 0x0000000000000000000000000000000000000000000000000000000000000003) {
return
Attestation({
uid: "0x000000000000000000000000000001",
schema: schema,
time: 0,
expirationTime: 0,
revocationTime: 0,
refUID: "0x000000000000000000000000000001",
recipient: address(0),
attester: attester,
revocable: false,
data: ""
});
// invalid attester
} else if (attestationId == 0x0000000000000000000000000000000000000000000000000000000000000004) {
return
Attestation({
uid: "0x000000000000000000000000000001",
schema: schema,
time: 0,
expirationTime: 0,
revocationTime: 0,
refUID: "0x000000000000000000000000000001",
recipient: recipient,
attester: address(0),
revocable: false,
data: ""
});
// valid
} else {
return
Attestation({
uid: "0x000000000000000000000000000001",
schema: schema,
time: 0,
expirationTime: 0,
revocationTime: 0,
refUID: "0x000000000000000000000000000001",
recipient: recipient,
attester: attester,
revocable: false,
data: ""
});
}
}
Comment on lines +26 to +103

Check warning

Code scanning / Slither

Too many digits Warning

Comment on lines +26 to +103

Check warning

Code scanning / Slither

Too many digits Warning

Comment on lines +26 to +103

Check warning

Code scanning / Slither

Too many digits Warning

Comment on lines +26 to +103

Check warning

Code scanning / Slither

Too many digits Warning

}
107 changes: 30 additions & 77 deletions contracts/tests/EASGatekeeper.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { expect } from "chai";
import dotenv from "dotenv";
import { AbiCoder, Signer, ZeroAddress, toBeArray } from "ethers";
import { ethers, network } from "hardhat";
import { Keypair } from "maci-domainobjs";

import { deployContract } from "../ts/deploy";
import { getDefaultSigner, getSigners, sleep } from "../ts/utils";
import { getDefaultSigner, getSigners } from "../ts/utils";
import { EASGatekeeper, MACI } from "../typechain-types";

import { STATE_TREE_DEPTH, initialVoiceCreditBalance } from "./constants";
Expand All @@ -17,52 +16,25 @@ describe("EAS Gatekeeper", () => {
let easGatekeeper: EASGatekeeper;
let signer: Signer;
let signerAddress: string;
let easAddress: string;

const schema = "0xfdcfdad2dbe7489e0ce56b260348b7f14e8365a8a325aef9834818c00d46b31b";
const easAddress = "0x4200000000000000000000000000000000000021";
const attestation = "0xe9d4e5a14ec840656d9def34075d9523d1536176d5f0a7d574f2e93bea641b66";
const revokedAttestation = "0x10207e0381318820574f8c99efde13b9dfe0b24114c9ec5337109d2435a8f13b";
const invalidAttesterAttestation = "0x5f66cb6eaebece82ec3a47918afee718afa7dca838faab1ee156df3a6187cb9c";
const attestationOwner = "0x849151d7D0bF1F34b70d5caD5149D28CC2308bf1";
const trustedAttester = "0x621477dBA416E12df7FF0d48E14c4D20DC85D7D9";
// random gitcoin passport attestation
const wrongAttestation = "0x8c60cf319b553194519098c7ecaad38fc0e818c538b939730c0b55bb1eeedaae";

const revokedAttestation = "0x0000000000000000000000000000000000000000000000000000000000000001";
const invalidSchemaAttestation = "0x0000000000000000000000000000000000000000000000000000000000000002";
const invalidRecipientAttestation = "0x0000000000000000000000000000000000000000000000000000000000000003";
const invalidAttesterAttestation = "0x0000000000000000000000000000000000000000000000000000000000000004";
// valid attestation
const attestation = "0x0000000000000000000000000000000000000000000000000000000000000000";

const user = new Keypair();

before(async () => {
// fork the optimism mainnet network
if (network.name === "hardhat") {
await network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
jsonRpcUrl: process.env.OP_RPC_URL || "https://optimism.drpc.org",
},
},
],
});
}
signer = await getDefaultSigner();
signerAddress = await signer.getAddress();
easGatekeeper = await deployContract("EASGatekeeper", signer, true, easAddress, trustedAttester, toBeArray(schema));
});

after(async () => {
// we reset
if (network.name === "hardhat") {
await network.provider.request({
method: "hardhat_reset",
params: [],
});
}
});

// add some sleep to ensure we don't have problems with the fork
// as one might use a free RPC plan
afterEach(async () => {
await sleep(3000);
const mockEAS = await deployContract("MockEAS", signer, true, signerAddress, toBeArray(schema), signerAddress);
easAddress = await mockEAS.getAddress();
easGatekeeper = await deployContract("EASGatekeeper", signer, true, easAddress, signerAddress, toBeArray(schema));
});

describe("Deployment", () => {
Expand All @@ -72,7 +44,7 @@ describe("EAS Gatekeeper", () => {

it("should fail to deploy when the eas contract address is not valid", async () => {
await expect(
deployContract("EASGatekeeper", signer, true, ZeroAddress, trustedAttester, toBeArray(schema)),
deployContract("EASGatekeeper", signer, true, ZeroAddress, signerAddress, toBeArray(schema)),
).to.be.revertedWithCustomError(easGatekeeper, "ZeroAddress");
});

Expand Down Expand Up @@ -117,76 +89,57 @@ describe("EAS Gatekeeper", () => {
it("should throw when the attestation is not owned by the caller (mocking maci.signUp call)", async () => {
await easGatekeeper.setMaciInstance(signerAddress).then((tx) => tx.wait());

await expect(easGatekeeper.register(signerAddress, toBeArray(attestation))).to.be.revertedWithCustomError(
await expect(easGatekeeper.register(signerAddress, invalidRecipientAttestation)).to.be.revertedWithCustomError(
easGatekeeper,
"NotYourAttestation",
);
});

it("should throw when the attestation has been revoked", async () => {
await expect(easGatekeeper.register(signerAddress, toBeArray(revokedAttestation))).to.be.revertedWithCustomError(
await expect(easGatekeeper.register(signerAddress, revokedAttestation)).to.be.revertedWithCustomError(
easGatekeeper,
"AttestationRevoked",
);
});

it("should throw when the attestation schema is not the one expected by the gatekeeper", async () => {
await easGatekeeper.setMaciInstance(signerAddress).then((tx) => tx.wait());
await expect(easGatekeeper.register(signerAddress, toBeArray(wrongAttestation))).to.be.revertedWithCustomError(
await expect(easGatekeeper.register(signerAddress, invalidSchemaAttestation)).to.be.revertedWithCustomError(
easGatekeeper,
"InvalidSchema",
);
});

it("should throw when the attestation is not signed by the attestation owner", async () => {
await easGatekeeper.setMaciInstance(signerAddress).then((tx) => tx.wait());
await expect(
easGatekeeper.register(signerAddress, toBeArray(invalidAttesterAttestation)),
).to.be.revertedWithCustomError(easGatekeeper, "AttesterNotTrusted");
await expect(easGatekeeper.register(signerAddress, invalidAttesterAttestation)).to.be.revertedWithCustomError(
easGatekeeper,
"AttesterNotTrusted",
);
});

it("should register a user if the register function is called with the valid data", async () => {
// impersonate a user that owns the attestation
await network.provider.request({
method: "hardhat_impersonateAccount",
params: [attestationOwner],
});

const userSigner = await ethers.getSigner(attestationOwner);

await easGatekeeper.setMaciInstance(await maciContract.getAddress()).then((tx) => tx.wait());

// signup via MACI
const tx = await maciContract
.connect(userSigner)
.signUp(
user.pubKey.asContractParam(),
toBeArray(attestation),
AbiCoder.defaultAbiCoder().encode(["uint256"], [1]),
);
const tx = await maciContract.signUp(
user.pubKey.asContractParam(),
attestation,
AbiCoder.defaultAbiCoder().encode(["uint256"], [1]),
);

const receipt = await tx.wait();

expect(receipt?.status).to.eq(1);
});

it("should prevent signing up twice", async () => {
// impersonate a user that owns the attestation
await network.provider.request({
method: "hardhat_impersonateAccount",
params: [attestationOwner],
});

const userSigner = await ethers.getSigner(attestationOwner);

await expect(
maciContract
.connect(userSigner)
.signUp(
user.pubKey.asContractParam(),
toBeArray(attestation),
AbiCoder.defaultAbiCoder().encode(["uint256"], [1]),
),
maciContract.signUp(
user.pubKey.asContractParam(),
attestation,
AbiCoder.defaultAbiCoder().encode(["uint256"], [1]),
),
).to.be.revertedWithCustomError(easGatekeeper, "AlreadyRegistered");
});
});
Expand Down
Loading