Skip to content

Commit

Permalink
refactor(excubiae): improve types and testing
Browse files Browse the repository at this point in the history
  • Loading branch information
0xjei committed Jun 28, 2024
1 parent cff108f commit fe1bd24
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 43 deletions.
2 changes: 2 additions & 0 deletions packages/excubiae/contracts/extensions/EASExcubia.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ contract EASExcubia is Excubia {
/// @param data Additional data required for the check (e.g., encoded attestation ID).
/// @return True if the attestation is valid and the passerby passes the check, false otherwise.
function _check(address passerby, bytes calldata data) internal view override returns (bool) {
super._check(passerby, data);

bytes32 attestationId = abi.decode(data, (bytes32));

Attestation memory attestation = EAS.getAttestation(attestationId);
Expand Down
2 changes: 2 additions & 0 deletions packages/excubiae/contracts/extensions/ERC721Excubia.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ contract ERC721Excubia is Excubia {
/// @param data Additional data required for the check (e.g., encoded token ID).
/// @return True if the passerby owns the token, false otherwise.
function _check(address passerby, bytes calldata data) internal view override returns (bool) {
super._check(passerby, data);

uint256 tokenId = abi.decode(data, (uint256));

// Check if the user owns the token.
Expand Down
14 changes: 7 additions & 7 deletions packages/excubiae/contracts/extensions/FreeForAllExcubia.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ contract FreeForAllExcubia is Excubia {
constructor() {}

/// @notice Mapping to track already registered passersby.
mapping(bytes32 => bool) public registeredPassersby;
mapping(address => bool) public registeredPassersby;

/// @notice Internal function to handle the gate passing logic.
/// @dev This function calls the parent `_pass` function and then tracks the passerby.
Expand All @@ -21,18 +21,18 @@ contract FreeForAllExcubia is Excubia {
function _pass(address passerby, bytes calldata data) internal override {
super._pass(passerby, data);

bytes32 encodedPasserby = keccak256(abi.encodePacked(passerby));

// Avoiding double check of the same passerby.
if (registeredPassersby[encodedPasserby]) revert AlreadyRegistered();
if (registeredPassersby[passerby]) revert AlreadyRegistered();

registeredPassersby[encodedPasserby] = true;
registeredPassersby[passerby] = true;
}

/// @notice Internal function to handle the gate protection logic.
/// @dev This function always returns true, signaling that any passerby is able to pass the gate.
/// @return True, allowing any passerby to pass the gate.
function _check(address /*passerby*/, bytes calldata /*data*/) internal pure override returns (bool) {
return true; /// @todo check if optional.
function _check(address passerby, bytes calldata data) internal view override returns (bool) {
super._check(passerby, data);

return true;
}
}
38 changes: 22 additions & 16 deletions packages/excubiae/contracts/test/MockEAS.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,75 +25,81 @@ contract MockEAS is IEAS {
getSchemaRegistry = ISchemaRegistry(address(1));

Attestation memory valid = Attestation({
uid: bytes32("0x01"),
uid: bytes32(hex"0100000000000000000000000000000000000000000000000000000000000000"),
schema: _schema,
time: 0,
expirationTime: 0,
revocationTime: 0,
refUID: bytes32("0x01"),
refUID: bytes32(hex"0100000000000000000000000000000000000000000000000000000000000000"),
recipient: _recipient,
attester: _attester,
revocable: true,
data: bytes("")
});

Attestation memory revoked = Attestation({
uid: bytes32("0x02"),
uid: bytes32(hex"0200000000000000000000000000000000000000000000000000000000000000"),
schema: _schema,
time: 0,
expirationTime: 0,
revocationTime: 1,
refUID: bytes32("0x01"),
refUID: bytes32(hex"0100000000000000000000000000000000000000000000000000000000000000"),
recipient: _recipient,
attester: _attester,
revocable: true,
data: bytes("")
});

Attestation memory invalidSchema = Attestation({
uid: bytes32("0x03"),
schema: bytes32("0x01"),
uid: bytes32(hex"0300000000000000000000000000000000000000000000000000000000000000"),
schema: bytes32(hex"0100000000000000000000000000000000000000000000000000000000000000"),
time: 0,
expirationTime: 0,
revocationTime: 0,
refUID: bytes32("0x01"),
refUID: bytes32(hex"0100000000000000000000000000000000000000000000000000000000000000"),
recipient: _recipient,
attester: _attester,
revocable: true,
data: bytes("")
});

Attestation memory invalidRecipient = Attestation({
uid: bytes32("0x04"),
uid: bytes32(hex"0400000000000000000000000000000000000000000000000000000000000000"),
schema: _schema,
time: 0,
expirationTime: 0,
revocationTime: 0,
refUID: bytes32("0x01"),
refUID: bytes32(hex"0100000000000000000000000000000000000000000000000000000000000000"),
recipient: address(1),
attester: _attester,
revocable: true,
data: bytes("")
});

Attestation memory invalidAttester = Attestation({
uid: bytes32("0x05"),
uid: bytes32(hex"0500000000000000000000000000000000000000000000000000000000000000"),
schema: _schema,
time: 0,
expirationTime: 0,
revocationTime: 0,
refUID: bytes32("0x000000000000000000000000000001"),
refUID: bytes32(hex"0100000000000000000000000000000000000000000000000000000000000000"),
recipient: _recipient,
attester: address(1),
revocable: true,
data: bytes("")
});

mockedAttestations[bytes32("0x01")] = valid;
mockedAttestations[bytes32("0x02")] = revoked;
mockedAttestations[bytes32("0x03")] = invalidSchema;
mockedAttestations[bytes32("0x04")] = invalidRecipient;
mockedAttestations[bytes32("0x05")] = invalidAttester;
mockedAttestations[bytes32(hex"0100000000000000000000000000000000000000000000000000000000000000")] = valid;
mockedAttestations[bytes32(hex"0200000000000000000000000000000000000000000000000000000000000000")] = revoked;
mockedAttestations[
bytes32(hex"0300000000000000000000000000000000000000000000000000000000000000")
] = invalidSchema;
mockedAttestations[
bytes32(hex"0400000000000000000000000000000000000000000000000000000000000000")
] = invalidRecipient;
mockedAttestations[
bytes32(hex"0500000000000000000000000000000000000000000000000000000000000000")
] = invalidAttester;
}

/// @notice Retrieves a mocked attestation by its unique identifier.
Expand Down
22 changes: 14 additions & 8 deletions packages/excubiae/test/EASExcubia.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect } from "chai"
import { ethers } from "hardhat"
import { Signer, ZeroAddress } from "ethers"
import { AbiCoder, Signer, ZeroAddress, toBeHex, zeroPadBytes } from "ethers"
import { EASExcubia, EASExcubia__factory, MockEAS, MockEAS__factory } from "../typechain-types"

describe("EASExcubia", function () {
Expand All @@ -18,11 +18,11 @@ describe("EASExcubia", function () {
let mockEASAddress: string

const schemaId = "0xfdcfdad2dbe7489e0ce56b260348b7f14e8365a8a325aef9834818c00d46b31b"
const validAttestationId = ethers.encodeBytes32String("0x01")
const revokedAttestationId = ethers.encodeBytes32String("0x02")
const invalidSchemaAttestationId = ethers.encodeBytes32String("0x03")
const invalidRecipientAttestationId = ethers.encodeBytes32String("0x04")
const invalidAttesterAttestationId = ethers.encodeBytes32String("0x05")
const validAttestationId = AbiCoder.defaultAbiCoder().encode(["bytes32"], [zeroPadBytes(toBeHex(1), 32)])
const revokedAttestationId = AbiCoder.defaultAbiCoder().encode(["bytes32"], [zeroPadBytes(toBeHex(2), 32)])
const invalidSchemaAttestationId = AbiCoder.defaultAbiCoder().encode(["bytes32"], [zeroPadBytes(toBeHex(3), 32)])
const invalidRecipientAttestationId = AbiCoder.defaultAbiCoder().encode(["bytes32"], [zeroPadBytes(toBeHex(4), 32)])
const invalidAttesterAttestationId = AbiCoder.defaultAbiCoder().encode(["bytes32"], [zeroPadBytes(toBeHex(5), 32)])

before(async function () {
;[signer, gate] = await ethers.getSigners()
Expand All @@ -46,12 +46,18 @@ describe("EASExcubia", function () {
expect(mockEAS).to.not.eq(undefined)
})

it("Should fail to deploy EASExcubia when attester parameter is not valid", async () => {
await expect(EASExcubiaContract.deploy(signerAddress, ZeroAddress, schemaId)).to.be.revertedWithCustomError(
it("Should fail to deploy EASExcubia when eas parameter is not valid", async () => {
await expect(EASExcubiaContract.deploy(ZeroAddress, ZeroAddress, schemaId)).to.be.revertedWithCustomError(
easExcubia,
"ZeroAddress"
)
})

it("Should fail to deploy EASExcubia when attester parameter is not valid", async () => {
await expect(
EASExcubiaContract.deploy(await easExcubia.getAddress(), ZeroAddress, schemaId)
).to.be.revertedWithCustomError(easExcubia, "ZeroAddress")
})
})

describe("setGate()", function () {
Expand Down
17 changes: 9 additions & 8 deletions packages/excubiae/test/ERC721Excubia.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ describe("ERC721Excubia", function () {
let mockERC721: MockERC721
let mockERC721Address: string

const encodedValidTokenId = AbiCoder.defaultAbiCoder().encode(["uint256"], [0])
const encodedInvalidOwnerTokenId = AbiCoder.defaultAbiCoder().encode(["uint256"], [1])
const decodedValidTokenId = AbiCoder.defaultAbiCoder().decode(["uint256"], encodedValidTokenId)
const decodedInvalidOwnerTokenId = AbiCoder.defaultAbiCoder().decode(["uint256"], encodedInvalidOwnerTokenId)
const rawValidTokenId = 0
const rawInvalidOwnerTokenId = 1

const encodedValidTokenId = AbiCoder.defaultAbiCoder().encode(["uint256"], [rawValidTokenId])
const encodedInvalidOwnerTokenId = AbiCoder.defaultAbiCoder().encode(["uint256"], [rawInvalidOwnerTokenId])

before(async function () {
;[signer, gate, anotherTokenOwner] = await ethers.getSigners()
Expand Down Expand Up @@ -108,12 +109,12 @@ describe("ERC721Excubia", function () {
)
})

it("should pass the check", async () => {
it("should check", async () => {
const passed = await erc721Excubia.check(signerAddress, encodedValidTokenId)

expect(passed).to.be.true
// check does NOT change the state of the contract (see pass()).
expect(await erc721Excubia.registeredTokenIds(decodedValidTokenId[0])).to.be.false
expect(await erc721Excubia.registeredTokenIds(rawValidTokenId)).to.be.false
})
})

Expand All @@ -130,7 +131,7 @@ describe("ERC721Excubia", function () {
).to.be.revertedWithCustomError(erc721Excubia, "UnexpectedTokenOwner")
})

it("should pass the check", async () => {
it("should pass", async () => {
const tx = await erc721Excubia.connect(gate).pass(signerAddress, encodedValidTokenId)
const receipt = await tx.wait()
const event = ERC721ExcubiaContract.interface.parseLog(
Expand All @@ -145,7 +146,7 @@ describe("ERC721Excubia", function () {
expect(receipt?.status).to.eq(1)
expect(event.args.passerby).to.eq(signerAddress)
expect(event.args.gate).to.eq(gateAddress)
expect(await erc721Excubia.registeredTokenIds(decodedValidTokenId[0])).to.be.true
expect(await erc721Excubia.registeredTokenIds(rawValidTokenId)).to.be.true
})

it("should prevent to pass twice", async () => {
Expand Down
8 changes: 4 additions & 4 deletions packages/excubiae/test/FreeForAllExcubia.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ describe("FreeForAllExcubia", function () {
})

describe("check()", function () {
it("should pass the check", async () => {
it("should check", async () => {
// `data` parameter value can be whatever (e.g., ZeroHash default).
const passed = await freeForAllExcubia.check(signerAddress, ZeroHash)

expect(passed).to.be.true
// check does NOT change the state of the contract (see pass()).
expect(await freeForAllExcubia.registeredPassersby(ethers.keccak256(signerAddress))).to.be.false
expect(await freeForAllExcubia.registeredPassersby(signerAddress)).to.be.false
})
})

Expand All @@ -88,7 +88,7 @@ describe("FreeForAllExcubia", function () {
).to.be.revertedWithCustomError(freeForAllExcubia, "GateOnly")
})

it("should pass the check", async () => {
it("should pass", async () => {
// `data` parameter value can be whatever (e.g., ZeroHash default).
const tx = await freeForAllExcubia.connect(gate).pass(signerAddress, ZeroHash)
const receipt = await tx.wait()
Expand All @@ -104,7 +104,7 @@ describe("FreeForAllExcubia", function () {
expect(receipt?.status).to.eq(1)
expect(event.args.passerby).to.eq(signerAddress)
expect(event.args.gate).to.eq(gateAddress)
expect(await freeForAllExcubia.registeredPassersby(ethers.keccak256(signerAddress))).to.be.true
expect(await freeForAllExcubia.registeredPassersby(signerAddress)).to.be.true
})

it("should prevent to pass twice", async () => {
Expand Down

0 comments on commit fe1bd24

Please sign in to comment.