@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
@@ -9,7 +9,7 @@
9
9
  "deploy-test": "../../bin/graph deploy test/basic-event-handlers --version-label v0.0.1 --ipfs http://localhost:15001 --node http://127.0.0.1:18020"
10
10
  },
11
11
  "devDependencies": {
12
- "@graphprotocol/graph-ts": "0.24.0",
12
+ "@graphprotocol/graph-ts": "0.24.1",
13
13
  "apollo-fetch": "^0.7.0"
14
14
  },
15
15
  "dependencies": {
@@ -2,10 +2,10 @@
2
2
  # yarn lockfile v1
3
3
 
4
4
 
5
- "@graphprotocol/graph-ts@0.24.0":
6
- version "0.24.0"
7
- resolved "https://registry.yarnpkg.com/@graphprotocol/graph-ts/-/graph-ts-0.24.0.tgz#ccfa14edf015f3fc6d37b7d2a95e71ec6acc0005"
8
- integrity sha512-XciVlalOXzS2Iv8WeAwO0jwWzPBlzEWLtwNT5FdII962TAzbgZ6fx1nNGjGZLwwq38/aUX154+tdvEmL57gZqQ==
5
+ "@graphprotocol/graph-ts@0.24.1":
6
+ version "0.24.1"
7
+ resolved "https://registry.yarnpkg.com/@graphprotocol/graph-ts/-/graph-ts-0.24.1.tgz#50961b52b5383f9c5cf5e6e23fa039f24e729ddf"
8
+ integrity sha512-2vU4m5ZPQIqMlMce/z5vmOtGHRlRmcRhMfemS3NIwxCSxSBGVnX2zb7QBTzzdQKGwsAZdbz6V0okkOtvohELfQ==
9
9
  dependencies:
10
10
  assemblyscript "0.19.10"
11
11
 
@@ -7,7 +7,7 @@
7
7
  "build-wast": "../../bin/graph build -t wast subgraph.yaml"
8
8
  },
9
9
  "devDependencies": {
10
- "@graphprotocol/graph-ts": "0.24.0"
10
+ "@graphprotocol/graph-ts": "0.24.1"
11
11
  },
12
12
  "resolutions": {
13
13
  "assemblyscript": "0.19.10"
@@ -2,10 +2,10 @@
2
2
  # yarn lockfile v1
3
3
 
4
4
 
5
- "@graphprotocol/graph-ts@0.24.0":
6
- version "0.24.0"
7
- resolved "https://registry.yarnpkg.com/@graphprotocol/graph-ts/-/graph-ts-0.24.0.tgz#ccfa14edf015f3fc6d37b7d2a95e71ec6acc0005"
8
- integrity sha512-XciVlalOXzS2Iv8WeAwO0jwWzPBlzEWLtwNT5FdII962TAzbgZ6fx1nNGjGZLwwq38/aUX154+tdvEmL57gZqQ==
5
+ "@graphprotocol/graph-ts@0.24.1":
6
+ version "0.24.1"
7
+ resolved "https://registry.yarnpkg.com/@graphprotocol/graph-ts/-/graph-ts-0.24.1.tgz#50961b52b5383f9c5cf5e6e23fa039f24e729ddf"
8
+ integrity sha512-2vU4m5ZPQIqMlMce/z5vmOtGHRlRmcRhMfemS3NIwxCSxSBGVnX2zb7QBTzzdQKGwsAZdbz6V0okkOtvohELfQ==
9
9
  dependencies:
10
10
  assemblyscript "0.19.10"
11
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphprotocol/graph-cli",
3
- "version": "0.24.0",
3
+ "version": "0.25.2",
4
4
  "description": "CLI for building for and deploying to The Graph",
5
5
  "dependencies": {
6
6
  "assemblyscript": "0.19.10",
@@ -12,7 +12,7 @@
12
12
  "dockerode": "^2.5.8",
13
13
  "fs-extra": "^9.0.0",
14
14
  "glob": "^7.1.2",
15
- "gluegun": "^4.3.1",
15
+ "gluegun": "https://github.com/edgeandnode/gluegun#v4.3.1-pin-colors-dep",
16
16
  "graphql": "^15.5.0",
17
17
  "immutable": "^3.8.2",
18
18
  "ipfs-http-client": "^34.0.0",
@@ -80,17 +80,24 @@ module.exports = class SchemaCodeGenerator {
80
80
  .map(field => {
81
81
  const name = field.getIn(['name', 'value'])
82
82
  const type = this._typeFromGraphQl(field.get('type'))
83
+
83
84
  const isNullable = type instanceof tsCodegen.NullableType
85
+ const isPrimitive = type.isPrimitive && type.isPrimitive()
84
86
 
85
87
  const directives = field.get('directives')
86
88
  const isDerivedFrom = directives.some(directive => directive.getIn(['name', 'value']) === 'derivedFrom')
87
89
 
88
- return { name, type, isNullable, isDerivedFrom }
90
+ return { name, type, isNullable, isPrimitive, isDerivedFrom }
89
91
  })
90
92
  // We only call the setter with the default value in the constructor for fields that are:
93
+ // - Not primitive (such as Int/i32)
91
94
  // - Not nullable, so that AS doesn't break when subgraph developers try to access them before a `set`
92
95
  // - Not tagged as `derivedFrom`, because they only exist in query time
93
- .filter(({ isNullable, isDerivedFrom }) => !isNullable && !isDerivedFrom)
96
+ .filter(({
97
+ isNullable,
98
+ isPrimitive,
99
+ isDerivedFrom,
100
+ }) => !(isNullable || isPrimitive || isDerivedFrom))
94
101
  .map(({ name, type, isNullable }) => {
95
102
  const fieldTypeString = isNullable ? type.inner.toString() : type.toString()
96
103
 
@@ -0,0 +1,34 @@
1
+ const immutable = require('immutable')
2
+
3
+ // TODO: kill me
4
+ const EMPTY_ARRAY = 'new Array(0)'
5
+
6
+ const ASC_DEFAULTS = [
7
+ // Scalar values
8
+
9
+ ['Address', 'Address.zero()'],
10
+ ['Bytes', 'Bytes.empty()'],
11
+ ['boolean', 'false'],
12
+ ['i32', '0'],
13
+ ['string', '""'],
14
+ ['BigInt', 'BigInt.zero()'],
15
+ ['BigDecimal', 'BigDecimal.zero()'],
16
+
17
+ // Arrays
18
+
19
+ ['Array<Address>', EMPTY_ARRAY],
20
+ ['Array<Bytes>', EMPTY_ARRAY],
21
+ ['Array<boolean>', EMPTY_ARRAY],
22
+ ['Array<i32>', EMPTY_ARRAY],
23
+ ['Array<string>', EMPTY_ARRAY],
24
+ ['Array<BigInt>', EMPTY_ARRAY],
25
+ ['Array<BigDecimal>', EMPTY_ARRAY],
26
+ ['Array<string | null>', EMPTY_ARRAY],
27
+ ]
28
+
29
+ module.exports = immutable.fromJS({
30
+ AssemblyScript: ASC_DEFAULTS,
31
+ })
32
+ // TODO: use me:
33
+ // [/Array<.*>/, 'new Array(0)'],
34
+ // [/Array\<.*\>/, 'new Array(0)'],
@@ -89,8 +89,12 @@ const findInitializationForType = (fromTypeSystem, toTypeSystem, ascType) => {
89
89
 
90
90
  // High-level type system API
91
91
 
92
+ const ascTypeForProtocol = (protocol, protocolType) =>
93
+ findConversionFromType(protocol, 'AssemblyScript', protocolType).getIn(['to', 'type'])
94
+
95
+ // TODO: this can be removed/replaced by the function above
92
96
  const ascTypeForEthereum = ethereumType =>
93
- findConversionFromType('ethereum', 'AssemblyScript', ethereumType).getIn(['to', 'type'])
97
+ ascTypeForProtocol('ethereum', ethereumType)
94
98
 
95
99
  const ethereumTypeForAsc = ascType =>
96
100
  findConversionFromType('AssemblyScript', 'ethereum', ascType).getIn(['to', 'type'])
@@ -120,6 +124,9 @@ const initializedValueFromAsc = ascType =>
120
124
  findInitializationForType('AssemblyScript', 'Value', ascType)
121
125
 
122
126
  module.exports = {
127
+ // protocol <-> AssemblyScript
128
+ ascTypeForProtocol,
129
+
123
130
  // ethereum <-> AssemblyScript
124
131
  ascTypeForEthereum,
125
132
  ethereumTypeForAsc,
@@ -0,0 +1,66 @@
1
+ const fs = require('fs-extra')
2
+ const path = require('path')
3
+
4
+ const { step } = require('./spinner')
5
+ const Scaffold = require('../scaffold')
6
+
7
+ const generateScaffold = async (
8
+ {
9
+ protocolInstance,
10
+ abi,
11
+ contract,
12
+ network,
13
+ subgraphName,
14
+ indexEvents,
15
+ contractName = 'Contract',
16
+ node,
17
+ },
18
+ spinner,
19
+ ) => {
20
+ step(spinner, 'Generate subgraph')
21
+
22
+ const scaffold = new Scaffold({
23
+ protocol: protocolInstance,
24
+ abi,
25
+ indexEvents,
26
+ contract,
27
+ network,
28
+ contractName,
29
+ subgraphName,
30
+ node,
31
+ })
32
+
33
+ return scaffold.generate()
34
+ }
35
+
36
+ const writeScaffoldDirectory = async (scaffold, directory, spinner) => {
37
+ // Create directory itself
38
+ await fs.mkdirs(directory)
39
+
40
+ let promises = Object.keys(scaffold).map(async basename => {
41
+ let content = scaffold[basename]
42
+ let filename = path.join(directory, basename)
43
+
44
+ // Write file or recurse into subdirectory
45
+ if (typeof content === 'string') {
46
+ await fs.writeFile(filename, content, { encoding: 'utf-8' })
47
+ } else if (content == null) {
48
+ return // continue loop
49
+ } else {
50
+ writeScaffoldDirectory(content, path.join(directory, basename), spinner)
51
+ }
52
+ })
53
+
54
+ await Promise.all(promises)
55
+ }
56
+
57
+ const writeScaffold = async (scaffold, directory, spinner) => {
58
+ step(spinner, `Write subgraph to directory`)
59
+ await writeScaffoldDirectory(scaffold, directory, spinner)
60
+ }
61
+
62
+ module.exports = {
63
+ ...module.exports,
64
+ generateScaffold,
65
+ writeScaffold,
66
+ }
@@ -57,7 +57,7 @@ const assertGraphTsVersion = async (sourceDir, minimumGraphTsVersion) => {
57
57
  if (graphTsVersion && semver.lt(semver.coerce(graphTsVersion), minimumGraphTsVersion)) {
58
58
  throw new Error(
59
59
  `To use this version of the graph-cli you must upgrade the graph-ts dependency to a version greater than or equal to ${minimumGraphTsVersion}
60
- Also, you'll probably need to take a look at our AssemblyScript migration guide because of language breaking changes: https://gist.github.com/otaviopace/8406cb39644d2e7678570d1e7f50dac4`
60
+ Also, you'll probably need to take a look at our AssemblyScript migration guide because of language breaking changes: https://thegraph.com/docs/developer/assemblyscript-migration-guide`
61
61
  )
62
62
  }
63
63
  }
@@ -197,7 +197,7 @@ describe('Version Command Helpers', () => {
197
197
  .rejects
198
198
  .toThrow(new Error(
199
199
  `To use this version of the graph-cli you must upgrade the graph-ts dependency to a version greater than or equal to ${minimumGraphTsVersion}
200
- Also, you'll probably need to take a look at our AssemblyScript migration guide because of language breaking changes: https://gist.github.com/otaviopace/8406cb39644d2e7678570d1e7f50dac4`
200
+ Also, you'll probably need to take a look at our AssemblyScript migration guide because of language breaking changes: https://thegraph.com/docs/developer/assemblyscript-migration-guide`
201
201
  ))
202
202
  })
203
203
  test('When the installed graph-ts version is a supported one', async () => {
@@ -14,98 +14,107 @@ const { validateStudioNetwork } = require('../command-helpers/studio')
14
14
  const { withSpinner, step } = require('../command-helpers/spinner')
15
15
  const { fixParameters } = require('../command-helpers/gluegun')
16
16
  const { chooseNodeUrl } = require('../command-helpers/node')
17
- const { abiEvents, generateScaffold, writeScaffold } = require('../scaffold')
18
- // TODO: Use Protocol class to getABI
19
- const ABI = require('../protocols/ethereum/abi')
20
-
21
- const networkChoices = [
22
- 'mainnet',
23
- 'kovan',
24
- 'rinkeby',
25
- 'ropsten',
26
- 'goerli',
27
- 'poa-core',
28
- 'poa-sokol',
29
- 'xdai',
30
- 'matic',
31
- 'mumbai',
32
- 'fantom',
33
- 'bsc',
34
- 'chapel',
35
- 'clover',
36
- 'avalanche',
37
- 'fuji',
38
- 'celo',
39
- 'celo-alfajores',
40
- 'fuse',
41
- 'mbase',
42
- 'arbitrum-one',
43
- 'arbitrum-rinkeby',
44
- 'optimism',
45
- 'optimism-kovan'
46
- ]
17
+ const { generateScaffold, writeScaffold } = require('../command-helpers/scaffold')
18
+ const { abiEvents } = require('../scaffold/schema')
19
+ const { validateContract } = require('../validation')
20
+ const Protocol = require('../protocols')
21
+
22
+ const protocolChoices = Array.from(Protocol.availableProtocols().keys())
23
+ const availableNetworks = Protocol.availableNetworks()
47
24
 
48
25
  const HELP = `
49
26
  ${chalk.bold('graph init')} [options] [subgraph-name] [directory]
50
27
 
51
28
  ${chalk.dim('Options:')}
52
29
 
30
+ --protocol <${protocolChoices.join('|')}>
53
31
  --product <subgraph-studio|hosted-service>
54
- Selects the product for which to initialize
55
- --studio Shortcut for --product subgraph-studio
56
- -g, --node <node> Graph node for which to initialize
57
- --allow-simple-name Use a subgraph name without a prefix (default: false)
58
- -h, --help Show usage information
32
+ Selects the product for which to initialize
33
+ --studio Shortcut for --product subgraph-studio
34
+ -g, --node <node> Graph node for which to initialize
35
+ --allow-simple-name Use a subgraph name without a prefix (default: false)
36
+ -h, --help Show usage information
59
37
 
60
38
  ${chalk.dim('Choose mode with one of:')}
61
39
 
62
- --from-contract <address> Creates a scaffold based on an existing contract
63
- --from-example Creates a scaffold based on an example subgraph
40
+ --from-contract <contract> Creates a scaffold based on an existing contract
41
+ --from-example Creates a scaffold based on an example subgraph
64
42
 
65
43
  ${chalk.dim('Options for --from-contract:')}
66
44
 
67
- --abi <path> Path to the contract ABI (default: download from Etherscan)
68
- --network <${networkChoices.join('|')}>
69
- Selects the network the contract is deployed to
70
- --index-events Index contract events as entities
71
- --contract-name Name of the contract (default: Contract)
45
+ --contract-name Name of the contract (default: Contract)
46
+ --index-events Index contract events as entities
47
+
48
+ ${chalk.dim.underline('Ethereum:')}
49
+
50
+ --abi <path> Path to the contract ABI (default: download from Etherscan)
51
+ --network <${availableNetworks.get('ethereum').join('|')}>
52
+ Selects the network the contract is deployed to
53
+
54
+ ${chalk.dim.underline('NEAR:')}
55
+
56
+ --network <${availableNetworks.get('near').join('|')}>
57
+ Selects the network the contract is deployed to
72
58
  `
73
59
 
74
60
  const processInitForm = async (
75
61
  toolbox,
76
62
  {
63
+ protocol,
77
64
  product,
78
65
  studio,
79
66
  node,
80
67
  abi,
81
68
  allowSimpleName,
82
69
  directory,
83
- address,
70
+ contract,
84
71
  fromExample,
85
72
  network,
86
73
  subgraphName,
87
74
  contractName
88
75
  },
89
76
  ) => {
90
- let addressPattern = /^(0x)?[0-9a-fA-F]{40}$/
91
-
92
77
  let abiFromEtherscan = undefined
93
78
  let abiFromFile = undefined
79
+ let protocolInstance
80
+ let ProtocolContract
81
+ let ABI
94
82
 
95
83
  let questions = [
84
+ {
85
+ type: 'select',
86
+ name: 'protocol',
87
+ message: 'Protocol',
88
+ choices: protocolChoices,
89
+ skip: protocolChoices.includes(protocol),
90
+ result: value => {
91
+ protocol = protocol || value
92
+ protocolInstance = new Protocol(protocol)
93
+ return protocol
94
+ },
95
+ },
96
96
  {
97
97
  type: 'select',
98
98
  name: 'product',
99
99
  message: 'Product for which to initialize',
100
100
  choices: ['subgraph-studio', 'hosted-service'],
101
- skip:
101
+ skip: () =>
102
+ protocol === 'near' ||
102
103
  product === 'subgraph-studio' ||
103
104
  product === 'hosted-service' ||
104
105
  studio !== undefined || node !== undefined,
105
106
  result: value => {
107
+ // For now we only support NEAR subgraphs in the Hosted Service
108
+ if (protocol === 'near') {
109
+ // Can be overwritten because the question will be skipped (product === undefined)
110
+ product = 'hosted-service'
111
+ return product
112
+ }
113
+
106
114
  if (value == 'subgraph-studio') {
107
115
  allowSimpleName = true
108
116
  }
117
+
109
118
  product = value
110
119
  return value
111
120
  },
@@ -146,8 +155,11 @@ const processInitForm = async (
146
155
  {
147
156
  type: 'select',
148
157
  name: 'network',
149
- message: 'Ethereum network',
150
- choices: networkChoices,
158
+ message: () => `${protocolInstance.displayName()} network`,
159
+ choices: () =>
160
+ availableNetworks
161
+ .get(protocol) // Get networks related to the chosen protocol.
162
+ .toArray(), // Needed because of gluegun. It can't even receive a JS iterable.
151
163
  skip: fromExample !== undefined,
152
164
  initial: network || 'mainnet',
153
165
  result: value => {
@@ -157,35 +169,39 @@ const processInitForm = async (
157
169
  },
158
170
  {
159
171
  type: 'input',
160
- name: 'address',
161
- message: 'Contract address',
172
+ name: 'contract',
173
+ message: () => {
174
+ ProtocolContract = protocolInstance.getContract()
175
+ return `Contract ${ProtocolContract.identifierName()}`
176
+ },
162
177
  skip: fromExample !== undefined,
163
- initial: address,
178
+ initial: contract,
164
179
  validate: async value => {
165
180
  if (fromExample !== undefined) {
166
181
  return true
167
182
  }
168
183
 
169
- // Validate whether the address is valid
170
- if (!addressPattern.test(value)) {
171
- return `Contract address "${value}" is invalid.
172
- Must be 40 hexadecimal characters, with an optional '0x' prefix.`
173
- }
184
+ // Validate whether the contract is valid
185
+ const { valid, error } = validateContract(value, ProtocolContract)
174
186
 
175
- return true
187
+ return valid
188
+ ? true
189
+ : error
176
190
  },
177
191
  result: async value => {
178
192
  if (fromExample !== undefined) {
179
193
  return value
180
194
  }
181
195
 
196
+ ABI = protocolInstance.getABI()
197
+
182
198
  // Try loading the ABI from Etherscan, if none was provided
183
- if (!abi) {
199
+ if (protocolInstance.hasABIs() && !abi) {
184
200
  try {
185
201
  if (network === 'poa-core') {
186
- abiFromBlockScout = await loadAbiFromBlockScout(network, value)
202
+ abiFromBlockScout = await loadAbiFromBlockScout(ABI, network, value)
187
203
  } else {
188
- abiFromEtherscan = await loadAbiFromEtherscan(network, value)
204
+ abiFromEtherscan = await loadAbiFromEtherscan(ABI, network, value)
189
205
  }
190
206
  } catch (e) {}
191
207
  }
@@ -197,14 +213,17 @@ const processInitForm = async (
197
213
  name: 'abi',
198
214
  message: 'ABI file (path)',
199
215
  initial: abi,
200
- skip: () => fromExample !== undefined || abiFromEtherscan !== undefined,
216
+ skip: () =>
217
+ !protocolInstance.hasABIs() ||
218
+ fromExample !== undefined ||
219
+ abiFromEtherscan !== undefined,
201
220
  validate: async value => {
202
- if (fromExample || abiFromEtherscan) {
221
+ if (fromExample || abiFromEtherscan || !protocolInstance.hasABIs()) {
203
222
  return true
204
223
  }
205
224
 
206
225
  try {
207
- abiFromFile = await loadAbiFromFile(value)
226
+ abiFromFile = await loadAbiFromFile(ABI, value)
208
227
  return true
209
228
  } catch (e) {
210
229
  return e.message
@@ -227,13 +246,13 @@ const processInitForm = async (
227
246
 
228
247
  try {
229
248
  let answers = await toolbox.prompt.ask(questions)
230
- return { ...answers, abi: abiFromEtherscan || abiFromFile }
249
+ return { ...answers, abi: abiFromEtherscan || abiFromFile, protocolInstance }
231
250
  } catch (e) {
232
251
  return undefined
233
252
  }
234
253
  }
235
254
 
236
- const loadAbiFromBlockScout = async (network, address) =>
255
+ const loadAbiFromBlockScout = async (ABI, network, address) =>
237
256
  await withSpinner(
238
257
  `Fetching ABI from BlockScout`,
239
258
  `Failed to fetch ABI from BlockScout`,
@@ -260,6 +279,7 @@ const loadAbiFromBlockScout = async (network, address) =>
260
279
  const getEtherscanLikeAPIUrl = (network) => {
261
280
  switch(network){
262
281
  case "mainnet": return `https://api.etherscan.io/api`;
282
+ case "arbitrum-one": return `https://api.arbiscan.io/api`;
263
283
  case "bsc": return `https://api.bscscan.com/api`;
264
284
  case "matic": return `https://api.polygonscan.com/api`;
265
285
  case "mumbai": return `https://api-testnet.polygonscan.com/api`;
@@ -267,7 +287,7 @@ const getEtherscanLikeAPIUrl = (network) => {
267
287
  }
268
288
  }
269
289
 
270
- const loadAbiFromEtherscan = async (network, address) =>
290
+ const loadAbiFromEtherscan = async (ABI, network, address) =>
271
291
  await withSpinner(
272
292
  `Fetching ABI from Etherscan`,
273
293
  `Failed to fetch ABI from Etherscan`,
@@ -290,7 +310,7 @@ const loadAbiFromEtherscan = async (network, address) =>
290
310
  },
291
311
  )
292
312
 
293
- const loadAbiFromFile = async filename => {
313
+ const loadAbiFromFile = async (ABI, filename) => {
294
314
  let exists = await toolbox.filesystem.exists(filename)
295
315
 
296
316
  if (!exists) {
@@ -315,6 +335,7 @@ module.exports = {
315
335
 
316
336
  // Read CLI parameters
317
337
  let {
338
+ protocol,
318
339
  product,
319
340
  studio,
320
341
  node,
@@ -400,35 +421,47 @@ module.exports = {
400
421
 
401
422
  // If all parameters are provided from the command-line,
402
423
  // go straight to creating the subgraph from an existing contract
403
- if (fromContract && subgraphName && directory && network && node) {
404
- if (abi) {
405
- try {
406
- abi = await loadAbiFromFile(abi)
407
- } catch (e) {
408
- print.error(`Failed to load ABI: ${e.message}`)
409
- process.exitCode = 1
410
- return
411
- }
412
- } else {
413
- try {
414
- if (network === 'poa-core') {
415
- abi = await loadAbiFromBlockScout(network, fromContract)
416
- } else {
417
- abi = await loadAbiFromEtherscan(network, fromContract)
424
+ if (fromContract && protocol && subgraphName && directory && network && node) {
425
+ if (!protocolChoices.includes(protocol)) {
426
+ print.error(`Protocol '${protocol}' is not supported, choose from these options: ${protocolChoices.join(', ')}`)
427
+ process.exitCode = 1
428
+ return
429
+ }
430
+
431
+ const protocolInstance = new Protocol(protocol)
432
+
433
+ if (protocolInstance.hasABIs()) {
434
+ const ABI = protocolInstance.getABI()
435
+ if (abi) {
436
+ try {
437
+ abi = await loadAbiFromFile(ABI, abi)
438
+ } catch (e) {
439
+ print.error(`Failed to load ABI: ${e.message}`)
440
+ process.exitCode = 1
441
+ return
442
+ }
443
+ } else {
444
+ try {
445
+ if (network === 'poa-core') {
446
+ abi = await loadAbiFromBlockScout(ABI, network, fromContract)
447
+ } else {
448
+ abi = await loadAbiFromEtherscan(ABI, network, fromContract)
449
+ }
450
+ } catch (e) {
451
+ process.exitCode = 1
452
+ return
418
453
  }
419
- } catch (e) {
420
- process.exitCode = 1
421
- return
422
454
  }
423
455
  }
424
456
 
425
457
  return await initSubgraphFromContract(
426
458
  toolbox,
427
459
  {
460
+ protocolInstance,
428
461
  abi,
429
462
  allowSimpleName,
430
463
  directory,
431
- address: fromContract,
464
+ contract: fromContract,
432
465
  indexEvents,
433
466
  network,
434
467
  subgraphName,
@@ -443,13 +476,14 @@ module.exports = {
443
476
 
444
477
  // Otherwise, take the user through the interactive form
445
478
  let inputs = await processInitForm(toolbox, {
479
+ protocol,
446
480
  product,
447
481
  studio,
448
482
  node,
449
483
  abi,
450
484
  allowSimpleName,
451
485
  directory,
452
- address: fromContract,
486
+ contract: fromContract,
453
487
  fromExample,
454
488
  network,
455
489
  subgraphName,
@@ -484,12 +518,13 @@ module.exports = {
484
518
  await initSubgraphFromContract(
485
519
  toolbox,
486
520
  {
521
+ protocolInstance: inputs.protocolInstance,
487
522
  allowSimpleName,
488
523
  subgraphName: inputs.subgraphName,
489
524
  directory: inputs.directory,
490
525
  abi: inputs.abi,
491
526
  network: inputs.network,
492
- address: inputs.address,
527
+ contract: inputs.contract,
493
528
  indexEvents,
494
529
  contractName: inputs.contractName,
495
530
  node,
@@ -713,12 +748,13 @@ const initSubgraphFromExample = async (
713
748
  const initSubgraphFromContract = async (
714
749
  toolbox,
715
750
  {
751
+ protocolInstance,
716
752
  allowSimpleName,
717
753
  subgraphName,
718
754
  directory,
719
755
  abi,
720
756
  network,
721
- address,
757
+ contract,
722
758
  indexEvents,
723
759
  contractName,
724
760
  node,
@@ -742,7 +778,7 @@ const initSubgraphFromContract = async (
742
778
  return
743
779
  }
744
780
 
745
- if (abiEvents(abi).length === 0) {
781
+ if (protocolInstance.hasABIs() && abiEvents(abi).length === 0) {
746
782
  // Fail if the ABI does not contain any events
747
783
  print.error(`ABI does not contain any events`)
748
784
  process.exitCode = 1
@@ -760,7 +796,7 @@ const initSubgraphFromContract = async (
760
796
  return
761
797
  }
762
798
 
763
- // Scaffold subgraph from ABI
799
+ // Scaffold subgraph
764
800
  let scaffold = await withSpinner(
765
801
  `Create subgraph scaffold`,
766
802
  `Failed to create subgraph scaffold`,
@@ -768,10 +804,11 @@ const initSubgraphFromContract = async (
768
804
  async spinner => {
769
805
  let scaffold = await generateScaffold(
770
806
  {
807
+ protocolInstance,
771
808
  subgraphName,
772
809
  abi,
773
810
  network,
774
- address,
811
+ contract,
775
812
  indexEvents,
776
813
  contractName,
777
814
  node,