From a20ec8bb226b1b450ce0b521144136fffe5003cb Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Fri, 28 Apr 2023 12:22:51 -0300 Subject: [PATCH] feat: subgraph updated handlers (#235) * feat: add verifier when contract is initialized * feat: initialize git repository on new mint * feat: add created at in token entity * feat: add created at in ap entity * feat: handle verifier role grant and revoke * feat: add verified field to token * refactor: create constants file * feat: add total tokens counter on collection entity * refactor: verify verifier address for mint event * refactor: remove collection id --- subgraph/schema.graphql | 14 ++++-- subgraph/src/access-control.ts | 88 +++++++++++++++++++-------------- subgraph/src/access-point.ts | 1 + subgraph/src/constants.ts | 8 +++ subgraph/src/contract.ts | 13 ++++- subgraph/src/metadata-update.ts | 4 +- subgraph/src/mint.ts | 40 +++++++++++++-- subgraph/yarn.lock | 23 +-------- 8 files changed, 123 insertions(+), 68 deletions(-) create mode 100644 subgraph/src/constants.ts diff --git a/subgraph/schema.graphql b/subgraph/schema.graphql index 11292c6..5b5b28f 100644 --- a/subgraph/schema.graphql +++ b/subgraph/schema.graphql @@ -31,7 +31,7 @@ type NewMint @entity(immutable: true) { color: Int! accessPointAutoApproval: Boolean! triggeredBy: Bytes! # address - owner: Owner! # address + owner: Owner! # address verifier: Bytes! blockNumber: BigInt! blockTimestamp: BigInt! @@ -79,7 +79,9 @@ type Token @entity { gitRepository: GitRepository! commitHash: String! accessPoints: [AccessPoint!] @derivedFrom(field: "token") - verifier: Verifier! # Address + verifier: Verifier # Address + verified: Boolean! + createdAt: BigInt! } # Owner entity for collection, access points, and tokens @@ -115,4 +117,10 @@ type AccessPoint @entity { nameVerified: Boolean! owner: Owner! creationStatus: String! -} \ No newline at end of file + createdAt: BigInt! +} + +type Collection @entity { + id: Bytes! + totalTokens: BigInt! +} diff --git a/subgraph/src/access-control.ts b/subgraph/src/access-control.ts index d482072..f41256e 100644 --- a/subgraph/src/access-control.ts +++ b/subgraph/src/access-control.ts @@ -1,4 +1,4 @@ -import { Bytes, log } from '@graphprotocol/graph-ts'; +import { Bytes, log, store } from '@graphprotocol/graph-ts'; // Event Imports [based on the yaml config] import { @@ -7,15 +7,8 @@ import { } from '../generated/FleekNFA/FleekNFA'; // Entity Imports [based on the schema] -import { Owner, Token } from '../generated/schema'; - -enum CollectionRoles { - Owner, -} - -enum TokenRoles { - Controller, -} +import { Owner, Token, Verifier } from '../generated/schema'; +import { CollectionRoles, TokenRoles } from './constants'; export function handleCollectionRoleChanged( event: CollectionRoleChangedEvent @@ -25,35 +18,56 @@ export function handleCollectionRoleChanged( const role = event.params.role; const status = event.params.status; - if (role === CollectionRoles.Owner) { - // Owner role - if (status) { - // granted - let owner = Owner.load(toAddress); - if (!owner) { - owner = new Owner(toAddress); + switch (role) { + case CollectionRoles.Owner: + // Owner role + if (status) { + // granted + let owner = Owner.load(toAddress); + if (!owner) { + owner = new Owner(toAddress); + } + owner.collection = true; + owner.save(); + } else { + // revoked + const owner = Owner.load(toAddress); + if (!owner) { + log.error( + 'Owner entity not found. Role: {}, byAddress: {}, toAddress: {}', + [role.toString(), byAddress.toHexString(), toAddress.toHexString()] + ); + return; + } + owner.collection = false; + owner.save(); } - owner.collection = true; - owner.save(); - } else { - // revoked - const owner = Owner.load(toAddress); - if (!owner) { - log.error( - 'Owner entity not found. Role: {}, byAddress: {}, toAddress: {}', - [role.toString(), byAddress.toHexString(), toAddress.toHexString()] - ); - return; + break; + + case CollectionRoles.Verifier: + // Verifier role + if (status) { + // granted + let verifier = Verifier.load(toAddress); + if (!verifier) { + verifier = new Verifier(toAddress); + } + verifier.save(); + } else { + // revoked + const verifier = Verifier.load(toAddress); + if (verifier) { + store.remove('Verifier', verifier.id.toString()); + } } - owner.collection = false; - owner.save(); - } - } else { - log.error('Role not supported. Role: {}, byAddress: {}, toAddress: {}', [ - role.toString(), - byAddress.toHexString(), - toAddress.toHexString(), - ]); + + break; + default: + log.error('Role not supported. Role: {}, byAddress: {}, toAddress: {}', [ + role.toString(), + byAddress.toHexString(), + toAddress.toHexString(), + ]); } } diff --git a/subgraph/src/access-point.ts b/subgraph/src/access-point.ts index f3f074b..5e0aa65 100644 --- a/subgraph/src/access-point.ts +++ b/subgraph/src/access-point.ts @@ -29,6 +29,7 @@ export function handleNewAccessPoint(event: NewAccessPointEvent): void { accessPointEntity.token = Bytes.fromByteArray( Bytes.fromBigInt(event.params.tokenId) ); + accessPointEntity.createdAt = event.block.timestamp; // Load / Create an Owner entity let ownerEntity = Owner.load(event.params.owner); diff --git a/subgraph/src/constants.ts b/subgraph/src/constants.ts new file mode 100644 index 0000000..c2d272c --- /dev/null +++ b/subgraph/src/constants.ts @@ -0,0 +1,8 @@ +export enum CollectionRoles { + Owner, + Verifier, +} + +export enum TokenRoles { + Controller, +} diff --git a/subgraph/src/contract.ts b/subgraph/src/contract.ts index 1b6d918..0162ee9 100644 --- a/subgraph/src/contract.ts +++ b/subgraph/src/contract.ts @@ -1,10 +1,10 @@ -import { log, ethereum } from '@graphprotocol/graph-ts'; +import { log, ethereum, BigInt } from '@graphprotocol/graph-ts'; // Event Imports [based on the yaml config] import { Initialized as InitializedEvent } from '../generated/FleekNFA/FleekNFA'; // Entity Imports [based on the schema] -import { Owner } from '../generated/schema'; +import { Collection, Owner, Verifier } from '../generated/schema'; export function handleInitialized(event: InitializedEvent): void { // This is the contract creation transaction. log.warning('This is the contract creation transaction.', []); @@ -14,9 +14,18 @@ export function handleInitialized(event: InitializedEvent): void { receipt.contractAddress.toHexString(), ]); + // start collection entity + const collection = new Collection(event.address.toHexString()); + collection.totalTokens = BigInt.fromU32(0); + collection.save(); + // add owner const owner = new Owner(event.transaction.from); owner.collection = true; owner.save(); + + // add verifier + const verifier = new Verifier(event.transaction.from); + verifier.save(); } } diff --git a/subgraph/src/metadata-update.ts b/subgraph/src/metadata-update.ts index 449e2c1..4d1ebaf 100644 --- a/subgraph/src/metadata-update.ts +++ b/subgraph/src/metadata-update.ts @@ -2,7 +2,6 @@ import { Bytes } from '@graphprotocol/graph-ts'; // Event Imports [based on the yaml config] import { - MetadataUpdate as MetadataUpdateEvent, MetadataUpdate1 as MetadataUpdateEvent1, MetadataUpdate2 as MetadataUpdateEvent2, MetadataUpdate3 as MetadataUpdateEvent3, @@ -159,6 +158,9 @@ export function handleMetadataUpdateWithBooleanValue( if (event.params.key == 'accessPointAutoApproval') { token.accessPointAutoApproval = event.params.value; } + if (event.params.key == 'verified') { + token.verified = event.params.value; + } token.save(); } } diff --git a/subgraph/src/mint.ts b/subgraph/src/mint.ts index a0b24d1..64e1a77 100644 --- a/subgraph/src/mint.ts +++ b/subgraph/src/mint.ts @@ -1,10 +1,17 @@ -import { Bytes, log } from '@graphprotocol/graph-ts'; +import { BigInt, Bytes, log } from '@graphprotocol/graph-ts'; // Event Imports [based on the yaml config] import { NewMint as NewMintEvent } from '../generated/FleekNFA/FleekNFA'; // Entity Imports [based on the schema] -import { Owner, NewMint, Token } from '../generated/schema'; +import { + Owner, + NewMint, + Token, + GitRepository, + Collection, + Verifier, +} from '../generated/schema'; export function handleNewMint(event: NewMintEvent): void { const newMintEntity = new NewMint( @@ -67,14 +74,41 @@ export function handleNewMint(event: NewMintEvent): void { token.color = color; token.accessPointAutoApproval = accessPointAutoApproval; token.owner = ownerAddress; - token.verifier = verifierAddress; + token.verified = false; token.mintTransaction = event.transaction.hash.concatI32( event.logIndex.toI32() ); token.mintedBy = event.params.minter; token.controllers = [ownerAddress]; + token.createdAt = event.block.timestamp; + + if (Verifier.load(verifierAddress)) { + token.verifier = verifierAddress; + } + + // Populate GitRepository entity + let repository = GitRepository.load(gitRepository); + if (!repository) { + repository = new GitRepository(gitRepository); + } + + let repositoryTokens = repository.tokens; + if (repositoryTokens === null) { + repositoryTokens = [token.id]; + } else { + repositoryTokens.push(token.id); + } + repository.tokens = repositoryTokens; + + // Increase total tokens counter + const collection = Collection.load(event.address.toHexString()); + if (collection) { + collection.totalTokens = collection.totalTokens.plus(BigInt.fromU32(1)); + collection.save(); + } // Save entities owner.save(); token.save(); + repository.save(); } diff --git a/subgraph/yarn.lock b/subgraph/yarn.lock index b0f6dd6..e14c5dd 100644 --- a/subgraph/yarn.lock +++ b/subgraph/yarn.lock @@ -256,13 +256,6 @@ dependencies: assemblyscript "0.19.10" -"@graphprotocol/graph-ts@^0.27.0": - version "0.27.0" - resolved "https://registry.yarnpkg.com/@graphprotocol/graph-ts/-/graph-ts-0.27.0.tgz#948fe1716f6082964a01a63a19bcbf9ac44e06ff" - integrity sha512-r1SPDIZVQiGMxcY8rhFSM0y7d/xAbQf5vHMWUf59js1KgoyWpM6P3tczZqmQd7JTmeyNsDGIPzd9FeaxllsU4w== - dependencies: - assemblyscript "0.19.10" - "@rescript/std@9.0.0": version "9.0.0" resolved "https://registry.yarnpkg.com/@rescript/std/-/std-9.0.0.tgz#df53f3fa5911cb4e85bd66b92e9e58ddf3e4a7e1" @@ -496,7 +489,7 @@ assemblyscript@0.19.10: binaryen "101.0.0-nightly.20210723" long "^4.0.0" -assemblyscript@0.19.23, assemblyscript@^0.19.20: +assemblyscript@0.19.23: version "0.19.23" resolved "https://registry.yarnpkg.com/assemblyscript/-/assemblyscript-0.19.23.tgz#16ece69f7f302161e2e736a0f6a474e6db72134c" integrity sha512-fwOQNZVTMga5KRsfY80g7cpOl4PsFQczMwHzdtgoqLXaYhkhavufKb0sB0l3T1DUxpAufA0KNhlbpuuhZUwxMA== @@ -2227,15 +2220,6 @@ mafmt@^7.0.0: dependencies: multiaddr "^7.3.0" -matchstick-as@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/matchstick-as/-/matchstick-as-0.5.0.tgz#cdafc1ef49d670b9cbe98e933bc2a5cb7c450aeb" - integrity sha512-4K619YDH+so129qt4RB4JCNxaFwJJYLXPc7drpG+/mIj86Cfzg6FKs/bA91cnajmS1CLHdhHl9vt6Kd6Oqvfkg== - dependencies: - "@graphprotocol/graph-ts" "^0.27.0" - assemblyscript "^0.19.20" - wabt "1.0.24" - md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -3399,11 +3383,6 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -wabt@1.0.24: - version "1.0.24" - resolved "https://registry.yarnpkg.com/wabt/-/wabt-1.0.24.tgz#c02e0b5b4503b94feaf4a30a426ef01c1bea7c6c" - integrity sha512-8l7sIOd3i5GWfTWciPL0+ff/FK/deVK2Q6FN+MPz4vfUcD78i2M/49XJTwF6aml91uIiuXJEsLKWMB2cw/mtKg== - wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"