@graphprotocol/graph-cli 0.23.2 → 0.25.0

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/node_modules/@graphprotocol/graph-ts/README.md +83 -0
  2. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/ethereum.ts +2 -0
  3. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/common/json.ts +2 -2
  4. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/package.json +2 -7
  5. package/examples/basic-event-handlers/package.json +1 -1
  6. package/examples/basic-event-handlers/yarn.lock +4 -4
  7. package/examples/example-subgraph/package.json +1 -1
  8. package/examples/example-subgraph/yarn.lock +4 -4
  9. package/package.json +1 -1
  10. package/src/codegen/types/index.js +8 -1
  11. package/src/command-helpers/scaffold.js +66 -0
  12. package/src/commands/init.js +128 -92
  13. package/src/migrations/mapping_api_version_0_0_5.js +74 -0
  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 +88 -8
  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
package/src/scaffold.js DELETED
@@ -1,364 +0,0 @@
1
- const fs = require('fs-extra')
2
- const path = require('path')
3
- const prettier = require('prettier')
4
- const pkginfo = require('pkginfo')(module)
5
-
6
- const { getSubgraphBasename } = require('./command-helpers/subgraph')
7
- const { step } = require('./command-helpers/spinner')
8
- const { ascTypeForEthereum, valueTypeForAsc } = require('./codegen/types')
9
- // TODO: Use Protocol class to getABI
10
- const ABI = require('./protocols/ethereum/abi')
11
- const AbiCodeGenerator = require('./protocols/ethereum/codegen/abi')
12
- const util = require('./codegen/util')
13
-
14
- const abiEvents = abi =>
15
- util.disambiguateNames({
16
- values: abi.data.filter(item => item.get('type') === 'event'),
17
- getName: event => event.get('name'),
18
- setName: (event, name) => event.set('_alias', name),
19
- })
20
-
21
- const graphCliVersion = process.env.GRAPH_CLI_TESTS
22
- // JSON.stringify should remove this key, we will install the local
23
- // graph-cli for the tests using `npm link` instead of fetching from npm.
24
- ? undefined
25
- // For scaffolding real subgraphs
26
- : `${module.exports.version}`
27
-
28
- // package.json
29
-
30
- const generatePackageJson = ({ subgraphName, node }) =>
31
- prettier.format(
32
- JSON.stringify({
33
- name: getSubgraphBasename(subgraphName),
34
- license: 'UNLICENSED',
35
- scripts: {
36
- codegen: 'graph codegen',
37
- build: 'graph build',
38
- deploy:
39
- `graph deploy ` +
40
- `--node ${node} ` +
41
- subgraphName,
42
- 'create-local': `graph create --node http://localhost:8020/ ${subgraphName}`,
43
- 'remove-local': `graph remove --node http://localhost:8020/ ${subgraphName}`,
44
- 'deploy-local':
45
- `graph deploy ` +
46
- `--node http://localhost:8020/ ` +
47
- `--ipfs http://localhost:5001 ` +
48
- subgraphName,
49
- },
50
- dependencies: {
51
- '@graphprotocol/graph-cli': graphCliVersion,
52
- '@graphprotocol/graph-ts': `0.23.1`,
53
- },
54
- }),
55
- { parser: 'json' },
56
- )
57
-
58
- // Subgraph manifest
59
-
60
- const generateManifest = ({ abi, address, network, contractName }) =>
61
- prettier.format(
62
- `
63
- specVersion: 0.0.1
64
- schema:
65
- file: ./schema.graphql
66
- dataSources:
67
- - kind: ethereum/contract
68
- name: ${contractName}
69
- network: ${network}
70
- source:
71
- address: '${address}'
72
- abi: ${contractName}
73
- mapping:
74
- kind: ethereum/events
75
- apiVersion: 0.0.5
76
- language: wasm/assemblyscript
77
- entities:
78
- ${abiEvents(abi)
79
- .map(event => `- ${event.get('_alias')}`)
80
- .join('\n ')}
81
- abis:
82
- - name: ${contractName}
83
- file: ./abis/${contractName}.json
84
- eventHandlers:
85
- ${abiEvents(abi)
86
- .map(
87
- event => `
88
- - event: ${ABI.eventSignature(event)}
89
- handler: handle${event.get('_alias')}`,
90
- )
91
- .join('')}
92
- file: ./src/mapping.ts
93
- `,
94
- { parser: 'yaml' },
95
- )
96
-
97
- // Schema
98
-
99
- const ethereumTypeToGraphQL = name => {
100
- let ascType = ascTypeForEthereum(name)
101
- return valueTypeForAsc(ascType)
102
- }
103
-
104
- const generateField = ({ name, type }) =>
105
- `${name}: ${ethereumTypeToGraphQL(type)}! # ${type}`
106
-
107
- const generateEventFields = ({ index, input }) =>
108
- input.type == 'tuple'
109
- ? util
110
- .unrollTuple({ value: input, path: [input.name || `param${index}`], index })
111
- .map(({ path, type }) => generateField({ name: path.join('_'), type }))
112
- : [generateField({ name: input.name || `param${index}`, type: input.type })]
113
-
114
- const generateEventType = event => `type ${event._alias} @entity {
115
- id: ID!
116
- ${event.inputs
117
- .reduce(
118
- (acc, input, index) => acc.concat(generateEventFields({ input, index })),
119
- [],
120
- )
121
- .join('\n')}
122
- }`
123
-
124
- const generateExampleEntityType = events => {
125
- if (events.length > 0) {
126
- return `type ExampleEntity @entity {
127
- id: ID!
128
- count: BigInt!
129
- ${events[0].inputs
130
- .reduce((acc, input, index) => acc.concat(generateEventFields({ input, index })), [])
131
- .slice(0, 2)
132
- .join('\n')}
133
- }`
134
- } else {
135
- return `type ExampleEntity @entity {
136
- id: ID!
137
- block: Bytes!
138
- transaction: Bytes!
139
- }`
140
- }
141
- }
142
-
143
- const generateSchema = ({ abi, indexEvents }) => {
144
- let events = abiEvents(abi).toJS()
145
- return prettier.format(
146
- indexEvents
147
- ? events.map(generateEventType).join('\n\n')
148
- : generateExampleEntityType(events),
149
- {
150
- parser: 'graphql',
151
- },
152
- )
153
- }
154
-
155
- const tsConfig = prettier.format(
156
- JSON.stringify({
157
- extends: '@graphprotocol/graph-ts/types/tsconfig.base.json',
158
- include: ['src'],
159
- }),
160
- { parser: 'json' },
161
- )
162
-
163
- // Mapping
164
-
165
- const generateTupleFieldAssignments = ({ keyPath, index, component }) => {
166
- let name = component.name || `value${index}`
167
- keyPath = [...keyPath, name]
168
-
169
- let flatName = keyPath.join('_')
170
- let nestedName = keyPath.join('.')
171
-
172
- return component.type === 'tuple'
173
- ? component.components.reduce(
174
- (acc, subComponent, subIndex) =>
175
- acc.concat(
176
- generateTupleFieldAssignments({
177
- keyPath,
178
- index: subIndex,
179
- component: subComponent,
180
- }),
181
- ),
182
- [],
183
- )
184
- : [`entity.${flatName} = event.params.${nestedName}`]
185
- }
186
-
187
- const generateFieldAssignment = path =>
188
- `entity.${path.join('_')} = event.params.${path.join('.')}`
189
-
190
- const generateFieldAssignments = ({ index, input }) =>
191
- input.type === 'tuple'
192
- ? util
193
- .unrollTuple({ value: input, index, path: [input.name || `param${index}`] })
194
- .map(({ path }) => generateFieldAssignment(path))
195
- : generateFieldAssignment([input.name || `param${index}`])
196
-
197
- const generateEventFieldAssignments = event =>
198
- event.inputs.reduce(
199
- (acc, input, index) => acc.concat(generateFieldAssignments({ input, index })),
200
- [],
201
- )
202
-
203
- const generateEventIndexingHandlers = (events, contractName) =>
204
- `
205
- import { ${events.map(
206
- event => `${event._alias} as ${event._alias}Event`,
207
- )}} from '../generated/${contractName}/${contractName}'
208
- import { ${events.map(event => event._alias)} } from '../generated/schema'
209
-
210
- ${events
211
- .map(
212
- event =>
213
- `
214
- export function handle${event._alias}(event: ${event._alias}Event): void {
215
- let entity = new ${
216
- event._alias
217
- }(event.transaction.hash.toHex() + '-' + event.logIndex.toString())
218
- ${generateEventFieldAssignments(event).join('\n')}
219
- entity.save()
220
- }
221
- `,
222
- )
223
- .join('\n')}
224
- `
225
-
226
- const generatePlaceholderHandlers = ({ abi, events, contractName }) =>
227
- `
228
- import { BigInt } from '@graphprotocol/graph-ts'
229
- import { ${contractName}, ${events.map(event => event._alias)} }
230
- from '../generated/${contractName}/${contractName}'
231
- import { ExampleEntity } from '../generated/schema'
232
-
233
- ${events
234
- .map((event, index) =>
235
- index === 0
236
- ? `
237
- export function handle${event._alias}(event: ${event._alias}): void {
238
- // Entities can be loaded from the store using a string ID; this ID
239
- // needs to be unique across all entities of the same type
240
- let entity = ExampleEntity.load(event.transaction.from.toHex())
241
-
242
- // Entities only exist after they have been saved to the store;
243
- // \`null\` checks allow to create entities on demand
244
- if (!entity) {
245
- entity = new ExampleEntity(event.transaction.from.toHex())
246
-
247
- // Entity fields can be set using simple assignments
248
- entity.count = BigInt.fromI32(0)
249
- }
250
-
251
- // BigInt and BigDecimal math are supported
252
- entity.count = entity.count + BigInt.fromI32(1)
253
-
254
- // Entity fields can be set based on event parameters
255
- ${generateEventFieldAssignments(event)
256
- .slice(0, 2)
257
- .join('\n')}
258
-
259
- // Entities can be written to the store with \`.save()\`
260
- entity.save()
261
-
262
- // Note: If a handler doesn't require existing field values, it is faster
263
- // _not_ to load the entity from the store. Instead, create it fresh with
264
- // \`new Entity(...)\`, set the fields that should be updated and save the
265
- // entity back to the store. Fields that were not set or unset remain
266
- // unchanged, allowing for partial updates to be applied.
267
-
268
- // It is also possible to access smart contracts from mappings. For
269
- // example, the contract that has emitted the event can be connected to
270
- // with:
271
- //
272
- // let contract = Contract.bind(event.address)
273
- //
274
- // The following functions can then be called on this contract to access
275
- // state variables and other data:
276
- //
277
- // ${
278
- abi
279
- .codeGenerator()
280
- .callableFunctions()
281
- .isEmpty()
282
- ? 'None'
283
- : abi
284
- .codeGenerator()
285
- .callableFunctions()
286
- .map(fn => `- contract.${fn.get('name')}(...)`)
287
- .join('\n// ')
288
- }
289
- }
290
- `
291
- : `
292
- export function handle${event._alias}(event: ${event._alias}): void {}
293
- `,
294
- )
295
- .join('\n')}`
296
-
297
- const generateMapping = ({ abi, indexEvents, contractName }) => {
298
- let events = abiEvents(abi).toJS()
299
- return prettier.format(
300
- indexEvents
301
- ? generateEventIndexingHandlers(events, contractName)
302
- : generatePlaceholderHandlers({ abi, events: events, contractName }),
303
- { parser: 'typescript', semi: false },
304
- )
305
- }
306
-
307
- const generateScaffold = async (
308
- { abi, address, network, subgraphName, indexEvents, contractName = 'Contract', node },
309
- spinner,
310
- ) => {
311
- step(spinner, 'Generate subgraph from ABI')
312
- let packageJson = generatePackageJson({ subgraphName, node })
313
- let manifest = generateManifest({ abi, address, network, contractName })
314
- let schema = generateSchema({ abi, indexEvents, contractName })
315
- let mapping = generateMapping({ abi, subgraphName, indexEvents, contractName })
316
-
317
- return {
318
- 'package.json': packageJson,
319
- 'subgraph.yaml': manifest,
320
- 'schema.graphql': schema,
321
- 'tsconfig.json': tsConfig,
322
- src: { 'mapping.ts': mapping },
323
- abis: {
324
- [`${contractName}.json`]: prettier.format(JSON.stringify(abi.data), {
325
- parser: 'json',
326
- }),
327
- },
328
- }
329
- }
330
-
331
- const writeScaffoldDirectory = async (scaffold, directory, spinner) => {
332
- // Create directory itself
333
- await fs.mkdirs(directory)
334
-
335
- let promises = Object.keys(scaffold).map(async basename => {
336
- let content = scaffold[basename]
337
- let filename = path.join(directory, basename)
338
-
339
- // Write file or recurse into subdirectory
340
- if (typeof content === 'string') {
341
- await fs.writeFile(filename, content, { encoding: 'utf-8' })
342
- } else {
343
- writeScaffoldDirectory(content, path.join(directory, basename), spinner)
344
- }
345
- })
346
-
347
- await Promise.all(promises)
348
- }
349
-
350
- const writeScaffold = async (scaffold, directory, spinner) => {
351
- step(spinner, `Write subgraph to directory`)
352
- await writeScaffoldDirectory(scaffold, directory, spinner)
353
- }
354
-
355
- module.exports = {
356
- ...module.exports,
357
- abiEvents,
358
- generateEventFieldAssignments,
359
- generateManifest,
360
- generateMapping,
361
- generateScaffold,
362
- generateSchema,
363
- writeScaffold,
364
- }