@graphprotocol/graph-cli 0.30.0-alpha.0 → 0.30.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 (66) hide show
  1. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/arweave.ts +76 -0
  2. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/cosmos.ts +341 -0
  3. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/ethereum.ts +39 -0
  4. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/global/global.ts +286 -142
  5. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/index.ts +4 -2
  6. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/package.json +2 -1
  7. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/test/test.js +4 -2
  8. package/examples/basic-event-handlers/node_modules/keccak/build/config.gypi +300 -125
  9. package/examples/basic-event-handlers/node_modules/websocket/build/config.gypi +292 -15
  10. package/examples/basic-event-handlers/package.json +1 -1
  11. package/examples/basic-event-handlers/yarn.lock +4 -4
  12. package/examples/example-subgraph/package.json +1 -1
  13. package/examples/example-subgraph/yarn.lock +4 -4
  14. package/package.json +1 -1
  15. package/resources/test/docker-compose.yml +4 -2
  16. package/src/codegen/schema.js +8 -45
  17. package/src/codegen/schema.test.js +102 -6
  18. package/src/codegen/types/conversions.js +19 -19
  19. package/src/codegen/types/index.js +0 -25
  20. package/src/codegen/types/index.test.js +0 -22
  21. package/src/command-helpers/abi.js +69 -0
  22. package/src/command-helpers/scaffold.js +67 -0
  23. package/src/commands/add.js +198 -0
  24. package/src/commands/init.js +25 -71
  25. package/src/migrations/spec_version_0_0_2.js +1 -1
  26. package/src/migrations/{spec_version_0_0_4.js → spec_version_0_0_3.js} +10 -6
  27. package/src/migrations.js +1 -1
  28. package/src/protocols/arweave/manifest.graphql +57 -0
  29. package/src/protocols/arweave/scaffold/manifest.js +19 -0
  30. package/src/protocols/arweave/scaffold/mapping.js +53 -0
  31. package/src/protocols/arweave/subgraph.js +20 -0
  32. package/src/protocols/{tendermint → cosmos}/manifest.graphql +6 -0
  33. package/src/protocols/cosmos/scaffold/manifest.js +16 -0
  34. package/src/protocols/cosmos/scaffold/mapping.js +39 -0
  35. package/src/protocols/{tendermint → cosmos}/subgraph.js +2 -1
  36. package/src/protocols/ethereum/codegen/abi.js +21 -4
  37. package/src/protocols/ethereum/scaffold/manifest.js +2 -1
  38. package/src/protocols/index.js +53 -20
  39. package/src/protocols/near/manifest.graphql +1 -0
  40. package/src/protocols/near/scaffold/manifest.js +4 -2
  41. package/src/scaffold/cosmos.test.js +86 -0
  42. package/src/scaffold/ethereum.test.js +2 -1
  43. package/src/scaffold/index.js +5 -3
  44. package/src/scaffold/near.test.js +2 -1
  45. package/src/validation/manifest.js +52 -12
  46. package/src/validation/schema.js +2 -0
  47. package/tests/cli/validation/conflicting-protocol-names/Abi.json +7 -0
  48. package/tests/cli/validation/conflicting-protocol-names/mapping.ts +0 -0
  49. package/tests/cli/validation/conflicting-protocol-names/schema.graphql +3 -0
  50. package/tests/cli/validation/conflicting-protocol-names/subgraph.yaml +41 -0
  51. package/tests/cli/validation/conflicting-protocol-names.stderr +10 -0
  52. package/tests/cli/validation.test.js +9 -0
  53. package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/tendermint.ts +0 -554
  54. package/examples/basic-event-handlers/node_modules/keccak/build/Makefile +0 -342
  55. package/examples/basic-event-handlers/node_modules/keccak/build/Release/.deps/Release/obj.target/keccak/src/addon.o.d.raw +0 -27
  56. package/examples/basic-event-handlers/node_modules/keccak/build/binding.Makefile +0 -6
  57. package/examples/basic-event-handlers/node_modules/keccak/build/gyp-mac-tool +0 -615
  58. package/examples/basic-event-handlers/node_modules/keccak/build/keccak.target.mk +0 -209
  59. package/examples/basic-event-handlers/node_modules/websocket/build/Makefile +0 -347
  60. package/examples/basic-event-handlers/node_modules/websocket/build/Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d.raw +0 -25
  61. package/examples/basic-event-handlers/node_modules/websocket/build/binding.Makefile +0 -6
  62. package/examples/basic-event-handlers/node_modules/websocket/build/bufferutil.target.mk +0 -192
  63. package/examples/basic-event-handlers/node_modules/websocket/build/gyp-mac-tool +0 -615
  64. package/examples/basic-event-handlers/node_modules/websocket/build/validation.target.mk +0 -192
  65. package/src/codegen/types/defaults.js +0 -34
  66. package/src/migrations/mapping_api_version_0_0_6.js +0 -74
@@ -188,28 +188,28 @@ const VALUE_TO_ASSEMBLYSCRIPT = [
188
188
  const ASSEMBLYSCRIPT_TO_VALUE = [
189
189
  // Arrays
190
190
 
191
- ['Array<Address>', '[Bytes]', code => `Value.fromBytesArray(${code})`, 'new Array(0)'],
192
- ['Array<Bytes>', '[Bytes]', code => `Value.fromBytesArray(${code})`, 'new Array(0)'],
193
- ['Array<boolean>', '[Boolean]', code => `Value.fromBooleanArray(${code})`, 'new Array(0)'],
194
- ['Array<i32>', '[Int]', code => `Value.fromI32Array(${code})`, 'new Array(0)'],
195
- ['Array<BigInt>', '[BigInt]', code => `Value.fromBigIntArray(${code})`, 'new Array(0)'],
196
- ['Array<string>', '[String]', code => `Value.fromStringArray(${code})`, 'new Array(0)'],
197
- ['Array<string>', '[ID]', code => `Value.fromStringArray(${code})`, 'new Array(0)'],
198
- ['Array<BigDecimal>', '[BigDecimal]', code => `Value.fromBigDecimalArray(${code})`, 'new Array(0)'],
199
- ['Array<string>', /\[.*\]/, code => `Value.fromStringArray(${code})`, 'new Array(0)'],
200
- ['Array<string | null>', null, code => `Value.fromStringArray(${code})`, 'new Array(0)'],
191
+ ['Array<Address>', '[Bytes]', code => `Value.fromBytesArray(${code})`],
192
+ ['Array<Bytes>', '[Bytes]', code => `Value.fromBytesArray(${code})`],
193
+ ['Array<boolean>', '[Boolean]', code => `Value.fromBooleanArray(${code})`],
194
+ ['Array<i32>', '[Int]', code => `Value.fromI32Array(${code})`],
195
+ ['Array<BigInt>', '[BigInt]', code => `Value.fromBigIntArray(${code})`],
196
+ ['Array<string>', '[String]', code => `Value.fromStringArray(${code})`],
197
+ ['Array<string>', '[ID]', code => `Value.fromStringArray(${code})`],
198
+ ['Array<BigDecimal>', '[BigDecimal]', code => `Value.fromBigDecimalArray(${code})`],
199
+ ['Array<string>', /\[.*\]/, code => `Value.fromStringArray(${code})`],
200
+ ['Array<string | null>', null, code => `Value.fromStringArray(${code})`],
201
201
 
202
202
  // Scalar values
203
203
 
204
- ['Address', 'Bytes', code => `Value.fromBytes(${code})`, 'Address.zero()'],
205
- ['Bytes', 'Bytes', code => `Value.fromBytes(${code})`, 'Bytes.empty()'],
206
- ['boolean', 'Boolean', code => `Value.fromBoolean(${code})`, 'false'],
207
- ['i32', 'Int', code => `Value.fromI32(${code})`, '0'],
208
- ['BigInt', 'BigInt', code => `Value.fromBigInt(${code})`, 'BigInt.zero()'],
209
- ['string', 'String', code => `Value.fromString(${code})`, "''"],
210
- ['string', 'ID', code => `Value.fromString(${code})`, "''"],
211
- ['BigDecimal', 'BigDecimal', code => `Value.fromBigDecimal(${code})`, 'BigDecimal.zero()'],
212
- ['string', /.*/, code => `Value.fromString(${code})`, "''"],
204
+ ['Address', 'Bytes', code => `Value.fromBytes(${code})`],
205
+ ['Bytes', 'Bytes', code => `Value.fromBytes(${code})`],
206
+ ['boolean', 'Boolean', code => `Value.fromBoolean(${code})`],
207
+ ['i32', 'Int', code => `Value.fromI32(${code})`],
208
+ ['BigInt', 'BigInt', code => `Value.fromBigInt(${code})`],
209
+ ['string', 'String', code => `Value.fromString(${code})`],
210
+ ['string', 'ID', code => `Value.fromString(${code})`],
211
+ ['BigDecimal', 'BigDecimal', code => `Value.fromBigDecimal(${code})`],
212
+ ['string', /.*/, code => `Value.fromString(${code})`],
213
213
  ]
214
214
 
215
215
  /**
@@ -66,27 +66,6 @@ const findConversionToType = (fromTypeSystem, toTypeSystem, toType) => {
66
66
  return objectifyConversion(fromTypeSystem, toTypeSystem, conversion)
67
67
  }
68
68
 
69
- const findInitializationForType = (fromTypeSystem, toTypeSystem, ascType) => {
70
- const conversions = conversionsForTypeSystems(fromTypeSystem, toTypeSystem)
71
-
72
- const conversion = conversions.find(conversion =>
73
- typeof conversion.get(0) === 'string'
74
- ? conversion.get(0) === ascType
75
- : ascType.match(conversion.get(0)),
76
- )
77
-
78
- if (conversion === undefined) {
79
- throw new Error(
80
- `Conversion from '${fromTypeSystem}' to '${toTypeSystem}' for ` +
81
- `target type '${ascType}' is not supported`,
82
- )
83
- }
84
-
85
- const conversionObj = objectifyConversion(fromTypeSystem, toTypeSystem, conversion)
86
-
87
- return conversionObj.get('convert')(conversion.get(3))
88
- }
89
-
90
69
  // High-level type system API
91
70
 
92
71
  const ascTypeForProtocol = (protocol, protocolType) =>
@@ -120,9 +99,6 @@ const valueToAsc = (code, valueType) =>
120
99
  const valueFromAsc = (code, valueType) =>
121
100
  findConversionToType('AssemblyScript', 'Value', valueType).get('convert')(code)
122
101
 
123
- const initializedValueFromAsc = ascType =>
124
- findInitializationForType('AssemblyScript', 'Value', ascType)
125
-
126
102
  module.exports = {
127
103
  // protocol <-> AssemblyScript
128
104
  ascTypeForProtocol,
@@ -138,5 +114,4 @@ module.exports = {
138
114
  valueTypeForAsc,
139
115
  valueToAsc,
140
116
  valueFromAsc,
141
- initializedValueFromAsc,
142
117
  }
@@ -449,26 +449,4 @@ describe('AssemblyScript -> Value', () => {
449
449
  expect(codegen.valueFromAsc('x', '[String]')).toBe('Value.fromStringArray(x)')
450
450
  expect(codegen.valueTypeForAsc('Array<string>')).toBe('[String]')
451
451
  })
452
-
453
- describe('Initialization for zero/empty values', () => {
454
- test('Array<string>', () => {
455
- expect(codegen.initializedValueFromAsc('Array<string>')).toBe('Value.fromStringArray(new Array(0))')
456
- })
457
-
458
- test('Array<string | null>', () => {
459
- expect(codegen.initializedValueFromAsc('Array<string | null>')).toBe('Value.fromStringArray(new Array(0))')
460
- })
461
-
462
- test('i32', () => {
463
- expect(codegen.initializedValueFromAsc('i32')).toBe('Value.fromI32(0)')
464
- })
465
-
466
- test('string', () => {
467
- expect(codegen.initializedValueFromAsc('string')).toBe("Value.fromString('')")
468
- })
469
-
470
- test('BigInt', () => {
471
- expect(codegen.initializedValueFromAsc('BigInt')).toBe('Value.fromBigInt(BigInt.zero())')
472
- })
473
- })
474
452
  })
@@ -0,0 +1,69 @@
1
+ const { withSpinner } = require('./spinner')
2
+ const fetch = require('node-fetch')
3
+ const immutable = require('immutable')
4
+
5
+ const loadAbiFromEtherscan = async (ABI, network, address) =>
6
+ await withSpinner(
7
+ `Fetching ABI from Etherscan`,
8
+ `Failed to fetch ABI from Etherscan`,
9
+ `Warnings while fetching ABI from Etherscan`,
10
+ async spinner => {
11
+ const scanApiUrl = getEtherscanLikeAPIUrl(network);
12
+ let result = await fetch(
13
+ `${scanApiUrl}?module=contract&action=getabi&address=${address}`,
14
+ )
15
+ let json = await result.json()
16
+
17
+ // Etherscan returns a JSON object that has a `status`, a `message` and
18
+ // a `result` field. The `status` is '0' in case of errors and '1' in
19
+ // case of success
20
+ if (json.status === '1') {
21
+ return new ABI('Contract', undefined, immutable.fromJS(JSON.parse(json.result)))
22
+ } else {
23
+ throw new Error('ABI not found, try loading it from a local file')
24
+ }
25
+ },
26
+ )
27
+
28
+ const loadAbiFromBlockScout = async (ABI, network, address) =>
29
+ await withSpinner(
30
+ `Fetching ABI from BlockScout`,
31
+ `Failed to fetch ABI from BlockScout`,
32
+ `Warnings while fetching ABI from BlockScout`,
33
+ async spinner => {
34
+ let result = await fetch(
35
+ `https://blockscout.com/${
36
+ network.replace('-', '/')
37
+ }/api?module=contract&action=getabi&address=${address}`,
38
+ )
39
+ let json = await result.json()
40
+
41
+ // BlockScout returns a JSON object that has a `status`, a `message` and
42
+ // a `result` field. The `status` is '0' in case of errors and '1' in
43
+ // case of success
44
+ if (json.status === '1') {
45
+ return new ABI('Contract', undefined, immutable.fromJS(JSON.parse(json.result)))
46
+ } else {
47
+ throw new Error('ABI not found, try loading it from a local file')
48
+ }
49
+ },
50
+ )
51
+
52
+ const getEtherscanLikeAPIUrl = (network) => {
53
+ switch (network) {
54
+ case "mainnet": return `https://api.etherscan.io/api`
55
+ case "arbitrum-one": return `https://api.arbiscan.io/api`
56
+ case "bsc": return `https://api.bscscan.com/api`
57
+ case "matic": return `https://api.polygonscan.com/api`
58
+ case "mumbai": return `https://api-testnet.polygonscan.com/api`
59
+ case "aurora": return `https://api.aurorascan.dev/api`
60
+ case "aurora-testnet": return `https://api-testnet.aurorascan.dev/api`
61
+ case "optimism-kovan": return `https://api-kovan-optimistic.etherscan.io/api`
62
+ default: return `https://api-${network}.etherscan.io/api`
63
+ }
64
+ }
65
+
66
+ module.exports = {
67
+ loadAbiFromEtherscan,
68
+ loadAbiFromBlockScout,
69
+ }
@@ -1,8 +1,28 @@
1
1
  const fs = require('fs-extra')
2
2
  const path = require('path')
3
+ const prettier = require('prettier')
4
+ const yaml = require('yaml')
3
5
 
4
6
  const { step } = require('./spinner')
5
7
  const Scaffold = require('../scaffold')
8
+ const { generateEventIndexingHandlers } = require('../scaffold/mapping')
9
+ const { generateEventType, abiEvents } = require('../scaffold/schema')
10
+ const { strings } = require('gluegun')
11
+ const { Map } = require('immutable')
12
+
13
+ const generateDataSource = async (protocol, contractName, network, contractAddress, abi) => {
14
+ const protocolManifest = protocol.getManifestScaffold()
15
+
16
+ return Map.of(
17
+ 'kind', protocol.name,
18
+ 'name', contractName,
19
+ 'network', network,
20
+ 'source', yaml.parse(prettier.format(protocolManifest.source({contract: contractAddress, contractName}),
21
+ {parser: 'yaml'})),
22
+ 'mapping', yaml.parse(prettier.format(protocolManifest.mapping({abi, contractName}),
23
+ {parser: 'yaml'}))
24
+ ).asMutable()
25
+ }
6
26
 
7
27
  const generateScaffold = async (
8
28
  {
@@ -13,6 +33,7 @@ const generateScaffold = async (
13
33
  subgraphName,
14
34
  indexEvents,
15
35
  contractName = 'Contract',
36
+ dataSourceName,
16
37
  node,
17
38
  },
18
39
  spinner,
@@ -27,6 +48,7 @@ const generateScaffold = async (
27
48
  network,
28
49
  contractName,
29
50
  subgraphName,
51
+ dataSourceName,
30
52
  node,
31
53
  })
32
54
 
@@ -59,8 +81,53 @@ const writeScaffold = async (scaffold, directory, spinner) => {
59
81
  await writeScaffoldDirectory(scaffold, directory, spinner)
60
82
  }
61
83
 
84
+ const writeABI = async (abi, contractName, abiPath = `./abis/${contractName}.json`) => {
85
+ let data = prettier.format(JSON.stringify(abi.data), {
86
+ parser: 'json',
87
+ })
88
+
89
+ await fs.writeFile(abiPath, data, { encoding: 'utf-8' })
90
+ }
91
+
92
+ const writeSchema = async (abi, protocol, schemaPath, entities) => {
93
+ const events = protocol.hasEvents()
94
+ ? abiEvents(abi).filter(event => entities.indexOf(event.get('name')) === -1).toJS()
95
+ : []
96
+
97
+ let data = prettier.format(
98
+ events.map(
99
+ event => generateEventType(event, protocol.name)
100
+ ).join('\n\n'),
101
+ {
102
+ parser: 'graphql',
103
+ },
104
+ )
105
+
106
+ await fs.appendFile(schemaPath, data, { encoding: 'utf-8' })
107
+ }
108
+
109
+ const writeMapping = async (abi, protocol, contractName, entities) => {
110
+ const events = protocol.hasEvents()
111
+ ? abiEvents(abi).filter(event => entities.indexOf(event.get('name')) === -1).toJS()
112
+ : []
113
+
114
+ let mapping = prettier.format(
115
+ generateEventIndexingHandlers(
116
+ events,
117
+ contractName,
118
+ ),
119
+ { parser: 'typescript', semi: false },
120
+ )
121
+
122
+ await fs.writeFile(`./src/${strings.kebabCase(contractName)}.ts`, mapping, { encoding: 'utf-8' })
123
+ }
124
+
62
125
  module.exports = {
63
126
  ...module.exports,
64
127
  generateScaffold,
65
128
  writeScaffold,
129
+ generateDataSource,
130
+ writeABI,
131
+ writeSchema,
132
+ writeMapping,
66
133
  }
@@ -0,0 +1,198 @@
1
+ const chalk = require('chalk')
2
+ const toolbox = require('gluegun/toolbox')
3
+ const immutable = require('immutable')
4
+ const { withSpinner } = require('../command-helpers/spinner')
5
+ const Subgraph = require('../subgraph')
6
+ const Protocol = require('../protocols')
7
+ const DataSourcesExtractor = require('../command-helpers/data-sources')
8
+ const { generateDataSource, writeABI, writeSchema, writeMapping } = require('../command-helpers/scaffold')
9
+ const { loadAbiFromEtherscan, loadAbiFromBlockScout } = require('../command-helpers/abi')
10
+ const EthereumABI = require('../protocols/ethereum/abi')
11
+ const { fixParameters } = require('../command-helpers/gluegun')
12
+
13
+ const HELP = `
14
+ ${chalk.bold('graph add')} <address> [<subgraph-manifest default: "./subgraph.yaml">]
15
+
16
+ ${chalk.dim('Options:')}
17
+
18
+ --abi <path> Path to the contract ABI (default: download from Etherscan)
19
+ --contract-name Name of the contract (default: Contract)
20
+ --merge-entities Whether to merge entities with the same name (default: false)
21
+ -h, --help Show usage information
22
+ `
23
+
24
+ module.exports = {
25
+ description: 'Creates a new subgraph with basic scaffolding',
26
+ run: async toolbox => {
27
+ // Obtain tools
28
+ let { print, system } = toolbox
29
+
30
+ // Read CLI parameters
31
+ let {
32
+ abi,
33
+ contractName,
34
+ h,
35
+ help,
36
+ mergeEntities
37
+ } = toolbox.parameters.options
38
+
39
+ let address = toolbox.parameters.first
40
+ let manifestPath = toolbox.parameters.second || './subgraph.yaml'
41
+ contractName = contractName || 'Contract'
42
+
43
+ // Validate the address
44
+ if (!address) {
45
+ print.error('No contract address provided')
46
+ process.exitCode = 1
47
+ return
48
+ }
49
+
50
+ try {
51
+ fixParameters(toolbox.parameters, {
52
+ h,
53
+ help,
54
+ mergeEntities,
55
+ })
56
+ } catch (e) {
57
+ print.error(e.message)
58
+ process.exitCode = 1
59
+ return
60
+ }
61
+
62
+ // Show help text if requested
63
+ if (help || h) {
64
+ print.info(HELP)
65
+ return
66
+ }
67
+
68
+ const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifestPath)
69
+ let protocol = Protocol.fromDataSources(dataSourcesAndTemplates)
70
+ let manifest = await Subgraph.load(manifestPath, { protocol })
71
+ let network = manifest.result.get('dataSources').get(0).get('network')
72
+ let result = manifest.result.asMutable()
73
+
74
+ let entities = getEntities(manifest)
75
+ let contractNames = getContractNames(manifest)
76
+ if (contractNames.indexOf(contractName) !== -1) {
77
+ print.error(
78
+ `Datasource or template with name ${contractName} already exists, please choose a different name`,
79
+ )
80
+ process.exitCode = 1
81
+ return
82
+ }
83
+
84
+ let ethabi = null
85
+ if (abi) {
86
+ ethabi = EthereumABI.load(contractName, abi)
87
+ } else {
88
+ if (network === 'poa-core') {
89
+ ethabi = await loadAbiFromBlockScout(EthereumABI, network, address)
90
+ } else {
91
+ ethabi = await loadAbiFromEtherscan(EthereumABI, network, address)
92
+ }
93
+ }
94
+
95
+ let { collisionEntities, onlyCollisions, abiData } = updateEventNamesOnCollision(ethabi, entities, contractName, mergeEntities)
96
+ ethabi.data = abiData
97
+
98
+ await writeABI(ethabi, contractName, abi)
99
+ await writeSchema(ethabi, protocol, result.getIn(['schema', 'file']), collisionEntities)
100
+ await writeMapping(ethabi, protocol, contractName, collisionEntities)
101
+
102
+ let dataSources = result.get('dataSources')
103
+ let dataSource = await generateDataSource(protocol,
104
+ contractName, network, address, ethabi)
105
+
106
+ // Handle the collisions edge case by copying another data source yaml data
107
+ if (mergeEntities && onlyCollisions) {
108
+ let firstDataSource = dataSources.get(0)
109
+ let source = dataSource.get('source')
110
+ let mapping = firstDataSource.get('mapping').asMutable()
111
+
112
+ // Save the address of the new data source
113
+ source.abi = firstDataSource.get('source').get('abi')
114
+
115
+ dataSource.set('mapping', mapping)
116
+ dataSource.set('source', source)
117
+ }
118
+
119
+ result.set('dataSources', dataSources.push(dataSource))
120
+
121
+ await Subgraph.write(result, manifestPath)
122
+
123
+ // Detect Yarn and/or NPM
124
+ let yarn = await system.which('yarn')
125
+ let npm = await system.which('npm')
126
+ if (!yarn && !npm) {
127
+ print.error(
128
+ `Neither Yarn nor NPM were found on your system. Please install one of them.`,
129
+ )
130
+ process.exitCode = 1
131
+ return
132
+ }
133
+
134
+ await withSpinner(
135
+ 'Running codegen',
136
+ 'Failed to run codegen',
137
+ 'Warning during codegen',
138
+ async spinner => {
139
+ await system.run(yarn ? 'yarn codegen' : 'npm run codegen')
140
+ }
141
+ )
142
+ }
143
+ }
144
+
145
+ const getEntities = (manifest) => {
146
+ let dataSources = manifest.result.get('dataSources', immutable.List())
147
+ let templates = manifest.result.get('templates', immutable.List())
148
+
149
+ return dataSources
150
+ .concat(templates)
151
+ .map(dataSource => dataSource.getIn(['mapping', 'entities']))
152
+ .flatten()
153
+ }
154
+
155
+ const getContractNames = (manifest) => {
156
+ let dataSources = manifest.result.get('dataSources', immutable.List())
157
+ let templates = manifest.result.get('templates', immutable.List())
158
+
159
+ return dataSources
160
+ .concat(templates)
161
+ .map(dataSource => dataSource.get('name'))
162
+ }
163
+
164
+ const updateEventNamesOnCollision = (ethabi, entities, contractName, mergeEntities) => {
165
+ let abiData = ethabi.data
166
+ let { print } = toolbox
167
+ let collisionEntities = []
168
+ let onlyCollisions = true
169
+
170
+ for (let i = 0; i < abiData.size; i++) {
171
+ let dataRow = abiData.get(i).asMutable()
172
+
173
+ if (dataRow.get('type') === 'event'){
174
+ if (entities.indexOf(dataRow.get('name')) !== -1) {
175
+ if (entities.indexOf(`${contractName}${dataRow.get('name')}`) !== -1) {
176
+ print.error(`Contract name ('${contractName}')
177
+ + event name ('${dataRow.get('name')}') entity already exists.`)
178
+ process.exitCode = 1
179
+ return
180
+ }
181
+
182
+ if (mergeEntities) {
183
+ collisionEntities.push(dataRow.get('name'))
184
+ abiData = abiData.asImmutable().delete(i) // needs to be immutable when deleting, yes you read that right - https://github.com/immutable-js/immutable-js/issues/1901
185
+ i-- // deletion also shifts values to the left
186
+ continue
187
+ } else {
188
+ dataRow.set('name', `${contractName}${dataRow.get('name')}`)
189
+ }
190
+ } else {
191
+ onlyCollisions = false
192
+ }
193
+ }
194
+ abiData = abiData.asMutable().set(i, dataRow)
195
+ }
196
+
197
+ return { abiData, collisionEntities, onlyCollisions }
198
+ }
@@ -16,6 +16,7 @@ const { initNetworksConfig } = require('../command-helpers/network')
16
16
  const { withSpinner, step } = require('../command-helpers/spinner')
17
17
  const { fixParameters } = require('../command-helpers/gluegun')
18
18
  const { chooseNodeUrl } = require('../command-helpers/node')
19
+ const { loadAbiFromEtherscan, loadAbiFromBlockScout } = require('../command-helpers/abi')
19
20
  const { generateScaffold, writeScaffold } = require('../command-helpers/scaffold')
20
21
  const { abiEvents } = require('../scaffold/schema')
21
22
  const { validateContract } = require('../validation')
@@ -57,6 +58,11 @@ ${chalk.dim.underline('NEAR:')}
57
58
 
58
59
  --network <${availableNetworks.get('near').join('|')}>
59
60
  Selects the network the contract is deployed to
61
+
62
+ ${chalk.dim.underline('Cosmos:')}
63
+
64
+ --network <${availableNetworks.get('cosmos').join('|')}>
65
+ Selects the network the contract is deployed to
60
66
  `
61
67
 
62
68
  const processInitForm = async (
@@ -169,6 +175,11 @@ const processInitForm = async (
169
175
  return value
170
176
  },
171
177
  },
178
+ // TODO:
179
+ //
180
+ // protocols that don't support contract
181
+ // - arweave
182
+ // - tendermint
172
183
  {
173
184
  type: 'input',
174
185
  name: 'contract',
@@ -176,10 +187,10 @@ const processInitForm = async (
176
187
  ProtocolContract = protocolInstance.getContract()
177
188
  return `Contract ${ProtocolContract.identifierName()}`
178
189
  },
179
- skip: fromExample !== undefined,
190
+ skip: () => fromExample !== undefined || !protocolInstance.hasContract(),
180
191
  initial: contract,
181
192
  validate: async value => {
182
- if (fromExample !== undefined) {
193
+ if (fromExample !== undefined || !protocolInstance.hasContract()) {
183
194
  return true
184
195
  }
185
196
 
@@ -237,11 +248,11 @@ const processInitForm = async (
237
248
  name: 'contractName',
238
249
  message: 'Contract Name',
239
250
  initial: contractName || 'Contract',
240
- skip: () => fromExample !== undefined,
251
+ skip: () => fromExample !== undefined || !protocolInstance.hasContract(),
241
252
  validate: value => value && value.length > 0,
242
253
  result: value => {
243
- contractName = value;
244
- return value;
254
+ contractName = value
255
+ return value
245
256
  }
246
257
  },
247
258
  ]
@@ -254,67 +265,6 @@ const processInitForm = async (
254
265
  }
255
266
  }
256
267
 
257
- const loadAbiFromBlockScout = async (ABI, network, address) =>
258
- await withSpinner(
259
- `Fetching ABI from BlockScout`,
260
- `Failed to fetch ABI from BlockScout`,
261
- `Warnings while fetching ABI from BlockScout`,
262
- async spinner => {
263
- let result = await fetch(
264
- `https://blockscout.com/${
265
- network.replace('-', '/')
266
- }/api?module=contract&action=getabi&address=${address}`,
267
- )
268
- let json = await result.json()
269
-
270
- // BlockScout returns a JSON object that has a `status`, a `message` and
271
- // a `result` field. The `status` is '0' in case of errors and '1' in
272
- // case of success
273
- if (json.status === '1') {
274
- return new ABI('Contract', undefined, immutable.fromJS(JSON.parse(json.result)))
275
- } else {
276
- throw new Error('ABI not found, try loading it from a local file')
277
- }
278
- },
279
- )
280
-
281
- const getEtherscanLikeAPIUrl = (network) => {
282
- switch(network){
283
- case "mainnet": return `https://api.etherscan.io/api`;
284
- case "arbitrum-one": return `https://api.arbiscan.io/api`;
285
- case "bsc": return `https://api.bscscan.com/api`;
286
- case "matic": return `https://api.polygonscan.com/api`;
287
- case "mumbai": return `https://api-testnet.polygonscan.com/api`;
288
- case "aurora": return `https://api.aurorascan.dev/api`;
289
- case "aurora-testnet": return `https://api-testnet.aurorascan.dev/api`;
290
- case "optimism-kovan": return `https://api-kovan-optimistic.etherscan.io/api`;
291
- default: return `https://api-${network}.etherscan.io/api`;
292
- }
293
- }
294
-
295
- const loadAbiFromEtherscan = async (ABI, network, address) =>
296
- await withSpinner(
297
- `Fetching ABI from Etherscan`,
298
- `Failed to fetch ABI from Etherscan`,
299
- `Warnings while fetching ABI from Etherscan`,
300
- async spinner => {
301
- const scanApiUrl = getEtherscanLikeAPIUrl(network);
302
- let result = await fetch(
303
- `${scanApiUrl}?module=contract&action=getabi&address=${address}`,
304
- )
305
- let json = await result.json()
306
-
307
- // Etherscan returns a JSON object that has a `status`, a `message` and
308
- // a `result` field. The `status` is '0' in case of errors and '1' in
309
- // case of success
310
- if (json.status === '1') {
311
- return new ABI('Contract', undefined, immutable.fromJS(JSON.parse(json.result)))
312
- } else {
313
- throw new Error('ABI not found, try loading it from a local file')
314
- }
315
- },
316
- )
317
-
318
268
  const loadAbiFromFile = async (ABI, filename) => {
319
269
  let exists = await toolbox.filesystem.exists(filename)
320
270
 
@@ -768,6 +718,7 @@ const initSubgraphFromContract = async (
768
718
  contract,
769
719
  indexEvents,
770
720
  contractName,
721
+ dataSourceName,
771
722
  node,
772
723
  studio,
773
724
  product,
@@ -822,6 +773,7 @@ const initSubgraphFromContract = async (
822
773
  contract,
823
774
  indexEvents,
824
775
  contractName,
776
+ dataSourceName,
825
777
  node,
826
778
  },
827
779
  spinner,
@@ -835,11 +787,13 @@ const initSubgraphFromContract = async (
835
787
  return
836
788
  }
837
789
 
838
- let identifierName = protocolInstance.getContract().identifierName()
839
- let networkConf = await initNetworksConfig(toolbox, directory, identifierName)
840
- if (networkConf !== true) {
841
- process.exitCode = 1
842
- return
790
+ if (protocolInstance.hasContract()) {
791
+ let identifierName = protocolInstance.getContract().identifierName()
792
+ let networkConf = await initNetworksConfig(toolbox, directory, identifierName)
793
+ if (networkConf !== true) {
794
+ process.exitCode = 1
795
+ return
796
+ }
843
797
  }
844
798
 
845
799
  // Initialize a fresh Git repository
@@ -6,7 +6,7 @@ const { loadManifest } = require('./util/load-manifest')
6
6
  // Spec version to 0.0.2 uses top level templates. graph-cli no longer supports
7
7
  // 0.0.1 which used nested templates.
8
8
  module.exports = {
9
- name: 'Bump mapping specVersion from 0.0.1 to 0.0.2',
9
+ name: 'Bump manifest specVersion from 0.0.1 to 0.0.2',
10
10
  predicate: async ({ sourceDir, manifestFile }) => {
11
11
  let manifest = await loadManifest(manifestFile)
12
12
  return (