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: As a user, I want the indexed objects to contain some "audit" data #568

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
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ dist
.pnp.*
lcov.info
pnpm-lock.yaml
.latest.json
14 changes: 11 additions & 3 deletions subgraph/.env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
DEPLOY_ENDPOINT_LINEA_GOERLI=
DEPLOY_ENDPOINT_LINEA_MAINNET=
DEPLOY_ENDPOINT_ARBITRUM_GOERLI=
DEPLOY_ENDPOINT_ARBITRUM_MAINNET=
DEPLOY_ENDPOINT_ARBITRUM_NOVA=
DEPLOY_ENDPOINT_ARBITRUM_SEPOLIA=
DEPLOY_ENDPOINT_LINEA_GOERLI=
DEPLOY_ENDPOINT_LINEA_MAINNET=

IPFS_ENDPOINT=
IPFS_IDENTIFIERS=
SUBGRAPH_NAME_ARBITRUM=

SUBGRAPH_NAME_ARBITRUM_GOERLI=
SUBGRAPH_NAME_ARBITRUM_MAINNET=
SUBGRAPH_NAME_ARBITRUM_NOVA=
SUBGRAPH_NAME_ARBITRUM_SEPOLIA=
SUBGRAPH_NAME_LINEA_GOERLI=
SUBGRAPH_NAME_LINEA_MAINNET=
9 changes: 6 additions & 3 deletions subgraph/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ This subgraph aims to index the data generated by the smart contracts of Verax.
Our subgraph is deployable on all the networks where Verax is deployed.
You can replace `XXX` by the name of the networks you want to work on in the commands below:

- `arbitrum-goerli`
- `arbitrum-mainnet`
- `arbitrum-nova`
- `arbitrum-sepolia`
- `linea-goerli`
- `linea-mainnet`
- `arbitrum-goerli`
- `arbitrum-one`

### 1. Add secrets

1. Copy the .env.example file to a .env file
2. Fill `DEPLOY_ENDPOINT_XXX` with the endpoint(s) dedicated to network(s) you want to work on
3. Fill `IPFS_ENDPOINT` with your IPFS endpoint (you can get one for free via Infura)
4. Fill `IPFS_IDENTIFIERS` with your IPFS identifiers (you can get them for free via Infura).
4. Fill `IPFS_IDENTIFIERS` with your IPFS identifiers (you can get them for free via Infura)
5. Fill `SUBGRAPH_NAME_XXX` with the name you want to give to the subgraph

Note: You need to encode your identifier and secret key to Base64, following this format: `IDENTIFIER:SECRET`.

Expand Down
26 changes: 26 additions & 0 deletions subgraph/abis/PortalRegistry.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,19 @@
"name": "PortalRegistered",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "portalAddress",
"type": "address"
}
],
"name": "PortalRevoked",
"type": "event"
},
{
"inputs": [
{
Expand Down Expand Up @@ -345,6 +358,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "id",
"type": "address"
}
],
"name": "revoke",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "router",
Expand Down
2 changes: 1 addition & 1 deletion subgraph/networks.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"startBlock": 1454671
}
},
"linea-mainnet": {
"linea": {
"AttestationRegistry": {
"address": "0x3de3893aa4Cdea029e84e75223a152FD08315138",
"startBlock": 346695
Expand Down
14 changes: 6 additions & 8 deletions subgraph/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"license": "MIT",
"author": "Consensys",
"scripts": {
"build:linea-mainnet": "cp subgraph.linea-mainnet.yaml subgraph.yaml && pnpm run codegen:linea-mainnet && graph build --network linea-mainnet",
"build:linea-mainnet": "cp subgraph.linea-mainnet.yaml subgraph.yaml && pnpm run codegen:linea-mainnet && graph build --network linea",
"build:linea-goerli": "cp subgraph.linea-goerli.yaml subgraph.yaml && pnpm run codegen:linea-goerli && graph build --network linea-goerli",
"build:arbitrum-goerli": "cp subgraph.arbitrum-goerli.yaml subgraph.yaml && pnpm run codegen:arbitrum-goerli && graph build --network arbitrum-goerli",
"build:arbitrum-sepolia": "cp subgraph.arbitrum-sepolia.yaml subgraph.yaml && pnpm run codegen:arbitrum-sepolia && graph build --network arbitrum-sepolia",
Expand All @@ -27,19 +27,17 @@
"codegen:arbitrum-sepolia": "cp subgraph.arbitrum-sepolia.yaml subgraph.yaml && graph codegen",
"codegen:arbitrum-mainnet": "cp subgraph.arbitrum-mainnet.yaml subgraph.yaml && graph codegen",
"codegen:arbitrum-nova": "cp subgraph.arbitrum-nova.yaml subgraph.yaml && graph codegen",
"create:linea-mainnet": "source .env && graph create --node $DEPLOY_ENDPOINT_LINEA_MAINNET Consensys/linea-attestation-registry",
"create:linea-goerli": "source .env && graph create --node $DEPLOY_ENDPOINT_LINEA_GOERLI Consensys/linea-attestation-registry",
"create:linea-mainnet": "source .env && graph create --node $DEPLOY_ENDPOINT_LINEA_MAINNET $SUBGRAPH_NAME_LINEA_MAINNET",
"create:linea-goerli": "source .env && graph create --node $DEPLOY_ENDPOINT_LINEA_GOERLI $SUBGRAPH_NAME_LINEA_GOERLI",
"create:arbitrum-goerli": "source .env && graph create --node $DEPLOY_ENDPOINT_ARBITRUM_GOERLI Consensys/verax-arbitrum-goerli",
"create:arbitrum-sepolia": "source .env && graph create --node $DEPLOY_ENDPOINT_ARBITRUM_SEPOLIA $SUBGRAPH_NAME_ARBITRUM_SEPOLIA",
"create:arbitrum-one": "source .env && graph create --node $DEPLOY_ENDPOINT_ARBITRUM_GOERLI Consensys/verax-arbitrum",
"deploy:linea-mainnet": "source .env && cp subgraph.linea-mainnet.yaml subgraph.yaml && pnpm run build:linea-mainnet && graph deploy --network linea-mainnet --node $DEPLOY_ENDPOINT_LINEA_MAINNET --headers \"{\\\"Authorization\\\": \\\"Basic $IPFS_IDENTIFIERS\\\"}\" --ipfs $IPFS_ENDPOINT --version-label v0.0.1 Consensys/linea-attestation-registry",
"deploy:linea-goerli": "source .env && cp subgraph.linea-goerli.yaml subgraph.yaml && pnpm run build:linea-goerli && graph deploy --network linea-goerli --node $DEPLOY_ENDPOINT_LINEA_GOERLI --headers \"{\\\"Authorization\\\": \\\"Basic $IPFS_IDENTIFIERS\\\"}\" --ipfs $IPFS_ENDPOINT --version-label v0.0.5 Consensys/linea-attestation-registry",
"deploy:arbitrum-goerli": "source .env && cp subgraph.arbitrum-goerli.yaml subgraph.yaml && pnpm run build:arbitrum-goerli && graph deploy --network arbitrum-goerli --node $DEPLOY_ENDPOINT_ARBITRUM_GOERLI --headers \"{\\\"Authorization\\\": \\\"Basic $IPFS_IDENTIFIERS\\\"}\" --ipfs $IPFS_ENDPOINT --version-label v0.0.5 Consensys/verax-arbitrum-goerli",
"deploy:linea-mainnet": "source .env && cp subgraph.linea-mainnet.yaml subgraph.yaml && graph deploy --studio $SUBGRAPH_NAME_LINEA_MAINNET",
"deploy:linea-goerli": "source .env && cp subgraph.linea-goerli.yaml subgraph.yaml && graph deploy --studio $SUBGRAPH_NAME_LINEA_GOERLI",
"deploy:arbitrum-goerli": "source .env && cp subgraph.arbitrum-goerli.yaml subgraph.yaml && graph deploy --network arbitrum-goerli --node $DEPLOY_ENDPOINT_ARBITRUM_GOERLI --headers \"{\\\"Authorization\\\": \\\"Basic $IPFS_IDENTIFIERS\\\"}\" --ipfs $IPFS_ENDPOINT --version-label v0.0.5 Consensys/verax-arbitrum-goerli",
"deploy:arbitrum-sepolia": "source .env && cp subgraph.arbitrum-sepolia.yaml subgraph.yaml && pnpm run build:arbitrum-sepolia && graph deploy --studio $SUBGRAPH_NAME_ARBITRUM_SEPOLIA",
"deploy:arbitrum-mainnet": "source .env && cp subgraph.arbitrum-mainnet.yaml subgraph.yaml && pnpm run build:arbitrum-mainnet && graph deploy --network arbitrum-mainnet --node $DEPLOY_ENDPOINT_ARBITRUM_MAINNET --headers \"{\\\"Authorization\\\": \\\"Basic $IPFS_IDENTIFIERS\\\"}\" --ipfs $IPFS_ENDPOINT --version-label v0.0.5 Consensys/verax-arbitrum",
"deploy:arbitrum-nova": "source .env && cp subgraph.arbitrum-nova.yaml subgraph.yaml && pnpm run build:arbitrum-nova && goldsky subgraph deploy 'verax-arbitrum-nova/0.0.5'",
"remove:linea-mainnet": "source .env && graph remove --node $DEPLOY_ENDPOINT_LINEA_MAINNET Consensys/linea-attestation-registry",
"remove:linea-goerli": "source .env && graph remove --node $DEPLOY_ENDPOINT_LINEA_GOERLI Consensys/linea-attestation-registry",
"test": "pnpm run codegen:linea-goerli && graph test",
"test:coverage": "graph test -c",
"test:docker": "graph test -d"
Expand Down
29 changes: 26 additions & 3 deletions subgraph/schema.graphql
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
type Attestation @entity {
id: ID!
schemaId: Bytes!
schema: Schema!
replacedBy: Bytes!
attester: Bytes!
portal: Bytes!
portal: Portal!
attestedDate: BigInt!
expirationDate: BigInt!
revocationDate: BigInt!
Expand All @@ -12,15 +12,16 @@ type Attestation @entity {
subject: Bytes!
encodedSubject: Bytes!
attestationData: Bytes!
schemaString: String
decodedData: [String!]
auditInformation: AuditInformation!
}

type Module @entity {
id: ID!
moduleAddress: Bytes!
name: String!
description: String!
auditInformation: AuditInformation!
}

type Portal @entity {
Expand All @@ -32,6 +33,7 @@ type Portal @entity {
description: String!
ownerName: String!
attestationCounter: Int
auditInformation: AuditInformation!
}

type Schema @entity {
Expand All @@ -41,6 +43,7 @@ type Schema @entity {
context: String!
schema: String!
attestationCounter: Int
auditInformation: AuditInformation!
}

type Counter @entity {
Expand All @@ -53,10 +56,30 @@ type Counter @entity {

type Issuer @entity {
id: ID!
auditInformation: AuditInformation!
}

type RegistryVersion @entity {
id: ID!
versionNumber: Int
timestamp: BigInt
auditInformation: AuditInformation!
}

type AuditInformation @entity {
id: ID!
creation: Audit!
lastModification: Audit!
modifications: [Audit!]!
}

type Audit @entity {
id: ID!
blockNumber: BigInt!
transactionHash: Bytes!
transactionTimestamp: BigInt!
fromAddress: Bytes!
toAddress: Bytes
valueTransferred: BigInt
gasPrice: BigInt
}
113 changes: 100 additions & 13 deletions subgraph/src/attestation-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,54 @@ import {
AttestationRevoked,
VersionUpdated,
} from "../generated/AttestationRegistry/AttestationRegistry";
import { Attestation, Counter, Portal, RegistryVersion, Schema } from "../generated/schema";
import { Attestation, Audit, AuditInformation, Counter, Portal, RegistryVersion, Schema } from "../generated/schema";
import { BigInt, ByteArray, Bytes, ethereum } from "@graphprotocol/graph-ts";

export function handleAttestationRegistered(event: AttestationRegisteredEvent): void {
const attestationRegistryContract = AttestationRegistry.bind(event.address);
const attestationData = attestationRegistryContract.getAttestation(event.params.attestationId);
const attestation = new Attestation(event.params.attestationId.toHex());
const attestation = new Attestation(event.params.attestationId.toHexString().toLowerCase());

incrementAttestationCount(attestationData.portal.toHexString(), attestationData.schemaId.toHex());
const audit = new Audit(event.transaction.hash.toHexString().toLowerCase());
audit.blockNumber = event.block.number;
audit.transactionHash = event.transaction.hash;
audit.transactionTimestamp = event.block.timestamp;
audit.fromAddress = event.transaction.from;
audit.toAddress = event.transaction.to;
audit.valueTransferred = event.transaction.value;
audit.gasPrice = event.transaction.gasPrice;

audit.save();

const auditInformation = new AuditInformation(attestation.id);
auditInformation.creation = audit.id.toLowerCase();
auditInformation.lastModification = audit.id.toLowerCase();
auditInformation.modifications = [audit.id.toLowerCase()];

auditInformation.save();

attestation.auditInformation = auditInformation.id.toLowerCase();

incrementAttestationCount(attestationData.portal.toHexString(), attestationData.schemaId.toHexString());

attestation.schemaId = attestationData.schemaId;
attestation.replacedBy = attestationData.replacedBy;
attestation.attester = attestationData.attester;
attestation.portal = attestationData.portal;
attestation.attestedDate = attestationData.attestedDate;
attestation.expirationDate = attestationData.expirationDate;
attestation.revocationDate = attestationData.revocationDate;
attestation.version = BigInt.fromI32(attestationData.version);
attestation.revoked = attestationData.revoked;
attestation.encodedSubject = attestationData.subject;
attestation.attestationData = attestationData.attestationData;
attestation.schema = attestationData.schemaId.toHexString().toLowerCase();
attestation.portal = attestationData.portal.toHexString().toLowerCase();

// If the subject looks like an encoded address, decode it to an address
const tempSubject = ethereum.decode("address", attestationData.subject);
attestation.subject = tempSubject ? tempSubject.toAddress() : attestationData.subject;

// Get matching Schema
const schema = Schema.load(attestationData.schemaId.toHex());
// Get matching Schemax
const schema = Schema.load(attestation.schema);

if (schema) {
// Split Schema into a "type fieldName" array
Expand All @@ -44,9 +64,6 @@ export function handleAttestationRegistered(event: AttestationRegisteredEvent):
// Join the types in a single coma-separated string
const schemaString = schemaTypes.toString();

// Add this Schema string to the Attestation Entity
attestation.schemaString = schemaString;

const encodedData = attestationData.attestationData;

// Initiate the decoded data in case it's not decoded at all
Expand Down Expand Up @@ -93,20 +110,64 @@ export function handleAttestationRegistered(event: AttestationRegisteredEvent):
export function handleAttestationRevoked(event: AttestationRevoked): void {
const attestationRegistryContract = AttestationRegistry.bind(event.address);
const attestationData = attestationRegistryContract.getAttestation(event.params.attestationId);
const attestation = Attestation.load(event.params.attestationId.toHex());
const attestation = Attestation.load(event.params.attestationId.toHexString().toLowerCase());

if (attestation) {
attestation.revoked = true;
attestation.revocationDate = attestationData.revocationDate;

const audit = new Audit(event.transaction.hash.toHexString().toLowerCase());
audit.blockNumber = event.block.number;
audit.transactionHash = event.transaction.hash;
audit.transactionTimestamp = event.block.timestamp;
audit.fromAddress = event.transaction.from;
audit.toAddress = event.transaction.to;
audit.valueTransferred = event.transaction.value;
audit.gasPrice = event.transaction.gasPrice;

audit.save();

const auditInformation = AuditInformation.load(attestation.id);
if (auditInformation !== null) {
auditInformation.lastModification = audit.id.toLowerCase();
auditInformation.modifications.push(audit.id.toLowerCase());

auditInformation.save();

attestation.auditInformation = auditInformation.id.toLowerCase();
}

attestation.save();
}
}

export function handleAttestationReplaced(event: AttestationReplaced): void {
const attestation = Attestation.load(event.params.attestationId.toHex());
const attestation = Attestation.load(event.params.attestationId.toHexString().toLowerCase());

if (attestation) {
attestation.replacedBy = event.params.replacedBy;

const audit = new Audit(event.transaction.hash.toHexString().toLowerCase());
audit.blockNumber = event.block.number;
audit.transactionHash = event.transaction.hash;
audit.transactionTimestamp = event.block.timestamp;
audit.fromAddress = event.transaction.from;
audit.toAddress = event.transaction.to;
audit.valueTransferred = event.transaction.value;
audit.gasPrice = event.transaction.gasPrice;

audit.save();

const auditInformation = AuditInformation.load(attestation.id);
if (auditInformation !== null) {
auditInformation.lastModification = audit.id.toLowerCase();
auditInformation.modifications.push(audit.id.toLowerCase());

auditInformation.save();

attestation.auditInformation = auditInformation.id.toLowerCase();
}

attestation.save();
}
}
Expand All @@ -118,6 +179,32 @@ export function handleVersionUpdated(event: VersionUpdated): void {
registryVersion = new RegistryVersion("registry-version");
}

const audit = new Audit(event.transaction.hash.toHexString().toLowerCase());
audit.blockNumber = event.block.number;
audit.transactionHash = event.transaction.hash;
audit.transactionTimestamp = event.block.timestamp;
audit.fromAddress = event.transaction.from;
audit.toAddress = event.transaction.to;
audit.valueTransferred = event.transaction.value;
audit.gasPrice = event.transaction.gasPrice;

audit.save();

let auditInformation = AuditInformation.load(registryVersion.id);
if (auditInformation === null) {
auditInformation = new AuditInformation(registryVersion.id);
auditInformation.creation = audit.id.toLowerCase();
auditInformation.lastModification = audit.id.toLowerCase();
auditInformation.modifications = [audit.id.toLowerCase()];
} else {
auditInformation.lastModification = audit.id.toLowerCase();
auditInformation.modifications.push(audit.id.toLowerCase());
}

auditInformation.save();

registryVersion.auditInformation = auditInformation.id.toLowerCase();

registryVersion.versionNumber = event.params.version;
registryVersion.timestamp = event.block.timestamp;

Expand All @@ -129,7 +216,7 @@ function valueToString(value: ethereum.Value): string {
case ethereum.ValueKind.ADDRESS:
return value.toAddress().toHexString();
case ethereum.ValueKind.FIXED_BYTES:
return value.toBytes().toHex();
return value.toBytes().toHexString().toLowerCase();
case ethereum.ValueKind.BYTES:
return value.toString();
case ethereum.ValueKind.INT:
Expand Down
Loading
Loading