Skip to content

Commit

Permalink
feat: As a user, I want the indexed objects to contain some "audit" data
Browse files Browse the repository at this point in the history
fix: All indexed objects should have lowercase IDs
  • Loading branch information
alainncls committed Apr 8, 2024
1 parent f2874e6 commit ed5654a
Show file tree
Hide file tree
Showing 19 changed files with 379 additions and 54 deletions.
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

0 comments on commit ed5654a

Please sign in to comment.