diff --git a/contracts/GitcoinResolver.sol b/contracts/GitcoinResolver.sol index 38dc46b..155fda3 100644 --- a/contracts/GitcoinResolver.sol +++ b/contracts/GitcoinResolver.sol @@ -176,7 +176,10 @@ contract GitcoinResolver is } /** - * @dev Returns the cached score for a given address. + * + * @param user The ETH address of the recipient + * @return The `CachedScore` for the given ETH address. + * A non-zero value in the `issuanceDate` indicates that a valid score has been retreived. */ function getCachedScore( address user @@ -242,6 +245,12 @@ contract GitcoinResolver is return true; } + /** + * + * @param user The ETH address of the recipient + * @param schema THE UID of the chema + * @return The attestation UID or 0x0 if not found + */ function getUserAttestation( address user, bytes32 schema diff --git a/contracts/IGitcoinResolver.sol b/contracts/IGitcoinResolver.sol index 63eca3b..6cdb5d8 100644 --- a/contracts/IGitcoinResolver.sol +++ b/contracts/IGitcoinResolver.sol @@ -12,14 +12,27 @@ interface IGitcoinResolver { uint32 score; // compacted uint value 4 decimal places uint64 issuanceDate; // For checking the age of the stamp, without loading the attestation uint64 expirationDate; // This makes sense because we want to make sure the stamp is not expired, and also do not want to load the attestation - uint32 scorerId; // would we need this ??? + uint32 scorerId; // would we need this ??? TODO: to be clarified } + /** + * + * @param user The ETH address of the recipient + * @param schema THE UID of the chema + * @return The attestation UID or 0x0 if not found + */ function getUserAttestation( address user, bytes32 schema ) external view returns (bytes32); + /** + * + * @param user The ETH address of the recipient + * @return The `CachedScore` for the given ETH address. + * A non-zero value in the `issuanceDate` indicates that a valid score has been retreived. + */ + function getCachedScore( address user ) external view returns (CachedScore memory); diff --git a/docs/00-onchain-data.md b/docs/00-onchain-data.md index 118df75..73f1f42 100644 --- a/docs/00-onchain-data.md +++ b/docs/00-onchain-data.md @@ -43,6 +43,7 @@ OpenZeppelin's `Ownable`. All of the smart contracts are upgradeable and pauseable. The flow: + ```mermaid sequenceDiagram actor User @@ -67,13 +68,13 @@ sequenceDiagram Attester->>EAS : multiAttest activate Resolver EAS->>Resolver : multiAttest - Resolver-->>EAS : + Resolver-->>EAS : deactivate Resolver EAS-->>Attester : UUIDs: bytes32[] deactivate EAS - Attester-->>Verifier : + Attester-->>Verifier : deactivate Attester - Verifier-->>App : + Verifier-->>App : deactivate Verifier App-->>User : display onchain status @@ -96,7 +97,6 @@ sequenceDiagram deactivate Decoder ``` - ## GitcoinAttester Here are the main features: @@ -161,13 +161,19 @@ recipient, in order for the call to `verifyAndAttest` to get through. It will be reverted otherwise. ## GitcoinResolver +You can find the implementation of the GitcoinResolver _[here](../contracts/GitcoinResolver.sol)_ EAS provides a mechanism to perform additional validations for stamps and implement additional smart contract functionality related to attestations using [resolver contracts](https://docs.attest.sh/docs/tutorials/resolver-contracts). -For our use-case we will use resolver contracts to track which attestations a -given recipient owns (this information is not provided by the EAS smart contract -by default). +For our use-case we will use resolver contracts for the following purposes: + +- to track which attestations a given recipient owns (this information is not + provided by the EAS smart contract by default) +- caching the latest score that a user has, in order to provide more efficient + access to a users score (cheaper in terms of gas costs) + +### Tracking attestations The attestations are stored in a mapping that allows storing attestations from any schema: @@ -176,16 +182,52 @@ from any schema: mapping(address => mapping(bytes32 => bytes32)) public userAttestations; ``` +The meaning of this nested mapping is the following: + +```txt +user ETH address => schema UID => attestation UID +``` + In order to ensure the integrity of the data that a resolver stores, resolver -smart contract shall only validate and store date from trusted sources: +smart contract shall only validate and store data from trusted sources: - a trusted EAS contract - a trusted Attester +### Caching users scores + +In order to provide faster access to a users score, the informatio from score +attestations is cached in an attribute of the `GitcoinResolver` smart contract: + +```sol + // Mapping of addresses to scores + mapping(address => CachedScore) private scores; +``` + +where `CachedScore` is defined as follows: + +```sol +struct CachedScore { + uint32 score; + uint64 issuanceDate; + uint64 expirationDate; + uint32 scorerId; +} +``` + +Retreiving the latest score for a user becomes much cheaper in terms of gas costs +and easier using the helper function: + +```sol +function getCachedScore( + address user +) external view returns (CachedScore memory); +``` ## GitcoinPassportDecoder -This is a convenience smart contract that can be used by any party to check for the on-chain passport attestation for a given ETH address. +This is a convenience smart contract that can be used by any party to check for +the on-chain passport attestation for a given ETH address. See the documentation [How to Decode Passport Attestations ](./05-querying-passport-attestations-onchain.md) for more details. diff --git a/test/GitcoinResolver.ts b/test/GitcoinResolver.ts index 936d68d..cad641e 100644 --- a/test/GitcoinResolver.ts +++ b/test/GitcoinResolver.ts @@ -193,7 +193,7 @@ describe("GitcoinResolver", function () { .attest(attestation); const attestReceipt = attestRequest.wait(); - const score = await gitcoinResolver.scores(recipient.address); + const score = await gitcoinResolver.getCachedScore(recipient.address); // Score should have been casted to a 4 digit value expect(score[0]).to.equal("123456"); @@ -223,7 +223,7 @@ describe("GitcoinResolver", function () { .attest(attestation); const attestReceipt = attestRequest.wait(); - const score = await gitcoinResolver.scores(recipient.address); + const score = await gitcoinResolver.getCachedScore(recipient.address); // Score should have been casted to a 4 digit value expect(score[0]).to.equal("123400"); @@ -253,7 +253,7 @@ describe("GitcoinResolver", function () { .attest(attestation); const attestReceipt = attestRequest.wait(); - const score = await gitcoinResolver.scores(recipient.address); + const score = await gitcoinResolver.getCachedScore(recipient.address); // Score should have been casted to a 4 digit value expect(score[0]).to.equal("123456"); diff --git a/test/Upgrades.ts b/test/Upgrades.ts index 378a5fa..5c70554 100644 --- a/test/Upgrades.ts +++ b/test/Upgrades.ts @@ -103,7 +103,7 @@ describe("Upgrading GitcoinAttester", function () { }); }); -describe.only("Upgrading GitcoinResolver", function () { +describe("Upgrading GitcoinResolver", function () { this.beforeEach(async function () { const [owner, mockEASAccount] = await ethers.getSigners(); this.owner = owner;