@graphprotocol/graph-cli 0.26.0 → 0.27.1

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 (42) hide show
  1. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/ethereum.ts +1 -1
  2. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/tendermint.ts +554 -0
  3. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/collections.ts +52 -2
  4. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/numbers.ts +11 -0
  5. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/value.ts +47 -0
  6. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/global/global.ts +150 -1
  7. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/index.ts +2 -0
  8. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/package.json +2 -1
  9. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/test/test.js +2 -0
  10. package/examples/basic-event-handlers/node_modules/keccak/build/Makefile +1 -1
  11. package/examples/basic-event-handlers/node_modules/keccak/build/Release/.deps/Release/obj.target/keccak/src/addon.o.d.raw +16 -16
  12. package/examples/basic-event-handlers/node_modules/keccak/build/config.gypi +4 -4
  13. package/examples/basic-event-handlers/node_modules/keccak/build/keccak.target.mk +14 -14
  14. package/examples/basic-event-handlers/node_modules/websocket/build/Makefile +1 -1
  15. package/examples/basic-event-handlers/node_modules/websocket/build/Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d.raw +16 -16
  16. package/examples/basic-event-handlers/node_modules/websocket/build/bufferutil.target.mk +14 -14
  17. package/examples/basic-event-handlers/node_modules/websocket/build/config.gypi +1 -1
  18. package/examples/basic-event-handlers/node_modules/websocket/build/validation.target.mk +14 -14
  19. package/examples/basic-event-handlers/package.json +4 -4
  20. package/examples/basic-event-handlers/yarn.lock +8 -8
  21. package/package.json +27 -24
  22. package/src/codegen/schema.js +5 -46
  23. package/src/codegen/schema.test.js +0 -6
  24. package/src/codegen/types/conversions.js +19 -19
  25. package/src/codegen/types/index.js +0 -25
  26. package/src/codegen/types/index.test.js +0 -22
  27. package/src/commands/deploy.js +3 -1
  28. package/src/commands/init.js +2 -0
  29. package/src/commands/test.js +82 -59
  30. package/src/protocols/ethereum/codegen/abi.js +72 -2
  31. package/src/protocols/ethereum/manifest.graphql +92 -0
  32. package/src/protocols/index.js +17 -7
  33. package/src/protocols/near/manifest.graphql +57 -0
  34. package/src/subgraph.js +18 -13
  35. package/src/validation/manifest.js +12 -8
  36. package/tests/cli/validation/example-values-found.stderr +2 -2
  37. package/tests/cli/validation/invalid-manifest/subgraph.yaml +2 -1
  38. package/tests/cli/validation/invalid-manifest-cannot-infer-protocol/subgraph.yaml +12 -0
  39. package/tests/cli/validation/invalid-manifest-cannot-infer-protocol.stderr +5 -0
  40. package/tests/cli/validation/invalid-manifest.stderr +0 -3
  41. package/tests/cli/validation.test.js +8 -0
  42. package/manifest-schema.graphql +0 -122
@@ -1,16 +1,22 @@
1
1
  const immutable = require('immutable')
2
+ const fs = require('fs')
3
+ const yaml = require('yaml')
4
+ const request = require('sync-request')
5
+ const Web3EthAbi = require('web3-eth-abi');
2
6
 
3
7
  const tsCodegen = require('../../../codegen/typescript')
4
8
  const typesCodegen = require('../../../codegen/types')
5
9
  const util = require('../../../codegen/util')
6
10
 
11
+ const doFixtureCodegen = fs.existsSync('./fixtures.yaml');
12
+
7
13
  module.exports = class AbiCodeGenerator {
8
14
  constructor(abi) {
9
15
  this.abi = abi
10
16
  }
11
17
 
12
18
  generateModuleImports() {
13
- return [
19
+ let imports = [
14
20
  tsCodegen.moduleImports(
15
21
  [
16
22
  // Ethereum integration
@@ -27,8 +33,21 @@ module.exports = class AbiCodeGenerator {
27
33
  'BigInt',
28
34
  ],
29
35
  '@graphprotocol/graph-ts',
30
- ),
36
+ )
31
37
  ]
38
+
39
+ if (doFixtureCodegen) {
40
+ imports.push(
41
+ tsCodegen.moduleImports(
42
+ [
43
+ 'newMockEvent',
44
+ ],
45
+ 'matchstick-as/assembly/index',
46
+ )
47
+ )
48
+ }
49
+
50
+ return imports
32
51
  }
33
52
 
34
53
  generateTypes() {
@@ -182,6 +201,7 @@ module.exports = class AbiCodeGenerator {
182
201
  setName: (input, name) => input.set('name', name),
183
202
  })
184
203
 
204
+ let namesAndTypes = []
185
205
  inputs.forEach((input, index) => {
186
206
  // Generate getters and classes for event params
187
207
  let paramObject = this._generateInputOrOutput(
@@ -192,6 +212,11 @@ module.exports = class AbiCodeGenerator {
192
212
  `parameters`,
193
213
  )
194
214
  paramsClass.addMethod(paramObject.getter)
215
+ let ethType = typesCodegen.ethereumTypeForAsc(paramObject.getter.returnType)
216
+ if (typeof ethType === typeof {} && (ethType.test("int256") || ethType.test("uint256"))) {
217
+ ethType = "int32"
218
+ }
219
+ namesAndTypes.push({name: paramObject.getter.name.slice(4), type: ethType})
195
220
  tupleClasses.push(...paramObject.classes)
196
221
  })
197
222
 
@@ -208,6 +233,51 @@ module.exports = class AbiCodeGenerator {
208
233
  `return new ${paramsClassName}(this)`,
209
234
  ),
210
235
  )
236
+
237
+ // Fixture generation
238
+ if (doFixtureCodegen) {
239
+ const args = yaml.parse(fs.readFileSync('./fixtures.yaml', 'utf8'))
240
+ const blockNumber = args['blockNumber']
241
+ const contractAddr = args['contractAddr']
242
+ const topic0 = args['topic0']
243
+ const apiKey = args['apiKey']
244
+ const url = `https://api.etherscan.io/api?module=logs&action=getLogs&fromBlock=${blockNumber}&toBlock=${blockNumber}&address=${contractAddr}&${topic0}=topic0&apikey=${apiKey}`;
245
+
246
+ let resp = request("GET", url)
247
+ let body = JSON.parse(resp.getBody("utf8"))
248
+ if (body.status === '0') {
249
+ throw new Error(body.result)
250
+ }
251
+
252
+ let res = Web3EthAbi.decodeLog(
253
+ namesAndTypes,
254
+ body.result[0].data,
255
+ []
256
+ );
257
+
258
+ let stmnts = ""
259
+ for (let i = 0; i < namesAndTypes.length; i++) {
260
+ let code = '"' + res[i] + '"'
261
+ if (namesAndTypes[i].type.toString() == "address") {
262
+ code = `Address.fromString(${code})`
263
+ }
264
+ stmnts = stmnts.concat(`event.parameters.push(new ethereum.EventParam(\"${namesAndTypes[i].name}\", ${typesCodegen.ethereumFromAsc(code, namesAndTypes[i].type)}));`, `\n`)
265
+ }
266
+
267
+ klass.addMethod(
268
+ tsCodegen.staticMethod(
269
+ `mock${eventClassName}`,
270
+ [],
271
+ tsCodegen.namedType(eventClassName),
272
+ `
273
+ let event = changetype<${eventClassName}>(newMockEvent());
274
+ ${stmnts}
275
+ return event;
276
+ `,
277
+ )
278
+ )
279
+ }
280
+
211
281
  return [klass, paramsClass, ...tupleClasses]
212
282
  })
213
283
 
@@ -0,0 +1,92 @@
1
+ # Each referenced type's in any of the types below must be listed
2
+ # here either as `scalar` or `type` for the validation code to work
3
+ # properly.
4
+ #
5
+ # That's why `String` is listed as a scalar even though it's built-in
6
+ # GraphQL basic types.
7
+ scalar String
8
+ scalar File
9
+ scalar BigInt
10
+
11
+ type SubgraphManifest {
12
+ specVersion: String!
13
+ features: [String!]
14
+ schema: Schema!
15
+ description: String
16
+ repository: String
17
+ graft: Graft
18
+ dataSources: [DataSource!]!
19
+ templates: [DataSourceTemplate!]
20
+ }
21
+
22
+ type Schema {
23
+ file: File!
24
+ }
25
+
26
+ type DataSource {
27
+ kind: String!
28
+ name: String!
29
+ network: String
30
+ source: ContractSource!
31
+ mapping: ContractMapping!
32
+ }
33
+
34
+ type ContractSource {
35
+ address: String
36
+ abi: String!
37
+ startBlock: BigInt
38
+ }
39
+
40
+ type ContractMapping {
41
+ kind: String
42
+ apiVersion: String!
43
+ language: String!
44
+ file: File!
45
+ entities: [String!]!
46
+ abis: [ContractAbi!]!
47
+ blockHandlers: [BlockHandler!]
48
+ callHandlers: [CallHandler!]
49
+ eventHandlers: [ContractEventHandler!]
50
+ }
51
+
52
+ type ContractAbi {
53
+ name: String!
54
+ file: File!
55
+ }
56
+
57
+ type BlockHandler {
58
+ handler: String!
59
+ filter: BlockFilter
60
+ }
61
+
62
+ type BlockFilter {
63
+ kind: String!
64
+ }
65
+
66
+ type CallHandler {
67
+ function: String!
68
+ handler: String!
69
+ }
70
+
71
+ type ContractEventHandler {
72
+ event: String!
73
+ topic0: String
74
+ handler: String!
75
+ }
76
+
77
+ type Graft {
78
+ base: String!
79
+ block: BigInt!
80
+ }
81
+
82
+ type DataSourceTemplate {
83
+ kind: String!
84
+ name: String!
85
+ network: String
86
+ source: ContractSourceTemplate!
87
+ mapping: ContractMapping!
88
+ }
89
+
90
+ type ContractSourceTemplate {
91
+ abi: String!
92
+ }
@@ -60,10 +60,7 @@ module.exports = class Protocol {
60
60
  'aurora',
61
61
  'aurora-testnet',
62
62
  ],
63
- near: [
64
- 'near-mainnet',
65
- 'near-testnet'
66
- ],
63
+ near: ['near-mainnet', 'near-testnet'],
67
64
  })
68
65
  }
69
66
 
@@ -108,6 +105,15 @@ module.exports = class Protocol {
108
105
  }
109
106
  }
110
107
 
108
+ hasTemplates() {
109
+ switch (this.name) {
110
+ case 'ethereum':
111
+ return true
112
+ case 'near':
113
+ return false
114
+ }
115
+ }
116
+
111
117
  getTypeGenerator(options) {
112
118
  switch (this.name) {
113
119
  case 'ethereum':
@@ -118,13 +124,17 @@ module.exports = class Protocol {
118
124
  }
119
125
 
120
126
  getTemplateCodeGen(template) {
127
+ if (!this.hasTemplates()) {
128
+ throw new Error(
129
+ `Template data sources with kind '${this.name}' are not supported yet`,
130
+ )
131
+ }
132
+
121
133
  switch (this.name) {
122
134
  case 'ethereum':
123
135
  return new EthereumTemplateCodeGen(template)
124
136
  default:
125
- throw new Error(
126
- `Template data sources with kind '${this.name}' are not supported yet`,
127
- )
137
+ throw new Error(`Template data sources with kind '${this.name}' is unknown`)
128
138
  }
129
139
  }
130
140
 
@@ -0,0 +1,57 @@
1
+ # Each referenced type's in any of the types below must be listed
2
+ # here either as `scalar` or `type` for the validation code to work
3
+ # properly.
4
+ #
5
+ # That's why `String` is listed as a scalar even though it's built-in
6
+ # GraphQL basic types.
7
+ scalar String
8
+ scalar File
9
+ scalar BigInt
10
+
11
+ type SubgraphManifest {
12
+ specVersion: String!
13
+ schema: Schema!
14
+ description: String
15
+ repository: String
16
+ graft: Graft
17
+ dataSources: [DataSource!]!
18
+ }
19
+
20
+ type Schema {
21
+ file: File!
22
+ }
23
+
24
+ type DataSource {
25
+ kind: String!
26
+ name: String!
27
+ network: String
28
+ source: ContractSource!
29
+ mapping: ContractMapping!
30
+ }
31
+
32
+ type ContractSource {
33
+ account: String
34
+ startBlock: BigInt
35
+ }
36
+
37
+ type ContractMapping {
38
+ apiVersion: String!
39
+ language: String!
40
+ file: File!
41
+ entities: [String!]!
42
+ blockHandlers: [BlockHandler!]
43
+ receiptHandlers: [ReceiptHandler!]
44
+ }
45
+
46
+ type BlockHandler {
47
+ handler: String!
48
+ }
49
+
50
+ type ReceiptHandler {
51
+ handler: String!
52
+ }
53
+
54
+ type Graft {
55
+ base: String!
56
+ block: BigInt!
57
+ }
package/src/subgraph.js CHANGED
@@ -27,7 +27,7 @@ const buildCombinedWarning = (filename, warnings) =>
27
27
  ? warnings.reduce(
28
28
  (msg, w) =>
29
29
  `${msg}
30
-
30
+
31
31
  Path: ${w.get('path').size === 0 ? '/' : w.get('path').join(' > ')}
32
32
  ${w
33
33
  .get('message')
@@ -39,9 +39,21 @@ const buildCombinedWarning = (filename, warnings) =>
39
39
 
40
40
  module.exports = class Subgraph {
41
41
  static async validate(data, protocol, { resolveFile }) {
42
+ if (protocol.name == null) {
43
+ return immutable.fromJS([
44
+ {
45
+ path: [],
46
+ message: `Unable to determine for which protocol manifest file is built for. Ensure you have at least one 'dataSources' and/or 'templates' elements defined in your subgraph.`,
47
+ },
48
+ ])
49
+ }
50
+
42
51
  // Parse the default subgraph schema
43
52
  let schema = graphql.parse(
44
- await fs.readFile(path.join(__dirname, '..', 'manifest-schema.graphql'), 'utf-8'),
53
+ await fs.readFile(
54
+ path.join(__dirname, 'protocols', protocol.name, `manifest.graphql`),
55
+ 'utf-8',
56
+ ),
45
57
  )
46
58
 
47
59
  // Obtain the root `SubgraphManifest` type from the schema
@@ -146,10 +158,7 @@ At least one such handler must be defined.`,
146
158
  }
147
159
 
148
160
  static validateContractValues(manifest, protocol) {
149
- return validation.validateContractValues(
150
- manifest,
151
- protocol,
152
- )
161
+ return validation.validateContractValues(manifest, protocol)
153
162
  }
154
163
 
155
164
  // Validate that data source names are unique, so they don't overwrite each other.
@@ -200,17 +209,13 @@ More than one template named '${name}', template names must be unique.`,
200
209
  return yaml.stringify(manifest.toJS())
201
210
  }
202
211
 
203
- static async load(
204
- filename,
205
- { protocol, skipValidation } = { skipValidation: false }
206
- ) {
212
+ static async load(filename, { protocol, skipValidation } = { skipValidation: false }) {
207
213
  // Load and validate the manifest
208
214
  let data = null
209
215
 
210
- if(filename.match(/.js$/)) {
216
+ if (filename.match(/.js$/)) {
211
217
  data = require(path.resolve(filename))
212
- }
213
- else {
218
+ } else {
214
219
  data = yaml.parse(await fs.readFile(filename, 'utf-8'))
215
220
  }
216
221
 
@@ -52,8 +52,7 @@ const validators = immutable.fromJS({
52
52
  validators.get(ctx.getIn(['type', 'name', 'value']))(value, ctx),
53
53
 
54
54
  UnionTypeDefinition: (value, ctx) => {
55
- const unionVariants = ctx
56
- .getIn(['type', 'types'])
55
+ const unionVariants = ctx.getIn(['type', 'types'])
57
56
 
58
57
  let errors = List()
59
58
 
@@ -78,7 +77,10 @@ const validators = immutable.fromJS({
78
77
 
79
78
  NonNullType: (value, ctx) =>
80
79
  value !== null && value !== undefined
81
- ? validateValue(value, ctx.update('type', type => type.get('type')))
80
+ ? validateValue(
81
+ value,
82
+ ctx.update('type', type => type.get('type')),
83
+ )
82
84
  : immutable.fromJS([
83
85
  {
84
86
  path: ctx.get('path'),
@@ -126,7 +128,7 @@ const validators = immutable.fromJS({
126
128
  ),
127
129
  )
128
130
  : errors.push(
129
- key == 'templates'
131
+ key == 'templates' && ctx.get('protocol').hasTemplates()
130
132
  ? immutable.fromJS({
131
133
  path: ctx.get('path'),
132
134
  message:
@@ -211,7 +213,8 @@ const validateValue = (value, ctx) => {
211
213
  }
212
214
 
213
215
  const validateDataSourceForNetwork = (dataSources, protocol) =>
214
- dataSources.filter(dataSource => protocol.isValidKindName(dataSource.kind))
216
+ dataSources
217
+ .filter(dataSource => protocol.isValidKindName(dataSource.kind))
215
218
  .reduce(
216
219
  (networks, dataSource) =>
217
220
  networks.update(dataSource.network, dataSources =>
@@ -235,11 +238,11 @@ const validateDataSourceNetworks = (value, protocol) => {
235
238
  ${networks
236
239
  .map(
237
240
  (dataSources, network) =>
238
- ` ${
241
+ ` ${
239
242
  network === undefined
240
243
  ? 'Data sources and templates having no network set'
241
- : `Data sources and templates using '${network}'`
242
- }:\n${dataSources.map(ds => ` - ${ds}`).join('\n')}`,
244
+ : `Data sources and templates using '${network}'`
245
+ }:\n${dataSources.map(ds => ` - ${ds}`).join('\n')}`,
243
246
  )
244
247
  .join('\n')}
245
248
  Recommendation: Make all data sources and templates use the same network name.`,
@@ -262,6 +265,7 @@ const validateManifest = (value, type, schema, protocol, { resolveFile }) => {
262
265
  path: [],
263
266
  errors: [],
264
267
  resolveFile,
268
+ protocol,
265
269
  }),
266
270
  )
267
271
  : immutable.fromJS([
@@ -1,10 +1,10 @@
1
1
  - Load subgraph from subgraph.yaml
2
2
  ⚠ Warnings while loading subgraph from subgraph.yaml: Warnings in subgraph.yaml:
3
-
3
+
4
4
  Path: repository
5
5
  The repository is still set to https://github.com/graphprotocol/example-subgraph.
6
6
  Please replace it with a link to your subgraph source code.
7
-
7
+
8
8
  Path: description
9
9
  The description is still the one from the example subgraph.
10
10
  Please update it to tell users more about your subgraph.
@@ -1,7 +1,8 @@
1
1
  schema:
2
2
  file: ./non-existent.grapqhl
3
3
  dataSources:
4
- - name: 5
4
+ - kind: ethereum/contract
5
+ name: 5
5
6
  abis:
6
7
  name: Foo
7
8
  mapping:
@@ -0,0 +1,12 @@
1
+ schema:
2
+ file: ./non-existent.grapqhl
3
+ dataSources:
4
+ - name: 5
5
+ abis:
6
+ name: Foo
7
+ mapping:
8
+ - 12
9
+ - 13
10
+ - 14
11
+ templates:
12
+ field: foo
@@ -0,0 +1,5 @@
1
+ - Load subgraph from subgraph.yaml
2
+ ✖ Failed to load subgraph from subgraph.yaml: Error in subgraph.yaml:
3
+
4
+ Path: /
5
+ Unable to determine for which protocol manifest file is built for. Ensure you have at least one 'dataSources' and/or 'templates' elements defined in your subgraph.
@@ -7,9 +7,6 @@
7
7
  Path: schema > file
8
8
  File does not exist: non-existent.grapqhl
9
9
 
10
- Path: dataSources > 0 > kind
11
- No value provided
12
-
13
10
  Path: dataSources > 0 > name
14
11
  Expected string, found number:
15
12
  5
@@ -9,6 +9,14 @@ describe('Validation', () => {
9
9
  exitCode: 1,
10
10
  },
11
11
  )
12
+ cliTest(
13
+ 'Invalid subgraph manifest (cannot infer protocol)',
14
+ ['codegen', '--skip-migrations'],
15
+ 'validation/invalid-manifest-cannot-infer-protocol',
16
+ {
17
+ exitCode: 1,
18
+ },
19
+ )
12
20
  cliTest(
13
21
  'ABI not found in data source',
14
22
  ['codegen', '--skip-migrations'],
@@ -1,122 +0,0 @@
1
- scalar String
2
- scalar File
3
- scalar BigInt
4
-
5
- type Schema {
6
- file: File!
7
- }
8
-
9
- union DataSource =
10
- EthereumContractDataSource |
11
- NearContractDataSource
12
-
13
- union DataSourceTemplate = EthereumContractDataSourceTemplate
14
-
15
- type EthereumContractDataSource {
16
- kind: String!
17
- name: String!
18
- network: String
19
- source: EthereumContractSource!
20
- mapping: EthereumContractMapping!
21
- }
22
-
23
- type NearContractDataSource {
24
- kind: String!
25
- name: String!
26
- network: String
27
- source: NearContractSource!
28
- mapping: NearContractMapping!
29
- }
30
-
31
- type EthereumContractSource {
32
- address: String
33
- abi: String!
34
- startBlock: BigInt
35
- }
36
-
37
- type NearContractSource {
38
- account: String
39
- startBlock: BigInt
40
- }
41
-
42
- type EthereumContractMapping {
43
- kind: String
44
- apiVersion: String!
45
- language: String!
46
- file: File!
47
- entities: [String!]!
48
- abis: [EthereumContractAbi!]!
49
- blockHandlers: [EthereumBlockHandler!]
50
- callHandlers: [EthereumCallHandler!]
51
- eventHandlers: [EthereumContractEventHandler!]
52
- }
53
-
54
- type NearContractMapping {
55
- apiVersion: String!
56
- language: String!
57
- file: File!
58
- entities: [String!]!
59
- blockHandlers: [NearBlockHandler!]
60
- receiptHandlers: [NearReceiptHandler!]
61
- }
62
-
63
- type EthereumContractAbi {
64
- name: String!
65
- file: File!
66
- }
67
-
68
- type EthereumBlockHandler {
69
- handler: String!
70
- filter: EthereumBlockFilter
71
- }
72
-
73
- type EthereumBlockFilter {
74
- kind: String!
75
- }
76
-
77
- type NearBlockHandler {
78
- handler: String!
79
- }
80
-
81
- type EthereumCallHandler {
82
- function: String!
83
- handler: String!
84
- }
85
-
86
- type NearReceiptHandler {
87
- handler: String!
88
- }
89
-
90
- type EthereumContractEventHandler {
91
- event: String!
92
- topic0: String
93
- handler: String!
94
- }
95
-
96
- type Graft {
97
- base: String!
98
- block: BigInt!
99
- }
100
-
101
- type SubgraphManifest {
102
- specVersion: String!
103
- features: [String!]
104
- schema: Schema!
105
- description: String
106
- repository: String
107
- graft: Graft
108
- dataSources: [DataSource!]!
109
- templates: [DataSourceTemplate!]
110
- }
111
-
112
- type EthereumContractDataSourceTemplate {
113
- kind: String!
114
- name: String!
115
- network: String
116
- source: EthereumContractSourceTemplate!
117
- mapping: EthereumContractMapping!
118
- }
119
-
120
- type EthereumContractSourceTemplate {
121
- abi: String!
122
- }