generated from ethereum-optimism/scaffold-op
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updating ethers service, adding eas, adding worldcoin verification
- Loading branch information
Showing
14 changed files
with
901 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,69 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
import { AttestationService } from 'src/eas/attestation.service'; | ||
import { Web3Service } from 'src/web3/web3.service'; | ||
|
||
@Injectable() | ||
export class BotService { | ||
|
||
constructor( | ||
private readonly web3Service: Web3Service, | ||
private attestationService: AttestationService | ||
) {} | ||
|
||
async handleIssueClosed(id: string, name: string, body: any) { | ||
const issue = JSON.parse(JSON.stringify(body.issue)); | ||
const user = JSON.parse(JSON.stringify(issue.user)); | ||
const repository = JSON.parse(JSON.stringify(body.repository)); | ||
const issueId = issue.id; | ||
const repoId = repository.id; | ||
const contributorGithubId = user.id; | ||
const contributorAddress = '1234'; //get this from smart contract | ||
console.log(`issueID: ${issueId}, repoId: ${repoId}, | ||
contributorId: ${contributorGithubId}, contributorAddress: ${contributorAddress}`); | ||
this.web3Service.callDistribution(issueId, repoId, contributorGithubId, contributorAddress); | ||
try { | ||
//parsing data from github events | ||
const issue = JSON.parse(JSON.stringify(body.issue)); | ||
const user = JSON.parse(JSON.stringify(issue.user)); | ||
const repository = JSON.parse(JSON.stringify(body.repository)); | ||
const organisation = JSON.parse(JSON.stringify(body.organization)); | ||
const issueId = issue.id; | ||
const issueTitle = issue.title; | ||
const repoId = repository.id; | ||
const repoTitle = repository.name; | ||
const organisationName = organisation.login; | ||
const contributorGithubId = user.id; | ||
const contributorGithubUsername = user.login; | ||
const contributorGithubUrl = user.html_url; | ||
const issueUrl = issue.html_url; | ||
const githubRepositoryUrl = repository.html_url; | ||
const githubOrganisationUrl = organisation.url; | ||
const attestorName = 'Repo Rewards'; | ||
const achivement = `Successfully contributed to ${organisationName}'s open-source repo ${repoTitle} by creating and submitting a pull request, demonstrating collaborative software development skills and commitment to improving opensource codebases.`; | ||
|
||
// Fetching Contributor WalletAddress From Contract | ||
const contributorAddress = await this.web3Service.getUserWalletByUsername('optSepoliaNet', contributorGithubUsername); | ||
|
||
//logging for debug purpose | ||
console.log(` | ||
issueID: ${issueId}, | ||
issueTitle: ${issueTitle}, | ||
repoId: ${repoId}, | ||
repoTitle: ${repoTitle}, | ||
contributorId: ${contributorGithubId}, | ||
contributorAddress: ${contributorAddress}, | ||
contributorGithubUsername ${contributorGithubUsername}, | ||
organisationName: ${organisationName}` | ||
); | ||
|
||
console.log(` | ||
contributorGithubUrl: ${contributorGithubUrl}, | ||
issueUrl: ${issueUrl}, | ||
githubRepositoryUrl: ${githubRepositoryUrl}, | ||
githubOrganisationUrl: ${githubOrganisationUrl}` | ||
); | ||
|
||
// Distributing Reward on Contract | ||
await this.web3Service.distributeReward('optSepoliaNet', repoId, issueId, contributorAddress); | ||
|
||
//Attesting Open Source Contribution | ||
this.attestationService.createAttestation(contributorGithubId, contributorGithubUsername, | ||
issueId, issueTitle, repoId, repoTitle, organisationName, attestorName, achivement, | ||
contributorGithubUrl, issueUrl, githubRepositoryUrl, githubOrganisationUrl, contributorAddress | ||
); | ||
} catch(error) { | ||
console.error('BotService Error:', error); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
163 changes: 163 additions & 0 deletions
163
packages/github-bot-nestjs/src/eas/attestation.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
// attestation.service.ts | ||
import { Inject, Injectable } from '@nestjs/common'; | ||
import { EAS, SchemaEncoder } from "@ethereum-attestation-service/eas-sdk"; | ||
import { ethers } from 'ethers'; | ||
import { map, Observable } from 'rxjs'; | ||
import { ApolloClient, InMemoryCache, gql, HttpLink } from '@apollo/client/core'; | ||
import fetch from 'cross-fetch'; | ||
|
||
@Injectable() | ||
export class AttestationService { | ||
private eas: EAS; | ||
private signer: ethers.Wallet; | ||
private apolloClient: ApolloClient<any>; | ||
|
||
constructor( | ||
@Inject('Config') | ||
private readonly config: { | ||
apiKey: string; | ||
baseSepoliaNet: string; | ||
optSepoliaNet: string; | ||
privateKey: string | ||
}) { | ||
const EAS_CONTRACT_ADDRESS = "0x4200000000000000000000000000000000000021"; // OP Sepolia address | ||
const ALCHEMY_URL = `${this.config.optSepoliaNet}${this.config.apiKey}`; | ||
const provider = new ethers.JsonRpcProvider(ALCHEMY_URL); | ||
this.signer = new ethers.Wallet(this.config.privateKey, provider); | ||
this.eas = new EAS(EAS_CONTRACT_ADDRESS); | ||
this.eas.connect(this.signer); | ||
|
||
this.apolloClient = new ApolloClient({ | ||
link: new HttpLink({ uri: 'https://optimism-sepolia.easscan.org/graphql', fetch }), | ||
cache: new InMemoryCache(), | ||
}); | ||
} | ||
|
||
async createAttestation( | ||
contributorGithubId: string, | ||
contributorGithubUsername: string, | ||
issueId: string, | ||
issueTitle: string, | ||
repoId: string, | ||
repoTitle: string, | ||
organisationName: string, | ||
attestorName: string, | ||
achivement: string, | ||
contributorGithubUrl: string, | ||
issueUrl: string, | ||
githubRepositoryUrl: string, | ||
githubOrganisationUrl: string, | ||
contributorAddress: any | ||
) { | ||
try { | ||
const schemaUID = "0xb022941841c03fab69d4e4a55de2b8c9159ead78c7d6ee62b3f7e17d16e427f1"; | ||
const schemaEncoder = new SchemaEncoder("string Contributor_Github_Username,string Achievement,string Issue_Title,string Github_Repository,string Github_Organisation,string Attestor,string Contributor_Github_Url,string Issue_Url,string Github_Repository_Url,string Github_Organisation_Url,uint40 Contributor_Github_Id,uint40 Issue_Id,uint40 Github_Repository_Id"); | ||
const encodedData = schemaEncoder.encodeData([ | ||
{ name: "Contributor_Github_Username", value: contributorGithubUsername, type: "string" }, | ||
{ name: "Achievement", value: achivement, type: "string" }, | ||
{ name: "Issue_Title", value: issueTitle, type: "string" }, | ||
{ name: "Github_Repository", value: repoTitle, type: "string" }, | ||
{ name: "Github_Organisation", value: organisationName, type: "string" }, | ||
{ name: "Attestor", value: attestorName, type: "string" }, | ||
{ name: "Contributor_Github_Url", value: contributorGithubUrl, type: "string" }, | ||
{ name: "Issue_Url", value: issueUrl, type: "string" }, | ||
{ name: "Github_Repository_Url", value: githubRepositoryUrl, type: "string" }, | ||
{ name: "Github_Organisation_Url", value: githubOrganisationUrl, type: "string" }, | ||
{ name: "Contributor_Github_Id", value: Number(contributorGithubId), type: "uint40" }, | ||
{ name: "Issue_Id", value: Number(issueId), type: "uint40" }, | ||
{ name: "Github_Repository_Id", value: Number(repoId), type: "uint40" } | ||
]); | ||
|
||
const tx = await this.eas.attest({ | ||
schema: schemaUID, | ||
data: { | ||
recipient: contributorAddress, | ||
expirationTime: BigInt(0), | ||
revocable: true, | ||
data: encodedData, | ||
}, | ||
}); | ||
|
||
const newAttestationUID = await tx.wait(); | ||
console.log("New attestation UID:", newAttestationUID); | ||
} catch(error) { | ||
console.error('AttestationService Error: ', error); | ||
} | ||
} | ||
|
||
async getAttestationsByRecipient(recipientAddress: string): Promise<any> { | ||
const GET_ATTESTATIONS = gql` | ||
query AttestationsByRecipient($recipient: String!) { | ||
attestations( | ||
where: { recipient: { equals: $recipient }} | ||
orderBy: { time: desc } | ||
) { | ||
id | ||
attester | ||
recipient | ||
revocable | ||
data | ||
time | ||
decodedDataJson | ||
isOffchain | ||
schema { | ||
schema | ||
} | ||
} | ||
} | ||
`; | ||
|
||
try { | ||
const { data } = await this.apolloClient.query({ | ||
query: GET_ATTESTATIONS, | ||
variables: { | ||
recipient: recipientAddress, | ||
}, | ||
}); | ||
console.log(`Attestations found for Recipient: ${recipientAddress}, Total: `, data.attestations.length); | ||
return data.attestations; | ||
} catch (error) { | ||
console.error('AttestationService Error, error fetching attestations:', error); | ||
throw error; | ||
} | ||
} | ||
|
||
async getAttestationsByAttester(attesterAddress: string): Promise<any> { | ||
const GET_ATTESTATIONS_BY_ATTESTER = gql` | ||
query AttestationsByAttester($attester: String!) { | ||
attestations( | ||
where: { attester: { equals: $attester }} | ||
orderBy: { time: desc } | ||
take: 15 | ||
) { | ||
id | ||
attester | ||
recipient | ||
revocable | ||
data | ||
time | ||
decodedDataJson | ||
isOffchain | ||
schema { | ||
schema | ||
} | ||
} | ||
} | ||
`; | ||
|
||
try { | ||
const { data } = await this.apolloClient.query({ | ||
query: GET_ATTESTATIONS_BY_ATTESTER, | ||
variables: { | ||
attester: attesterAddress | ||
} | ||
}); | ||
console.log(`Attestations found for Attester: ${attesterAddress}, Total: `, data.attestations.length); | ||
return data.attestations; | ||
} catch (error) { | ||
console.error('Error fetching attestations by attester:', error); | ||
throw error; | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { AttestationService } from './attestation.service'; | ||
import { ConfigService } from '@nestjs/config'; | ||
|
||
@Module({ | ||
providers: [ | ||
{ | ||
provide: 'Config', | ||
useFactory: (configService: ConfigService) => { | ||
return { | ||
baseSepoliaNet: configService.get<string>('ALCHEMY_BASE_SEPOLIA_URL'), | ||
optSepoliaNet: configService.get<string>('ALCHEMY_OPT_SEPOLIA_URL'), | ||
apiKey: configService.get<string>('ALCHEMY_API_KEY'), | ||
privateKey: configService.get<string>('PRIVATE_KEY'), | ||
}; | ||
}, | ||
inject: [ConfigService], | ||
}, | ||
AttestationService], | ||
exports: [AttestationService] | ||
}) | ||
export class EasModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.