diff --git a/package.json b/package.json index 38701a1..a1d1671 100644 --- a/package.json +++ b/package.json @@ -4,18 +4,18 @@ "description": "Subgraph for Generalized TCR contracts", "scripts": { "fix-schema.ts": "replace-in-file '/(;\\s*if \\()value === null/mg' '$1value === null || value.kind === ValueKind.NULL' generated/schema.ts --isRegex", - "codegen:xdai": "node render-templates.js xdai && graph codegen && yarn fix-schema.ts", - "build:xdai": "yarn codegen:xdai && graph build", - "publish:xdai": "yarn build:xdai && graph deploy --product hosted-service kleros/legacy-curate-xdai", + "codegen:gnosis": "node render-templates.js gnosis && graph codegen && yarn fix-schema.ts", + "build:gnosis": "yarn codegen:gnosis && graph build", + "publish:gnosis": "yarn build:gnosis && graph deploy --studio legacy-curate-gnosis", "codegen:mainnet": "node render-templates.js mainnet && graph codegen && yarn fix-schema.ts", "build:mainnet": "yarn codegen:mainnet && graph build", - "publish:mainnet": "yarn build:mainnet && graph deploy --product hosted-service kleros/curate", + "publish:mainnet": "yarn build:mainnet && graph deploy --studio legacy-curate-mainnet", "codegen:goerli": "node render-templates.js goerli && graph codegen && yarn fix-schema.ts", "build:goerli": "yarn codegen:goerli && graph build", "publish:goerli": "yarn build:goerli && graph deploy --product hosted-service kleros/curate-goerli", "codegen:sepolia": "node render-templates.js sepolia && graph codegen && yarn fix-schema.ts", "build:sepolia": "yarn codegen:sepolia && graph build", - "publish:sepolia": "yarn build:sepolia && graph deploy --studio kleros/curate-sepolia", + "publish:sepolia": "yarn build:sepolia && graph deploy --studio legacy-curate-sepolia", "lint:eslint": "eslint . --ext .ts,.tsx", "lint:prettier": "prettier --config .prettierrc 'src/**/*.ts' --check", "lint": "yarn lint:eslint && yarn lint:prettier && yarn lint:secrets", @@ -61,6 +61,9 @@ "typescript": "^4.3.5", "wait-on": "^5.2.0" }, + "resolutions": { + "ejs": "^3.1.10" + }, "volta": { "node": "20.11.0", "yarn": "1.22.19" diff --git a/render-templates.js b/render-templates.js index 484f991..4ed4cd4 100644 --- a/render-templates.js +++ b/render-templates.js @@ -2,7 +2,7 @@ const fs = require('fs-extra'); const mustache = require('mustache'); const chainNameToChainId = { - xdai: 100, + gnosis: 100, mainnet: 1, goerli: 5, sepolia: 11155111, @@ -12,14 +12,10 @@ async function main() { const networkName = process.argv[2]; const chainId = chainNameToChainId[networkName]; const deployments = JSON.parse(fs.readFileSync('networks.json', 'utf8')); - const { - address: lgtcrFactoryAddr, - startBlock: lgtcrFactoryStartBlock, - } = deployments['LightGTCRFactory'][chainId]; - const { - address: gtcrFactoryAddr, - startBlock: gtcrFactoryStartBlock, - } = deployments['GTCRFactory'][chainId]; + const { address: lgtcrFactoryAddr, startBlock: lgtcrFactoryStartBlock } = + deployments['LightGTCRFactory'][chainId]; + const { address: gtcrFactoryAddr, startBlock: gtcrFactoryStartBlock } = + deployments['GTCRFactory'][chainId]; const templateData = { network: networkName, }; diff --git a/schema.graphql b/schema.graphql index fcc170f..64be599 100644 --- a/schema.graphql +++ b/schema.graphql @@ -57,7 +57,7 @@ type Evidence @entity { metadata: EvidenceMetadata } -type EvidenceMetadata @entity { +type EvidenceMetadata @entity(immutable: true) { id: ID! "Name of the evidence" name: String @@ -116,8 +116,24 @@ type LRegistry @entity { numberOfChallengedClearing: BigInt! "Connected TCR. Can be the 0 address. In practice, will never be null." connectedTCR: Bytes + metadata: LRegistryMetadata } +type LRegistryMetadata @entity { + id: ID! + title: String + description: String + itemName: String + itemNamePlural: String + isConnectedTCR: Boolean + requireRemovalEvidence: Boolean + isTCRofTcrs: Boolean + parentTCRAddress: String + relTcrDisabled: Boolean + registry: LRegistry @derivedFrom(field: "metadata") +} + + type MetaEvidence @entity { "The meta evidence ID." id: ID! @@ -155,8 +171,8 @@ type LItem @entity { metadata: LItemMetadata } -type LItemMetadata @entity { - "ipfs cid" +type LItemMetadata @entity(immutable: true) { + "ipfs cid - Litem ID" id: ID! "The parsed data describing the item." props: [ItemProp!]! @derivedFrom(field: "item") @@ -183,8 +199,14 @@ type _Schema_ algorithm: rank include: [{ entity: "LItemMetadata", fields: [{ name: "keywords" }] }] ) + @fulltext( + name: "registrySearch" + language: en + algorithm: rank + include: [{ entity: "LRegistryMetadata", fields: [{ name: "title" }, { name: "description" }, { name: "itemName" }] }] + ) -type ItemProp @entity { +type ItemProp @entity(immutable: true) { id: ID! type: String! label: String! diff --git a/src/GeneralizedTCRMapping.ts b/src/GeneralizedTCRMapping.ts index 637f66c..49e8a09 100644 --- a/src/GeneralizedTCRMapping.ts +++ b/src/GeneralizedTCRMapping.ts @@ -1,5 +1,11 @@ /* eslint-disable prefer-const */ -import { Bytes, BigInt, Address, log } from '@graphprotocol/graph-ts'; +import { + Bytes, + BigInt, + Address, + log, + DataSourceContext, +} from '@graphprotocol/graph-ts'; import { Item, Request, @@ -127,13 +133,15 @@ export function handleRequestSubmitted(event: RequestEvidenceGroupID): void { let requestID = graphItemID + '-' + itemInfo.value2.minus(BigInt.fromI32(1)).toString(); + let requestIndex = item.numberOfRequests.minus(BigInt.fromI32(1)); + let requestInfo = tcr.getRequestInfo(event.params._itemID, requestIndex); let request = new Request(requestID); request.disputed = false; request.arbitrator = tcr.arbitrator(); request.arbitratorExtraData = tcr.arbitratorExtraData(); request.challenger = ZERO_ADDRESS; - request.requester = event.transaction.from; + request.requester = requestInfo.value4[1]; request.item = item.id; request.registry = registry.id; request.registryAddress = event.address; @@ -257,16 +265,16 @@ export function handleRequestChallenged(event: Dispute): void { log.error(`Request of requestID {} not found.`, [requestID]); return; } + let requestInfo = tcr.getRequestInfo( + itemID, + itemInfo.value2.minus(BigInt.fromI32(1)), + ); request.disputed = true; - request.challenger = event.transaction.from; + request.challenger = requestInfo.value4[2]; request.numberOfRounds = BigInt.fromI32(2); request.disputeID = event.params._disputeID; - let requestInfo = tcr.getRequestInfo( - itemID, - itemInfo.value2.minus(BigInt.fromI32(1)), - ); let roundID = requestID + '-' + requestInfo.value5.minus(BigInt.fromI32(2)).toString(); let round = Round.load(roundID); @@ -612,8 +620,12 @@ export function handleEvidence(event: EvidenceEvent): void { ); const ipfsHash = extractPath(event.params._evidence); - evidence.metadata = ipfsHash; - EvidenceMetadataTemplate.create(ipfsHash); + evidence.metadata = `${ipfsHash}-${evidence.id}`; + + const context = new DataSourceContext(); + context.setString('evidenceId', evidence.id); + + EvidenceMetadataTemplate.createWithContext(ipfsHash, context); evidenceGroup.save(); evidence.save(); diff --git a/src/LightGeneralizedTCRMapping.ts b/src/LightGeneralizedTCRMapping.ts index 10cb155..96a7c9d 100644 --- a/src/LightGeneralizedTCRMapping.ts +++ b/src/LightGeneralizedTCRMapping.ts @@ -25,6 +25,7 @@ import { LIArbitrator as IArbitratorDataSourceTemplate, LGTCREvidence as EvidenceMetadataTemplate, LItemMetadata as LItemMetadataTemplate, + LRegistryMetadata as LRegistryMetadataTemplate, } from '../generated/templates'; import { Contribution, @@ -250,7 +251,9 @@ export function handleNewItem(event: NewItem): void { item.latestRequestSubmissionTime = BigInt.fromI32(0); const ipfsHash = extractPath(event.params._data); - item.metadata = ipfsHash; + item.metadata = `${ipfsHash}-${graphItemID}`; + + log.debug('Creating datasource for ipfs hash : {}', [ipfsHash]); const context = new DataSourceContext(); context.setString('graphItemID', graphItemID); @@ -298,6 +301,7 @@ export function handleRequestSubmitted(event: RequestSubmitted): void { let newStatus = getExtendedStatus(item.disputed, item.status); let requestIndex = item.numberOfRequests.minus(BigInt.fromI32(1)); + let requestInfo = tcr.getRequestInfo(event.params._itemID, requestIndex); let requestID = graphItemID + '-' + requestIndex.toString(); let request = new LRequest(requestID); @@ -305,7 +309,7 @@ export function handleRequestSubmitted(event: RequestSubmitted): void { request.arbitrator = tcr.arbitrator(); request.arbitratorExtraData = tcr.arbitratorExtraData(); request.challenger = ZERO_ADDRESS; - request.requester = event.transaction.from; + request.requester = requestInfo.value4[1]; request.item = item.id; request.registry = registry.id; request.registryAddress = event.address; @@ -446,6 +450,7 @@ export function handleRequestChallenged(event: Dispute): void { let newStatus = getExtendedStatus(item.disputed, item.status); let requestIndex = item.numberOfRequests.minus(BigInt.fromI32(1)); + let requestInfo = tcr.getRequestInfo(itemID, requestIndex); let requestID = graphItemID + '-' + requestIndex.toString(); let request = LRequest.load(requestID); if (!request) { @@ -454,7 +459,7 @@ export function handleRequestChallenged(event: Dispute): void { } request.disputed = true; - request.challenger = event.transaction.from; + request.challenger = requestInfo.value4[2]; request.numberOfRounds = BigInt.fromI32(2); request.disputeID = event.params._disputeID; @@ -790,6 +795,18 @@ export function handleMetaEvidence(event: MetaEvidenceEvent): void { } metaEvidence.URI = event.params._evidence; + + const ipfsHash = extractPath(event.params._evidence); + registry.metadata = `${ipfsHash}-${event.address.toHexString()}-${ + registry.metaEvidenceCount + }`; + + const context = new DataSourceContext(); + context.setString('address', event.address.toHexString()); + context.setBigInt('count', registry.metaEvidenceCount); + + LRegistryMetadataTemplate.createWithContext(ipfsHash, context); + metaEvidence.save(); if ( @@ -848,8 +865,11 @@ export function handleEvidence(event: EvidenceEvent): void { ); const ipfsHash = extractPath(event.params._evidence); - evidence.metadata = ipfsHash; - EvidenceMetadataTemplate.create(ipfsHash); + evidence.metadata = `${ipfsHash}-${evidence.id}`; + + const context = new DataSourceContext(); + context.setString('evidenceId', evidence.id); + EvidenceMetadataTemplate.createWithContext(ipfsHash, context); evidenceGroup.save(); evidence.save(); diff --git a/src/fileHandlers/EvidenceMetadataHandler.ts b/src/fileHandlers/EvidenceMetadataHandler.ts index b214adb..f2e005b 100644 --- a/src/fileHandlers/EvidenceMetadataHandler.ts +++ b/src/fileHandlers/EvidenceMetadataHandler.ts @@ -3,7 +3,11 @@ import { EvidenceMetadata } from '../../generated/schema'; export function handleGTCREvidenceMetadata(content: Bytes): void { const id = dataSource.stringParam(); - const evidence = new EvidenceMetadata(id); + + const context = dataSource.context(); + const evidenceId = context.getString('evidenceId'); + + const evidence = new EvidenceMetadata(`${id}-${evidenceId}`); const value = json.fromBytes(content).toObject(); log.debug(`ipfs hash : {}, content : {}`, [id, content.toString()]); diff --git a/src/fileHandlers/LEvidenceMetadataHandler.ts b/src/fileHandlers/LEvidenceMetadataHandler.ts index 77ad980..c41e782 100644 --- a/src/fileHandlers/LEvidenceMetadataHandler.ts +++ b/src/fileHandlers/LEvidenceMetadataHandler.ts @@ -3,7 +3,10 @@ import { EvidenceMetadata } from '../../generated/schema'; export function handleLGTCREvidenceMetadata(content: Bytes): void { const id = dataSource.stringParam(); - const evidence = new EvidenceMetadata(id); + const context = dataSource.context(); + const evidenceId = context.getString('evidenceId'); + + const evidence = new EvidenceMetadata(`${id}-${evidenceId}`); const value = json.fromBytes(content).toObject(); log.debug(`ipfs hash : {}, content : {}`, [id, content.toString()]); diff --git a/src/fileHandlers/LItemMetadataHandler.ts b/src/fileHandlers/LItemMetadataHandler.ts index 449240f..f432baa 100644 --- a/src/fileHandlers/LItemMetadataHandler.ts +++ b/src/fileHandlers/LItemMetadataHandler.ts @@ -3,18 +3,21 @@ import { ItemProp, LItemMetadata } from '../../generated/schema'; import { JSONValueToBool, JSONValueToMaybeString } from '../utils'; export function handleLItemMetadata(content: Bytes): void { - const id = dataSource.stringParam(); - const metadata = new LItemMetadata(id); + const ipfsHash = dataSource.stringParam(); const value = json.fromBytes(content).toObject(); - const context = dataSource.context(); + const context = dataSource.context(); const graphItemID = context.getString('graphItemID'); const address = context.getString('address'); + const id = `${ipfsHash}-${graphItemID}`; + + const metadata = new LItemMetadata(id); + metadata.keywords = address; - log.debug(`ipfs hash : {}, content : {}`, [id, content.toString()]); + log.debug(`ipfs hash : {}, content : {}`, [ipfsHash, content.toString()]); if (!value) { log.warning(`Error converting object for graphItemId {}`, [graphItemID]); diff --git a/src/fileHandlers/LRegistryMetadataHandler.ts b/src/fileHandlers/LRegistryMetadataHandler.ts new file mode 100644 index 0000000..4719540 --- /dev/null +++ b/src/fileHandlers/LRegistryMetadataHandler.ts @@ -0,0 +1,56 @@ +import { Bytes, dataSource, json, log } from '@graphprotocol/graph-ts'; +import { LRegistryMetadata } from '../../generated/schema'; +import { JSONValueToBool, JSONValueToMaybeString } from '../utils'; + +export function handleLRegistryMetadata(content: Bytes): void { + const ipfsHash = dataSource.stringParam(); + + const value = json.fromBytes(content).toObject(); + + const context = dataSource.context(); + const count = context.getBigInt('count'); + const address = context.getString('address'); + + const id = `${ipfsHash}-${address}-${count.toString()}`; + + const metadata = new LRegistryMetadata(id); + + log.debug(`ipfs hash : {}, content : {}`, [ipfsHash, content.toString()]); + + if (!value) { + log.warning(`Error converting object for hash {}`, [ipfsHash]); + metadata.save(); + return; + } + + const metadataValue = value.get('metadata'); + if (!metadataValue) { + log.error(`Error getting metadata values from ipfs hash {}`, [ipfsHash]); + metadata.save(); + return; + } + + const data = metadataValue.toObject(); + + const title = data.get('tcrTitle'); + const description = data.get('tcrDescription'); + const itemName = data.get('itemName'); + const itemNamePlural = data.get('itemNamePlural'); + const isConnectedTCR = data.get('isConnectedTCR'); + const requireRemovalEvidence = data.get('requireRemovalEvidence'); + const isTCRofTcrs = data.get('isTCRofTcrs'); + const parentTCRAddress = data.get('parentTCRAddress'); + const relTcrDisabled = data.get('relTcrDisabled'); + + metadata.title = JSONValueToMaybeString(title); + metadata.description = JSONValueToMaybeString(description); + metadata.itemName = JSONValueToMaybeString(itemName); + metadata.parentTCRAddress = JSONValueToMaybeString(parentTCRAddress); + metadata.itemNamePlural = JSONValueToMaybeString(itemNamePlural); + metadata.isConnectedTCR = JSONValueToBool(isConnectedTCR); + metadata.requireRemovalEvidence = JSONValueToBool(requireRemovalEvidence); + metadata.isTCRofTcrs = JSONValueToBool(isTCRofTcrs); + metadata.relTcrDisabled = JSONValueToBool(relTcrDisabled); + + metadata.save(); +} diff --git a/subgraph.template.yaml b/subgraph.template.yaml index a4ccbf2..9a0c28d 100644 --- a/subgraph.template.yaml +++ b/subgraph.template.yaml @@ -1,4 +1,4 @@ -specVersion: 0.0.4 +specVersion: 1.0.0 description: Generalized TCR features: - fullTextSearch @@ -220,6 +220,18 @@ templates: entities: - LItemMetadata - ItemProp + abis: + - name: LightGeneralizedTCR + file: ./abis/LightGeneralizedTCR.json + - name: LRegistryMetadata + kind: file/ipfs + mapping: + apiVersion: 0.0.7 + language: wasm/assemblyscript + file: ./src/fileHandlers/LRegistryMetadataHandler.ts + handler: handleLRegistryMetadata + entities: + - LRegistryMetadata abis: - name: LightGeneralizedTCR file: ./abis/LightGeneralizedTCR.json \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 2247e97..e5b0964 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3232,17 +3232,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -ejs@3.1.8: - version "3.1.8" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b" - integrity sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ== - dependencies: - jake "^10.8.5" - -ejs@^3.1.8: - version "3.1.9" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" - integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ== +ejs@3.1.8, ejs@^3.1.10, ejs@^3.1.8: + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== dependencies: jake "^10.8.5"