@graphprotocol/graph-cli 0.24.0 → 0.25.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/examples/basic-event-handlers/package.json +1 -1
  2. package/examples/basic-event-handlers/yarn.lock +4 -4
  3. package/examples/example-subgraph/package.json +1 -1
  4. package/examples/example-subgraph/yarn.lock +4 -4
  5. package/package.json +2 -2
  6. package/src/codegen/schema.js +9 -2
  7. package/src/codegen/types/defaults.js +34 -0
  8. package/src/codegen/types/index.js +8 -1
  9. package/src/command-helpers/scaffold.js +66 -0
  10. package/src/command-helpers/version.js +1 -1
  11. package/src/command-helpers/version.test.js +1 -1
  12. package/src/commands/init.js +129 -92
  13. package/src/commands/test.js +210 -27
  14. package/src/protocols/ethereum/contract.js +22 -0
  15. package/src/protocols/ethereum/scaffold/manifest.js +32 -0
  16. package/src/protocols/ethereum/scaffold/mapping.js +76 -0
  17. package/src/protocols/ethereum/subgraph.js +0 -14
  18. package/src/protocols/index.js +94 -12
  19. package/src/protocols/near/contract.js +46 -0
  20. package/src/protocols/near/scaffold/manifest.js +16 -0
  21. package/src/protocols/near/scaffold/mapping.js +39 -0
  22. package/src/protocols/near/subgraph.js +1 -23
  23. package/src/{scaffold.test.js → scaffold/ethereum.test.js} +27 -19
  24. package/src/scaffold/index.js +149 -0
  25. package/src/scaffold/mapping.js +49 -0
  26. package/src/scaffold/near.test.js +89 -0
  27. package/src/scaffold/schema.js +62 -0
  28. package/src/subgraph.js +8 -0
  29. package/src/validation/contract.js +56 -0
  30. package/src/validation/index.js +2 -1
  31. package/src/validation/manifest.js +0 -29
  32. package/tests/cli/init/{abis → ethereum/abis}/Marketplace.json +0 -0
  33. package/tests/cli/init/{abis → ethereum/abis}/OverloadedElements.json +0 -0
  34. package/tests/cli/init/{abis → ethereum/abis}/SoloMargin.json +0 -0
  35. package/tests/cli/init/{from-contract-with-abi-and-structs.stderr → ethereum/from-contract-with-abi-and-structs.stderr} +1 -1
  36. package/tests/cli/init/{from-contract-with-abi-and-structs.stdout → ethereum/from-contract-with-abi-and-structs.stdout} +0 -0
  37. package/tests/cli/init/{from-contract-with-abi.stderr → ethereum/from-contract-with-abi.stderr} +1 -1
  38. package/tests/cli/init/{from-contract-with-abi.stdout → ethereum/from-contract-with-abi.stdout} +0 -0
  39. package/tests/cli/init/{from-contract-with-overloaded-elements.stderr → ethereum/from-contract-with-overloaded-elements.stderr} +1 -1
  40. package/tests/cli/init/{from-contract-with-overloaded-elements.stdout → ethereum/from-contract-with-overloaded-elements.stdout} +0 -0
  41. package/tests/cli/init/{from-contract.stderr → ethereum/from-contract.stderr} +1 -1
  42. package/tests/cli/init/{from-contract.stdout → ethereum/from-contract.stdout} +0 -0
  43. package/tests/cli/init/{from-example.stderr → ethereum/from-example.stderr} +0 -0
  44. package/tests/cli/init/{from-example.stdout → ethereum/from-example.stdout} +0 -0
  45. package/tests/cli/init/near/from-contract.stderr +12 -0
  46. package/tests/cli/init/near/from-contract.stdout +12 -0
  47. package/tests/cli/init.test.js +143 -112
  48. package/tests/cli/util.js +56 -41
  49. package/tests/cli/validation/near-is-valid/subgraph.yaml +1 -0
  50. package/src/scaffold.js +0 -364
@@ -0,0 +1,39 @@
1
+ const generatePlaceholderHandlers = () =>
2
+ `
3
+ import { near, BigInt } from '@graphprotocol/graph-ts'
4
+ import { ExampleEntity } from '../generated/schema'
5
+
6
+ export function handleReceipt(receiptWithOutcome: near.ReceiptWithOutcome): void {
7
+ // Entities can be loaded from the store using a string ID; this ID
8
+ // needs to be unique across all entities of the same type
9
+ let entity = ExampleEntity.load(receiptWithOutcome.receipt.id.toHex())
10
+
11
+ // Entities only exist after they have been saved to the store;
12
+ // \`null\` checks allow to create entities on demand
13
+ if (!entity) {
14
+ entity = new ExampleEntity(receiptWithOutcome.receipt.id.toHex())
15
+
16
+ // Entity fields can be set using simple assignments
17
+ entity.count = BigInt.fromI32(0)
18
+ }
19
+
20
+ // BigInt and BigDecimal math are supported
21
+ entity.count = entity.count + BigInt.fromI32(1)
22
+
23
+ // Entity fields can be set based on receipt information
24
+ entity.block = receiptWithOutcome.block.header.hash
25
+
26
+ // Entities can be written to the store with \`.save()\`
27
+ entity.save()
28
+
29
+ // Note: If a handler doesn't require existing field values, it is faster
30
+ // _not_ to load the entity from the store. Instead, create it fresh with
31
+ // \`new Entity(...)\`, set the fields that should be updated and save the
32
+ // entity back to the store. Fields that were not set or unset remain
33
+ // unchanged, allowing for partial updates to be applied.
34
+ }
35
+ `
36
+
37
+ module.exports = {
38
+ generatePlaceholderHandlers,
39
+ }
@@ -1,5 +1,4 @@
1
1
  const immutable = require('immutable')
2
- const { validateContractValues } = require('../../validation')
3
2
 
4
3
  module.exports = class NearSubgraph {
5
4
  constructor(options = {}) {
@@ -9,28 +8,7 @@ module.exports = class NearSubgraph {
9
8
  }
10
9
 
11
10
  validateManifest() {
12
- return this.validateContractAccounts()
13
- }
14
-
15
- validateContractAccounts() {
16
- // Reference: https://docs.near.org/docs/concepts/account#account-id-rules
17
- const MINIMUM_ACCOUNT_ID_LENGTH = 2
18
- const MAXIMUM_ACCOUNT_ID_LENGTH = 64
19
- const validateLength = accountId =>
20
- accountId.length >= MINIMUM_ACCOUNT_ID_LENGTH &&
21
- accountId.length <= MAXIMUM_ACCOUNT_ID_LENGTH
22
- const nearAccountIdPattern = /^(([a-z\d]+[\-_])*[a-z\d]+\.)*([a-z\d]+[\-_])*[a-z\d]+$/
23
-
24
- return validateContractValues(
25
- this.manifest,
26
- this.protocol,
27
- 'account',
28
- accountId => validateLength(accountId) && nearAccountIdPattern.test(accountId),
29
- `Must be between '${MINIMUM_ACCOUNT_ID_LENGTH}' and '${MAXIMUM_ACCOUNT_ID_LENGTH}' characters
30
- An Account ID consists of Account ID parts separated by '.' (dots)
31
- Each Account ID part consists of lowercase alphanumeric symbols separated by either a '_' (underscore) or '-' (dash)
32
- For further information look for: https://docs.near.org/docs/concepts/account#account-id-rules`,
33
- )
11
+ return immutable.List()
34
12
  }
35
13
 
36
14
  handlerTypes() {
@@ -1,11 +1,7 @@
1
- const ABI = require('./protocols/ethereum/abi')
1
+ const ABI = require('../protocols/ethereum/abi')
2
2
  const immutable = require('immutable')
3
- const {
4
- generateEventFieldAssignments,
5
- generateManifest,
6
- generateMapping,
7
- generateSchema,
8
- } = require('./scaffold')
3
+ const Scaffold = require('./')
4
+ const Protocol = require('../protocols')
9
5
 
10
6
  const TEST_EVENT = {
11
7
  name: 'ExampleEvent',
@@ -73,21 +69,33 @@ const TEST_ABI = new ABI(
73
69
  ]),
74
70
  )
75
71
 
76
- describe('Subgraph scaffolding', () => {
72
+ const protocol = new Protocol('ethereum')
73
+
74
+ const scaffoldOptions = {
75
+ protocol,
76
+ abi: TEST_ABI,
77
+ contract: '0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d',
78
+ network: 'kovan',
79
+ contractName: 'Contract',
80
+ }
81
+
82
+ const scaffold = new Scaffold(scaffoldOptions)
83
+
84
+ const scaffoldWithIndexEvents = new Scaffold({
85
+ ...scaffoldOptions,
86
+ indexEvents: true,
87
+ })
88
+
89
+ describe('Ethereum subgraph scaffolding', () => {
77
90
  test('Manifest', () => {
78
91
  expect(
79
- generateManifest({
80
- abi: TEST_ABI,
81
- network: 'kovan',
82
- address: '0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d',
83
- contractName: 'Contract'
84
- }),
92
+ scaffold.generateManifest(),
85
93
  ).toEqual(`\
86
94
  specVersion: 0.0.1
87
95
  schema:
88
96
  file: ./schema.graphql
89
97
  dataSources:
90
- - kind: ethereum/contract
98
+ - kind: ethereum
91
99
  name: Contract
92
100
  network: kovan
93
101
  source:
@@ -113,7 +121,7 @@ dataSources:
113
121
  })
114
122
 
115
123
  test('Schema (default)', () => {
116
- expect(generateSchema({ abi: TEST_ABI })).toEqual(`\
124
+ expect(scaffold.generateSchema()).toEqual(`\
117
125
  type ExampleEntity @entity {
118
126
  id: ID!
119
127
  count: BigInt!
@@ -124,7 +132,7 @@ type ExampleEntity @entity {
124
132
  })
125
133
 
126
134
  test('Schema (for indexing events)', () => {
127
- expect(generateSchema({ abi: TEST_ABI, indexEvents: true })).toEqual(`\
135
+ expect(scaffoldWithIndexEvents.generateSchema()).toEqual(`\
128
136
  type ExampleEvent @entity {
129
137
  id: ID!
130
138
  a: BigInt! # uint256
@@ -147,7 +155,7 @@ type ExampleEvent1 @entity {
147
155
  })
148
156
 
149
157
  test('Mapping (default)', () => {
150
- expect(generateMapping({ abi: TEST_ABI, contractName: 'Contract' })).toEqual(`\
158
+ expect(scaffold.generateMapping()).toEqual(`\
151
159
  import { BigInt } from "@graphprotocol/graph-ts"
152
160
  import {
153
161
  Contract,
@@ -204,7 +212,7 @@ export function handleExampleEvent1(event: ExampleEvent1): void {}
204
212
  })
205
213
 
206
214
  test('Mapping (for indexing events)', () => {
207
- expect(generateMapping({ abi: TEST_ABI, indexEvents: true, contractName: 'Contract' })).toEqual(`\
215
+ expect(scaffoldWithIndexEvents.generateMapping()).toEqual(`\
208
216
  import {
209
217
  ExampleEvent as ExampleEventEvent,
210
218
  ExampleEvent1 as ExampleEvent1Event
@@ -0,0 +1,149 @@
1
+ const prettier = require('prettier')
2
+ const pkginfo = require('pkginfo')(module)
3
+
4
+ const GRAPH_CLI_VERSION = process.env.GRAPH_CLI_TESTS
5
+ // JSON.stringify should remove this key, we will install the local
6
+ // graph-cli for the tests using `npm link` instead of fetching from npm.
7
+ ? undefined
8
+ // For scaffolding real subgraphs
9
+ : `${module.exports.version}`
10
+
11
+ const {
12
+ abiEvents,
13
+ generateEventType,
14
+ generateExampleEntityType,
15
+ } = require('./schema')
16
+ const { generateEventIndexingHandlers } = require('./mapping')
17
+ const { getSubgraphBasename } = require('../command-helpers/subgraph')
18
+
19
+ module.exports = class Scaffold {
20
+ constructor(options = {}) {
21
+ this.protocol = options.protocol
22
+ this.abi = options.abi
23
+ this.indexEvents = options.indexEvents
24
+ this.contract = options.contract
25
+ this.network = options.network
26
+ this.contractName = options.contractName
27
+ this.subgraphName = options.subgraphName
28
+ this.node = options.node
29
+ }
30
+
31
+ generatePackageJson() {
32
+ return prettier.format(
33
+ JSON.stringify({
34
+ name: getSubgraphBasename(this.subgraphName),
35
+ license: 'UNLICENSED',
36
+ scripts: {
37
+ codegen: 'graph codegen',
38
+ build: 'graph build',
39
+ deploy:
40
+ `graph deploy ` +
41
+ `--node ${this.node} ` +
42
+ this.subgraphName,
43
+ 'create-local': `graph create --node http://localhost:8020/ ${this.subgraphName}`,
44
+ 'remove-local': `graph remove --node http://localhost:8020/ ${this.subgraphName}`,
45
+ 'deploy-local':
46
+ `graph deploy ` +
47
+ `--node http://localhost:8020/ ` +
48
+ `--ipfs http://localhost:5001 ` +
49
+ this.subgraphName,
50
+ },
51
+ dependencies: {
52
+ '@graphprotocol/graph-cli': GRAPH_CLI_VERSION,
53
+ '@graphprotocol/graph-ts': `0.24.1`,
54
+ },
55
+ }),
56
+ { parser: 'json' },
57
+ )
58
+ }
59
+
60
+ generateManifest() {
61
+ const protocolManifest = this.protocol.getManifestScaffold()
62
+
63
+ return prettier.format(`
64
+ specVersion: 0.0.1
65
+ schema:
66
+ file: ./schema.graphql
67
+ dataSources:
68
+ - kind: ${this.protocol.name}
69
+ name: ${this.contractName}
70
+ network: ${this.network}
71
+ source: ${protocolManifest.source(this)}
72
+ mapping: ${protocolManifest.mapping(this)}
73
+ `,
74
+ { parser: 'yaml' },
75
+ )
76
+ }
77
+
78
+ generateSchema() {
79
+ const hasEvents = this.protocol.hasEvents()
80
+ const events = hasEvents
81
+ ? abiEvents(this.abi).toJS()
82
+ : []
83
+
84
+ return prettier.format(
85
+ hasEvents && this.indexEvents
86
+ ? events.map(
87
+ event => generateEventType(event, this.protocol.name)
88
+ )
89
+ .join('\n\n')
90
+ : generateExampleEntityType(this.protocol, events),
91
+ {
92
+ parser: 'graphql',
93
+ },
94
+ )
95
+ }
96
+
97
+ generateTsConfig() {
98
+ return prettier.format(
99
+ JSON.stringify({
100
+ extends: '@graphprotocol/graph-ts/types/tsconfig.base.json',
101
+ include: ['src'],
102
+ }),
103
+ { parser: 'json' },
104
+ )
105
+ }
106
+
107
+ generateMapping() {
108
+ const hasEvents = this.protocol.hasEvents()
109
+ const events = hasEvents
110
+ ? abiEvents(this.abi).toJS()
111
+ : []
112
+
113
+ const protocolMapping = this.protocol.getMappingScaffold()
114
+
115
+ return prettier.format(
116
+ hasEvents && this.indexEvents
117
+ ? generateEventIndexingHandlers(
118
+ events,
119
+ this.contractName,
120
+ )
121
+ : protocolMapping.generatePlaceholderHandlers({
122
+ ...this,
123
+ events,
124
+ }),
125
+ { parser: 'typescript', semi: false },
126
+ )
127
+ }
128
+
129
+ generateABIs() {
130
+ return this.protocol.hasABIs()
131
+ ? {
132
+ [`${this.contractName}.json`]: prettier.format(JSON.stringify(this.abi.data), {
133
+ parser: 'json',
134
+ }),
135
+ }
136
+ : undefined
137
+ }
138
+
139
+ generate() {
140
+ return {
141
+ 'package.json': this.generatePackageJson(),
142
+ 'subgraph.yaml': this.generateManifest(),
143
+ 'schema.graphql': this.generateSchema(),
144
+ 'tsconfig.json': this.generateTsConfig(),
145
+ src: { 'mapping.ts': this.generateMapping() },
146
+ abis: this.generateABIs(),
147
+ }
148
+ }
149
+ }
@@ -0,0 +1,49 @@
1
+ const path = require('path')
2
+
3
+ const util = require('../codegen/util')
4
+
5
+ const generateFieldAssignment = path =>
6
+ `entity.${path.join('_')} = event.params.${path.join('.')}`
7
+
8
+ const generateFieldAssignments = ({ index, input }) =>
9
+ input.type === 'tuple'
10
+ ? util
11
+ .unrollTuple({ value: input, index, path: [input.name || `param${index}`] })
12
+ .map(({ path }) => generateFieldAssignment(path))
13
+ : generateFieldAssignment([input.name || `param${index}`])
14
+
15
+ const generateEventFieldAssignments = event =>
16
+ event.inputs.reduce(
17
+ (acc, input, index) => acc.concat(generateFieldAssignments({ input, index })),
18
+ [],
19
+ )
20
+
21
+ const generateEventIndexingHandlers = (events, contractName) =>
22
+ `
23
+ import { ${events.map(
24
+ event => `${event._alias} as ${event._alias}Event`,
25
+ )}} from '../generated/${contractName}/${contractName}'
26
+ import { ${events.map(event => event._alias)} } from '../generated/schema'
27
+
28
+ ${events
29
+ .map(
30
+ event =>
31
+ `
32
+ export function handle${event._alias}(event: ${event._alias}Event): void {
33
+ let entity = new ${
34
+ event._alias
35
+ }(event.transaction.hash.toHex() + '-' + event.logIndex.toString())
36
+ ${generateEventFieldAssignments(event).join('\n')}
37
+ entity.save()
38
+ }
39
+ `,
40
+ )
41
+ .join('\n')}
42
+ `
43
+
44
+ module.exports = {
45
+ generateFieldAssignment,
46
+ generateFieldAssignments,
47
+ generateEventFieldAssignments,
48
+ generateEventIndexingHandlers,
49
+ }
@@ -0,0 +1,89 @@
1
+ const immutable = require('immutable')
2
+ const Scaffold = require('./')
3
+ const Protocol = require('../protocols')
4
+
5
+ const protocol = new Protocol('near')
6
+
7
+ const scaffoldOptions = {
8
+ protocol,
9
+ contract: 'abc.def.near',
10
+ network: 'near-mainnet',
11
+ contractName: 'Contract',
12
+ }
13
+
14
+ const scaffold = new Scaffold(scaffoldOptions)
15
+
16
+ describe('NEAR subgraph scaffolding', () => {
17
+ test('Manifest', () => {
18
+ expect(
19
+ scaffold.generateManifest(),
20
+ ).toEqual(`\
21
+ specVersion: 0.0.1
22
+ schema:
23
+ file: ./schema.graphql
24
+ dataSources:
25
+ - kind: near
26
+ name: Contract
27
+ network: near-mainnet
28
+ source:
29
+ account: "abc.def.near"
30
+ mapping:
31
+ apiVersion: 0.0.5
32
+ language: wasm/assemblyscript
33
+ entities:
34
+ - ExampleEntity
35
+ receiptHandlers:
36
+ - handler: handleReceipt
37
+ file: ./src/mapping.ts
38
+ `)
39
+ })
40
+
41
+ test('Schema (default)', () => {
42
+ expect(scaffold.generateSchema()).toEqual(`\
43
+ type ExampleEntity @entity {
44
+ id: ID!
45
+ block: Bytes!
46
+ count: BigInt!
47
+ }
48
+ `)
49
+ })
50
+
51
+ test('Mapping (default)', () => {
52
+ expect(scaffold.generateMapping()).toEqual(`\
53
+ import { near, BigInt } from "@graphprotocol/graph-ts"
54
+ import { ExampleEntity } from "../generated/schema"
55
+
56
+ export function handleReceipt(
57
+ receiptWithOutcome: near.ReceiptWithOutcome
58
+ ): void {
59
+ // Entities can be loaded from the store using a string ID; this ID
60
+ // needs to be unique across all entities of the same type
61
+ let entity = ExampleEntity.load(receiptWithOutcome.receipt.id.toHex())
62
+
63
+ // Entities only exist after they have been saved to the store;
64
+ // \`null\` checks allow to create entities on demand
65
+ if (!entity) {
66
+ entity = new ExampleEntity(receiptWithOutcome.receipt.id.toHex())
67
+
68
+ // Entity fields can be set using simple assignments
69
+ entity.count = BigInt.fromI32(0)
70
+ }
71
+
72
+ // BigInt and BigDecimal math are supported
73
+ entity.count = entity.count + BigInt.fromI32(1)
74
+
75
+ // Entity fields can be set based on receipt information
76
+ entity.block = receiptWithOutcome.block.header.hash
77
+
78
+ // Entities can be written to the store with \`.save()\`
79
+ entity.save()
80
+
81
+ // Note: If a handler doesn't require existing field values, it is faster
82
+ // _not_ to load the entity from the store. Instead, create it fresh with
83
+ // \`new Entity(...)\`, set the fields that should be updated and save the
84
+ // entity back to the store. Fields that were not set or unset remain
85
+ // unchanged, allowing for partial updates to be applied.
86
+ }
87
+ `)
88
+ })
89
+ })
@@ -0,0 +1,62 @@
1
+ const { ascTypeForProtocol, valueTypeForAsc } = require('../codegen/types')
2
+ const util = require('../codegen/util')
3
+
4
+ const abiEvents = abi =>
5
+ util.disambiguateNames({
6
+ values: abi.data.filter(item => item.get('type') === 'event'),
7
+ getName: event => event.get('name'),
8
+ setName: (event, name) => event.set('_alias', name),
9
+ })
10
+
11
+ const protocolTypeToGraphQL = (protocol, name) => {
12
+ let ascType = ascTypeForProtocol(protocol, name)
13
+ return valueTypeForAsc(ascType)
14
+ }
15
+
16
+ const generateField = ({ name, type, protocolName }) =>
17
+ `${name}: ${protocolTypeToGraphQL(protocolName, type)}! # ${type}`
18
+
19
+ const generateEventFields = ({ index, input, protocolName }) =>
20
+ input.type == 'tuple'
21
+ ? util
22
+ .unrollTuple({ value: input, path: [input.name || `param${index}`], index })
23
+ .map(({ path, type }) => generateField({ name: path.join('_'), type, protocolName }))
24
+ : [generateField({ name: input.name || `param${index}`, type: input.type, protocolName })]
25
+
26
+ const generateEventType = (event, protocolName) => `type ${event._alias} @entity {
27
+ id: ID!
28
+ ${event.inputs
29
+ .reduce(
30
+ (acc, input, index) => acc.concat(generateEventFields({ input, index, protocolName })),
31
+ [],
32
+ )
33
+ .join('\n')}
34
+ }`
35
+
36
+ const generateExampleEntityType = (protocol, events) => {
37
+ if (protocol.hasABIs() && events.length > 0) {
38
+ return `type ExampleEntity @entity {
39
+ id: ID!
40
+ count: BigInt!
41
+ ${events[0].inputs
42
+ .reduce((acc, input, index) => acc.concat(generateEventFields({ input, index, protocolName: protocol.name })), [])
43
+ .slice(0, 2)
44
+ .join('\n')}
45
+ }`
46
+ } else {
47
+ return `type ExampleEntity @entity {
48
+ id: ID!
49
+ block: Bytes!
50
+ count: BigInt!
51
+ }`
52
+ }
53
+ }
54
+
55
+ module.exports = {
56
+ abiEvents,
57
+ protocolTypeToGraphQL,
58
+ generateField,
59
+ generateEventFields,
60
+ generateEventType,
61
+ generateExampleEntityType,
62
+ }
package/src/subgraph.js CHANGED
@@ -145,6 +145,13 @@ At least one such handler must be defined.`,
145
145
  }, immutable.List())
146
146
  }
147
147
 
148
+ static validateContractValues(manifest, protocol) {
149
+ return validation.validateContractValues(
150
+ manifest,
151
+ protocol,
152
+ )
153
+ }
154
+
148
155
  // Validate that data source names are unique, so they don't overwrite each other.
149
156
  static validateUniqueDataSourceNames(manifest) {
150
157
  let names = []
@@ -231,6 +238,7 @@ More than one template named '${name}', template names must be unique.`,
231
238
  ? immutable.List()
232
239
  : immutable.List.of(
233
240
  ...protocolSubgraph.validateManifest(),
241
+ ...Subgraph.validateContractValues(manifest, protocol),
234
242
  ...Subgraph.validateUniqueDataSourceNames(manifest),
235
243
  ...Subgraph.validateUniqueTemplateNames(manifest),
236
244
  ...Subgraph.validateHandlers(manifest, protocol, protocolSubgraph),
@@ -0,0 +1,56 @@
1
+ const immutable = require('immutable')
2
+
3
+ const validateContract = (value, ProtocolContract) => {
4
+ const contract = new ProtocolContract(value)
5
+
6
+ const { valid, error } = contract.validate()
7
+
8
+ if (!valid) {
9
+ return {
10
+ valid,
11
+ error: `Contract ${ProtocolContract.identifierName()} is invalid: ${value}\n${error}`,
12
+ }
13
+ }
14
+
15
+ return { valid, error }
16
+ }
17
+
18
+ const validateContractValues = (manifest, protocol) => {
19
+ const ProtocolContract = protocol.getContract()
20
+
21
+ const fieldName = ProtocolContract.identifierName()
22
+
23
+ return manifest
24
+ .get('dataSources')
25
+ .filter(dataSource => protocol.isValidKindName(dataSource.get('kind')))
26
+ .reduce((errors, dataSource, dataSourceIndex) => {
27
+ let path = ['dataSources', dataSourceIndex, 'source', fieldName]
28
+
29
+ // No need to validate if the source has no contract field
30
+ if (!dataSource.get('source').has(fieldName)) {
31
+ return errors
32
+ }
33
+
34
+ let contractValue = dataSource.getIn(['source', fieldName])
35
+
36
+
37
+ const { valid, error } = validateContract(contractValue, ProtocolContract)
38
+
39
+ // Validate whether the contract is valid for the protocol
40
+ if (valid) {
41
+ return errors
42
+ } else {
43
+ return errors.push(
44
+ immutable.fromJS({
45
+ path,
46
+ message: error,
47
+ }),
48
+ )
49
+ }
50
+ }, immutable.List())
51
+ }
52
+
53
+ module.exports = {
54
+ validateContract,
55
+ validateContractValues,
56
+ }
@@ -1,5 +1,6 @@
1
1
  module.exports = {
2
2
  validateSchema: require('./schema').validateSchema,
3
3
  validateManifest: require('./manifest').validateManifest,
4
- validateContractValues: require('./manifest').validateContractValues,
4
+ validateContractValues: require('./contract').validateContractValues,
5
+ validateContract: require('./contract').validateContract,
5
6
  }
@@ -282,35 +282,6 @@ const validateManifest = (value, type, schema, protocol, { resolveFile }) => {
282
282
  return validateDataSourceNetworks(value, protocol)
283
283
  }
284
284
 
285
- const validateContractValues = (manifest, protocol, fieldName, validator, errorMessage) =>
286
- manifest
287
- .get('dataSources')
288
- .filter(dataSource => protocol.isValidKindName(dataSource.get('kind')))
289
- .reduce((errors, dataSource, dataSourceIndex) => {
290
- let path = ['dataSources', dataSourceIndex, 'source', fieldName]
291
-
292
- // No need to validate if the source has no contract field
293
- if (!dataSource.get('source').has(fieldName)) {
294
- return errors
295
- }
296
-
297
- let contractValue = dataSource.getIn(['source', fieldName])
298
-
299
- // Validate whether the contract is valid
300
- if (validator(contractValue)) {
301
- return errors
302
- } else {
303
- return errors.push(
304
- immutable.fromJS({
305
- path,
306
- message: `\
307
- Contract ${fieldName} is invalid: ${contractValue}${errorMessage ? `\n${errorMessage}` : ''}`,
308
- }),
309
- )
310
- }
311
- }, immutable.List())
312
-
313
285
  module.exports = {
314
286
  validateManifest,
315
- validateContractValues,
316
287
  }
@@ -1,5 +1,5 @@
1
1
  - Create subgraph scaffold
2
- Generate subgraph from ABI
2
+ Generate subgraph
3
3
  - Create subgraph scaffold
4
4
  Write subgraph to directory
5
5
  - Create subgraph scaffold
@@ -1,5 +1,5 @@
1
1
  - Create subgraph scaffold
2
- Generate subgraph from ABI
2
+ Generate subgraph
3
3
  - Create subgraph scaffold
4
4
  Write subgraph to directory
5
5
  - Create subgraph scaffold
@@ -1,5 +1,5 @@
1
1
  - Create subgraph scaffold
2
- Generate subgraph from ABI
2
+ Generate subgraph
3
3
  - Create subgraph scaffold
4
4
  Write subgraph to directory
5
5
  - Create subgraph scaffold