diff --git a/.github/workflows/subgraph.yml b/.github/workflows/subgraph.yml new file mode 100644 index 00000000..3ea20e8c --- /dev/null +++ b/.github/workflows/subgraph.yml @@ -0,0 +1,64 @@ +name: Subgraph + +on: + pull_request: + branches: + - main + - dev + - release/* + push: + branches: + - main + - dev + - release/* + +jobs: + test: + runs-on: ubuntu-latest + + defaults: + run: + working-directory: subgraph + + steps: + - name: Check out the repo + uses: actions/checkout@v3 + + - name: Install Pnpm + uses: pnpm/action-setup@v2 + with: + version: 8 + run_install: false + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: pnpm + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build the subgraph + run: pnpm run build:goerli + + - name: Run the unit tests + run: pnpm run test + + - name: Add test summary + run: | + echo "## Unit tests result" >> $GITHUB_STEP_SUMMARY + echo "✅ Passed" >> $GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore index 157884c0..e235ddc9 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,8 @@ typechain-types build generated subgraph.yaml +.bin +.latest.json # Misc .DS_Store diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 79428e9c..2e8026a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -140,11 +140,17 @@ importers: subgraph: devDependencies: '@graphprotocol/graph-cli': - specifier: 0.58.0 - version: 0.58.0(@types/node@20.8.0)(node-fetch@3.3.2)(typescript@5.2.2) + specifier: 0.59.0 + version: 0.59.0(@types/node@20.8.0)(node-fetch@3.3.2)(typescript@5.2.2) '@graphprotocol/graph-ts': - specifier: 0.31.0 - version: 0.31.0 + specifier: 0.30.0 + version: 0.30.0 + assemblyscript: + specifier: 0.19.10 + version: 0.19.10 + matchstick-as: + specifier: 0.5.2 + version: 0.5.2 packages: @@ -2256,8 +2262,8 @@ packages: tslib: 2.6.2 dev: false - /@graphprotocol/graph-cli@0.58.0(@types/node@20.8.0)(node-fetch@3.3.2)(typescript@5.2.2): - resolution: {integrity: sha512-EbdL5LZFmIMAuItQXv7LXgd7cqYQ3BdIJR2jxNr+LRL0juBAxmEz6zVvYnIUmgXoa5SB5rxE9ZT6pfe+fhbD6Q==} + /@graphprotocol/graph-cli@0.59.0(@types/node@20.8.0)(node-fetch@3.3.2)(typescript@5.2.2): + resolution: {integrity: sha512-uddsyUootdhQgMqQXkrD0INn/nNkQB+3t5luRzjY0pxA4O9hidXjYZNScjvSgf3eiaN0rcEs/s56qa/dsy4LwA==} engines: {node: '>=14'} hasBin: true dependencies: @@ -2301,8 +2307,8 @@ packages: - utf-8-validate dev: true - /@graphprotocol/graph-ts@0.31.0: - resolution: {integrity: sha512-xreRVM6ho2BtolyOh2flDkNoGZximybnzUnF53zJVp0+Ed0KnAlO1/KOCUYw06euVI9tk0c9nA2Z/D5SIQV2Rg==} + /@graphprotocol/graph-ts@0.30.0: + resolution: {integrity: sha512-h5tJqlsZXglGYM0PcBsBOqof4PT0Fr4Z3QBTYN/IjMF3VvRX2A8/bdpqaAnva+2N0uAfXXwRcwcOcW5O35yzXw==} dependencies: assemblyscript: 0.19.10 dev: true @@ -5211,7 +5217,7 @@ packages: /@types/cli-progress@3.11.2: resolution: {integrity: sha512-Yt/8rEJalfa9ve2SbfQnwFHrc9QF52JIZYHW3FDaTMpkCvnns26ueKiPHDxyJ0CS//IqjMINTx7R5Xa7k7uFHQ==} dependencies: - '@types/node': 20.5.7 + '@types/node': 20.8.0 dev: true /@types/concat-stream@1.6.1: @@ -5223,7 +5229,7 @@ packages: /@types/connect@3.4.36: resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==} dependencies: - '@types/node': 20.5.7 + '@types/node': 20.8.0 dev: true /@types/form-data@0.0.33: @@ -5352,7 +5358,7 @@ packages: /@types/ws@7.4.7: resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} dependencies: - '@types/node': 20.5.7 + '@types/node': 20.8.0 dev: true /@types/ws@8.5.6: @@ -8283,7 +8289,7 @@ packages: /fs-jetpack@4.3.1: resolution: {integrity: sha512-dbeOK84F6BiQzk2yqqCVwCPWTxAvVGJ3fMQc6E2wuEohS28mR6yHngbrKuVCK1KHRx/ccByDylqu4H5PCP2urQ==} dependencies: - minimatch: 3.1.2 + minimatch: 9.0.3 rimraf: 2.7.1 dev: true @@ -9614,7 +9620,7 @@ packages: resolution: {integrity: sha512-Ch2Dzhw4URfB9L/0ZHyY+uqOnKvBNeS/SMcRiPmJfpHiM0TsUZn+GkpcZxAoF3dJVdPm/PuIk3A4wlV7SUo23Q==} dependencies: '@types/minimatch': 3.0.5 - minimatch: 3.1.2 + minimatch: 9.0.3 dev: true /it-last@1.0.6: @@ -10622,6 +10628,12 @@ packages: resolution: {integrity: sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==} dev: true + /matchstick-as@0.5.2: + resolution: {integrity: sha512-fb1OVphDKEvJY06Ue02Eh1CNncuW95vp6b8tNAP7UIqplICSLoU/zgN6U7ge7R0upsoO78C7CRi4EyK/7Jxz7g==} + dependencies: + wabt: 1.0.24 + dev: true + /mcl-wasm@0.7.9: resolution: {integrity: sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==} engines: {node: '>=8.9.0'} @@ -13758,6 +13770,11 @@ packages: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} dev: false + /wabt@1.0.24: + resolution: {integrity: sha512-8l7sIOd3i5GWfTWciPL0+ff/FK/deVK2Q6FN+MPz4vfUcD78i2M/49XJTwF6aml91uIiuXJEsLKWMB2cw/mtKg==} + hasBin: true + dev: true + /walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} dependencies: diff --git a/subgraph/package.json b/subgraph/package.json index 0b35af66..502e6710 100644 --- a/subgraph/package.json +++ b/subgraph/package.json @@ -24,10 +24,13 @@ "deploy": "source .env && cp subgraph.mainnet.yaml subgraph.yaml && pnpm run build && graph deploy --network linea-mainnet --node $DEPLOY_ENDPOINT_MAINNET --headers \"{\\\"Authorization\\\": \\\"Basic $IPFS_IDENTIFIERS\\\"}\" --ipfs $IPFS_ENDPOINT --version-label v0.0.1 Consensys/linea-attestation-registry", "deploy:goerli": "source .env && cp subgraph.goerli.yaml subgraph.yaml && pnpm run build:goerli && graph deploy --network linea-goerli --node $DEPLOY_ENDPOINT_GOERLI --headers \"{\\\"Authorization\\\": \\\"Basic $IPFS_IDENTIFIERS\\\"}\" --ipfs $IPFS_ENDPOINT --version-label v0.0.5 Consensys/linea-attestation-registry", "remove": "source .env && graph remove --node $DEPLOY_ENDPOINT_MAINNET Consensys/linea-attestation-registry", - "remove:goerli": "source .env && graph remove --node $DEPLOY_ENDPOINT_GOERLI Consensys/linea-attestation-registry" + "remove:goerli": "source .env && graph remove --node $DEPLOY_ENDPOINT_GOERLI Consensys/linea-attestation-registry", + "test": "graph test -v 0.5.2" }, "devDependencies": { - "@graphprotocol/graph-cli": "0.58.0", - "@graphprotocol/graph-ts": "0.31.0" + "@graphprotocol/graph-cli": "0.59.0", + "@graphprotocol/graph-ts": "0.30.0", + "matchstick-as": "0.5.2", + "assemblyscript": "0.19.10" } } diff --git a/subgraph/src/module-registry.ts b/subgraph/src/module-registry.ts index 2b87823b..612dd9f6 100644 --- a/subgraph/src/module-registry.ts +++ b/subgraph/src/module-registry.ts @@ -1,16 +1,14 @@ -import { ModuleRegistered as ModuleRegisteredEvent, ModuleRegistry } from "../generated/ModuleRegistry/ModuleRegistry"; +import { ModuleRegistered as ModuleRegisteredEvent } from "../generated/ModuleRegistry/ModuleRegistry"; import { Counter, Module } from "../generated/schema"; export function handleModuleRegistered(event: ModuleRegisteredEvent): void { - const contract = ModuleRegistry.bind(event.address); - const moduleData = contract.modules(event.params.moduleAddress); - const module = new Module(event.params.moduleAddress.toHex()); + const module = new Module(event.params.moduleAddress.toHexString()); incrementModulesCount(); - module.moduleAddress = moduleData.getModuleAddress(); - module.name = moduleData.getName(); - module.description = moduleData.getDescription(); + module.moduleAddress = event.params.moduleAddress; + module.name = event.params.name; + module.description = event.params.description; module.save(); } diff --git a/subgraph/src/schema-registry.ts b/subgraph/src/schema-registry.ts index 816e5e6a..373fcaf5 100644 --- a/subgraph/src/schema-registry.ts +++ b/subgraph/src/schema-registry.ts @@ -1,17 +1,15 @@ -import { SchemaCreated as SchemaCreatedEvent, SchemaRegistry } from "../generated/SchemaRegistry/SchemaRegistry"; +import { SchemaCreated as SchemaCreatedEvent } from "../generated/SchemaRegistry/SchemaRegistry"; import { Counter, Schema } from "../generated/schema"; export function handleSchemaCreated(event: SchemaCreatedEvent): void { - const contract = SchemaRegistry.bind(event.address); - const schemaData = contract.getSchema(event.params.id); - const schema = new Schema(event.params.id.toHex()); + const schema = new Schema(event.params.id.toString()); incrementSchemasCount(); - schema.name = schemaData.name; - schema.description = schemaData.description; - schema.context = schemaData.context; - schema.schema = schemaData.schema; + schema.name = event.params.name; + schema.description = event.params.description; + schema.context = event.params.context; + schema.schema = event.params.schemaString; schema.save(); } diff --git a/subgraph/tests/module-registry.test.ts b/subgraph/tests/module-registry.test.ts new file mode 100644 index 00000000..e788bec8 --- /dev/null +++ b/subgraph/tests/module-registry.test.ts @@ -0,0 +1,51 @@ +import { afterEach, assert, clearStore, describe, log, test } from "matchstick-as"; +import { + ModuleRegistered as ModuleRegisteredEvent, + ModuleRegistered, +} from "../generated/ModuleRegistry/ModuleRegistry"; +import { Address, ethereum } from "@graphprotocol/graph-ts"; +import { newTypedMockEvent } from "matchstick-as/assembly/defaults"; +import { handleModuleRegistered } from "../src/module-registry"; + +describe("handleModuleRegistered()", () => { + const moduleAddress = "0xF75BE6f9418710fd516fA82Afb3AAD07e11a0f1b"; + const moduleName = "module name"; + const moduleDescription = "module description"; + + afterEach(() => { + clearStore(); + }); + + test("Should create a new Module entity", () => { + assert.entityCount("Module", 0); + + const moduleRegisteredEvent = createModuleRegisteredEvent(moduleAddress, moduleName, moduleDescription); + + handleModuleRegistered(moduleRegisteredEvent); + + assert.entityCount("Module", 1); + + assert.fieldEquals("Module", moduleAddress, "id", moduleAddress); + assert.fieldEquals("Module", moduleAddress, "name", moduleName); + assert.fieldEquals("Module", moduleAddress, "description", moduleDescription); + assert.fieldEquals("Module", moduleAddress, "moduleAddress", moduleAddress); + }); +}); + +function createModuleRegisteredEvent( + moduleAddress: string, + moduleName: string, + moduleDescription: string, +): ModuleRegistered { + const moduleRegisteredEvent = newTypedMockEvent(); + + moduleRegisteredEvent.parameters.push( + new ethereum.EventParam("moduleAddress", ethereum.Value.fromAddress(Address.fromString(moduleAddress))), + ); + moduleRegisteredEvent.parameters.push(new ethereum.EventParam("moduleName", ethereum.Value.fromString(moduleName))); + moduleRegisteredEvent.parameters.push( + new ethereum.EventParam("moduleDescription", ethereum.Value.fromString(moduleDescription)), + ); + + return moduleRegisteredEvent; +} diff --git a/subgraph/tests/schema-registry.test.ts b/subgraph/tests/schema-registry.test.ts new file mode 100644 index 00000000..e7b28ee4 --- /dev/null +++ b/subgraph/tests/schema-registry.test.ts @@ -0,0 +1,61 @@ +import { afterEach, assert, clearStore, describe, test } from "matchstick-as"; +import { BigInt, ethereum } from "@graphprotocol/graph-ts"; +import { newTypedMockEvent } from "matchstick-as/assembly/defaults"; +import { handleSchemaCreated } from "../src/schema-registry"; +import { SchemaCreated, SchemaCreated as SchemaCreatedEvent } from "../generated/SchemaRegistry/SchemaRegistry"; + +describe("handleSchemaCreated()", () => { + const schemaId = "0x7930a5ebfabdd4ef76bbb8cdcbc2225b6256d9511d9cf5ff0d6514c1bdb4d7dc"; + const schemaName = "module name"; + const schemaDescription = "module description"; + const schemaContext = "schema context"; + const schemaString = "(bool isBuilder)"; + + afterEach(() => { + clearStore(); + }); + + test("Should create a new Schema entity", () => { + assert.entityCount("Schema", 0); + + const schemaCreatedEvent = createSchemaCreatedEvent( + schemaId, + schemaName, + schemaDescription, + schemaContext, + schemaString, + ); + + handleSchemaCreated(schemaCreatedEvent); + + assert.entityCount("Schema", 1); + + assert.fieldEquals("Schema", schemaId, "id", schemaId); + assert.fieldEquals("Schema", schemaId, "name", schemaName); + assert.fieldEquals("Schema", schemaId, "description", schemaDescription); + assert.fieldEquals("Schema", schemaId, "context", schemaContext); + assert.fieldEquals("Schema", schemaId, "schema", schemaString); + }); +}); + +function createSchemaCreatedEvent( + schemaId: string, + schemaName: string, + schemaDescription: string, + schemaContext: string, + schemaString: string, +): SchemaCreated { + const schemaCreatedEvent = newTypedMockEvent(); + + schemaCreatedEvent.parameters.push( + new ethereum.EventParam("id", ethereum.Value.fromI32(BigInt.fromString(schemaId).toI32())), + ); + schemaCreatedEvent.parameters.push(new ethereum.EventParam("name", ethereum.Value.fromString(schemaName))); + schemaCreatedEvent.parameters.push( + new ethereum.EventParam("description", ethereum.Value.fromString(schemaDescription)), + ); + schemaCreatedEvent.parameters.push(new ethereum.EventParam("context", ethereum.Value.fromString(schemaContext))); + schemaCreatedEvent.parameters.push(new ethereum.EventParam("schemaString", ethereum.Value.fromString(schemaString))); + + return schemaCreatedEvent; +} diff --git a/subgraph/tsconfig.json b/subgraph/tsconfig.json index a6d2ae82..4e866720 100644 --- a/subgraph/tsconfig.json +++ b/subgraph/tsconfig.json @@ -1,3 +1,4 @@ { - "extends": "@graphprotocol/graph-ts/types/tsconfig.base.json" + "extends": "@graphprotocol/graph-ts/types/tsconfig.base.json", + "include": ["src", "tests"] }