@graphprotocol/graph-cli 0.30.0-alpha.0 → 0.30.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/examples/basic-event-handlers/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 +1 -1
  6. package/resources/test/docker-compose.yml +4 -2
  7. package/src/codegen/schema.js +3 -44
  8. package/src/codegen/schema.test.js +0 -6
  9. package/src/codegen/types/conversions.js +19 -19
  10. package/src/codegen/types/index.js +0 -25
  11. package/src/codegen/types/index.test.js +0 -22
  12. package/src/commands/init.js +1 -0
  13. package/src/migrations/spec_version_0_0_2.js +1 -1
  14. package/src/migrations/spec_version_0_0_3.js +29 -0
  15. package/src/migrations.js +2 -0
  16. package/src/protocols/index.js +2 -2
  17. package/src/scaffold/index.js +1 -1
  18. package/src/validation/manifest.js +52 -12
  19. package/tests/cli/init/ethereum/from-example/.gitattributes +1 -0
  20. package/tests/cli/init/ethereum/from-example/LICENSE +21 -0
  21. package/tests/cli/init/ethereum/from-example/README.md +3 -0
  22. package/tests/cli/init/ethereum/from-example/abis/Gravity.json +1 -0
  23. package/tests/cli/init/ethereum/from-example/bin/Counter.bin +1 -0
  24. package/tests/cli/init/ethereum/from-example/contracts/Gravity.sol +63 -0
  25. package/tests/cli/init/ethereum/from-example/contracts/Migrations.sol +23 -0
  26. package/tests/cli/init/ethereum/from-example/docker-compose.yml +39 -0
  27. package/tests/cli/init/ethereum/from-example/migrations/1_initial_migration.js +5 -0
  28. package/tests/cli/init/ethereum/from-example/migrations/2_deploy_contract.js +5 -0
  29. package/tests/cli/init/ethereum/from-example/migrations/3_create_gravatars.js +15 -0
  30. package/tests/cli/init/ethereum/from-example/networks.json +7 -0
  31. package/tests/cli/init/ethereum/from-example/package.json +23 -0
  32. package/tests/cli/init/ethereum/from-example/schema.graphql +6 -0
  33. package/tests/cli/init/ethereum/from-example/src/mapping.ts +22 -0
  34. package/tests/cli/init/ethereum/from-example/subgraph.yaml +27 -0
  35. package/tests/cli/init/ethereum/from-example/truffle.js +27 -0
  36. package/tests/cli/init/ethereum/from-example/yarn.lock +5977 -0
  37. package/tests/cli/validation/conflicting-protocol-names/Abi.json +7 -0
  38. package/tests/cli/validation/conflicting-protocol-names/mapping.ts +0 -0
  39. package/tests/cli/validation/conflicting-protocol-names/schema.graphql +3 -0
  40. package/tests/cli/validation/conflicting-protocol-names/subgraph.yaml +41 -0
  41. package/tests/cli/validation/conflicting-protocol-names.stderr +10 -0
  42. package/tests/cli/validation.test.js +9 -0
@@ -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.27.0-alpha.0",
12
+ "@graphprotocol/graph-ts": "0.27.0-alpha.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.27.0-alpha.0":
6
- version "0.27.0-alpha.0"
7
- resolved "https://registry.yarnpkg.com/@graphprotocol/graph-ts/-/graph-ts-0.27.0-alpha.0.tgz#1d50fc3fe7e574b09f206d60a5d9889d5e95beba"
8
- integrity sha512-aS1VQUgj3dSvodDMJSBoyYfHjBA8UsUc/JUIrz+R5DjpxFx7wq5yzzB6GGlwEhuBV93UEh4UdmRDPWT/SKD5sg==
5
+ "@graphprotocol/graph-ts@0.27.0-alpha.1":
6
+ version "0.27.0-alpha.1"
7
+ resolved "https://registry.yarnpkg.com/@graphprotocol/graph-ts/-/graph-ts-0.27.0-alpha.1.tgz#1ea72417944820959c6edb24e217b4e37099deaa"
8
+ integrity sha512-zQzbGZnP9SPo3K0y+DqPY0j80KSDAQHzGoPcR3wN8rz9++UF/vTGqWZV4f9RGY+n29SQ4KLzFzDiQaL67hxBsA==
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.27.0-alpha.0"
10
+ "@graphprotocol/graph-ts": "0.27.0-alpha.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.27.0-alpha.0":
6
- version "0.27.0-alpha.0"
7
- resolved "https://registry.yarnpkg.com/@graphprotocol/graph-ts/-/graph-ts-0.27.0-alpha.0.tgz#1d50fc3fe7e574b09f206d60a5d9889d5e95beba"
8
- integrity sha512-aS1VQUgj3dSvodDMJSBoyYfHjBA8UsUc/JUIrz+R5DjpxFx7wq5yzzB6GGlwEhuBV93UEh4UdmRDPWT/SKD5sg==
5
+ "@graphprotocol/graph-ts@0.27.0-alpha.1":
6
+ version "0.27.0-alpha.1"
7
+ resolved "https://registry.yarnpkg.com/@graphprotocol/graph-ts/-/graph-ts-0.27.0-alpha.1.tgz#1ea72417944820959c6edb24e217b4e37099deaa"
8
+ integrity sha512-zQzbGZnP9SPo3K0y+DqPY0j80KSDAQHzGoPcR3wN8rz9++UF/vTGqWZV4f9RGY+n29SQ4KLzFzDiQaL67hxBsA==
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.30.0-alpha.0",
3
+ "version": "0.30.0-alpha.1",
4
4
  "license": "(Apache-2.0 OR MIT)",
5
5
  "description": "CLI for building for and deploying to The Graph",
6
6
  "dependencies": {
@@ -1,7 +1,8 @@
1
1
  version: '3'
2
2
  services:
3
3
  graph-node:
4
- image: graphprotocol/graph-node:2e0dc0b # TODO: change to latest once it has 0.0.5
4
+ # TODO: change to "latest" once it supports apiVersion 0.0.5 and specVersion 0.0.7
5
+ image: graphprotocol/graph-node:4a8e819
5
6
  ports:
6
7
  - '18000:8000'
7
8
  - '18001:8001'
@@ -20,7 +21,8 @@ services:
20
21
  ipfs: 'ipfs:5001'
21
22
  ethereum: 'test:http://ethereum:8545'
22
23
  GRAPH_LOG: trace
23
- GRAPH_MAX_API_VERSION: '0.0.5' # TODO: remove once latest has 0.0.5 by default
24
+ GRAPH_MAX_API_VERSION: '0.0.7' # TODO: remove once "latest" supports apiVersion 0.0.7 by default
25
+ GRAPH_MAX_SPEC_VERSION: '0.0.5' # TODO: remove once "latest" supports specVersion 0.0.5 by default
24
26
  ethereum:
25
27
  image: trufflesuite/ganache-cli:latest
26
28
  ports:
@@ -120,41 +120,6 @@ module.exports = class SchemaCodeGenerator {
120
120
  return klass
121
121
  }
122
122
 
123
- // Fields that are non-nullable get an empty/zero value set in the class constructor.
124
- _generateDefaultFieldValues(fields) {
125
- const indexOfIdField = fields.findIndex(field => field.getIn(['name', 'value']) === 'id')
126
- const fieldsWithoutId = fields.remove(indexOfIdField)
127
-
128
- const fieldsSetCalls = fieldsWithoutId
129
- .map(field => {
130
- const name = field.getIn(['name', 'value'])
131
- const type = this._typeFromGraphQl(field.get('type'), true, true)
132
-
133
- const isNullable = type instanceof tsCodegen.NullableType
134
-
135
- const directives = field.get('directives')
136
- const isDerivedFrom = directives.some(directive => directive.getIn(['name', 'value']) === 'derivedFrom')
137
-
138
- return { name, type, isNullable, isDerivedFrom }
139
- })
140
- // We only call the setter with the default value in the constructor for fields that are:
141
- // - Not nullable, so that AS doesn't break when subgraph developers try to access them before a `set`
142
- // - It doesn't matter if it's primitive or not
143
- // - Not tagged as `derivedFrom`, because they only exist in query time
144
- .filter(({
145
- isNullable,
146
- isDerivedFrom,
147
- }) => !isNullable && !isDerivedFrom)
148
- .map(({ name, type, isNullable }) => {
149
- const fieldTypeString = isNullable ? type.inner.toString() : type.toString()
150
-
151
- return `
152
- this.set('${name}', ${typesCodegen.initializedValueFromAsc(fieldTypeString)})`
153
- })
154
-
155
- return fieldsSetCalls.join('')
156
- }
157
-
158
123
  _generateConstructor(entityName, fields) {
159
124
  const idField = IdField.fromFields(fields)
160
125
  return tsCodegen.method(
@@ -164,7 +129,6 @@ module.exports = class SchemaCodeGenerator {
164
129
  `
165
130
  super()
166
131
  this.set('id', ${idField.tsValueFrom()})
167
- ${this._generateDefaultFieldValues(fields)}
168
132
  `,
169
133
  )
170
134
  }
@@ -313,7 +277,7 @@ Suggestion: add an '!' to the member type of the List, change from '[${baseType}
313
277
  }
314
278
  }
315
279
 
316
- _typeFromGraphQl(gqlType, nullable = true, nullablePrimitive = false) {
280
+ _typeFromGraphQl(gqlType, nullable = true) {
317
281
  if (gqlType.get('kind') === 'NonNullType') {
318
282
  return this._typeFromGraphQl(gqlType.get('type'), false)
319
283
  } else if (gqlType.get('kind') === 'ListType') {
@@ -324,13 +288,8 @@ Suggestion: add an '!' to the member type of the List, change from '[${baseType}
324
288
  let type = tsCodegen.namedType(
325
289
  typesCodegen.ascTypeForValue(this._resolveFieldType(gqlType)),
326
290
  )
327
-
328
- // Will not wrap primitives into NullableType by default.
329
- if (!nullablePrimitive && type.isPrimitive()) {
330
- return type
331
- }
332
-
333
- return nullable ? tsCodegen.nullableType(type) : type
291
+ // In AssemblyScript, primitives cannot be nullable.
292
+ return nullable && !type.isPrimitive() ? tsCodegen.nullableType(type) : type
334
293
  }
335
294
  }
336
295
  }
@@ -114,9 +114,6 @@ describe('Schema code generator', () => {
114
114
  body: `
115
115
  super()
116
116
  this.set('id', Value.fromString(id))
117
-
118
- this.set('name', Value.fromString(''))
119
- this.set('count', Value.fromI32(0))
120
117
  `,
121
118
  },
122
119
  {
@@ -277,9 +274,6 @@ describe('Schema code generator', () => {
277
274
  body: `
278
275
  super()
279
276
  this.set('id', Value.fromString(id))
280
-
281
- this.set('amount', Value.fromBigInt(BigInt.zero()))
282
- this.set('account', Value.fromString(''))
283
277
  `,
284
278
  },
285
279
  {
@@ -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
  })
@@ -288,6 +288,7 @@ const getEtherscanLikeAPIUrl = (network) => {
288
288
  case "aurora": return `https://api.aurorascan.dev/api`;
289
289
  case "aurora-testnet": return `https://api-testnet.aurorascan.dev/api`;
290
290
  case "optimism-kovan": return `https://api-kovan-optimistic.etherscan.io/api`;
291
+ case "avalanche": return `https://api.snowtrace.io/api`;
291
292
  default: return `https://api-${network}.etherscan.io/api`;
292
293
  }
293
294
  }
@@ -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 (
@@ -0,0 +1,29 @@
1
+ const fs = require('fs-extra')
2
+ const toolbox = require('gluegun/toolbox')
3
+ const yaml = require('js-yaml')
4
+ const { loadManifest } = require('./util/load-manifest')
5
+
6
+ // Spec version 0.0.4 uses feature management, but features are
7
+ // detected and validated by the graph-node instance during subgraph
8
+ // deployment.
9
+ //
10
+ // Also, we skip spec version 0.0.3, which is considered invalid and
11
+ // non-canonical.
12
+ module.exports = {
13
+ name: 'Bump manifest specVersion from 0.0.2 to 0.0.4',
14
+ predicate: async ({ sourceDir, manifestFile }) => {
15
+ let manifest = await loadManifest(manifestFile)
16
+ return (
17
+ manifest &&
18
+ typeof manifest === 'object' &&
19
+ manifest.specVersion &&
20
+ (manifest.specVersion === '0.0.2' || manifest.specVersion === '0.0.3')
21
+ )
22
+ },
23
+ apply: async ({ manifestFile }) => {
24
+ await toolbox.patching.patch(manifestFile, {
25
+ insert: 'specVersion: 0.0.4',
26
+ replace: new RegExp(`specVersion: ['"]?0.0.[23]['"]?`),
27
+ })
28
+ },
29
+ }
package/src/migrations.js CHANGED
@@ -6,7 +6,9 @@ const MIGRATIONS = [
6
6
  require('./migrations/mapping_api_version_0_0_3'),
7
7
  require('./migrations/mapping_api_version_0_0_4'),
8
8
  require('./migrations/mapping_api_version_0_0_5'),
9
+ require('./migrations/mapping_api_version_0_0_6'),
9
10
  require('./migrations/spec_version_0_0_2'),
11
+ require('./migrations/spec_version_0_0_3'),
10
12
  require('./migrations/spec_version_0_0_4'),
11
13
  ]
12
14
 
@@ -19,7 +19,7 @@ module.exports = class Protocol {
19
19
  }
20
20
 
21
21
  constructor(name) {
22
- this.name = this.normalizeName(name)
22
+ this.name = Protocol.normalizeName(name)
23
23
  }
24
24
 
25
25
  static availableProtocols() {
@@ -67,7 +67,7 @@ module.exports = class Protocol {
67
67
  })
68
68
  }
69
69
 
70
- normalizeName(name) {
70
+ static normalizeName(name) {
71
71
  return Protocol.availableProtocols().findKey(possibleNames =>
72
72
  possibleNames.includes(name),
73
73
  )
@@ -50,7 +50,7 @@ module.exports = class Scaffold {
50
50
  },
51
51
  dependencies: {
52
52
  '@graphprotocol/graph-cli': GRAPH_CLI_VERSION,
53
- '@graphprotocol/graph-ts': `0.27.0-alpha.0`,
53
+ '@graphprotocol/graph-ts': `0.27.0-alpha.1`,
54
54
  },
55
55
  }),
56
56
  { parser: 'json' },
@@ -2,6 +2,8 @@ const immutable = require('immutable')
2
2
  const yaml = require('js-yaml')
3
3
  const path = require('path')
4
4
 
5
+ const Protocol = require('../protocols')
6
+
5
7
  const List = immutable.List
6
8
  const Map = immutable.Map
7
9
 
@@ -241,23 +243,61 @@ const validateValue = (value, ctx) => {
241
243
  }
242
244
  }
243
245
 
244
- const validateDataSourceForNetwork = (dataSources, protocol) =>
246
+ // Transforms list of data sources like this:
247
+ // [
248
+ // { name: 'contract0', kind: 'ethereum/contract', network: 'mainnet' },
249
+ // { name: 'contract1', kind: 'ethereum', network: 'mainnet' },
250
+ // { name: 'contract2', kind: 'ethereum/contract', network: 'xdai' },
251
+ // { name: 'contract3', kind: 'near', network: 'near-mainnet' },
252
+ // ]
253
+ //
254
+ // Into Immutable JS structure like this (protocol kind is normalized):
255
+ // {
256
+ // ethereum: {
257
+ // mainnet: ['contract0', 'contract1'],
258
+ // xdai: ['contract2'],
259
+ // },
260
+ // near: {
261
+ // 'near-mainnet': ['contract3'],
262
+ // },
263
+ // }
264
+ const dataSourceListToMap = dataSources =>
245
265
  dataSources
246
- .filter(dataSource => protocol.isValidKindName(dataSource.kind))
247
266
  .reduce(
248
- (networks, dataSource) =>
249
- networks.update(dataSource.network, dataSources =>
250
- (dataSources || immutable.OrderedSet()).add(dataSource.name),
267
+ (protocolKinds, dataSource) =>
268
+ protocolKinds.update(Protocol.normalizeName(dataSource.kind), networks =>
269
+ (networks || immutable.OrderedMap()).update(dataSource.network, dataSourceNames =>
270
+ (dataSourceNames || immutable.OrderedSet()).add(dataSource.name)),
251
271
  ),
252
272
  immutable.OrderedMap(),
253
273
  )
254
274
 
255
- const validateDataSourceNetworks = (value, protocol) => {
275
+ const validateDataSourceProtocolAndNetworks = value => {
256
276
  const dataSources = [...value.dataSources, ...(value.templates || [])]
257
277
 
258
- // Networks found valid for a protocol.
259
- // By searching through all data sources and templates.
260
- const networks = validateDataSourceForNetwork(dataSources, protocol)
278
+ const protocolNetworkMap = dataSourceListToMap(dataSources)
279
+
280
+ if (protocolNetworkMap.size > 1) {
281
+ return immutable.fromJS([
282
+ {
283
+ path: [],
284
+ message: `Conflicting protocol kinds used in data sources and templates:
285
+ ${protocolNetworkMap
286
+ .map(
287
+ (dataSourceNames, protocolKind) =>
288
+ ` ${
289
+ protocolKind === undefined
290
+ ? 'Data sources and templates having no protocol kind set'
291
+ : `Data sources and templates using '${protocolKind}'`
292
+ }:\n${dataSourceNames.valueSeq().flatten().map(ds => ` - ${ds}`).join('\n')}`,
293
+ )
294
+ .join('\n')}
295
+ Recommendation: Make all data sources and templates use the same protocol kind.`,
296
+ },
297
+ ])
298
+ }
299
+
300
+ const networks = protocolNetworkMap.first()
261
301
 
262
302
  if (networks.size > 1) {
263
303
  return immutable.fromJS([
@@ -310,9 +350,9 @@ const validateManifest = (value, type, schema, protocol, { resolveFile }) => {
310
350
  return errors
311
351
  }
312
352
 
313
- // Validate that all data sources are for the same `network` (this includes
314
- // _no_ network at all)
315
- return validateDataSourceNetworks(value, protocol)
353
+ // Validate that all data sources are for the same `network` and `protocol` (kind)
354
+ // (this includes _no_ network/protocol at all)
355
+ return validateDataSourceProtocolAndNetworks(value)
316
356
  }
317
357
 
318
358
  module.exports = {
@@ -0,0 +1 @@
1
+ *.sol linguist-language=Solidity
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 The Graph
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ # Example Subgraph
2
+
3
+ An example to help you get started with The Graph. For more information see the docs on https://thegraph.com/docs/.
@@ -0,0 +1 @@
1
+ [{"constant":false,"inputs":[{"name":"_imageUrl","type":"string"}],"name":"updateGravatarImage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"setMythicalGravatar","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"getGravatar","outputs":[{"name":"","type":"string"},{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"gravatarToOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"ownerToGravatar","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_displayName","type":"string"}],"name":"updateGravatarName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_displayName","type":"string"},{"name":"_imageUrl","type":"string"}],"name":"createGravatar","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"gravatars","outputs":[{"name":"owner","type":"address"},{"name":"displayName","type":"string"},{"name":"imageUrl","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"displayName","type":"string"},{"indexed":false,"name":"imageUrl","type":"string"}],"name":"NewGravatar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"displayName","type":"string"},{"indexed":false,"name":"imageUrl","type":"string"}],"name":"UpdatedGravatar","type":"event"}]
@@ -0,0 +1 @@
1
+ 60806040526000808190555060f5806100196000396000f3fe6080604052600436106043576000357c0100000000000000000000000000000000000000000000000000000000900480633fa4f245146048578063d09de08a146070575b600080fd5b348015605357600080fd5b50605a6078565b6040518082815260200191505060405180910390f35b6076607e565b005b60005481565b600160008082825401925050819055507f20d8a6f5a693f9d1d627a598e8820f7a55ee74c183aa8f1a30e8d4e8dd9a8d846000546040518082815260200191505060405180910390a156fea165627a7a72305820fca3d11af59a6ac98027ec3bebdb10711f195860d6d9abd07921c88c8c50228f0029
@@ -0,0 +1,63 @@
1
+ pragma solidity ^0.4.0;
2
+
3
+ contract GravatarRegistry {
4
+ event NewGravatar(uint id, address owner, string displayName, string imageUrl);
5
+ event UpdatedGravatar(uint id, address owner, string displayName, string imageUrl);
6
+
7
+ struct Gravatar {
8
+ address owner;
9
+ string displayName;
10
+ string imageUrl;
11
+ }
12
+
13
+ Gravatar[] public gravatars;
14
+
15
+ mapping (uint => address) public gravatarToOwner;
16
+ mapping (address => uint) public ownerToGravatar;
17
+
18
+ function createGravatar(string _displayName, string _imageUrl) public {
19
+ require(ownerToGravatar[msg.sender] == 0);
20
+ uint id = gravatars.push(Gravatar(msg.sender, _displayName, _imageUrl)) - 1;
21
+
22
+ gravatarToOwner[id] = msg.sender;
23
+ ownerToGravatar[msg.sender] = id;
24
+
25
+ emit NewGravatar(id, msg.sender, _displayName, _imageUrl);
26
+ }
27
+
28
+ function getGravatar(address owner) public view returns (string, string) {
29
+ uint id = ownerToGravatar[owner];
30
+ return (gravatars[id].displayName, gravatars[id].imageUrl);
31
+ }
32
+
33
+ function updateGravatarName(string _displayName) public {
34
+ require(ownerToGravatar[msg.sender] != 0);
35
+ require(msg.sender == gravatars[ownerToGravatar[msg.sender]].owner);
36
+
37
+ uint id = ownerToGravatar[msg.sender];
38
+
39
+ gravatars[id].displayName = _displayName;
40
+ emit UpdatedGravatar(id, msg.sender, _displayName, gravatars[id].imageUrl);
41
+ }
42
+
43
+ function updateGravatarImage(string _imageUrl) public {
44
+ require(ownerToGravatar[msg.sender] != 0);
45
+ require(msg.sender == gravatars[ownerToGravatar[msg.sender]].owner);
46
+
47
+ uint id = ownerToGravatar[msg.sender];
48
+
49
+ gravatars[id].imageUrl = _imageUrl;
50
+ emit UpdatedGravatar(id, msg.sender, gravatars[id].displayName, _imageUrl);
51
+ }
52
+
53
+ // the gravatar at position 0 of gravatars[]
54
+ // is fake
55
+ // it's a mythical gravatar
56
+ // that doesn't really exist
57
+ // dani will invoke this function once when this contract is deployed
58
+ // but then no more
59
+ function setMythicalGravatar() public {
60
+ require(msg.sender == 0x8d3e809Fbd258083a5Ba004a527159Da535c8abA);
61
+ gravatars.push(Gravatar(0x0, " ", " "));
62
+ }
63
+ }
@@ -0,0 +1,23 @@
1
+ pragma solidity ^0.4.0;
2
+
3
+ contract Migrations {
4
+ address public owner;
5
+ uint public last_completed_migration;
6
+
7
+ constructor() public {
8
+ owner = msg.sender;
9
+ }
10
+
11
+ modifier restricted() {
12
+ if (msg.sender == owner) _;
13
+ }
14
+
15
+ function setCompleted(uint completed) public restricted {
16
+ last_completed_migration = completed;
17
+ }
18
+
19
+ function upgrade(address new_address) public restricted {
20
+ Migrations upgraded = Migrations(new_address);
21
+ upgraded.setCompleted(last_completed_migration);
22
+ }
23
+ }
@@ -0,0 +1,39 @@
1
+ version: '3'
2
+ services:
3
+ graph-node:
4
+ image: graphprotocol/graph-node:v0.22.0
5
+ ports:
6
+ - '8000:8000'
7
+ - '8001:8001'
8
+ - '8020:8020'
9
+ - '8030:8030'
10
+ - '8040:8040'
11
+ depends_on:
12
+ - ipfs
13
+ - postgres
14
+ environment:
15
+ postgres_host: postgres
16
+ postgres_user: graph-node
17
+ postgres_pass: let-me-in
18
+ postgres_db: graph-node
19
+ ipfs: 'ipfs:5001'
20
+ # Change next line if you want to connect to a different JSON-RPC endpoint
21
+ ethereum: 'mainnet:http://host.docker.internal:8545'
22
+ GRAPH_LOG: info
23
+ ipfs:
24
+ image: ipfs/go-ipfs:v0.4.23
25
+ ports:
26
+ - '5001:5001'
27
+ volumes:
28
+ - ./data/ipfs:/data/ipfs
29
+ postgres:
30
+ image: postgres
31
+ ports:
32
+ - '5432:5432'
33
+ command: ["postgres", "-cshared_preload_libraries=pg_stat_statements"]
34
+ environment:
35
+ POSTGRES_USER: graph-node
36
+ POSTGRES_PASSWORD: let-me-in
37
+ POSTGRES_DB: graph-node
38
+ volumes:
39
+ - ./data/postgres:/var/lib/postgresql/data