@graphprotocol/graph-cli 0.27.1 → 0.28.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 (35) hide show
  1. package/README.md +6 -6
  2. package/examples/basic-event-handlers/package.json +1 -1
  3. package/examples/basic-event-handlers/yarn.lock +4 -4
  4. package/examples/example-subgraph/package.json +1 -1
  5. package/examples/example-subgraph/yarn.lock +4 -4
  6. package/package.json +1 -1
  7. package/src/codegen/schema.js +105 -26
  8. package/src/codegen/schema.test.js +2 -6
  9. package/src/commands/codegen.js +1 -1
  10. package/src/commands/deploy.js +1 -1
  11. package/src/commands/init.js +1 -0
  12. package/src/protocols/index.js +34 -0
  13. package/src/protocols/tendermint/manifest.graphql +64 -0
  14. package/src/protocols/tendermint/subgraph.js +20 -0
  15. package/src/scaffold/index.js +1 -1
  16. package/src/subgraph.js +4 -0
  17. package/src/validation/manifest.js +17 -0
  18. package/src/validation/schema.js +120 -119
  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/package.json +23 -0
  31. package/tests/cli/init/ethereum/from-example/schema.graphql +6 -0
  32. package/tests/cli/init/ethereum/from-example/src/mapping.ts +22 -0
  33. package/tests/cli/init/ethereum/from-example/subgraph.yaml +27 -0
  34. package/tests/cli/init/ethereum/from-example/truffle.js +27 -0
  35. package/tests/cli/init/ethereum/from-example/yarn.lock +5977 -0
@@ -76,12 +76,12 @@ const validateEntityDirective = def =>
76
76
  def.directives.find(directive => directive.name.value === 'entity')
77
77
  ? List()
78
78
  : immutable.fromJS([
79
- {
80
- loc: def.loc,
81
- entity: def.name.value,
82
- message: `Defined without @entity directive`,
83
- },
84
- ])
79
+ {
80
+ loc: def.loc,
81
+ entity: def.name.value,
82
+ message: `Defined without @entity directive`,
83
+ },
84
+ ])
85
85
 
86
86
  const validateEntityID = def => {
87
87
  let idField = def.fields.find(field => field.name.value === 'id')
@@ -99,7 +99,9 @@ const validateEntityID = def => {
99
99
  if (
100
100
  idField.type.kind === 'NonNullType' &&
101
101
  idField.type.type.kind === 'NamedType' &&
102
- idField.type.type.name.value === 'ID'
102
+ (idField.type.type.name.value === 'ID' ||
103
+ idField.type.type.name.value === 'Bytes' ||
104
+ idField.type.type.name.value === 'String')
103
105
  ) {
104
106
  return List()
105
107
  } else {
@@ -107,7 +109,7 @@ const validateEntityID = def => {
107
109
  {
108
110
  loc: idField.loc,
109
111
  entity: def.name.value,
110
- message: `Field 'id': Entity IDs must be of type ID!`,
112
+ message: `Field 'id': Entity ids must be of type Bytes! or String!`,
111
113
  },
112
114
  ])
113
115
  }
@@ -115,22 +117,22 @@ const validateEntityID = def => {
115
117
 
116
118
  const validateListFieldType = (def, field) =>
117
119
  field.type.kind === 'NonNullType' &&
118
- field.type.kind === 'ListType' &&
119
- field.type.type.kind !== 'NonNullType'
120
+ field.type.kind === 'ListType' &&
121
+ field.type.type.kind !== 'NonNullType'
120
122
  ? immutable.fromJS([
121
- {
122
- loc: field.loc,
123
- entity: def.name.value,
124
- message: `\
123
+ {
124
+ loc: field.loc,
125
+ entity: def.name.value,
126
+ message: `\
125
127
  Field '${field.name.value}':
126
128
  Field has type [${field.type.type.name.value}]! but
127
129
  must have type [${field.type.type.name.value}!]!
128
130
 
129
131
  Reason: Lists with null elements are not supported.`,
130
- },
131
- ])
132
+ },
133
+ ])
132
134
  : field.type.kind === 'ListType' && field.type.type.kind !== 'NonNullType'
133
- ? immutable.fromJS([
135
+ ? immutable.fromJS([
134
136
  {
135
137
  loc: field.loc,
136
138
  entity: def.name.value,
@@ -142,7 +144,7 @@ must have type [${field.type.type.name.value}!]
142
144
  Reason: Lists with null elements are not supported.`,
143
145
  },
144
146
  ])
145
- : List()
147
+ : List()
146
148
 
147
149
  const unwrapType = type => {
148
150
  let innerTypeFromList = listType =>
@@ -159,8 +161,8 @@ const unwrapType = type => {
159
161
  return type.kind === 'NonNullType'
160
162
  ? innerTypeFromNonNull(type)
161
163
  : type.kind === 'ListType'
162
- ? innerTypeFromList(type)
163
- : type
164
+ ? innerTypeFromList(type)
165
+ : type
164
166
  }
165
167
 
166
168
  const gatherLocalTypes = defs =>
@@ -206,8 +208,8 @@ const gatherImportedTypes = defs =>
206
208
  type.fields.find(
207
209
  field => field.name.value == 'as' && field.value.kind == 'StringValue',
208
210
  )
209
- ? type.fields.find(field => field.name.value == 'as').value.value
210
- : undefined,
211
+ ? type.fields.find(field => field.name.value == 'as').value.value
212
+ : undefined,
211
213
  ),
212
214
  ),
213
215
  )
@@ -256,16 +258,15 @@ const validateInnerFieldType = (defs, def, field) => {
256
258
  return availableTypes.includes(typeName)
257
259
  ? List()
258
260
  : immutable.fromJS([
259
- {
260
- loc: field.loc,
261
- entity: def.name.value,
262
- message: `\
261
+ {
262
+ loc: field.loc,
263
+ entity: def.name.value,
264
+ message: `\
263
265
  Field '${field.name.value}': \
264
- Unknown type '${typeName}'.${
265
- suggestion !== undefined ? ` Did you mean '${suggestion}'?` : ''
266
+ Unknown type '${typeName}'.${suggestion !== undefined ? ` Did you mean '${suggestion}'?` : ''
266
267
  }`,
267
- },
268
- ])
268
+ },
269
+ ])
269
270
  }
270
271
 
271
272
  const validateEntityFieldType = (defs, def, field) =>
@@ -277,14 +278,14 @@ const validateEntityFieldType = (defs, def, field) =>
277
278
  const validateEntityFieldArguments = (defs, def, field) =>
278
279
  field.arguments.length > 0
279
280
  ? immutable.fromJS([
280
- {
281
- loc: field.loc,
282
- entity: def.name.value,
283
- message: `\
281
+ {
282
+ loc: field.loc,
283
+ entity: def.name.value,
284
+ message: `\
284
285
  Field '${field.name.value}': \
285
286
  Field arguments are not supported.`,
286
- },
287
- ])
287
+ },
288
+ ])
288
289
  : List()
289
290
 
290
291
  const entityFieldExists = (entityDef, name) =>
@@ -390,23 +391,23 @@ const validateEntityFields = (defs, def) =>
390
391
  const validateNoImportDirective = def =>
391
392
  def.directives.find(directive => directive.name.value == 'import')
392
393
  ? List([
393
- immutable.fromJS({
394
- loc: def.name.loc,
395
- entity: def.name.value,
396
- message: `@import directive only allowed on '${RESERVED_TYPE}' type`,
397
- }),
398
- ])
394
+ immutable.fromJS({
395
+ loc: def.name.loc,
396
+ entity: def.name.value,
397
+ message: `@import directive only allowed on '${RESERVED_TYPE}' type`,
398
+ }),
399
+ ])
399
400
  : List()
400
401
 
401
402
  const validateNoFulltext = def =>
402
403
  def.directives.find(directive => directive.name.value == 'fulltext')
403
404
  ? List([
404
- immutable.fromJS({
405
- loc: def.name.loc,
406
- entity: def.name.value,
407
- message: `@fulltext directive only allowed on '${RESERVED_TYPE}' type`,
408
- }),
409
- ])
405
+ immutable.fromJS({
406
+ loc: def.name.loc,
407
+ entity: def.name.value,
408
+ message: `@fulltext directive only allowed on '${RESERVED_TYPE}' type`,
409
+ }),
410
+ ])
410
411
  : List()
411
412
 
412
413
  const validateFulltextFields = (def, directive) => {
@@ -415,13 +416,13 @@ const validateFulltextFields = (def, directive) => {
415
416
  ['name', 'language', 'algorithm', 'include'].includes(argument.name.value)
416
417
  ? List([])
417
418
  : List([
418
- immutable.fromJS({
419
- loc: directive.name.loc,
420
- entity: def.name.value,
421
- directive: fulltextDirectiveName(directive),
422
- message: `found invalid argument: '${argument.name.value}', @fulltext directives only allow 'name', 'language', 'algorithm', and 'includes' arguments`,
423
- }),
424
- ]),
419
+ immutable.fromJS({
420
+ loc: directive.name.loc,
421
+ entity: def.name.value,
422
+ directive: fulltextDirectiveName(directive),
423
+ message: `found invalid argument: '${argument.name.value}', @fulltext directives only allow 'name', 'language', 'algorithm', and 'includes' arguments`,
424
+ }),
425
+ ]),
425
426
  )
426
427
  }, List([]))
427
428
  }
@@ -431,25 +432,25 @@ const validateFulltextName = (def, directive) => {
431
432
  return name
432
433
  ? validateFulltextArgumentName(def, directive, name)
433
434
  : List([
434
- immutable.fromJS({
435
- loc: directive.name.loc,
436
- entity: def.name.value,
437
- directive: fulltextDirectiveName(directive),
438
- message: `@fulltext argument 'name' must be specified`,
439
- }),
440
- ])
435
+ immutable.fromJS({
436
+ loc: directive.name.loc,
437
+ entity: def.name.value,
438
+ directive: fulltextDirectiveName(directive),
439
+ message: `@fulltext argument 'name' must be specified`,
440
+ }),
441
+ ])
441
442
  }
442
443
 
443
444
  const validateFulltextArgumentName = (def, directive, argument) => {
444
445
  return argument.value.kind != 'StringValue'
445
446
  ? List([
446
- immutable.fromJS({
447
- loc: directive.name.loc,
448
- entity: def.name.value,
449
- directive: fulltextDirectiveName(directive),
450
- message: `@fulltext argument 'name' must be a string`,
451
- }),
452
- ])
447
+ immutable.fromJS({
448
+ loc: directive.name.loc,
449
+ entity: def.name.value,
450
+ directive: fulltextDirectiveName(directive),
451
+ message: `@fulltext argument 'name' must be a string`,
452
+ }),
453
+ ])
453
454
  : List([])
454
455
  }
455
456
 
@@ -463,13 +464,13 @@ const validateFulltextLanguage = (def, directive) => {
463
464
  return language
464
465
  ? validateFulltextArgumentLanguage(def, directive, language)
465
466
  : List([
466
- immutable.fromJS({
467
- loc: directive.name.loc,
468
- entity: def.name.value,
469
- directive: fulltextDirectiveName(directive),
470
- message: `@fulltext argument 'language' must be specified`,
471
- }),
472
- ])
467
+ immutable.fromJS({
468
+ loc: directive.name.loc,
469
+ entity: def.name.value,
470
+ directive: fulltextDirectiveName(directive),
471
+ message: `@fulltext argument 'language' must be specified`,
472
+ }),
473
+ ])
473
474
  }
474
475
 
475
476
  const validateFulltextArgumentLanguage = (def, directive, argument) => {
@@ -521,13 +522,13 @@ const validateFulltextAlgorithm = (def, directive) => {
521
522
  return algorithm
522
523
  ? validateFulltextArgumentAlgorithm(def, directive, algorithm)
523
524
  : List([
524
- immutable.fromJS({
525
- loc: directive.name.loc,
526
- entity: def.name.value,
527
- directive: fulltextDirectiveName(directive),
528
- message: `@fulltext argument 'algorithm' must be specified`,
529
- }),
530
- ])
525
+ immutable.fromJS({
526
+ loc: directive.name.loc,
527
+ entity: def.name.value,
528
+ directive: fulltextDirectiveName(directive),
529
+ message: `@fulltext argument 'algorithm' must be specified`,
530
+ }),
531
+ ])
531
532
  }
532
533
 
533
534
  const validateFulltextArgumentAlgorithm = (def, directive, argument) => {
@@ -740,12 +741,12 @@ const validateImportDirectiveType = (def, directive, type) => {
740
741
  return importDirectiveTypeValidators[type.kind]
741
742
  ? importDirectiveTypeValidators[type.kind](def, directive, type)
742
743
  : List([
743
- immutable.fromJS({
744
- loc: directive.name.loc,
745
- entity: def.name.value,
746
- message: `Import must be one of "Name" or { name: "Name", as: "Alias" }`,
747
- }),
748
- ])
744
+ immutable.fromJS({
745
+ loc: directive.name.loc,
746
+ entity: def.name.value,
747
+ message: `Import must be one of "Name" or { name: "Name", as: "Alias" }`,
748
+ }),
749
+ ])
749
750
  }
750
751
 
751
752
  const validateImportDirectiveArgumentTypes = (def, directive, argument) => {
@@ -815,12 +816,12 @@ const validateImportDirectiveFields = (def, directive) => {
815
816
  ['types', 'from'].includes(argument.name.value)
816
817
  ? List([])
817
818
  : List([
818
- immutable.fromJS({
819
- loc: directive.name.loc,
820
- entity: def.name.value,
821
- message: `found invalid argument: '${argument.name.value}', @import directives only allow 'types' and 'from' arguments`,
822
- }),
823
- ]),
819
+ immutable.fromJS({
820
+ loc: directive.name.loc,
821
+ entity: def.name.value,
822
+ message: `found invalid argument: '${argument.name.value}', @import directives only allow 'types' and 'from' arguments`,
823
+ }),
824
+ ]),
824
825
  )
825
826
  }, List([]))
826
827
  }
@@ -830,12 +831,12 @@ const validateImportDirectiveTypes = (def, directive) => {
830
831
  return types
831
832
  ? validateImportDirectiveArgumentTypes(def, directive, types)
832
833
  : List([
833
- immutable.fromJS({
834
- loc: directive.name.loc,
835
- entity: def.name.value,
836
- message: `@import argument 'types' must be specified`,
837
- }),
838
- ])
834
+ immutable.fromJS({
835
+ loc: directive.name.loc,
836
+ entity: def.name.value,
837
+ message: `@import argument 'types' must be specified`,
838
+ }),
839
+ ])
839
840
  }
840
841
 
841
842
  const validateImportDirectiveFrom = (def, directive) => {
@@ -843,12 +844,12 @@ const validateImportDirectiveFrom = (def, directive) => {
843
844
  return from
844
845
  ? validateImportDirectiveArgumentFrom(def, directive, from)
845
846
  : List([
846
- immutable.fromJS({
847
- loc: directive.name.loc,
848
- entity: def.name.value,
849
- message: `@import argument 'from' must be specified`,
850
- }),
851
- ])
847
+ immutable.fromJS({
848
+ loc: directive.name.loc,
849
+ entity: def.name.value,
850
+ message: `@import argument 'from' must be specified`,
851
+ }),
852
+ ])
852
853
  }
853
854
 
854
855
  const validateImportDirective = (def, directive) =>
@@ -892,12 +893,12 @@ const validateSubgraphSchemaDirectives = def =>
892
893
  const validateTypeHasNoFields = def =>
893
894
  def.fields.length
894
895
  ? List([
895
- immutable.fromJS({
896
- loc: def.name.loc,
897
- entity: def.name.value,
898
- message: `${def.name.value} type is not allowed any fields by convention`,
899
- }),
900
- ])
896
+ immutable.fromJS({
897
+ loc: def.name.loc,
898
+ entity: def.name.value,
899
+ message: `${def.name.value} type is not allowed any fields by convention`,
900
+ }),
901
+ ])
901
902
  : List()
902
903
 
903
904
  const validateAtLeastOneExtensionField = def => List()
@@ -907,12 +908,12 @@ const typeDefinitionValidators = {
907
908
  def.name && def.name.value == RESERVED_TYPE
908
909
  ? List.of(...validateSubgraphSchemaDirectives(def), ...validateTypeHasNoFields(def))
909
910
  : List.of(
910
- ...validateEntityDirective(def),
911
- ...validateEntityID(def),
912
- ...validateEntityFields(defs, def),
913
- ...validateNoImportDirective(def),
914
- ...validateNoFulltext(def),
915
- ),
911
+ ...validateEntityDirective(def),
912
+ ...validateEntityID(def),
913
+ ...validateEntityFields(defs, def),
914
+ ...validateNoImportDirective(def),
915
+ ...validateNoFulltext(def),
916
+ ),
916
917
  ObjectTypeExtension: (_defs, def) => validateAtLeastOneExtensionField(def),
917
918
  }
918
919
 
@@ -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
@@ -0,0 +1,5 @@
1
+ var Migrations = artifacts.require('./Migrations.sol')
2
+
3
+ module.exports = function(deployer) {
4
+ deployer.deploy(Migrations)
5
+ }
@@ -0,0 +1,5 @@
1
+ const GravatarRegistry = artifacts.require('./GravatarRegistry.sol')
2
+
3
+ module.exports = async function(deployer) {
4
+ await deployer.deploy(GravatarRegistry)
5
+ }
@@ -0,0 +1,15 @@
1
+ const GravatarRegistry = artifacts.require('./GravatarRegistry.sol')
2
+
3
+ module.exports = async function(deployer) {
4
+ const registry = await GravatarRegistry.deployed()
5
+
6
+ console.log('Account address:', registry.address)
7
+
8
+ let accounts = await web3.eth.getAccounts()
9
+ await registry.createGravatar('Carl', 'https://thegraph.com/img/team/team_04.png', {
10
+ from: accounts[0],
11
+ })
12
+ await registry.createGravatar('Lucas', 'https://thegraph.com/img/team/bw_Lucas.jpg', {
13
+ from: accounts[1],
14
+ })
15
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "example-subgraph",
3
+ "version": "0.1.0",
4
+ "scripts": {
5
+ "build-contract": "solc contracts/Gravity.sol --abi -o abis --overwrite && solc contracts/Gravity.sol --bin -o bin --overwrite",
6
+ "create": "graph create user/example-subgraph --node https://api.thegraph.com/deploy/",
7
+ "create-local": "graph create user/example-subgraph --node http://127.0.0.1:8020",
8
+ "codegen": "graph codegen",
9
+ "build": "graph build",
10
+ "deploy": "graph deploy user/example-subgraph --ipfs https://api.thegraph.com/ipfs/ --node https://api.thegraph.com/deploy/",
11
+ "deploy-local": "graph deploy user/example-subgraph --ipfs http://127.0.0.1:5001 --node http://127.0.0.1:8020"
12
+ },
13
+ "devDependencies": {
14
+ "@graphprotocol/graph-ts": "^0.26.0"
15
+ },
16
+ "dependencies": {
17
+ "babel-polyfill": "^6.26.0",
18
+ "babel-register": "^6.26.0",
19
+ "truffle": "^5.0.4",
20
+ "truffle-contract": "^4.0.5",
21
+ "truffle-hdwallet-provider": "^1.0.4"
22
+ }
23
+ }
@@ -0,0 +1,6 @@
1
+ type Gravatar @entity {
2
+ id: ID!
3
+ owner: Bytes!
4
+ displayName: String!
5
+ imageUrl: String!
6
+ }
@@ -0,0 +1,22 @@
1
+ import { NewGravatar, UpdatedGravatar } from '../generated/Gravity/Gravity'
2
+ import { Gravatar } from '../generated/schema'
3
+
4
+ export function handleNewGravatar(event: NewGravatar): void {
5
+ let gravatar = new Gravatar(event.params.id.toHex())
6
+ gravatar.owner = event.params.owner
7
+ gravatar.displayName = event.params.displayName
8
+ gravatar.imageUrl = event.params.imageUrl
9
+ gravatar.save()
10
+ }
11
+
12
+ export function handleUpdatedGravatar(event: UpdatedGravatar): void {
13
+ let id = event.params.id.toHex()
14
+ let gravatar = Gravatar.load(id)
15
+ if (gravatar == null) {
16
+ gravatar = new Gravatar(id)
17
+ }
18
+ gravatar.owner = event.params.owner
19
+ gravatar.displayName = event.params.displayName
20
+ gravatar.imageUrl = event.params.imageUrl
21
+ gravatar.save()
22
+ }