@graphprotocol/graph-cli 0.22.4 → 0.23.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.
- package/README.md +83 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/.travis.yml +4 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/ethereum.ts +10 -16
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/near.ts +402 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/collections.ts +125 -4
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/eager_offset.ts +2 -1
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/json.ts +14 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/numbers.ts +58 -16
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/value.ts +2 -5
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/global/global.ts +108 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/helper-functions.ts +5 -5
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/index.ts +6 -15
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/package.json +5 -2
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/test/bigInt.ts +138 -108
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/test/bytes.ts +31 -20
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/test/test.js +120 -88
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/tsconfig.json +2 -2
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/types/tsconfig.base.json +3 -0
- package/examples/basic-event-handlers/package.json +1 -1
- package/examples/basic-event-handlers/yarn.lock +4 -4
- package/examples/example-subgraph/package.json +1 -1
- package/examples/example-subgraph/yarn.lock +4 -4
- package/jest.config.js +2 -2
- package/manifest-schema.graphql +35 -2
- package/package.json +2 -6
- package/src/codegen/schema.js +1 -2
- package/src/codegen/template.js +9 -51
- package/src/codegen/typescript.js +7 -0
- package/src/command-helpers/compiler.js +6 -2
- package/src/command-helpers/data-sources.js +38 -0
- package/src/command-helpers/fs.js +8 -0
- package/src/commands/build.js +14 -0
- package/src/commands/codegen.js +8 -0
- package/src/commands/deploy.js +11 -8
- package/src/commands/init.js +36 -11
- package/src/commands/test.js +37 -27
- package/src/compiler/index.js +90 -73
- package/src/{abi.js → protocols/ethereum/abi.js} +0 -0
- package/src/{codegen → protocols/ethereum/codegen}/abi.js +9 -6
- package/src/{codegen → protocols/ethereum/codegen}/abi.test.js +1 -1
- package/src/protocols/ethereum/codegen/template.js +42 -0
- package/src/protocols/ethereum/subgraph.js +205 -0
- package/src/protocols/ethereum/type-generator.js +203 -0
- package/src/protocols/index.js +97 -0
- package/src/protocols/near/subgraph.js +42 -0
- package/src/scaffold.js +21 -4
- package/src/scaffold.test.js +1 -1
- package/src/subgraph.js +30 -252
- package/src/type-generator.js +31 -211
- package/src/validation/index.js +1 -0
- package/src/validation/manifest.js +73 -23
- package/src/validation/schema.js +6 -0
- package/tests/cli/globalSetup.js +6 -0
- package/tests/cli/globalTeardown.js +6 -0
- package/tests/cli/init.test.js +1 -1
- package/tests/cli/util.js +17 -8
- package/tests/cli/validation/near-is-valid/mapping.ts +0 -0
- package/tests/cli/validation/near-is-valid/schema.graphql +8 -0
- package/tests/cli/validation/near-is-valid/subgraph.yaml +21 -0
- package/tests/cli/validation.test.js +8 -0
package/src/compiler/index.js
CHANGED
|
@@ -9,7 +9,6 @@ const toolbox = require('gluegun/toolbox')
|
|
|
9
9
|
const { step, withSpinner } = require('../command-helpers/spinner')
|
|
10
10
|
const Subgraph = require('../subgraph')
|
|
11
11
|
const Watcher = require('../watcher')
|
|
12
|
-
const ABI = require('../abi')
|
|
13
12
|
const { applyMigrations } = require('../migrations')
|
|
14
13
|
const asc = require('./asc')
|
|
15
14
|
|
|
@@ -52,6 +51,9 @@ class Compiler {
|
|
|
52
51
|
|
|
53
52
|
this.globalsFile = path.join(globalsLib, globalsFile)
|
|
54
53
|
|
|
54
|
+
this.protocol = this.options.protocol
|
|
55
|
+
this.ABI = this.protocol.getABI()
|
|
56
|
+
|
|
55
57
|
process.on('uncaughtException', function(e) {
|
|
56
58
|
toolbox.print.error(`UNCAUGHT EXCEPTION: ${e}`)
|
|
57
59
|
})
|
|
@@ -104,8 +106,10 @@ class Compiler {
|
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
async loadSubgraph({ quiet } = { quiet: false }) {
|
|
109
|
+
const subgraphLoadOptions = { protocol: this.protocol, skipValidation: false }
|
|
110
|
+
|
|
107
111
|
if (quiet) {
|
|
108
|
-
return Subgraph.load(this.options.subgraphManifest).result
|
|
112
|
+
return Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions).result
|
|
109
113
|
} else {
|
|
110
114
|
const manifestPath = this.displayPath(this.options.subgraphManifest)
|
|
111
115
|
|
|
@@ -114,7 +118,7 @@ class Compiler {
|
|
|
114
118
|
`Failed to load subgraph from ${manifestPath}`,
|
|
115
119
|
`Warnings loading subgraph from ${manifestPath}`,
|
|
116
120
|
async spinner => {
|
|
117
|
-
return Subgraph.load(this.options.subgraphManifest)
|
|
121
|
+
return Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions)
|
|
118
122
|
},
|
|
119
123
|
)
|
|
120
124
|
}
|
|
@@ -132,9 +136,12 @@ class Compiler {
|
|
|
132
136
|
files.push(path.resolve(subgraph.getIn(['schema', 'file'])))
|
|
133
137
|
subgraph.get('dataSources').map(dataSource => {
|
|
134
138
|
files.push(dataSource.getIn(['mapping', 'file']))
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
139
|
+
// Only watch ABI related files if the target protocol has support/need for them.
|
|
140
|
+
if (this.protocol.hasABIs()) {
|
|
141
|
+
dataSource.getIn(['mapping', 'abis']).map(abi => {
|
|
142
|
+
files.push(abi.get('file'))
|
|
143
|
+
})
|
|
144
|
+
}
|
|
138
145
|
})
|
|
139
146
|
|
|
140
147
|
// Make paths absolute
|
|
@@ -403,52 +410,59 @@ class Compiler {
|
|
|
403
410
|
})
|
|
404
411
|
|
|
405
412
|
// Copy data source files and update their paths
|
|
406
|
-
subgraph = subgraph.update('dataSources', dataSources =>
|
|
407
|
-
|
|
408
|
-
dataSource
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
this.
|
|
417
|
-
this.
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
this.
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
413
|
+
subgraph = subgraph.update('dataSources', dataSources =>
|
|
414
|
+
dataSources.map(dataSource => {
|
|
415
|
+
let updatedDataSource = dataSource
|
|
416
|
+
|
|
417
|
+
if (this.protocol.hasABIs()) {
|
|
418
|
+
updatedDataSource = updatedDataSource
|
|
419
|
+
// Write data source ABIs to the output directory
|
|
420
|
+
.updateIn(['mapping', 'abis'], abis =>
|
|
421
|
+
abis.map(abi =>
|
|
422
|
+
abi.update('file', abiFile => {
|
|
423
|
+
abiFile = path.resolve(this.sourceDir, abiFile)
|
|
424
|
+
let abiData = this.ABI.load(abi.get('name'), abiFile)
|
|
425
|
+
return path.relative(
|
|
426
|
+
this.options.outputDir,
|
|
427
|
+
this._writeSubgraphFile(
|
|
428
|
+
abiFile,
|
|
429
|
+
JSON.stringify(abiData.data.toJS(), null, 2),
|
|
430
|
+
this.sourceDir,
|
|
431
|
+
this.subgraphDir(this.options.outputDir, dataSource),
|
|
432
|
+
spinner,
|
|
433
|
+
),
|
|
434
|
+
)
|
|
435
|
+
}),
|
|
436
|
+
),
|
|
437
|
+
)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// The mapping file is already being written to the output
|
|
441
|
+
// directory by the AssemblyScript compiler
|
|
442
|
+
return updatedDataSource.updateIn(['mapping', 'file'], mappingFile =>
|
|
443
|
+
path.relative(
|
|
444
|
+
this.options.outputDir,
|
|
445
|
+
path.resolve(this.sourceDir, mappingFile),
|
|
436
446
|
),
|
|
437
|
-
|
|
438
|
-
|
|
447
|
+
)
|
|
448
|
+
})
|
|
449
|
+
)
|
|
439
450
|
|
|
440
451
|
// Copy template files and update their paths
|
|
441
|
-
subgraph = subgraph.update('templates', templates =>
|
|
442
|
-
|
|
452
|
+
subgraph = subgraph.update('templates', templates =>
|
|
453
|
+
templates === undefined
|
|
443
454
|
? templates
|
|
444
|
-
: templates.map(template =>
|
|
445
|
-
|
|
455
|
+
: templates.map(template => {
|
|
456
|
+
let updatedTemplate = template
|
|
457
|
+
|
|
458
|
+
if (this.protocol.hasABIs()) {
|
|
459
|
+
updatedTemplate = updatedTemplate
|
|
446
460
|
// Write template ABIs to the output directory
|
|
447
461
|
.updateIn(['mapping', 'abis'], abis =>
|
|
448
462
|
abis.map(abi =>
|
|
449
463
|
abi.update('file', abiFile => {
|
|
450
464
|
abiFile = path.resolve(this.sourceDir, abiFile)
|
|
451
|
-
let abiData = ABI.load(abi.get('name'), abiFile)
|
|
465
|
+
let abiData = this.ABI.load(abi.get('name'), abiFile)
|
|
452
466
|
return path.relative(
|
|
453
467
|
this.options.outputDir,
|
|
454
468
|
this._writeSubgraphFile(
|
|
@@ -462,17 +476,18 @@ class Compiler {
|
|
|
462
476
|
}),
|
|
463
477
|
),
|
|
464
478
|
)
|
|
479
|
+
}
|
|
465
480
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
),
|
|
481
|
+
// The mapping file is already being written to the output
|
|
482
|
+
// directory by the AssemblyScript compiler
|
|
483
|
+
return updatedTemplate.updateIn(['mapping', 'file'], mappingFile =>
|
|
484
|
+
path.relative(
|
|
485
|
+
this.options.outputDir,
|
|
486
|
+
path.resolve(this.sourceDir, mappingFile),
|
|
487
|
+
),
|
|
474
488
|
)
|
|
475
|
-
|
|
489
|
+
})
|
|
490
|
+
)
|
|
476
491
|
|
|
477
492
|
// Write the subgraph manifest itself
|
|
478
493
|
let outputFilename = path.join(this.options.outputDir, 'subgraph.yaml')
|
|
@@ -506,17 +521,18 @@ class Compiler {
|
|
|
506
521
|
),
|
|
507
522
|
})
|
|
508
523
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
524
|
+
if (this.protocol.hasABIs()) {
|
|
525
|
+
for (let [i, dataSource] of subgraph.get('dataSources').entries()) {
|
|
526
|
+
for (let [j, abi] of dataSource.getIn(['mapping', 'abis']).entries()) {
|
|
527
|
+
updates.push({
|
|
528
|
+
keyPath: ['dataSources', i, 'mapping', 'abis', j, 'file'],
|
|
529
|
+
value: await this._uploadFileToIPFS(
|
|
530
|
+
abi.get('file'),
|
|
531
|
+
uploadedFiles,
|
|
532
|
+
spinner,
|
|
533
|
+
),
|
|
534
|
+
})
|
|
535
|
+
}
|
|
520
536
|
}
|
|
521
537
|
}
|
|
522
538
|
|
|
@@ -532,17 +548,18 @@ class Compiler {
|
|
|
532
548
|
})
|
|
533
549
|
}
|
|
534
550
|
|
|
535
|
-
// Upload the mapping and ABIs of all data source templates
|
|
536
551
|
for (let [i, template] of subgraph.get('templates', immutable.List()).entries()) {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
552
|
+
if (this.protocol.hasABIs()) {
|
|
553
|
+
for (let [j, abi] of template.getIn(['mapping', 'abis']).entries()) {
|
|
554
|
+
updates.push({
|
|
555
|
+
keyPath: ['templates', i, 'mapping', 'abis', j, 'file'],
|
|
556
|
+
value: await this._uploadFileToIPFS(
|
|
557
|
+
abi.get('file'),
|
|
558
|
+
uploadedFiles,
|
|
559
|
+
spinner,
|
|
560
|
+
),
|
|
561
|
+
})
|
|
562
|
+
}
|
|
546
563
|
}
|
|
547
564
|
|
|
548
565
|
updates.push({
|
|
File without changes
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
const immutable = require('immutable')
|
|
2
2
|
|
|
3
|
-
const tsCodegen = require('
|
|
4
|
-
const typesCodegen = require('
|
|
5
|
-
const util = require('
|
|
6
|
-
const ABI = require('../abi')
|
|
3
|
+
const tsCodegen = require('../../../codegen/typescript')
|
|
4
|
+
const typesCodegen = require('../../../codegen/types')
|
|
5
|
+
const util = require('../../../codegen/util')
|
|
7
6
|
|
|
8
7
|
module.exports = class AbiCodeGenerator {
|
|
9
8
|
constructor(abi) {
|
|
@@ -48,7 +47,7 @@ module.exports = class AbiCodeGenerator {
|
|
|
48
47
|
setName: (fn, name) => fn.set('_alias', name),
|
|
49
48
|
})
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
callFunctions = callFunctions
|
|
52
51
|
.map(fn => {
|
|
53
52
|
let fnAlias = fn.get('_alias')
|
|
54
53
|
let fnClassName = `${fnAlias.charAt(0).toUpperCase()}${fnAlias.slice(1)}Call`
|
|
@@ -141,6 +140,8 @@ module.exports = class AbiCodeGenerator {
|
|
|
141
140
|
)
|
|
142
141
|
return [klass, inputsClass, outputsClass, ...tupleClasses]
|
|
143
142
|
})
|
|
143
|
+
|
|
144
|
+
return callFunctions
|
|
144
145
|
.reduce(
|
|
145
146
|
// flatten the array
|
|
146
147
|
(array, classes) => array.concat(classes),
|
|
@@ -156,7 +157,7 @@ module.exports = class AbiCodeGenerator {
|
|
|
156
157
|
setName: (event, name) => event.set('_alias', name),
|
|
157
158
|
})
|
|
158
159
|
|
|
159
|
-
|
|
160
|
+
events = events
|
|
160
161
|
.map(event => {
|
|
161
162
|
let eventClassName = event.get('_alias')
|
|
162
163
|
let tupleClasses = []
|
|
@@ -209,6 +210,8 @@ module.exports = class AbiCodeGenerator {
|
|
|
209
210
|
)
|
|
210
211
|
return [klass, paramsClass, ...tupleClasses]
|
|
211
212
|
})
|
|
213
|
+
|
|
214
|
+
return events
|
|
212
215
|
.reduce(
|
|
213
216
|
// flatten the array
|
|
214
217
|
(array, classes) => array.concat(classes),
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const tsCodegen = require('../../../codegen/typescript')
|
|
2
|
+
|
|
3
|
+
module.exports = class EthereumTemplateCodeGen {
|
|
4
|
+
constructor(template) {
|
|
5
|
+
this.template = template
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
generateModuleImports() {
|
|
9
|
+
return [
|
|
10
|
+
'Address',
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
generateCreateMethod() {
|
|
15
|
+
const name = this.template.get('name')
|
|
16
|
+
|
|
17
|
+
return tsCodegen.staticMethod(
|
|
18
|
+
'create',
|
|
19
|
+
[tsCodegen.param('address', tsCodegen.namedType('Address'))],
|
|
20
|
+
tsCodegen.namedType('void'),
|
|
21
|
+
`
|
|
22
|
+
DataSourceTemplate.create('${name}', [address.toHex()])
|
|
23
|
+
`,
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
generateCreateWithContextMethod() {
|
|
28
|
+
const name = this.template.get('name')
|
|
29
|
+
|
|
30
|
+
return tsCodegen.staticMethod(
|
|
31
|
+
'createWithContext',
|
|
32
|
+
[
|
|
33
|
+
tsCodegen.param('address', tsCodegen.namedType('Address')),
|
|
34
|
+
tsCodegen.param('context', tsCodegen.namedType('DataSourceContext')),
|
|
35
|
+
],
|
|
36
|
+
tsCodegen.namedType('void'),
|
|
37
|
+
`
|
|
38
|
+
DataSourceTemplate.createWithContext('${name}', [address.toHex()], context)
|
|
39
|
+
`,
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
const immutable = require('immutable')
|
|
2
|
+
const ABI = require('./abi')
|
|
3
|
+
const DataSourcesExtractor = require('../../command-helpers/data-sources')
|
|
4
|
+
const { validateContractValues } = require('../../validation')
|
|
5
|
+
|
|
6
|
+
module.exports = class EthereumSubgraph {
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.manifest = options.manifest
|
|
9
|
+
this.resolveFile = options.resolveFile
|
|
10
|
+
this.protocol = options.protocol
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
validateManifest() {
|
|
14
|
+
return this.validateAbis()
|
|
15
|
+
.concat(this.validateContractAddresses())
|
|
16
|
+
.concat(this.validateEvents())
|
|
17
|
+
.concat(this.validateCallFunctions())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
validateAbis() {
|
|
21
|
+
const dataSourcesAndTemplates = DataSourcesExtractor.fromManifest(this.manifest, this.protocol)
|
|
22
|
+
|
|
23
|
+
return dataSourcesAndTemplates.reduce(
|
|
24
|
+
(errors, dataSourceOrTemplate) =>
|
|
25
|
+
errors.concat(
|
|
26
|
+
this.validateDataSourceAbis(
|
|
27
|
+
dataSourceOrTemplate.get('dataSource'),
|
|
28
|
+
dataSourceOrTemplate.get('path'),
|
|
29
|
+
),
|
|
30
|
+
),
|
|
31
|
+
immutable.List(),
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
validateDataSourceAbis(dataSource, path) {
|
|
36
|
+
// Validate that the the "source > abi" reference of all data sources
|
|
37
|
+
// points to an existing ABI in the data source ABIs
|
|
38
|
+
let abiName = dataSource.getIn(['source', 'abi'])
|
|
39
|
+
let abiNames = dataSource.getIn(['mapping', 'abis']).map(abi => abi.get('name'))
|
|
40
|
+
let nameErrors = abiNames.includes(abiName)
|
|
41
|
+
? immutable.List()
|
|
42
|
+
: immutable.fromJS([
|
|
43
|
+
{
|
|
44
|
+
path: [...path, 'source', 'abi'],
|
|
45
|
+
message: `\
|
|
46
|
+
ABI name '${abiName}' not found in mapping > abis.
|
|
47
|
+
Available ABIs:
|
|
48
|
+
${abiNames
|
|
49
|
+
.sort()
|
|
50
|
+
.map(name => `- ${name}`)
|
|
51
|
+
.join('\n')}`,
|
|
52
|
+
},
|
|
53
|
+
])
|
|
54
|
+
|
|
55
|
+
// Validate that all ABI files are valid
|
|
56
|
+
let fileErrors = dataSource
|
|
57
|
+
.getIn(['mapping', 'abis'])
|
|
58
|
+
.reduce((errors, abi, abiIndex) => {
|
|
59
|
+
try {
|
|
60
|
+
ABI.load(abi.get('name'), this.resolveFile(abi.get('file')))
|
|
61
|
+
return errors
|
|
62
|
+
} catch (e) {
|
|
63
|
+
return errors.push(
|
|
64
|
+
immutable.fromJS({
|
|
65
|
+
path: [...path, 'mapping', 'abis', abiIndex, 'file'],
|
|
66
|
+
message: e.message,
|
|
67
|
+
}),
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
}, immutable.List())
|
|
71
|
+
|
|
72
|
+
return nameErrors.concat(fileErrors)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
validateContractAddresses() {
|
|
76
|
+
const ethereumAddressPattern = /^(0x)?[0-9a-fA-F]{40}$/
|
|
77
|
+
|
|
78
|
+
return validateContractValues(
|
|
79
|
+
this.manifest,
|
|
80
|
+
this.protocol,
|
|
81
|
+
'address',
|
|
82
|
+
address => ethereumAddressPattern.test(address),
|
|
83
|
+
"Must be 40 hexadecimal characters, with an optional '0x' prefix.",
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
validateEvents() {
|
|
88
|
+
const dataSourcesAndTemplates = DataSourcesExtractor.fromManifest(this.manifest, this.protocol)
|
|
89
|
+
|
|
90
|
+
return dataSourcesAndTemplates
|
|
91
|
+
.reduce((errors, dataSourceOrTemplate) => {
|
|
92
|
+
return errors.concat(
|
|
93
|
+
this.validateDataSourceEvents(
|
|
94
|
+
dataSourceOrTemplate.get('dataSource'),
|
|
95
|
+
dataSourceOrTemplate.get('path'),
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
}, immutable.List())
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
validateDataSourceEvents(dataSource, path) {
|
|
102
|
+
let abi
|
|
103
|
+
try {
|
|
104
|
+
// Resolve the source ABI name into a real ABI object
|
|
105
|
+
let abiName = dataSource.getIn(['source', 'abi'])
|
|
106
|
+
let abiEntry = dataSource
|
|
107
|
+
.getIn(['mapping', 'abis'])
|
|
108
|
+
.find(abi => abi.get('name') === abiName)
|
|
109
|
+
abi = ABI.load(abiEntry.get('name'), this.resolveFile(abiEntry.get('file')))
|
|
110
|
+
} catch (_) {
|
|
111
|
+
// Ignore errors silently; we can't really say anything about
|
|
112
|
+
// the events if the ABI can't even be loaded
|
|
113
|
+
return immutable.List()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Obtain event signatures from the mapping
|
|
117
|
+
let manifestEvents = dataSource
|
|
118
|
+
.getIn(['mapping', 'eventHandlers'], immutable.List())
|
|
119
|
+
.map(handler => handler.get('event'))
|
|
120
|
+
|
|
121
|
+
// Obtain event signatures from the ABI
|
|
122
|
+
let abiEvents = abi.eventSignatures()
|
|
123
|
+
|
|
124
|
+
// Add errors for every manifest event signature that is not
|
|
125
|
+
// present in the ABI
|
|
126
|
+
return manifestEvents.reduce(
|
|
127
|
+
(errors, manifestEvent, index) =>
|
|
128
|
+
abiEvents.includes(manifestEvent)
|
|
129
|
+
? errors
|
|
130
|
+
: errors.push(
|
|
131
|
+
immutable.fromJS({
|
|
132
|
+
path: [...path, 'eventHandlers', index],
|
|
133
|
+
message: `\
|
|
134
|
+
Event with signature '${manifestEvent}' not present in ABI '${abi.name}'.
|
|
135
|
+
Available events:
|
|
136
|
+
${abiEvents
|
|
137
|
+
.sort()
|
|
138
|
+
.map(event => `- ${event}`)
|
|
139
|
+
.join('\n')}`,
|
|
140
|
+
}),
|
|
141
|
+
),
|
|
142
|
+
immutable.List(),
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
validateCallFunctions() {
|
|
147
|
+
return this.manifest
|
|
148
|
+
.get('dataSources')
|
|
149
|
+
.filter(dataSource => this.protocol.isValidKindName(dataSource.get('kind')))
|
|
150
|
+
.reduce((errors, dataSource, dataSourceIndex) => {
|
|
151
|
+
let path = ['dataSources', dataSourceIndex, 'callHandlers']
|
|
152
|
+
|
|
153
|
+
let abi
|
|
154
|
+
try {
|
|
155
|
+
// Resolve the source ABI name into a real ABI object
|
|
156
|
+
let abiName = dataSource.getIn(['source', 'abi'])
|
|
157
|
+
let abiEntry = dataSource
|
|
158
|
+
.getIn(['mapping', 'abis'])
|
|
159
|
+
.find(abi => abi.get('name') === abiName)
|
|
160
|
+
abi = ABI.load(abiEntry.get('name'), this.resolveFile(abiEntry.get('file')))
|
|
161
|
+
} catch (e) {
|
|
162
|
+
// Ignore errors silently; we can't really say anything about
|
|
163
|
+
// the call functions if the ABI can't even be loaded
|
|
164
|
+
return errors
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Obtain event signatures from the mapping
|
|
168
|
+
let manifestFunctions = dataSource
|
|
169
|
+
.getIn(['mapping', 'callHandlers'], immutable.List())
|
|
170
|
+
.map(handler => handler.get('function'))
|
|
171
|
+
|
|
172
|
+
// Obtain event signatures from the ABI
|
|
173
|
+
let abiFunctions = abi.callFunctionSignatures()
|
|
174
|
+
|
|
175
|
+
// Add errors for every manifest event signature that is not
|
|
176
|
+
// present in the ABI
|
|
177
|
+
return manifestFunctions.reduce(
|
|
178
|
+
(errors, manifestFunction, index) =>
|
|
179
|
+
abiFunctions.includes(manifestFunction)
|
|
180
|
+
? errors
|
|
181
|
+
: errors.push(
|
|
182
|
+
immutable.fromJS({
|
|
183
|
+
path: [...path, index],
|
|
184
|
+
message: `\
|
|
185
|
+
Call function with signature '${manifestFunction}' not present in ABI '${abi.name}'.
|
|
186
|
+
Available call functions:
|
|
187
|
+
${abiFunctions
|
|
188
|
+
.sort()
|
|
189
|
+
.map(tx => `- ${tx}`)
|
|
190
|
+
.join('\n')}`,
|
|
191
|
+
}),
|
|
192
|
+
),
|
|
193
|
+
errors,
|
|
194
|
+
)
|
|
195
|
+
}, immutable.List())
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
handlerTypes() {
|
|
199
|
+
return immutable.List([
|
|
200
|
+
'blockHandlers',
|
|
201
|
+
'callHandlers',
|
|
202
|
+
'eventHandlers',
|
|
203
|
+
])
|
|
204
|
+
}
|
|
205
|
+
}
|