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: add hasVerifiedAttestations and getVerifiedAttestations #95

Closed
wants to merge 5 commits into from

Conversation

alvaroraminelli
Copy link
Contributor

@alvaroraminelli alvaroraminelli commented Feb 7, 2024

What changed? Why?

Introduce new functionalities that make easier verify addresses in the Ethereum Attestation Service (EAS).

hasVerifiedAttestations
getAttestation

Notes to reviewers

How has it been tested?

Local build and consuming in a playground

@alvaroraminelli alvaroraminelli marked this pull request as ready for review February 7, 2024 16:57
@alvaroraminelli
Copy link
Contributor Author

  • Missing tests

`;

/**
* Retrieves attestations for a given address and chain, optionally filtered by schemas.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in the context of Coinbase Verifications. Do we want to be more specific here in that case?

e.g. getCoinbaseVerifications

Same with below, should we name it hasCoinbaseVerifications ?

Copy link

@cbfyi cbfyi Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bringing this up in case we extend Onchain Kit to support all attestations in general -- which IMO, we should!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the path to support all attestations in general?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we ever settled on a clear path for this.

But absent any decisions, I think we should be more opinionated with the naming to leave room for more general EAS support in the near future. Committing to something abstract like getAttestation which really only targets CB Verifications would preclude us from that option.

cc: @Zizzamia

* @returns A promise that resolves to an array of Attestations.
* @throws Will throw an error if the request to the GraphQL API fails.
*/
export async function getAttestation(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we set this up manually?

I was thinking longer term we could just use https://the-guild.dev/graphql/codegen

Allows us to appropriately keep up with EAS' GraphQL specs, and also more easily add new helpers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we want to codegen? I am generally against codegen as they are the eveil of good developer experience for OSS libraries.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically this.

If you look at the link I shared, you can arguably get the same experience, without having to manually plumb the queries.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In another scenario I'd agree with you if we're actually adding significantly more value / logic over what codegen already provides.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of codegen we want? Like one for each Attestation? help me understand

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends. In this context, we are asking GraphQL for "attestations that are not expired or revoked for a specific address, a specific attester and possibly a set of schema IDs". There's an additional dimension here which is the network.

I'd personally codegen what we already have:

query findActiveAttestations(...) {
    // ... current fields, but broken out as a fragment ...
}

Then this current function or if we rename it to findCoinbaseVerifications / getCoinbaseVerifications will just be a light wrapper around the generated code. But this ensures strong consistency with the actual EAS GraphQL schema, and we're not writing our types ourselves making it easier to maintain longer term. Our focus will simply be providing a better experience over someone writing their own queries or generating their own GraphQL client.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then for the other use-case in this context, we have hasVerifiedAttestations which can simply be another codegen query because there's actually a specific GraphQL resolver for that! That is, findFirstAttestation in EAS' GraphQL. This way, we are letting the GraphQL API handle most of the filtering for us.

Copy link

@cbfyi cbfyi Feb 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, I'm not strongly holding this opinion. It's something we can do later. I rather we don't block this PR from going out. But it would address your other comment:

Would love we have strong types on what's returing and what each of them means.

In the sense that we would have the types auto-gen.

* @returns A promise that resolves to an array of Attestations.
* @throws Will throw an error if the request to the GraphQL API fails.
*/
export async function getAttestation(
Copy link

@cbfyi cbfyi Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This implicitly filters out revoked or expired attestations. We may want a different name for it to reflect that. Similar to comment further up.

src/core/getAttestation.ts Outdated Show resolved Hide resolved
Comment on lines 29 to 33
const schemaUids = getChainSchemasUids(expectedSchemas, chain.id);
const attestations = await getAttestation(chain, address, { schemas: expectedSchemas });
const schemasFound = attestations.map((attestation) => attestation.schemaId);

return schemaUids.every((schemaUid) => schemasFound.includes(schemaUid));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no change needed, but a more optimal solution would be to let the GraphQL server handle all this.

README.md Show resolved Hide resolved
README.md Show resolved Hide resolved
package.json Outdated
@@ -18,6 +18,8 @@
"release:version": "changeset version && yarn install --immutable"
},
"peerDependencies": {
"graphql": "^16.8.1",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this clash with any other GraphQL dependcy in the industry? I am a bit ingronant here, but those work this well with Relay?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering if we can say

"graphql": "*",

or choose a minium version.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not an expert here, who should we loop in on this?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

graphql is the base dependency which Relay relies on too. But as we are setting this as a peer dependency, we're less likely to have clashes.

src/core/attestation.ts Outdated Show resolved Hide resolved
schemaId: string;
timeCreated: number;
txid: string;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a line of comment for each property, so we know what they are used for.

export async function hasVerifiedAttestations(
chain: Chain,
address: Address,
expectedSchemas: AttestationSchema[] = [],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expectedSchemas sounds odd. What exactly are we passing here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see we have those 'VERIFIED ACCOUNT' | 'VERIFIED COUNTRY', not sure I follow.

Step 1, tell me the chain
Step 2, tell me an address, ok but who address? Customer address? unclear.
Step 3, tell me a schema, ok what schema? how do I know where those schemas are?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to be more opinionated on naming address? what if it is not a customer, it is something else to me. Might name like 'walletAddress'. But I assume that address in onchain app is clear.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

address is probably fine, but we need good example in the docs on how this works and how and when should be used.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think address is fine. Otherwise it would be target / recipient / subject, all of which may not convey the desired meaning.

export async function getAttestation<TChain extends Chain>(
address: Address,
chain: TChain,
filters?: { schemas?: AttestationSchema[] },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cbfyi curios, what other kind of filters we imagine to have later on?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess GraphQL filters maybe

      where: { AND: [conditions] },
      orderBy: [{ timeCreated: 'desc' }],
      distinct: ['schemaId', 'attester'],
      take: 10,

mmmm

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah perhaps we can drive this with use-cases:

  1. Gating: I want to know if someone has X, Y, Z attestation
  2. Display / Visual: I want to get all latest attestations to display, by attester and/or schema
  3. Additional Logic: I want to get a specific attestation to check its payload / contents

And for both (1), and (2), we would want to filter by only active by default. (3) doesn't even have to hit GraphQL, but if we want the payload / contents to be unpacked, it's more convenient if we do.

That should cover 70% of apps leveraging attestations IMO.

@alvaroraminelli
Copy link
Contributor Author

closing as going to break down in smaller PRs.

@Zizzamia Zizzamia deleted the alvaroraminelli/feat-attestation branch August 5, 2024 02:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants