Explorar el Código

Merge branch 'working-groups-schemas' into forum-mappings

Leszek Wiesner hace 3 años
padre
commit
6ce5289f8b
Se han modificado 59 ficheros con 1555 adiciones y 1188 borrados
  1. 27 28
      metadata-protobuf/doc/index.md
  2. 1 1
      metadata-protobuf/package.json
  3. 4 4
      metadata-protobuf/proto/WorkingGroups.proto
  4. 1 6
      query-node/build.sh
  5. 2 2
      query-node/codegen/package.json
  6. 34 28
      query-node/codegen/yarn.lock
  7. 1 1
      query-node/manifest.yml
  8. 12 38
      query-node/mappings/common.ts
  9. 1 1
      query-node/mappings/init.ts
  10. 7 13
      query-node/mappings/initializeDb.ts
  11. 60 119
      query-node/mappings/membership.ts
  12. 3 3
      query-node/mappings/package.json
  13. 79 175
      query-node/mappings/workingGroups.ts
  14. 1 1
      query-node/package.json
  15. 7 85
      query-node/schemas/common.graphql
  16. 20 17
      query-node/schemas/membership.graphql
  17. 252 28
      query-node/schemas/membershipEvents.graphql
  18. 23 37
      query-node/schemas/workingGroups.graphql
  19. 398 46
      query-node/schemas/workingGroupsEvents.graphql
  20. 3 5
      tests/integration-tests/src/Fixture.ts
  21. 29 16
      tests/integration-tests/src/QueryNodeApi.ts
  22. 4 7
      tests/integration-tests/src/fixtures/membership/AddStakingAccountsHappyCaseFixture.ts
  23. 0 24
      tests/integration-tests/src/fixtures/membership/BaseMembershipFixture.ts
  24. 66 91
      tests/integration-tests/src/fixtures/membership/BuyMembershipHappyCaseFixture.ts
  25. 6 6
      tests/integration-tests/src/fixtures/membership/BuyMembershipWithInsufficienFundsFixture.ts
  26. 75 76
      tests/integration-tests/src/fixtures/membership/InviteMembersHappyCaseFixture.ts
  27. 3 5
      tests/integration-tests/src/fixtures/membership/RemoveStakingAccountsHappyCaseFixture.ts
  28. 5 5
      tests/integration-tests/src/fixtures/membership/SudoUpdateMembershipSystem.ts
  29. 3 10
      tests/integration-tests/src/fixtures/membership/TransferInvitesHappyCaseFixture.ts
  30. 3 5
      tests/integration-tests/src/fixtures/membership/UpdateAccountsHappyCaseFixture.ts
  31. 3 5
      tests/integration-tests/src/fixtures/membership/UpdateProfileHappyCaseFixture.ts
  32. 0 1
      tests/integration-tests/src/fixtures/membership/index.ts
  33. 19 0
      tests/integration-tests/src/fixtures/membership/utils.ts
  34. 8 6
      tests/integration-tests/src/fixtures/workingGroups/ApplyOnOpeningsHappyCaseFixture.ts
  35. 5 4
      tests/integration-tests/src/fixtures/workingGroups/CancelOpeningsFixture.ts
  36. 9 6
      tests/integration-tests/src/fixtures/workingGroups/CreateOpeningsFixture.ts
  37. 0 3
      tests/integration-tests/src/fixtures/workingGroups/CreateUpcomingOpeningsFixture.ts
  38. 0 2
      tests/integration-tests/src/fixtures/workingGroups/DecreaseWorkerStakesFixture.ts
  39. 24 18
      tests/integration-tests/src/fixtures/workingGroups/FillOpeningsFixture.ts
  40. 0 2
      tests/integration-tests/src/fixtures/workingGroups/IncreaseWorkerStakesFixture.ts
  41. 2 3
      tests/integration-tests/src/fixtures/workingGroups/LeaveRoleFixture.ts
  42. 0 2
      tests/integration-tests/src/fixtures/workingGroups/RemoveUpcomingOpeningsFixture.ts
  43. 0 2
      tests/integration-tests/src/fixtures/workingGroups/SetBudgetFixture.ts
  44. 0 2
      tests/integration-tests/src/fixtures/workingGroups/SlashWorkerStakesFixture.ts
  45. 0 2
      tests/integration-tests/src/fixtures/workingGroups/SpendBudgetFixture.ts
  46. 5 7
      tests/integration-tests/src/fixtures/workingGroups/TerminateWorkersFixture.ts
  47. 3 6
      tests/integration-tests/src/fixtures/workingGroups/UpdateGroupStatusFixture.ts
  48. 0 2
      tests/integration-tests/src/fixtures/workingGroups/UpdateWorkerRewardAccountsFixture.ts
  49. 0 2
      tests/integration-tests/src/fixtures/workingGroups/UpdateWorkerRewardAmountsFixture.ts
  50. 0 2
      tests/integration-tests/src/fixtures/workingGroups/UpdateWorkerRoleAccountsFixture.ts
  51. 5 3
      tests/integration-tests/src/fixtures/workingGroups/WithdrawApplicationsFixture.ts
  52. 1 1
      tests/integration-tests/src/flows/membership/creatingMemberships.ts
  53. 0 15
      tests/integration-tests/src/graphql/queries/common.graphql
  54. 22 10
      tests/integration-tests/src/graphql/queries/membership.graphql
  55. 74 51
      tests/integration-tests/src/graphql/queries/membershipEvents.graphql
  56. 37 30
      tests/integration-tests/src/graphql/queries/workingGroups.graphql
  57. 117 77
      tests/integration-tests/src/graphql/queries/workingGroupsEvents.graphql
  58. 5 2
      tests/integration-tests/src/types.ts
  59. 86 39
      yarn.lock

+ 27 - 28
metadata-protobuf/doc/index.md

@@ -5,15 +5,15 @@
 
 - [proto/Council.proto](#proto/Council.proto)
     - [CouncilCandidacyNoteMetadata](#.CouncilCandidacyNoteMetadata)
-  
+
 - [proto/Forum.proto](#proto/Forum.proto)
     - [ForumPostMetadata](#.ForumPostMetadata)
-  
+
     - [ForumPostReaction](#.ForumPostReaction)
-  
+
 - [proto/Membership.proto](#proto/Membership.proto)
     - [MembershipMetadata](#.MembershipMetadata)
-  
+
 - [proto/WorkingGroups.proto](#proto/WorkingGroups.proto)
     - [AddUpcomingOpening](#.AddUpcomingOpening)
     - [ApplicationMetadata](#.ApplicationMetadata)
@@ -24,9 +24,9 @@
     - [UpcomingOpeningMetadata](#.UpcomingOpeningMetadata)
     - [WorkingGroupMetadata](#.WorkingGroupMetadata)
     - [WorkingGroupMetadataAction](#.WorkingGroupMetadataAction)
-  
+
     - [OpeningMetadata.ApplicationFormQuestion.InputType](#.OpeningMetadata.ApplicationFormQuestion.InputType)
-  
+
 - [Scalar Value Types](#scalar-value-types)
 
 
@@ -55,13 +55,13 @@
 
 
 
- 
 
- 
 
- 
 
- 
+
+
+
+
 
 
 
@@ -87,7 +87,7 @@
 
 
 
- 
+
 
 
 <a name=".ForumPostReaction"></a>
@@ -101,11 +101,11 @@
 | LIKE | 1 |  |
 
 
- 
 
- 
 
- 
+
+
+
 
 
 
@@ -132,13 +132,13 @@
 
 
 
- 
 
- 
 
- 
 
- 
+
+
+
+
 
 
 
@@ -271,10 +271,9 @@
 
 | Field | Type | Label | Description |
 | ----- | ---- | ----- | ----------- |
-| description | [string](#string) | optional | Full status description (md-formatted) |
-| about | [string](#string) | optional | Status about text (md-formatted) |
-| status | [string](#string) | optional | The status itself (expected to be 1-3 words) |
-| status_message | [string](#string) | optional | Short status message |
+| set_group_metadata | [SetGroupMetadata](#SetGroupMetadata) | optional |  |
+| add_upcoming_opening | [AddUpcomingOpening](#AddUpcomingOpening) | optional |  |
+| remove_upcoming_opening | [RemoveUpcomingOpening](#RemoveUpcomingOpening) | optional |  |
 
 
 
@@ -297,7 +296,7 @@
 
 
 
- 
+
 
 
 <a name=".OpeningMetadata.ApplicationFormQuestion.InputType"></a>
@@ -311,11 +310,11 @@
 | TEXT | 1 |  |
 
 
- 
 
- 
 
- 
+
+
+
 
 
 
@@ -339,7 +338,7 @@
 | <a name="string" /> string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |
 | <a name="bytes" /> bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |
 
-<!-- 
+<!--
     This extra documentation will be appended to the generated docs.
 -->
 
@@ -379,4 +378,4 @@ meta = VideoMetadata {
     thumbnail_photo: 0,
     ...
 };
-```
+```

+ 1 - 1
metadata-protobuf/package.json

@@ -9,7 +9,7 @@
   "license": "MIT",
   "private": false,
   "scripts": {
-    "build": "tsc",
+    "build": "yarn compile && tsc",
     "compile": "./compile.sh",
     "generate-doc": "./generate-md-doc.sh",
     "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha -r ts-node/register 'test/**/*.ts'",

+ 4 - 4
metadata-protobuf/proto/WorkingGroups.proto

@@ -31,10 +31,10 @@ message ApplicationMetadata {
 // set_status_text extrinsic messages:
 
 message WorkingGroupMetadata {
-  optional string description = 1; // Full status description (md-formatted)
-  optional string about = 2; // Status about text (md-formatted)
-  optional string status = 3; // The status itself (expected to be 1-3 words)
-  optional string status_message = 4; // Short status message
+  optional string description = 1; // Group description text (md-formatted)
+  optional string about = 2; // Group about text (md-formatted)
+  optional string status = 3; // Current group status (expected to be 1-3 words)
+  optional string status_message = 4; // Short status message associated with the status
 }
 
 message SetGroupMetadata {

+ 1 - 6
query-node/build.sh

@@ -26,11 +26,6 @@ yarn format
 # and are inline with root workspace resolutions
 yarn
 
-# FIXME: Temporary workaround for Hydra bug. After it's fixed this can be just: "yarn workspace query-node build:dev"
-yarn workspace query-node config:dev
-yarn workspace query-node codegen
-sed -i 's/get bytes(): Option/get optBytes(): Option/' ./mappings/generated/types/storage-working-group.ts
-sed -i 's/get categoryId(): Option/get optCategoryId(): Option/' ./mappings/generated/types/forum.ts
-yarn workspace query-node compile
+yarn workspace query-node build:dev
 
 yarn workspace query-node-mappings build

+ 2 - 2
query-node/codegen/package.json

@@ -5,7 +5,7 @@
   "author": "",
   "license": "ISC",
   "dependencies": {
-    "@dzlzv/hydra-cli": "2.1.0-beta.8",
-    "@dzlzv/hydra-typegen": "2.1.0-beta.8"
+    "@dzlzv/hydra-cli": "3.0.0-beta.6",
+    "@dzlzv/hydra-typegen": "3.0.0-beta.6"
   }
 }

+ 34 - 28
query-node/codegen/yarn.lock

@@ -76,10 +76,10 @@
   dependencies:
     regenerator-runtime "^0.13.4"
 
-"@dzlzv/hydra-cli@2.1.0-beta.8":
-  version "2.1.0-beta.8"
-  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-cli/-/hydra-cli-2.1.0-beta.8.tgz#79c1aae06081354686eca2cbfd28b72389f65693"
-  integrity sha512-jIk5KcMuLVxRt3eBCBcuzZPg9fWx7qrtj/Kin9Z3a7OF6cAhcGEuu/YxtiVTJwpUFeFtjedukDO1TIkw+rXw3A==
+"@dzlzv/hydra-cli@3.0.0-beta.6":
+  version "3.0.0-beta.6"
+  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-cli/-/hydra-cli-3.0.0-beta.6.tgz#b85504ed9f4ec939b7108094fd7969d60a9b1f45"
+  integrity sha512-3ENzap6vq2DKOV8gA5Qq9ZX9xDJvP6WXpRvp+Aedf2yTms/gWB9vbhkp2oCZGnjqZqGZ9d2jIBBFJOwiRWpqsA==
   dependencies:
     "@inquirer/input" "^0.0.13-alpha.0"
     "@inquirer/password" "^0.0.12-alpha.0"
@@ -109,12 +109,12 @@
     mustache "^4.0.1"
     pluralize "^8.0.0"
     tslib "1.11.2"
-    warthog "https://github.com/metmirr/warthog/releases/download/v2.23.0/warthog-v2.23.0.tgz"
+    warthog "https://github.com/metmirr/warthog/releases/download/v2.30.0/warthog-v2.30.0.tgz"
 
-"@dzlzv/hydra-typegen@2.1.0-beta.8":
-  version "2.1.0-beta.8"
-  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-typegen/-/hydra-typegen-2.1.0-beta.8.tgz#a6ddcd21652310cf0e174e999f700f213e399ea8"
-  integrity sha512-MQRwhvzaTlurJQJ08QI12ORz+c3vHfBr7ycEzU1xG1fkadSNrVPY7pYjkH/Q2xphl79sohvzVnFCipqbkDTWkw==
+"@dzlzv/hydra-typegen@3.0.0-beta.6":
+  version "3.0.0-beta.6"
+  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-typegen/-/hydra-typegen-3.0.0-beta.6.tgz#665364fdde787a293df58196f81abd517847e976"
+  integrity sha512-mYDh3G8tHjPIy6lUhXS2lNNOs27SxW580ODd3Ib87sR/scHv3Xmdv2Tgcu3lDj367MeKfhQ0hRfFDdLZnxaHeA==
   dependencies:
     "@oclif/command" "^1.8.0"
     "@oclif/config" "^1"
@@ -1375,6 +1375,11 @@ bn.js@^4.11.9:
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
   integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
 
+bn.js@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
+  integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==
+
 body-parser@1.19.0, body-parser@^1.18.3:
   version "1.19.0"
   resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
@@ -3887,15 +3892,10 @@ pg-int8@1.0.1:
   resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c"
   integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==
 
-pg-packet-stream@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/pg-packet-stream/-/pg-packet-stream-1.1.0.tgz#e45c3ae678b901a2873af1e17b92d787962ef914"
-  integrity sha512-kRBH0tDIW/8lfnnOyTwKD23ygJ/kexQVXZs7gEyBljw4FYqimZFxnMMx50ndZ8In77QgfGuItS5LLclC2TtjYg==
-
-pg-pool@^2.0.10:
-  version "2.0.10"
-  resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-2.0.10.tgz#842ee23b04e86824ce9d786430f8365082d81c4a"
-  integrity sha512-qdwzY92bHf3nwzIUcj+zJ0Qo5lpG/YxchahxIN8+ZVmXqkahKXsnl2aiJPHLYN9o5mB/leG+Xh6XKxtP7e0sjg==
+pg-pool@^3.1.1:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.3.0.tgz#12d5c7f65ea18a6e99ca9811bd18129071e562fc"
+  integrity sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg==
 
 pg-pool@^3.2.2:
   version "3.2.2"
@@ -3907,6 +3907,11 @@ pg-protocol@^1.2.0, pg-protocol@^1.4.0:
   resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.4.0.tgz#43a71a92f6fe3ac559952555aa3335c8cb4908be"
   integrity sha512-El+aXWcwG/8wuFICMQjM5ZSAm6OWiJicFdNYo+VY3QP+8vI4SvLIWVe51PppTzMhikUJR+PsyIFKqfdXPz/yxA==
 
+pg-protocol@^1.2.2:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0"
+  integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==
+
 pg-types@^2.1.0, pg-types@^2.2.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3"
@@ -3918,16 +3923,16 @@ pg-types@^2.1.0, pg-types@^2.2.0:
     postgres-date "~1.0.4"
     postgres-interval "^1.1.0"
 
-pg@^7.12.1:
-  version "7.18.2"
-  resolved "https://registry.yarnpkg.com/pg/-/pg-7.18.2.tgz#4e219f05a00aff4db6aab1ba02f28ffa4513b0bb"
-  integrity sha512-Mvt0dGYMwvEADNKy5PMQGlzPudKcKKzJds/VbOeZJpb6f/pI3mmoXX0JksPgI3l3JPP/2Apq7F36O63J7mgveA==
+pg@8.0.3:
+  version "8.0.3"
+  resolved "https://registry.yarnpkg.com/pg/-/pg-8.0.3.tgz#b220ee468a1819e1c7e9ca9878f8ae50ba8e1952"
+  integrity sha512-fvcNXn4o/iq4jKq15Ix/e58q3jPSmzOp6/8C3CaHoSR/bsxdg+1FXfDRePdtE/zBb3++TytvOrS1hNef3WC/Kg==
   dependencies:
     buffer-writer "2.0.0"
     packet-reader "1.0.0"
     pg-connection-string "0.1.3"
-    pg-packet-stream "^1.1.0"
-    pg-pool "^2.0.10"
+    pg-pool "^3.1.1"
+    pg-protocol "^1.2.2"
     pg-types "^2.1.0"
     pgpass "1.x"
     semver "4.3.2"
@@ -4908,9 +4913,9 @@ vary@^1, vary@~1.1.2:
   resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
   integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
 
-"warthog@https://github.com/metmirr/warthog/releases/download/v2.23.0/warthog-v2.23.0.tgz":
-  version "2.23.0"
-  resolved "https://github.com/metmirr/warthog/releases/download/v2.23.0/warthog-v2.23.0.tgz#4582fc35554580e0af0f43a9b3725aad2eb808c6"
+"warthog@https://github.com/metmirr/warthog/releases/download/v2.30.0/warthog-v2.30.0.tgz":
+  version "2.30.0"
+  resolved "https://github.com/metmirr/warthog/releases/download/v2.30.0/warthog-v2.30.0.tgz#24a0b975f2ad5cba17a934752ac07052e856b49c"
   dependencies:
     "@types/app-root-path" "^1.2.4"
     "@types/bn.js" "^4.11.6"
@@ -4938,6 +4943,7 @@ vary@^1, vary@~1.1.2:
     apollo-server "^2.9.9"
     apollo-server-express "^2.9.9"
     app-root-path "^3.0.0"
+    bn.js "^5.2.0"
     caller "^1.0.1"
     class-transformer "^0.2.3"
     class-validator "^0.11.0"
@@ -4960,7 +4966,7 @@ vary@^1, vary@~1.1.2:
     mkdirp "^0.5.1"
     node-emoji "^1.10.0"
     open "^7.0.0"
-    pg "^7.12.1"
+    pg "8.0.3"
     pgtools "^0.3.0"
     prettier "^1.19.1"
     reflect-metadata "^0.1.13"

+ 1 - 1
query-node/manifest.yml

@@ -1,7 +1,7 @@
 version: '0.1'
 description: Joystream query-node manifest file for olympia
 repository: https://github.com/Joystream/joystream
-hydraVersion: "2"
+hydraVersion: "3"
 dataSource:
   kind: substrate
   chain: joystream

+ 12 - 38
query-node/mappings/common.ts

@@ -1,28 +1,22 @@
 import { SubstrateEvent } from '@dzlzv/hydra-common'
-import { EventType, Network } from 'query-node/dist/src/modules/enums/enums'
+import { Network } from 'query-node/dist/src/modules/enums/enums'
 import { Event } from 'query-node/dist/src/modules/event/event.model'
 import { Bytes } from '@polkadot/types'
-import { Block } from 'query-node/dist/model'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
 
 export const CURRENT_NETWORK = Network.OLYMPIA
 
-export async function createEvent(
-  db: DatabaseManager,
-  substrateEvent: SubstrateEvent,
-  type: EventType
-): Promise<Event> {
-  const { blockNumber, index, extrinsic } = substrateEvent
-  const event = new Event({
-    id: `${CURRENT_NETWORK}-${blockNumber}-${index}`,
-    inBlock: await getOrCreateBlock(db, substrateEvent),
+export function genericEventFields(substrateEvent: SubstrateEvent): Partial<Event> {
+  const { blockNumber, indexInBlock, extrinsic, blockTimestamp } = substrateEvent
+  const eventTime = new Date(blockTimestamp)
+  return {
+    createdAt: eventTime,
+    updatedAt: eventTime,
+    id: `${CURRENT_NETWORK}-${blockNumber}-${indexInBlock}`,
+    inBlock: blockNumber,
+    network: CURRENT_NETWORK,
     inExtrinsic: extrinsic?.hash,
-    indexInBlock: index,
-    type,
-  })
-  await db.save<Event>(event)
-
-  return event
+    indexInBlock,
+  }
 }
 
 type AnyMessage<T> = T & {
@@ -46,26 +40,6 @@ export function deserializeMetadata<T>(metadataType: AnyMetadataClass<T>, metada
   }
 }
 
-export async function getOrCreateBlock(
-  db: DatabaseManager,
-  { blockNumber, blockTimestamp }: SubstrateEvent
-): Promise<Block> {
-  const block = await db.get(Block, { where: { number: blockNumber } })
-  if (!block) {
-    const newBlock = new Block({
-      id: `${CURRENT_NETWORK}-${blockNumber}`,
-      number: blockNumber,
-      timestamp: blockTimestamp,
-      network: CURRENT_NETWORK,
-    })
-    await db.save<Block>(newBlock)
-
-    return newBlock
-  }
-
-  return block
-}
-
 export function bytesToString(b: Bytes): string {
   return (
     Buffer.from(b.toU8a(true))

+ 1 - 1
query-node/mappings/init.ts

@@ -1,7 +1,7 @@
 import { ApiPromise, WsProvider } from '@polkadot/api'
 import { types } from '@joystream/types'
-import { makeDatabaseManager } from '@dzlzv/hydra-db-utils'
 import { createDBConnection } from '@dzlzv/hydra-processor'
+import { makeDatabaseManager } from '@dzlzv/hydra-processor/lib/executor/TransactionalExecutor'
 import path from 'path'
 
 // A script to initialize processor database with some initial values that cannot be fetched from events / extrinics

+ 7 - 13
query-node/mappings/initializeDb.ts

@@ -1,30 +1,22 @@
 import { ApiPromise } from '@polkadot/api'
 import { BalanceOf } from '@polkadot/types/interfaces'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
-import { Block, MembershipSystemSnapshot, WorkingGroup } from 'query-node/dist/model'
-import { CURRENT_NETWORK } from './common'
-import BN from 'bn.js'
+import { DatabaseManager } from '@dzlzv/hydra-common'
+import { MembershipSystemSnapshot, WorkingGroup } from 'query-node/dist/model'
 
 async function initMembershipSystem(api: ApiPromise, db: DatabaseManager) {
   const initialInvitationCount = await api.query.members.initialInvitationCount.at(api.genesisHash)
   const initialInvitationBalance = await api.query.members.initialInvitationBalance.at(api.genesisHash)
   const referralCut = await api.query.members.referralCut.at(api.genesisHash)
   const membershipPrice = await api.query.members.membershipPrice.at(api.genesisHash)
-  const genesisBlock = new Block({
-    id: `${CURRENT_NETWORK}-0`,
-    network: CURRENT_NETWORK,
-    number: 0,
-    timestamp: new BN(0),
-  })
   const membershipSystem = new MembershipSystemSnapshot({
-    snapshotBlock: genesisBlock,
-    snapshotTime: new Date(0),
+    createdAt: new Date(0),
+    updatedAt: new Date(0),
+    snapshotBlock: 0,
     defaultInviteCount: initialInvitationCount.toNumber(),
     membershipPrice,
     referralCut: referralCut.toNumber(),
     invitedInitialBalance: initialInvitationBalance,
   })
-  await db.save<Block>(genesisBlock)
   await db.save<MembershipSystemSnapshot>(membershipSystem)
 }
 
@@ -34,6 +26,8 @@ async function initWorkingGroups(api: ApiPromise, db: DatabaseManager) {
     groupNames.map(async (groupName) => {
       const budget = await api.query[groupName].budget.at<BalanceOf>(api.genesisHash)
       return new WorkingGroup({
+        createdAt: new Date(0),
+        updatedAt: new Date(0),
         id: groupName,
         name: groupName,
         workers: [],

+ 60 - 119
query-node/mappings/membership.ts

@@ -1,16 +1,13 @@
 /*
 eslint-disable @typescript-eslint/naming-convention
 */
-import { SubstrateEvent } from '@dzlzv/hydra-common'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
+import { SubstrateEvent, DatabaseManager } from '@dzlzv/hydra-common'
 import { Members } from './generated/types'
-import BN from 'bn.js'
 import { MemberId, BuyMembershipParameters, InviteMembershipParameters } from '@joystream/types/augment/all'
 import { MembershipMetadata } from '@joystream/metadata-protobuf'
-import { bytesToString, createEvent, deserializeMetadata, getOrCreateBlock } from './common'
+import { bytesToString, deserializeMetadata, genericEventFields } from './common'
 import {
   Membership,
-  EventType,
   MembershipEntryMethod,
   MembershipSystemSnapshot,
   MemberMetadata,
@@ -28,6 +25,8 @@ import {
   InitialInvitationBalanceUpdatedEvent,
   StakingAccountAddedEvent,
   LeaderInvitationQuotaUpdatedEvent,
+  MembershipEntryPaid,
+  MembershipEntryInvited,
 } from 'query-node/dist/model'
 
 async function getMemberById(db: DatabaseManager, id: MemberId): Promise<Membership> {
@@ -41,7 +40,6 @@ async function getMemberById(db: DatabaseManager, id: MemberId): Promise<Members
 async function getLatestMembershipSystemSnapshot(db: DatabaseManager): Promise<MembershipSystemSnapshot> {
   const membershipSystem = await db.get(MembershipSystemSnapshot, {
     order: { snapshotBlock: 'DESC' },
-    relations: ['snapshotBlock'],
   })
   if (!membershipSystem) {
     throw new Error(`Membership system snapshot not found! Forgot to run "yarn workspace query-node-root db:init"?`)
@@ -51,30 +49,29 @@ async function getLatestMembershipSystemSnapshot(db: DatabaseManager): Promise<M
 
 async function getOrCreateMembershipSnapshot(db: DatabaseManager, event_: SubstrateEvent) {
   const latestSnapshot = await getLatestMembershipSystemSnapshot(db)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
-  return latestSnapshot.snapshotBlock.number === event_.blockNumber
+  const eventTime = new Date(event_.blockTimestamp)
+  return latestSnapshot.snapshotBlock === event_.blockNumber
     ? latestSnapshot
     : new MembershipSystemSnapshot({
         ...latestSnapshot,
         createdAt: eventTime,
         updatedAt: eventTime,
         id: undefined,
-        snapshotBlock: await getOrCreateBlock(db, event_),
-        snapshotTime: new Date(new BN(event_.blockTimestamp).toNumber()),
+        snapshotBlock: event_.blockNumber,
       })
 }
 
-async function newMembershipFromParams(
+async function createNewMemberFromParams(
   db: DatabaseManager,
   event_: SubstrateEvent,
   memberId: MemberId,
-  entryMethod: MembershipEntryMethod,
+  entryMethod: typeof MembershipEntryMethod,
   params: BuyMembershipParameters | InviteMembershipParameters
 ): Promise<Membership> {
   const { defaultInviteCount } = await getLatestMembershipSystemSnapshot(db)
   const { root_account: rootAccount, controller_account: controllerAccount, handle, metadata: metatadaBytes } = params
   const metadata = deserializeMetadata(MembershipMetadata, metatadaBytes)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const metadataEntity = new MemberMetadata({
     createdAt: eventTime,
@@ -92,11 +89,9 @@ async function newMembershipFromParams(
     controllerAccount: controllerAccount.toString(),
     handle: handle.unwrap().toString(),
     metadata: metadataEntity,
-    registeredAtBlock: await getOrCreateBlock(db, event_),
-    registeredAtTime: new Date(event_.blockTimestamp.toNumber()),
     entry: entryMethod,
     referredBy:
-      entryMethod === MembershipEntryMethod.PAID && (params as BuyMembershipParameters).referrer_id.isSome
+      entryMethod.isTypeOf === 'MembershipEntryPaid' && (params as BuyMembershipParameters).referrer_id.isSome
         ? new Membership({ id: (params as BuyMembershipParameters).referrer_id.unwrap().toString() })
         : undefined,
     isVerified: false,
@@ -105,7 +100,7 @@ async function newMembershipFromParams(
     invitees: [],
     referredMembers: [],
     invitedBy:
-      entryMethod === MembershipEntryMethod.INVITED
+      entryMethod.isTypeOf === 'MembershipEntryInvited'
         ? new Membership({ id: (params as InviteMembershipParameters).inviting_member_id.toString() })
         : undefined,
     isFoundingMember: false,
@@ -118,21 +113,13 @@ async function newMembershipFromParams(
 }
 
 export async function members_MembershipBought(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { memberId, buyMembershipParameters } = new Members.MembershipBoughtEvent(event_).data
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
-  const member = await newMembershipFromParams(
-    db,
-    event_,
-    memberId,
-    MembershipEntryMethod.PAID,
-    buyMembershipParameters
-  )
+  const [memberId, buyMembershipParameters] = new Members.MembershipBoughtEvent(event_).params
+
+  const memberEntry = new MembershipEntryPaid()
+  const member = await createNewMemberFromParams(db, event_, memberId, memberEntry, buyMembershipParameters)
 
   const membershipBoughtEvent = new MembershipBoughtEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.MembershipBought),
+    ...genericEventFields(event_),
     newMember: member,
     controllerAccount: member.controllerAccount,
     rootAccount: member.rootAccount,
@@ -146,17 +133,20 @@ export async function members_MembershipBought(db: DatabaseManager, event_: Subs
 
   await db.save<MemberMetadata>(membershipBoughtEvent.metadata)
   await db.save<MembershipBoughtEvent>(membershipBoughtEvent)
+
+  // Update the other side of event<->membership relation
+  memberEntry.membershipBoughtEventId = membershipBoughtEvent.id
+  await db.save<Membership>(member)
 }
 
 export async function members_MemberProfileUpdated(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { memberId } = new Members.MemberProfileUpdatedEvent(event_).data
+  const [memberId] = new Members.MemberProfileUpdatedEvent(event_).params
   const { metadata: metadataBytesOpt, handle } = new Members.UpdateProfileCall(event_).args
   const metadata = metadataBytesOpt.isSome
     ? deserializeMetadata(MembershipMetadata, metadataBytesOpt.unwrap())
     : undefined
   const member = await getMemberById(db, memberId)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   if (typeof metadata?.name === 'string') {
     member.metadata.name = metadata.name || undefined
@@ -176,9 +166,7 @@ export async function members_MemberProfileUpdated(db: DatabaseManager, event_:
   await db.save<Membership>(member)
 
   const memberProfileUpdatedEvent = new MemberProfileUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.MemberProfileUpdated),
+    ...genericEventFields(event_),
     member: member,
     newHandle: member.handle,
     newMetadata: new MemberMetadata({
@@ -192,11 +180,10 @@ export async function members_MemberProfileUpdated(db: DatabaseManager, event_:
 }
 
 export async function members_MemberAccountsUpdated(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { memberId } = new Members.MemberAccountsUpdatedEvent(event_).data
+  const [memberId] = new Members.MemberAccountsUpdatedEvent(event_).params
   const { newRootAccount, newControllerAccount } = new Members.UpdateAccountsCall(event_).args
   const member = await getMemberById(db, memberId)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   if (newControllerAccount.isSome) {
     member.controllerAccount = newControllerAccount.unwrap().toString()
@@ -209,9 +196,7 @@ export async function members_MemberAccountsUpdated(db: DatabaseManager, event_:
   await db.save<Membership>(member)
 
   const memberAccountsUpdatedEvent = new MemberAccountsUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.MemberAccountsUpdated),
+    ...genericEventFields(event_),
     member: member,
     newRootAccount: member.rootAccount,
     newControllerAccount: member.controllerAccount,
@@ -224,10 +209,9 @@ export async function members_MemberVerificationStatusUpdated(
   db: DatabaseManager,
   event_: SubstrateEvent
 ): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { memberId, bool: verificationStatus } = new Members.MemberVerificationStatusUpdatedEvent(event_).data
+  const [memberId, verificationStatus] = new Members.MemberVerificationStatusUpdatedEvent(event_).params
   const member = await getMemberById(db, memberId)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   member.isVerified = verificationStatus.valueOf()
   member.updatedAt = eventTime
@@ -235,9 +219,7 @@ export async function members_MemberVerificationStatusUpdated(
   await db.save<Membership>(member)
 
   const memberVerificationStatusUpdatedEvent = new MemberVerificationStatusUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.MemberVerificationStatusUpdated),
+    ...genericEventFields(event_),
     member: member,
     isVerified: member.isVerified,
   })
@@ -246,14 +228,10 @@ export async function members_MemberVerificationStatusUpdated(
 }
 
 export async function members_InvitesTransferred(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const {
-    memberIds: { 0: sourceMemberId, 1: targetMemberId },
-    u32: numberOfInvites,
-  } = new Members.InvitesTransferredEvent(event_).data
+  const [sourceMemberId, targetMemberId, numberOfInvites] = new Members.InvitesTransferredEvent(event_).params
   const sourceMember = await getMemberById(db, sourceMemberId)
   const targetMember = await getMemberById(db, targetMemberId)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   sourceMember.inviteCount -= numberOfInvites.toNumber()
   sourceMember.updatedAt = eventTime
@@ -264,9 +242,7 @@ export async function members_InvitesTransferred(db: DatabaseManager, event_: Su
   await db.save<Membership>(targetMember)
 
   const invitesTransferredEvent = new InvitesTransferredEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.InvitesTransferred),
+    ...genericEventFields(event_),
     sourceMember,
     targetMember,
     numberOfInvites: numberOfInvites.toNumber(),
@@ -276,27 +252,19 @@ export async function members_InvitesTransferred(db: DatabaseManager, event_: Su
 }
 
 export async function members_MemberInvited(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { memberId, inviteMembershipParameters } = new Members.MemberInvitedEvent(event_).data
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
-  const invitedMember = await newMembershipFromParams(
-    db,
-    event_,
-    memberId,
-    MembershipEntryMethod.INVITED,
-    inviteMembershipParameters
-  )
+  const [memberId, inviteMembershipParameters] = new Members.MemberInvitedEvent(event_).params
+  const eventTime = new Date(event_.blockTimestamp)
+  const entryMethod = new MembershipEntryInvited()
+  const invitedMember = await createNewMemberFromParams(db, event_, memberId, entryMethod, inviteMembershipParameters)
 
   // Decrease invite count of inviting member
   const invitingMember = await getMemberById(db, inviteMembershipParameters.inviting_member_id)
   invitingMember.inviteCount -= 1
-  invitedMember.updatedAt = eventTime
+  invitingMember.updatedAt = eventTime
   await db.save<Membership>(invitingMember)
 
   const memberInvitedEvent = new MemberInvitedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.MemberInvited),
+    ...genericEventFields(event_),
     invitingMember,
     newMember: invitedMember,
     handle: invitedMember.handle,
@@ -310,17 +278,16 @@ export async function members_MemberInvited(db: DatabaseManager, event_: Substra
 
   await db.save<MemberMetadata>(memberInvitedEvent.metadata)
   await db.save<MemberInvitedEvent>(memberInvitedEvent)
+  // Update the other side of event<->member relationship
+  entryMethod.memberInvitedEventId = memberInvitedEvent.id
+  await db.save<Membership>(invitedMember)
 }
 
 export async function members_StakingAccountAdded(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { memberId, accountId } = new Members.StakingAccountAddedEvent(event_).data
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const [accountId, memberId] = new Members.StakingAccountAddedEvent(event_).params
 
   const stakingAccountAddedEvent = new StakingAccountAddedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.StakingAccountAddedEvent),
+    ...genericEventFields(event_),
     member: new Membership({ id: memberId.toString() }),
     account: accountId.toString(),
   })
@@ -329,10 +296,9 @@ export async function members_StakingAccountAdded(db: DatabaseManager, event_: S
 }
 
 export async function members_StakingAccountConfirmed(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { memberId, accountId } = new Members.StakingAccountConfirmedEvent(event_).data
+  const [accountId, memberId] = new Members.StakingAccountConfirmedEvent(event_).params
   const member = await getMemberById(db, memberId)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   member.boundAccounts.push(accountId.toString())
   member.updatedAt = eventTime
@@ -340,9 +306,7 @@ export async function members_StakingAccountConfirmed(db: DatabaseManager, event
   await db.save<Membership>(member)
 
   const stakingAccountConfirmedEvent = new StakingAccountConfirmedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.StakingAccountConfirmed),
+    ...genericEventFields(event_),
     member,
     account: accountId.toString(),
   })
@@ -351,9 +315,8 @@ export async function members_StakingAccountConfirmed(db: DatabaseManager, event
 }
 
 export async function members_StakingAccountRemoved(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { memberId, accountId } = new Members.StakingAccountRemovedEvent(event_).data
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const [accountId, memberId] = new Members.StakingAccountRemovedEvent(event_).params
+  const eventTime = new Date(event_.blockTimestamp)
   const member = await getMemberById(db, memberId)
 
   member.boundAccounts.splice(
@@ -365,9 +328,7 @@ export async function members_StakingAccountRemoved(db: DatabaseManager, event_:
   await db.save<Membership>(member)
 
   const stakingAccountRemovedEvent = new StakingAccountRemovedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.StakingAccountRemoved),
+    ...genericEventFields(event_),
     member,
     account: accountId.toString(),
   })
@@ -379,19 +340,15 @@ export async function members_InitialInvitationCountUpdated(
   db: DatabaseManager,
   event_: SubstrateEvent
 ): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { u32: newDefaultInviteCount } = new Members.InitialInvitationCountUpdatedEvent(event_).data
+  const [newDefaultInviteCount] = new Members.InitialInvitationCountUpdatedEvent(event_).params
   const membershipSystemSnapshot = await getOrCreateMembershipSnapshot(db, event_)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
 
   membershipSystemSnapshot.defaultInviteCount = newDefaultInviteCount.toNumber()
 
   await db.save<MembershipSystemSnapshot>(membershipSystemSnapshot)
 
   const initialInvitationCountUpdatedEvent = new InitialInvitationCountUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.InitialInvitationCountUpdated),
+    ...genericEventFields(event_),
     newInitialInvitationCount: newDefaultInviteCount.toNumber(),
   })
 
@@ -399,19 +356,15 @@ export async function members_InitialInvitationCountUpdated(
 }
 
 export async function members_MembershipPriceUpdated(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { balance: newMembershipPrice } = new Members.MembershipPriceUpdatedEvent(event_).data
+  const [newMembershipPrice] = new Members.MembershipPriceUpdatedEvent(event_).params
   const membershipSystemSnapshot = await getOrCreateMembershipSnapshot(db, event_)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
 
   membershipSystemSnapshot.membershipPrice = newMembershipPrice
 
   await db.save<MembershipSystemSnapshot>(membershipSystemSnapshot)
 
   const membershipPriceUpdatedEvent = new MembershipPriceUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.MembershipPriceUpdated),
+    ...genericEventFields(event_),
     newPrice: newMembershipPrice,
   })
 
@@ -419,19 +372,15 @@ export async function members_MembershipPriceUpdated(db: DatabaseManager, event_
 }
 
 export async function members_ReferralCutUpdated(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { u8: newReferralCut } = new Members.ReferralCutUpdatedEvent(event_).data
+  const [newReferralCut] = new Members.ReferralCutUpdatedEvent(event_).params
   const membershipSystemSnapshot = await getOrCreateMembershipSnapshot(db, event_)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
 
   membershipSystemSnapshot.referralCut = newReferralCut.toNumber()
 
   await db.save<MembershipSystemSnapshot>(membershipSystemSnapshot)
 
   const referralCutUpdatedEvent = new ReferralCutUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.ReferralCutUpdated),
+    ...genericEventFields(event_),
     newValue: newReferralCut.toNumber(),
   })
 
@@ -442,19 +391,15 @@ export async function members_InitialInvitationBalanceUpdated(
   db: DatabaseManager,
   event_: SubstrateEvent
 ): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { balance: newInvitedInitialBalance } = new Members.InitialInvitationBalanceUpdatedEvent(event_).data
+  const [newInvitedInitialBalance] = new Members.InitialInvitationBalanceUpdatedEvent(event_).params
   const membershipSystemSnapshot = await getOrCreateMembershipSnapshot(db, event_)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
 
   membershipSystemSnapshot.invitedInitialBalance = newInvitedInitialBalance
 
   await db.save<MembershipSystemSnapshot>(membershipSystemSnapshot)
 
   const initialInvitationBalanceUpdatedEvent = new InitialInvitationBalanceUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.InitialInvitationBalanceUpdated),
+    ...genericEventFields(event_),
     newInitialBalance: newInvitedInitialBalance,
   })
 
@@ -462,14 +407,10 @@ export async function members_InitialInvitationBalanceUpdated(
 }
 
 export async function members_LeaderInvitationQuotaUpdated(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { u32: newQuota } = new Members.LeaderInvitationQuotaUpdatedEvent(event_).data
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const [newQuota] = new Members.LeaderInvitationQuotaUpdatedEvent(event_).params
 
   const leaderInvitationQuotaUpdatedEvent = new LeaderInvitationQuotaUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.LeaderInvitationQuotaUpdated),
+    ...genericEventFields(event_),
     newInvitationQuota: newQuota.toNumber(),
   })
 

+ 3 - 3
query-node/mappings/package.json

@@ -10,10 +10,10 @@
     "clean": "rm -rf lib"
   },
   "dependencies": {
-    "@dzlzv/hydra-common": "2.1.0-beta.8",
-    "@dzlzv/hydra-db-utils": "2.1.0-beta.8",
+    "@dzlzv/hydra-common": "3.0.0-beta.6",
+    "@dzlzv/hydra-db-utils": "3.0.0-beta.6",
     "@joystream/types": "^0.15.0",
-    "warthog": "https://github.com/metmirr/warthog/releases/download/v2.23.0/warthog-v2.23.0.tgz"
+    "warthog": "https://github.com/metmirr/warthog/releases/download/v2.30.0/warthog-v2.30.0.tgz"
   },
   "devDependencies": {
     "ts-node": "^9.0.0",

+ 79 - 175
query-node/mappings/workingGroups.ts

@@ -1,8 +1,7 @@
 /*
 eslint-disable @typescript-eslint/naming-convention
 */
-import { SubstrateEvent } from '@dzlzv/hydra-common'
-import { DatabaseManager } from '@dzlzv/hydra-db-utils'
+import { SubstrateEvent, DatabaseManager } from '@dzlzv/hydra-common'
 import { StorageWorkingGroup as WorkingGroups } from './generated/types'
 import {
   ApplicationMetadata,
@@ -16,7 +15,7 @@ import {
   WorkingGroupMetadataAction,
 } from '@joystream/metadata-protobuf'
 import { Bytes } from '@polkadot/types'
-import { createEvent, deserializeMetadata, getOrCreateBlock, bytesToString } from './common'
+import { deserializeMetadata, bytesToString, genericEventFields } from './common'
 import BN from 'bn.js'
 import {
   WorkingGroupOpening,
@@ -27,7 +26,6 @@ import {
   ApplicationFormQuestionType,
   OpeningStatusOpen,
   WorkingGroupOpeningType,
-  EventType,
   WorkingGroupApplication,
   ApplicationFormQuestionAnswer,
   AppliedOnOpeningEvent,
@@ -75,7 +73,6 @@ import {
   Event,
 } from 'query-node/dist/model'
 import { createType } from '@joystream/types'
-import _ from 'lodash'
 
 // Reusable functions
 async function getWorkingGroup(
@@ -165,7 +162,7 @@ async function createOpeningMeta(
     metadata = originalMeta
     originallyValid = true
   }
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const {
     applicationFormQuestions,
@@ -243,7 +240,7 @@ async function handleAddUpcomingOpeningAction(
 ): Promise<UpcomingOpeningAdded | InvalidActionMetadata> {
   const upcomingOpeningMeta = action.metadata || {}
   const group = await getWorkingGroup(db, event_)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
   const openingMeta = await createOpeningMeta(db, event_, upcomingOpeningMeta.metadata || {})
   const { rewardPerBlock, expectedStart, minApplicationStake } = upcomingOpeningMeta
   const upcomingOpening = new UpcomingWorkingGroupOpening({
@@ -255,7 +252,6 @@ async function handleAddUpcomingOpeningAction(
     expectedStart: expectedStart ? new Date(expectedStart) : undefined,
     stakeAmount: minApplicationStake?.toNumber() ? new BN(minApplicationStake.toString()) : undefined,
     createdInEvent: statusChangedEvent,
-    createdAtBlock: await getOrCreateBlock(db, event_),
   })
   await db.save<UpcomingWorkingGroupOpening>(upcomingOpening)
 
@@ -294,14 +290,13 @@ async function handleSetWorkingGroupMetadataAction(
   const { newMetadata } = action
   const group = await getWorkingGroup(db, event_, ['metadata'])
   const oldMetadata = group.metadata
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
   const setNewOptionalString = (field: keyof IWorkingGroupMetadata) =>
     typeof newMetadata?.[field] === 'string' ? newMetadata[field] || undefined : oldMetadata?.[field]
 
   const newGroupMetadata = new WorkingGroupMetadata({
     createdAt: eventTime,
     updatedAt: eventTime,
-    setAtBlock: await getOrCreateBlock(db, event_),
     setInEvent: statusChangedEvent,
     group,
     status: setNewOptionalString('status'),
@@ -341,20 +336,16 @@ async function handleWorkingGroupMetadataAction(
 }
 
 async function handleTerminatedWorker(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { workerId, balance: optPenalty, optBytes: optRationale } = new WorkingGroups.TerminatedWorkerEvent(event_).data
+  const [workerId, optPenalty, optRationale] = new WorkingGroups.TerminatedWorkerEvent(event_).params
   const group = await getWorkingGroup(db, event_)
   const worker = await getWorker(db, `${group.name}-${workerId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const EventConstructor = worker.isLead ? TerminatedLeaderEvent : TerminatedWorkerEvent
-  const eventType = worker.isLead ? EventType.TerminatedLeader : EventType.TerminatedWorker
 
   const terminatedEvent = new EventConstructor({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, eventType),
     worker,
     penalty: optPenalty.unwrapOr(undefined),
     rationale: optRationale.isSome ? bytesToString(optRationale.unwrap()) : undefined,
@@ -373,8 +364,7 @@ async function handleTerminatedWorker(db: DatabaseManager, event_: SubstrateEven
 }
 
 export async function findLeaderSetEventByTxHash(db: DatabaseManager, txHash?: string): Promise<LeaderSetEvent> {
-  const event = await db.get(Event, { where: { inExtrinsic: txHash } })
-  const leaderSetEvent = await db.get(LeaderSetEvent, { where: { event }, relations: ['event'] })
+  const leaderSetEvent = await db.get(LeaderSetEvent, { where: { inExtrinsic: txHash } })
 
   if (!leaderSetEvent) {
     throw new Error(`LeaderSet event not found by tx hash: ${txHash}`)
@@ -385,26 +375,24 @@ export async function findLeaderSetEventByTxHash(db: DatabaseManager, txHash?: s
 
 // Mapping functions
 export async function workingGroups_OpeningAdded(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const {
-    balance: rewardPerBlock,
-    bytes: metadataBytes,
-    openingId: openingRuntimeId,
+  const [
+    openingRuntimeId,
+    metadataBytes,
     openingType,
     stakePolicy,
-  } = new WorkingGroups.OpeningAddedEvent(event_).data
+    optRewardPerBlock,
+  ] = new WorkingGroups.OpeningAddedEvent(event_).params
   const group = await getWorkingGroup(db, event_)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const opening = new WorkingGroupOpening({
     createdAt: eventTime,
     updatedAt: eventTime,
-    createdAtBlock: await getOrCreateBlock(db, event_),
     id: `${group.name}-${openingRuntimeId.toString()}`,
     runtimeId: openingRuntimeId.toNumber(),
     applications: [],
     group,
-    rewardPerBlock: rewardPerBlock.unwrapOr(new BN(0)),
+    rewardPerBlock: optRewardPerBlock.unwrapOr(new BN(0)),
     stakeAmount: stakePolicy.stake_amount,
     unstakingPeriod: stakePolicy.leaving_unstaking_period.toNumber(),
     status: new OpeningStatusOpen(),
@@ -416,11 +404,8 @@ export async function workingGroups_OpeningAdded(db: DatabaseManager, event_: Su
 
   await db.save<WorkingGroupOpening>(opening)
 
-  const event = await createEvent(db, event_, EventType.OpeningAdded)
   const openingAddedEvent = new OpeningAddedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event,
+    ...genericEventFields(event_),
     group,
     opening,
   })
@@ -429,12 +414,10 @@ export async function workingGroups_OpeningAdded(db: DatabaseManager, event_: Su
 }
 
 export async function workingGroups_AppliedOnOpening(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
-  const {
-    applicationId: applicationRuntimeId,
-    applyOnOpeningParameters: {
+  const [
+    {
       opening_id: openingRuntimeId,
       description: metadataBytes,
       member_id: memberId,
@@ -442,14 +425,15 @@ export async function workingGroups_AppliedOnOpening(db: DatabaseManager, event_
       role_account_id: roleAccout,
       stake_parameters: { stake, staking_account_id: stakingAccount },
     },
-  } = new WorkingGroups.AppliedOnOpeningEvent(event_).data
+    applicationRuntimeId,
+  ] = new WorkingGroups.AppliedOnOpeningEvent(event_).params
+
   const group = await getWorkingGroup(db, event_)
   const openingDbId = `${group.name}-${openingRuntimeId.toString()}`
 
   const application = new WorkingGroupApplication({
     createdAt: eventTime,
     updatedAt: eventTime,
-    createdAtBlock: await getOrCreateBlock(db, event_),
     id: `${group.name}-${applicationRuntimeId.toString()}`,
     runtimeId: applicationRuntimeId.toNumber(),
     opening: new WorkingGroupOpening({ id: openingDbId }),
@@ -465,11 +449,8 @@ export async function workingGroups_AppliedOnOpening(db: DatabaseManager, event_
   await db.save<WorkingGroupApplication>(application)
   await createApplicationQuestionAnswers(db, application, metadataBytes)
 
-  const event = await createEvent(db, event_, EventType.AppliedOnOpening)
   const appliedOnOpeningEvent = new AppliedOnOpeningEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event,
+    ...genericEventFields(event_),
     group,
     opening: new WorkingGroupOpening({ id: openingDbId }),
     application,
@@ -479,15 +460,10 @@ export async function workingGroups_AppliedOnOpening(db: DatabaseManager, event_
 }
 
 export async function workingGroups_LeaderSet(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
   const group = await getWorkingGroup(db, event_)
 
-  const event = await createEvent(db, event_, EventType.LeaderSet)
   const leaderSetEvent = new LeaderSetEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event,
+    ...genericEventFields(event_),
     group,
   })
 
@@ -495,14 +471,11 @@ export async function workingGroups_LeaderSet(db: DatabaseManager, event_: Subst
 }
 
 export async function workingGroups_OpeningFilled(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
-  const {
-    openingId: openingRuntimeId,
-    applicationId: applicationIdsSet,
-    applicationIdToWorkerIdMap,
-  } = new WorkingGroups.OpeningFilledEvent(event_).data
+  const [openingRuntimeId, applicationIdToWorkerIdMap, applicationIdsSet] = new WorkingGroups.OpeningFilledEvent(
+    event_
+  ).params
 
   const group = await getWorkingGroup(db, event_)
   const opening = await getOpening(db, `${group.name}-${openingRuntimeId.toString()}`, [
@@ -512,11 +485,8 @@ export async function workingGroups_OpeningFilled(db: DatabaseManager, event_: S
   const acceptedApplicationIds = createType('Vec<ApplicationId>', applicationIdsSet.toHex() as any)
 
   // Save the event
-  const event = await createEvent(db, event_, EventType.OpeningFilled)
   const openingFilledEvent = new OpeningFilledEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event,
+    ...genericEventFields(event_),
     group,
     opening,
   })
@@ -553,8 +523,6 @@ export async function workingGroups_OpeningFilled(db: DatabaseManager, event_: S
               updatedAt: eventTime,
               id: `${group.name}-${workerRuntimeId.toString()}`,
               runtimeId: workerRuntimeId.toNumber(),
-              hiredAtBlock: await getOrCreateBlock(db, event_),
-              hiredAtTime: new Date(event_.blockTimestamp.toNumber()),
               application,
               group,
               isLead: opening.type === WorkingGroupOpeningType.LEADER,
@@ -588,7 +556,7 @@ export async function workingGroups_OpeningFilled(db: DatabaseManager, event_: S
     group.updatedAt = eventTime
     await db.save<WorkingGroup>(group)
 
-    const leaderSetEvent = await findLeaderSetEventByTxHash(db, openingFilledEvent.event.inExtrinsic)
+    const leaderSetEvent = await findLeaderSetEventByTxHash(db, openingFilledEvent.inExtrinsic)
     leaderSetEvent.worker = hiredWorkers[0]
     leaderSetEvent.updatedAt = eventTime
     await db.save<LeaderSetEvent>(leaderSetEvent)
@@ -596,19 +564,15 @@ export async function workingGroups_OpeningFilled(db: DatabaseManager, event_: S
 }
 
 export async function workingGroups_OpeningCanceled(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { openingId: openingRuntimeId } = new WorkingGroups.OpeningCanceledEvent(event_).data
+  const [openingRuntimeId] = new WorkingGroups.OpeningCanceledEvent(event_).params
 
   const group = await getWorkingGroup(db, event_)
   const opening = await getOpening(db, `${group.name}-${openingRuntimeId.toString()}`, ['applications'])
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   // Create and save event
-  const event = await createEvent(db, event_, EventType.OpeningCanceled)
   const openingCanceledEvent = new OpeningCanceledEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event,
+    ...genericEventFields(event_),
     group,
     opening,
   })
@@ -617,7 +581,7 @@ export async function workingGroups_OpeningCanceled(db: DatabaseManager, event_:
 
   // Set opening status
   const openingCancelled = new OpeningStatusCancelled()
-  openingCancelled.openingCancelledEventId = openingCanceledEvent.id
+  openingCancelled.openingCanceledEventId = openingCanceledEvent.id
   opening.status = openingCancelled
   opening.updatedAt = eventTime
 
@@ -625,7 +589,7 @@ export async function workingGroups_OpeningCanceled(db: DatabaseManager, event_:
 
   // Set applications status
   const applicationCancelled = new ApplicationStatusCancelled()
-  applicationCancelled.openingCancelledEventId = openingCanceledEvent.id
+  applicationCancelled.openingCanceledEventId = openingCanceledEvent.id
   await Promise.all(
     (opening.applications || [])
       // Skip withdrawn applications
@@ -639,19 +603,15 @@ export async function workingGroups_OpeningCanceled(db: DatabaseManager, event_:
 }
 
 export async function workingGroups_ApplicationWithdrawn(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { applicationId: applicationRuntimeId } = new WorkingGroups.ApplicationWithdrawnEvent(event_).data
+  const [applicationRuntimeId] = new WorkingGroups.ApplicationWithdrawnEvent(event_).params
 
   const group = await getWorkingGroup(db, event_)
   const application = await getApplication(db, `${group.name}-${applicationRuntimeId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   // Create and save event
-  const event = await createEvent(db, event_, EventType.ApplicationWithdrawn)
   const applicationWithdrawnEvent = new ApplicationWithdrawnEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event,
+    ...genericEventFields(event_),
     group,
     application,
   })
@@ -668,20 +628,16 @@ export async function workingGroups_ApplicationWithdrawn(db: DatabaseManager, ev
 }
 
 export async function workingGroups_StatusTextChanged(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { optBytes } = new WorkingGroups.StatusTextChangedEvent(event_).data
+  const [, optBytes] = new WorkingGroups.StatusTextChangedEvent(event_).params
   const group = await getWorkingGroup(db, event_)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
 
   // Since result cannot be empty at this point, but we already need to have an existing StatusTextChangedEvent
   // in order to be able to create UpcomingOpening.createdInEvent relation, we use a temporary "mock" result
   const mockResult = new InvalidActionMetadata()
   mockResult.reason = 'Metadata not yet processed'
   const statusTextChangedEvent = new StatusTextChangedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.StatusTextChanged),
     metadata: optBytes.isSome ? optBytes.unwrap().toString() : undefined,
     result: mockResult,
   })
@@ -714,17 +670,14 @@ export async function workingGroups_WorkerRoleAccountUpdated(
   db: DatabaseManager,
   event_: SubstrateEvent
 ): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { workerId, accountId } = new WorkingGroups.WorkerRoleAccountUpdatedEvent(event_).data
+  const [workerId, accountId] = new WorkingGroups.WorkerRoleAccountUpdatedEvent(event_).params
   const group = await getWorkingGroup(db, event_)
   const worker = await getWorker(db, `${group.name}-${workerId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const workerRoleAccountUpdatedEvent = new WorkerRoleAccountUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.WorkerRoleAccountUpdated),
     worker,
     newRoleAccount: accountId.toString(),
   })
@@ -741,17 +694,14 @@ export async function workingGroups_WorkerRewardAccountUpdated(
   db: DatabaseManager,
   event_: SubstrateEvent
 ): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { workerId, accountId } = new WorkingGroups.WorkerRewardAccountUpdatedEvent(event_).data
+  const [workerId, accountId] = new WorkingGroups.WorkerRewardAccountUpdatedEvent(event_).params
   const group = await getWorkingGroup(db, event_)
   const worker = await getWorker(db, `${group.name}-${workerId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const workerRewardAccountUpdatedEvent = new WorkerRewardAccountUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.WorkerRewardAccountUpdated),
     worker,
     newRewardAccount: accountId.toString(),
   })
@@ -765,17 +715,14 @@ export async function workingGroups_WorkerRewardAccountUpdated(
 }
 
 export async function workingGroups_StakeIncreased(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { workerId, balance: increaseAmount } = new WorkingGroups.StakeIncreasedEvent(event_).data
+  const [workerId, increaseAmount] = new WorkingGroups.StakeIncreasedEvent(event_).params
   const group = await getWorkingGroup(db, event_)
   const worker = await getWorker(db, `${group.name}-${workerId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const stakeIncreasedEvent = new StakeIncreasedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.StakeIncreased),
     worker,
     amount: increaseAmount,
   })
@@ -789,22 +736,14 @@ export async function workingGroups_StakeIncreased(db: DatabaseManager, event_:
 }
 
 export async function workingGroups_RewardPaid(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const {
-    workerId,
-    accountId: rewardAccountId,
-    balance: amount,
-    rewardPaymentType,
-  } = new WorkingGroups.RewardPaidEvent(event_).data
+  const [workerId, rewardAccountId, amount, rewardPaymentType] = new WorkingGroups.RewardPaidEvent(event_).params
   const group = await getWorkingGroup(db, event_)
   const worker = await getWorker(db, `${group.name}-${workerId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const rewardPaidEvent = new RewardPaidEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.RewardPaid),
     worker,
     amount,
     rewardAccount: rewardAccountId.toString(),
@@ -824,19 +763,14 @@ export async function workingGroups_NewMissedRewardLevelReached(
   db: DatabaseManager,
   event_: SubstrateEvent
 ): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { workerId, balance: newMissedRewardAmountOpt } = new WorkingGroups.NewMissedRewardLevelReachedEvent(
-    event_
-  ).data
+  const [workerId, newMissedRewardAmountOpt] = new WorkingGroups.NewMissedRewardLevelReachedEvent(event_).params
   const group = await getWorkingGroup(db, event_)
   const worker = await getWorker(db, `${group.name}-${workerId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const newMissedRewardLevelReachedEvent = new NewMissedRewardLevelReachedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.NewMissedRewardLevelReached),
     worker,
     newMissedRewardAmount: newMissedRewardAmountOpt.unwrapOr(new BN(0)),
   })
@@ -851,17 +785,14 @@ export async function workingGroups_NewMissedRewardLevelReached(
 }
 
 export async function workingGroups_WorkerExited(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { workerId } = new WorkingGroups.WorkerExitedEvent(event_).data
+  const [workerId] = new WorkingGroups.WorkerExitedEvent(event_).params
   const group = await getWorkingGroup(db, event_)
   const worker = await getWorker(db, `${group.name}-${workerId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const workerExitedEvent = new WorkerExitedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.WorkerExited),
     worker,
   })
 
@@ -875,15 +806,12 @@ export async function workingGroups_WorkerExited(db: DatabaseManager, event_: Su
 }
 
 export async function workingGroups_LeaderUnset(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
   const group = await getWorkingGroup(db, event_)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const leaderUnsetEvent = new LeaderUnsetEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.LeaderUnset),
     leader: group.leader,
   })
 
@@ -906,17 +834,14 @@ export async function workingGroups_WorkerRewardAmountUpdated(
   db: DatabaseManager,
   event_: SubstrateEvent
 ): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { workerId, balance: newRewardPerBlockOpt } = new WorkingGroups.WorkerRewardAmountUpdatedEvent(event_).data
+  const [workerId, newRewardPerBlockOpt] = new WorkingGroups.WorkerRewardAmountUpdatedEvent(event_).params
   const group = await getWorkingGroup(db, event_)
   const worker = await getWorker(db, `${group.name}-${workerId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const workerRewardAmountUpdatedEvent = new WorkerRewardAmountUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.WorkerRewardAmountUpdated),
     worker,
     newRewardPerBlock: newRewardPerBlockOpt.unwrapOr(new BN(0)),
   })
@@ -930,21 +855,14 @@ export async function workingGroups_WorkerRewardAmountUpdated(
 }
 
 export async function workingGroups_StakeSlashed(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const {
-    workerId,
-    balances: { 0: slashedAmount, 1: requestedAmount },
-    optBytes: optRationale,
-  } = new WorkingGroups.StakeSlashedEvent(event_).data
+  const [workerId, slashedAmount, requestedAmount, optRationale] = new WorkingGroups.StakeSlashedEvent(event_).params
   const group = await getWorkingGroup(db, event_)
   const worker = await getWorker(db, `${group.name}-${workerId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const workerStakeSlashedEvent = new StakeSlashedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.StakeSlashed),
     worker,
     requestedAmount,
     slashedAmount,
@@ -960,17 +878,14 @@ export async function workingGroups_StakeSlashed(db: DatabaseManager, event_: Su
 }
 
 export async function workingGroups_StakeDecreased(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { workerId, balance: amount } = new WorkingGroups.StakeDecreasedEvent(event_).data
+  const [workerId, amount] = new WorkingGroups.StakeDecreasedEvent(event_).params
   const group = await getWorkingGroup(db, event_)
   const worker = await getWorker(db, `${group.name}-${workerId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const workerStakeDecreasedEvent = new StakeDecreasedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.StakeDecreased),
     worker,
     amount,
   })
@@ -984,17 +899,14 @@ export async function workingGroups_StakeDecreased(db: DatabaseManager, event_:
 }
 
 export async function workingGroups_WorkerStartedLeaving(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { workerId, optBytes: optRationale } = new WorkingGroups.WorkerStartedLeavingEvent(event_).data
+  const [workerId, optRationale] = new WorkingGroups.WorkerStartedLeavingEvent(event_).params
   const group = await getWorkingGroup(db, event_)
   const worker = await getWorker(db, `${group.name}-${workerId.toString()}`)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const workerStartedLeavingEvent = new WorkerStartedLeavingEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.WorkerStartedLeaving),
     worker,
     rationale: optRationale.isSome ? bytesToString(optRationale.unwrap()) : undefined,
   })
@@ -1010,16 +922,13 @@ export async function workingGroups_WorkerStartedLeaving(db: DatabaseManager, ev
 }
 
 export async function workingGroups_BudgetSet(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { balance: newBudget } = new WorkingGroups.BudgetSetEvent(event_).data
+  const [newBudget] = new WorkingGroups.BudgetSetEvent(event_).params
   const group = await getWorkingGroup(db, event_)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const budgetSetEvent = new BudgetSetEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.BudgetSet),
     newBudget,
   })
 
@@ -1032,18 +941,13 @@ export async function workingGroups_BudgetSet(db: DatabaseManager, event_: Subst
 }
 
 export async function workingGroups_BudgetSpending(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  event_.blockTimestamp = new BN(event_.blockTimestamp) // FIXME: Temporary fix for wrong blockTimestamp type
-  const { accountId: reciever, balance: amount, optBytes: optRationale } = new WorkingGroups.BudgetSpendingEvent(
-    event_
-  ).data
+  const [reciever, amount, optRationale] = new WorkingGroups.BudgetSpendingEvent(event_).params
   const group = await getWorkingGroup(db, event_)
-  const eventTime = new Date(event_.blockTimestamp.toNumber())
+  const eventTime = new Date(event_.blockTimestamp)
 
   const budgetSpendingEvent = new BudgetSpendingEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
+    ...genericEventFields(event_),
     group,
-    event: await createEvent(db, event_, EventType.BudgetSpending),
     amount,
     reciever: reciever.toString(),
     rationale: optRationale.isSome ? bytesToString(optRationale.unwrap()) : undefined,

+ 1 - 1
query-node/package.json

@@ -42,7 +42,7 @@
     "tslib": "^2.0.0",
     "@types/bn.js": "^4.11.6",
     "bn.js": "^5.1.2",
-    "@dzlzv/hydra-processor": "2.1.0-beta.8",
+    "@dzlzv/hydra-processor": "3.0.0-beta.6",
     "envsub": "4.0.7"
   },
   "volta": {

+ 7 - 85
query-node/schemas/common.graphql

@@ -5,98 +5,20 @@ enum Network {
   OLYMPIA
 }
 
-enum EventType {
-  # Memberships
-  MembershipBought
-  MemberInvited
-  MemberProfileUpdated
-  MemberAccountsUpdated
-  MemberVerificationStatusUpdated
-  ReferralCutUpdated
-  InvitesTransferred
-  MembershipPriceUpdated
-  InitialInvitationBalanceUpdated
-  LeaderInvitationQuotaUpdated
-  InitialInvitationCountUpdated
-  StakingAccountAddedEvent
-  StakingAccountConfirmed
-  StakingAccountRemoved
-  # Working Groups
-  OpeningAdded
-  AppliedOnOpening
-  OpeningFilled
-  LeaderSet
-  WorkerRoleAccountUpdated
-  LeaderUnset
-  WorkerExited
-  TerminatedWorker
-  TerminatedLeader
-  WorkerStartedLeaving
-  StakeSlashed
-  StakeDecreased
-  StakeIncreased
-  ApplicationWithdrawn
-  OpeningCanceled
-  BudgetSet
-  WorkerRewardAccountUpdated
-  WorkerRewardAmountUpdated
-  StatusTextChanged
-  BudgetSpending
-  RewardPaid
-  NewMissedRewardLevelReached
-  # Forum
-  CategoryCreated
-  CategoryUpdated
-  CategoryDeleted
-  ThreadCreated
-  ThreadModerated
-  ThreadUpdated
-  ThreadTitleUpdated
-  ThreadDeleted
-  ThreadMoved
-  PostAdded
-  PostModerated
-  PostDeleted
-  PostTextUpdated
-  PostReacted
-  VoteOnPoll
-  CategoryStickyThreadUpdate
-  CategoryMembershipOfModeratorUpdated
-}
-
-type Block @entity {
-  "{network}-{blockNumber}"
-  id: ID!
-
-  "Block number (height)"
-  number: Int!
-
-  "Block timestamp"
-  timestamp: BigInt!
-
-  "Network the block was produced in"
-  network: Network!
-}
-
-type Event @entity {
+# FIXME: https://github.com/Joystream/hydra/issues/359
+interface Event @entity {
   "(network}-{blockNumber}-{indexInBlock}"
   id: ID!
 
   "Hash of the extrinsic which caused the event to be emitted"
   inExtrinsic: String
 
-  "Block in which the event was emitted."
-  inBlock: Block!
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
 
   "Index of event in block from which it was emitted."
   indexInBlock: Int!
-
-  "Type of the event"
-  type: EventType!
 }
-
-# FIXME: Warthog bug currently prevents it from beeing implemented
-# interface IEvent @entity {
-#   "Generic event data"
-#   event: Event!
-# }

+ 20 - 17
query-node/schemas/membership.graphql

@@ -1,9 +1,3 @@
-enum MembershipEntryMethod {
-  PAID
-  INVITED
-  GENESIS
-}
-
 type MemberMetadata @entity {
   "Member's name"
   name: String
@@ -15,6 +9,24 @@ type MemberMetadata @entity {
   about: String
 }
 
+type MembershipEntryPaid @variant {
+  "The event the membership was bought in"
+  # Must be optional because of member.entry <=> membershipBoughtEvent.newMember cross relationship
+  membershipBoughtEvent: MembershipBoughtEvent
+}
+
+type MembershipEntryInvited @variant {
+  "The event the member was invited in"
+  # Must be optional because of member.entry <=> memberInvitedEvent.newMember cross relationship
+  memberInvitedEvent: MemberInvitedEvent
+}
+
+type MembershipEntryGenesis @variant {
+  phantom: Int
+}
+
+union MembershipEntryMethod = MembershipEntryPaid | MembershipEntryInvited | MembershipEntryGenesis
+
 "Stored information about a registered user"
 type Membership @entity {
   "MemberId: runtime identifier for a user"
@@ -32,12 +44,6 @@ type Membership @entity {
   "Member's root account id"
   rootAccount: String!
 
-  "Block at which the member was registered"
-  registeredAtBlock: Block!
-
-  "Timestamp when member was registered"
-  registeredAtTime: DateTime!
-
   "How the member was registered"
   entry: MembershipEntryMethod!
 
@@ -70,11 +76,8 @@ type Membership @entity {
 }
 
 type MembershipSystemSnapshot @entity {
-  "The snapshot block"
-  snapshotBlock: Block!
-
-  "Time of the snapshot (based on block timestamp)"
-  snapshotTime: DateTime!
+  "The snapshot block number"
+  snapshotBlock: Int!
 
   "Initial invitation count of a new member."
   defaultInviteCount: Int!

+ 252 - 28
query-node/schemas/membershipEvents.graphql

@@ -1,6 +1,22 @@
 type MembershipBoughtEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "New membership created."
   newMember: Membership!
@@ -22,8 +38,24 @@ type MembershipBoughtEvent @entity {
 }
 
 type MemberInvitedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Inviting member."
   invitingMember: Membership!
@@ -45,8 +77,24 @@ type MemberInvitedEvent @entity {
 }
 
 type MemberProfileUpdatedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Membership being updated."
   member: Membership!
@@ -59,8 +107,24 @@ type MemberProfileUpdatedEvent @entity {
 }
 
 type MemberAccountsUpdatedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Membership in question."
   member: Membership!
@@ -73,8 +137,24 @@ type MemberAccountsUpdatedEvent @entity {
 }
 
 type MemberVerificationStatusUpdatedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Membership in question."
   member: Membership!
@@ -87,16 +167,48 @@ type MemberVerificationStatusUpdatedEvent @entity {
 }
 
 type ReferralCutUpdatedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "New cut value."
   newValue: Int!
 }
 
 type InvitesTransferredEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Membership sending invites."
   sourceMember: Membership!
@@ -109,40 +221,120 @@ type InvitesTransferredEvent @entity {
 }
 
 type MembershipPriceUpdatedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "The new membership price."
   newPrice: BigInt!
 }
 
 type InitialInvitationBalanceUpdatedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "New initial invitation balance."
   newInitialBalance: BigInt!
 }
 
 type LeaderInvitationQuotaUpdatedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "New quota."
   newInvitationQuota: Int!
 }
 
 type InitialInvitationCountUpdatedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "New initial invitation count for members."
   newInitialInvitationCount: Int!
 }
 
 type StakingAccountAddedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Membership in question."
   member: Membership!
@@ -152,8 +344,24 @@ type StakingAccountAddedEvent @entity {
 }
 
 type StakingAccountConfirmedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Membership in question."
   member: Membership!
@@ -163,8 +371,24 @@ type StakingAccountConfirmedEvent @entity {
 }
 
 type StakingAccountRemovedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Membership in question."
   member: Membership!

+ 23 - 37
query-node/schemas/workingGroups.graphql

@@ -4,16 +4,16 @@ type WorkerStatusActive @variant {
 }
 
 type WorkerStatusLeft @variant {
-  # TODO: Variant relationships
-  workerStartedLeavingEventId: ID!
+  "Related event emitted on leaving initialization"
+  workerStartedLeavingEvent: WorkerStartedLeavingEvent!
 
-  # Set when the unstaking period is finished
-  workerExitedEventId: ID
+  "Related event emitted (and set) when the unstaking period is finished"
+  workerExitedEvent: WorkerExitedEvent
 }
 
 type WorkerStatusTerminated @variant {
-  # TODO: Variant relationship
-  terminatedWorkerEventId: ID!
+  "Related event emitted on worker termination"
+  terminatedWorkerEvent: TerminatedWorkerEvent!
 }
 
 union WorkerStatus = WorkerStatusActive | WorkerStatusLeft | WorkerStatusTerminated
@@ -62,12 +62,6 @@ type Worker @entity {
   "All related stake slashes"
   slashes: [StakeSlashedEvent!] @derivedFrom(field: "worker")
 
-  "Block the worker was hired at"
-  hiredAtBlock: Block!
-
-  "Time the worker was hired at"
-  hiredAtTime: DateTime!
-
   "The event that caused the worker to be hired"
   entry: OpeningFilledEvent!
 
@@ -94,9 +88,6 @@ type WorkingGroupMetadata @entity {
   "Working group description text"
   description: String
 
-  "Block the metadata was set at"
-  setAtBlock: Block!
-
   "Event the working group metadata was set in"
   setInEvent: StatusTextChangedEvent!
 
@@ -128,8 +119,8 @@ type WorkingGroup @entity {
 }
 
 type OpeningStatusCancelled @variant {
-  # TODO: Variant relationships
-  openingCancelledEventId: ID!
+  "Related event emitted on opening cancellation"
+  openingCanceledEvent: OpeningCanceledEvent!
 }
 
 type OpeningStatusOpen @variant {
@@ -138,8 +129,8 @@ type OpeningStatusOpen @variant {
 }
 
 type OpeningStatusFilled @variant {
-  # TODO: Variant relationships
-  openingFilledEventId: ID!
+  "Related event emitted after filling the opening"
+  openingFilledEvent: OpeningFilledEvent!
 }
 
 union WorkingGroupOpeningStatus = OpeningStatusOpen | OpeningStatusFilled | OpeningStatusCancelled
@@ -203,8 +194,8 @@ type WorkingGroupOpening @entity {
   "Initial workers' reward per block"
   rewardPerBlock: BigInt!
 
-  "Block the opening was created at"
-  createdAtBlock: Block!
+  "Event the opening was created in"
+  createdInEvent: OpeningAddedEvent! @derivedFrom(field: "opening")
 
   "Time of opening creation"
   createdAt: DateTime!
@@ -212,10 +203,7 @@ type WorkingGroupOpening @entity {
 
 type UpcomingWorkingGroupOpening @entity {
   "Event the upcoming opening was created in"
-  createdInEvent: StatusTextChangedEvent! @unique
-
-  "Block the upcoming opening was added at"
-  createdAtBlock: Block!
+  createdInEvent: StatusTextChangedEvent!
 
   "Related working group"
   group: WorkingGroup!
@@ -239,22 +227,23 @@ type ApplicationStatusPending @variant {
 }
 
 type ApplicationStatusAccepted @variant {
-  # TODO: Variant relationships
-  openingFilledEventId: ID!
+  "Related OpeningFilled event"
+  openingFilledEvent: OpeningFilledEvent!
 }
 
 type ApplicationStatusRejected @variant {
-  # TODO: Variant relationships
-  openingFilledEventId: ID!
+  "Related OpeningFilled event"
+  openingFilledEvent: OpeningFilledEvent!
 }
 
 type ApplicationStatusCancelled @variant {
-  openingCancelledEventId: ID!
+  "Related OpeningCanceled event"
+  openingCanceledEvent: OpeningCanceledEvent!
 }
 
 type ApplicationStatusWithdrawn @variant {
-  # TODO: Variant relationships
-  applicationWithdrawnEventId: ID!
+  "Related ApplicationWithdrawn event"
+  applicationWithdrawnEvent: ApplicationWithdrawnEvent!
 }
 
 union WorkingGroupApplicationStatus =
@@ -295,11 +284,8 @@ type WorkingGroupApplication @entity {
   "Current application status"
   status: WorkingGroupApplicationStatus!
 
-  "Block the application was created at"
-  createdAtBlock: Block!
-
-  "Time of application creation"
-  createdAt: DateTime!
+  "Event the application was created in"
+  createdInEvent: AppliedOnOpeningEvent! @derivedFrom(field: "application")
 }
 
 type ApplicationFormQuestionAnswer @entity {

+ 398 - 46
query-node/schemas/workingGroupsEvents.graphql

@@ -1,6 +1,22 @@
 type OpeningAddedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -12,8 +28,24 @@ type OpeningAddedEvent @entity {
 }
 
 type AppliedOnOpeningEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -28,8 +60,24 @@ type AppliedOnOpeningEvent @entity {
 }
 
 type OpeningFilledEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -42,8 +90,24 @@ type OpeningFilledEvent @entity {
 }
 
 type LeaderSetEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -54,8 +118,24 @@ type LeaderSetEvent @entity {
 }
 
 type WorkerRoleAccountUpdatedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -68,8 +148,24 @@ type WorkerRoleAccountUpdatedEvent @entity {
 }
 
 type LeaderUnsetEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -79,8 +175,24 @@ type LeaderUnsetEvent @entity {
 }
 
 type WorkerExitedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -90,8 +202,24 @@ type WorkerExitedEvent @entity {
 }
 
 type TerminatedWorkerEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -107,8 +235,24 @@ type TerminatedWorkerEvent @entity {
 }
 
 type TerminatedLeaderEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -124,8 +268,24 @@ type TerminatedLeaderEvent @entity {
 }
 
 type WorkerStartedLeavingEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -138,8 +298,24 @@ type WorkerStartedLeavingEvent @entity {
 }
 
 type StakeSlashedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -158,8 +334,24 @@ type StakeSlashedEvent @entity {
 }
 
 type StakeDecreasedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -172,8 +364,24 @@ type StakeDecreasedEvent @entity {
 }
 
 type StakeIncreasedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -186,8 +394,24 @@ type StakeIncreasedEvent @entity {
 }
 
 type ApplicationWithdrawnEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -197,8 +421,24 @@ type ApplicationWithdrawnEvent @entity {
 }
 
 type OpeningCanceledEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -208,8 +448,24 @@ type OpeningCanceledEvent @entity {
 }
 
 type BudgetSetEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -219,8 +475,24 @@ type BudgetSetEvent @entity {
 }
 
 type WorkerRewardAccountUpdatedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -233,8 +505,24 @@ type WorkerRewardAccountUpdatedEvent @entity {
 }
 
 type WorkerRewardAmountUpdatedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -255,8 +543,8 @@ type UpcomingOpeningRemoved @variant {
 }
 
 type WorkingGroupMetadataSet @variant {
-  # TODO: Variant relationships
-  metadataId: ID!
+  "The new metadata snapshot resulting from the update"
+  metadata: WorkingGroupMetadata!
 }
 
 type InvalidActionMetadata @variant {
@@ -271,8 +559,24 @@ union WorkingGroupMetadataActionResult =
   | InvalidActionMetadata
 
 type StatusTextChangedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -285,8 +589,24 @@ type StatusTextChangedEvent @entity {
 }
 
 type BudgetSpendingEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -309,8 +629,24 @@ enum RewardPaymentType {
 }
 
 type RewardPaidEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!
@@ -329,8 +665,24 @@ type RewardPaidEvent @entity {
 }
 
 type NewMissedRewardLevelReachedEvent @entity {
-  "Generic event data"
-  event: Event!
+  ### GENERIC DATA ###
+
+  "(network}-{blockNumber}-{indexInBlock}"
+  id: ID!
+
+  "Hash of the extrinsic which caused the event to be emitted"
+  inExtrinsic: String
+
+  "Blocknumber of the block in which the event was emitted."
+  inBlock: Int!
+
+  "Network the block was produced in"
+  network: Network!
+
+  "Index of event in block from which it was emitted."
+  indexInBlock: Int!
+
+  ### SPECIFIC DATA ###
 
   "Related group"
   group: WorkingGroup!

+ 3 - 5
tests/integration-tests/src/Fixture.ts

@@ -109,9 +109,7 @@ export abstract class BaseQueryNodeFixture extends BaseFixture {
     queryNodeEvents: T[]
   ): T {
     const { blockNumber, indexInBlock } = eventToFind
-    const qEvent = queryNodeEvents.find(
-      (e) => e.event.inBlock.number === blockNumber && e.event.indexInBlock === indexInBlock
-    )
+    const qEvent = queryNodeEvents.find((e) => e.inBlock === blockNumber && e.indexInBlock === indexInBlock)
     if (!qEvent) {
       throw new Error(`Could not find matching query-node event (expected ${blockNumber}:${indexInBlock})!`)
     }
@@ -133,8 +131,8 @@ export abstract class StandardizedFixture extends BaseQueryNodeFixture {
   protected assertQueryNodeEventsAreValid(qEvents: AnyQueryNodeEvent[]): void {
     this.events.forEach((e, i) => {
       const qEvent = this.findMatchingQueryNodeEvent(e, qEvents)
-      assert.equal(qEvent.event.inExtrinsic, this.extrinsics[i].hash.toString())
-      assert.equal(qEvent.event.inBlock.timestamp, e.blockTimestamp)
+      assert.equal(qEvent.inExtrinsic, this.extrinsics[i].hash.toString())
+      assert.equal(new Date(qEvent.createdAt).getTime(), e.blockTimestamp)
       this.assertQueryNodeEventIsValid(qEvent, i)
     })
   }

+ 29 - 16
tests/integration-tests/src/QueryNodeApi.ts

@@ -7,18 +7,12 @@ import {
   GetMemberByIdQuery,
   GetMemberByIdQueryVariables,
   GetMemberById,
-  GetMembershipBoughtEventsByMemberIdQuery,
-  GetMembershipBoughtEventsByMemberIdQueryVariables,
-  GetMembershipBoughtEventsByMemberId,
   GetMemberProfileUpdatedEventsByMemberIdQuery,
   GetMemberProfileUpdatedEventsByMemberIdQueryVariables,
   GetMemberProfileUpdatedEventsByMemberId,
   GetMemberAccountsUpdatedEventsByMemberIdQuery,
   GetMemberAccountsUpdatedEventsByMemberIdQueryVariables,
   GetMemberAccountsUpdatedEventsByMemberId,
-  GetMemberInvitedEventsByNewMemberIdQuery,
-  GetMemberInvitedEventsByNewMemberIdQueryVariables,
-  GetMemberInvitedEventsByNewMemberId,
   GetInvitesTransferredEventsBySourceMemberIdQuery,
   GetInvitesTransferredEventsBySourceMemberIdQueryVariables,
   GetInvitesTransferredEventsBySourceMemberId,
@@ -204,6 +198,15 @@ import {
   GetThreadsWithPostsByIdsQuery,
   GetThreadsWithPostsByIdsQueryVariables,
   GetThreadsWithPostsByIds,
+  GetMembershipBoughtEventsByEventIdsQuery,
+  GetMembershipBoughtEventsByEventIdsQueryVariables,
+  GetMembershipBoughtEventsByEventIds,
+  GetMembersByIdsQuery,
+  GetMembersByIdsQueryVariables,
+  GetMembersByIds,
+  GetMemberInvitedEventsByEventIdsQuery,
+  GetMemberInvitedEventsByEventIdsQueryVariables,
+  GetMemberInvitedEventsByEventIds,
 } from './graphql/generated/queries'
 import { Maybe } from './graphql/generated/schema'
 import { OperationDefinitionNode } from 'graphql'
@@ -315,11 +318,20 @@ export class QueryNodeApi {
     )
   }
 
-  public async getMembershipBoughtEvent(memberId: MemberId): Promise<MembershipBoughtEventFieldsFragment | null> {
-    return this.firstEntityQuery<
-      GetMembershipBoughtEventsByMemberIdQuery,
-      GetMembershipBoughtEventsByMemberIdQueryVariables
-    >(GetMembershipBoughtEventsByMemberId, { memberId: memberId.toString() }, 'membershipBoughtEvents')
+  public async getMembersByIds(ids: MemberId[]): Promise<MembershipFieldsFragment[]> {
+    return this.multipleEntitiesQuery<GetMembersByIdsQuery, GetMembersByIdsQueryVariables>(
+      GetMembersByIds,
+      { ids: ids.map((id) => id.toString()) },
+      'memberships'
+    )
+  }
+
+  public async getMembershipBoughtEvents(events: EventDetails[]): Promise<MembershipBoughtEventFieldsFragment[]> {
+    const eventIds = events.map((e) => this.getQueryNodeEventId(e.blockNumber, e.indexInBlock))
+    return this.multipleEntitiesQuery<
+      GetMembershipBoughtEventsByEventIdsQuery,
+      GetMembershipBoughtEventsByEventIdsQueryVariables
+    >(GetMembershipBoughtEventsByEventIds, { eventIds }, 'membershipBoughtEvents')
   }
 
   public async getMemberProfileUpdatedEvents(memberId: MemberId): Promise<MemberProfileUpdatedEventFieldsFragment[]> {
@@ -336,11 +348,12 @@ export class QueryNodeApi {
     >(GetMemberAccountsUpdatedEventsByMemberId, { memberId: memberId.toString() }, 'memberAccountsUpdatedEvents')
   }
 
-  public async getMemberInvitedEvent(memberId: MemberId): Promise<MemberInvitedEventFieldsFragment | null> {
-    return this.firstEntityQuery<
-      GetMemberInvitedEventsByNewMemberIdQuery,
-      GetMemberInvitedEventsByNewMemberIdQueryVariables
-    >(GetMemberInvitedEventsByNewMemberId, { newMemberId: memberId.toString() }, 'memberInvitedEvents')
+  public async getMemberInvitedEvents(events: EventDetails[]): Promise<MemberInvitedEventFieldsFragment[]> {
+    const eventIds = events.map((e) => this.getQueryNodeEventId(e.blockNumber, e.indexInBlock))
+    return this.multipleEntitiesQuery<
+      GetMemberInvitedEventsByEventIdsQuery,
+      GetMemberInvitedEventsByEventIdsQueryVariables
+    >(GetMemberInvitedEventsByEventIds, { eventIds }, 'memberInvitedEvents')
   }
 
   // TODO: Use event id

+ 4 - 7
tests/integration-tests/src/fixtures/membership/AddStakingAccountsHappyCaseFixture.ts

@@ -2,16 +2,15 @@ import { Api } from '../../Api'
 import { assert } from 'chai'
 import { QueryNodeApi } from '../../QueryNodeApi'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
-import { BaseMembershipFixture } from './BaseMembershipFixture'
+import { BaseQueryNodeFixture } from '../../Fixture'
 import { MemberContext, EventDetails } from '../../types'
 import {
   StakingAccountAddedEventFieldsFragment,
   StakingAccountConfirmedEventFieldsFragment,
 } from '../../graphql/generated/queries'
-import { EventType } from '../../graphql/generated/schema'
 import { MINIMUM_STAKING_ACCOUNT_BALANCE } from '../../consts'
 
-export class AddStakingAccountsHappyCaseFixture extends BaseMembershipFixture {
+export class AddStakingAccountsHappyCaseFixture extends BaseQueryNodeFixture {
   private memberContext: MemberContext
   private accounts: string[]
 
@@ -33,8 +32,7 @@ export class AddStakingAccountsHappyCaseFixture extends BaseMembershipFixture {
     qEvents: StakingAccountAddedEventFieldsFragment[]
   ) {
     const qEvent = this.findMatchingQueryNodeEvent(eventDetails, qEvents)
-    assert.equal(qEvent.event.inExtrinsic, txHash)
-    assert.equal(qEvent.event.type, EventType.StakingAccountAddedEvent)
+    assert.equal(qEvent.inExtrinsic, txHash)
     assert.equal(qEvent.member.id, this.memberContext.memberId.toString())
     assert.equal(qEvent.account, account)
   }
@@ -46,8 +44,7 @@ export class AddStakingAccountsHappyCaseFixture extends BaseMembershipFixture {
     qEvents: StakingAccountConfirmedEventFieldsFragment[]
   ) {
     const qEvent = this.findMatchingQueryNodeEvent(eventDetails, qEvents)
-    assert.equal(qEvent.event.inExtrinsic, txHash)
-    assert.equal(qEvent.event.type, EventType.StakingAccountConfirmed)
+    assert.equal(qEvent.inExtrinsic, txHash)
     assert.equal(qEvent.member.id, this.memberContext.memberId.toString())
     assert.equal(qEvent.account, account)
   }

+ 0 - 24
tests/integration-tests/src/fixtures/membership/BaseMembershipFixture.ts

@@ -1,24 +0,0 @@
-import { BaseQueryNodeFixture } from '../../Fixture'
-import { MembershipMetadata } from '@joystream/metadata-protobuf'
-import { CreateInterface } from '@joystream/types'
-import { BuyMembershipParameters } from '@joystream/types/members'
-import { Utils } from '../../utils'
-
-// Common code for Membership fixtures
-// TODO: Refactor to use StandardizedFixture?
-export abstract class BaseMembershipFixture extends BaseQueryNodeFixture {
-  generateParamsFromAccountId(accountId: string): CreateInterface<BuyMembershipParameters> {
-    const metadataBytes = Utils.metadataToBytes(MembershipMetadata, {
-      name: `name${accountId.substring(0, 14)}`,
-      about: `about${accountId.substring(0, 14)}`,
-    })
-
-    // TODO: avatar
-    return {
-      root_account: accountId,
-      controller_account: accountId,
-      handle: `handle${accountId.substring(0, 14)}`,
-      metadata: metadataBytes,
-    }
-  }
-}

+ 66 - 91
tests/integration-tests/src/fixtures/membership/BuyMembershipHappyCaseFixture.ts

@@ -1,131 +1,106 @@
-import BN from 'bn.js'
 import { Api } from '../../Api'
 import { assert } from 'chai'
-import { BaseMembershipFixture } from './BaseMembershipFixture'
+import { generateParamsFromAccountId } from './utils'
 import { MemberId } from '@joystream/types/common'
 import { QueryNodeApi } from '../../QueryNodeApi'
 import { Membership } from '@joystream/types/members'
-import { EventType, MembershipEntryMethod } from '../../graphql/generated/schema'
-import { blake2AsHex } from '@polkadot/util-crypto'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { MembershipMetadata } from '@joystream/metadata-protobuf'
 import { MembershipBoughtEventDetails } from '../../types'
 import { MembershipBoughtEventFieldsFragment, MembershipFieldsFragment } from '../../graphql/generated/queries'
 import { Utils } from '../../utils'
+import { StandardizedFixture } from '../../Fixture'
+import { SubmittableResult } from '@polkadot/api'
 
-export class BuyMembershipHappyCaseFixture extends BaseMembershipFixture {
-  private accounts: string[]
-  private memberIds: MemberId[] = []
-
-  private extrinsics: SubmittableExtrinsic<'promise'>[] = []
-  private events: MembershipBoughtEventDetails[] = []
-  private members: Membership[] = []
+export class BuyMembershipHappyCaseFixture extends StandardizedFixture {
+  protected accounts: string[]
+  protected memberIds: MemberId[] = []
+  protected events: MembershipBoughtEventDetails[] = []
+  protected members: Membership[] = []
 
   public constructor(api: Api, query: QueryNodeApi, accounts: string[]) {
     super(api, query)
     this.accounts = accounts
   }
 
-  private generateBuyMembershipTx(accountId: string): SubmittableExtrinsic<'promise'> {
-    return this.api.tx.members.buyMembership(this.generateParamsFromAccountId(accountId))
+  protected async getSignerAccountOrAccounts(): Promise<string[]> {
+    return this.accounts
+  }
+
+  protected async getExtrinsics(): Promise<SubmittableExtrinsic<'promise'>[]> {
+    return this.accounts.map((a) => this.api.tx.members.buyMembership(generateParamsFromAccountId(a)))
+  }
+
+  protected async getEventFromResult(result: SubmittableResult): Promise<MembershipBoughtEventDetails> {
+    return this.api.retrieveMembershipBoughtEventDetails(result)
   }
 
   public getCreatedMembers(): MemberId[] {
-    return this.memberIds.slice()
+    return this.events.map((e) => e.memberId)
   }
 
-  private assertMemberMatchQueriedResult(member: Membership, qMember: MembershipFieldsFragment | null) {
-    if (!qMember) {
-      throw new Error('Query node: Membership not found!')
-    }
-    const {
-      handle,
-      rootAccount,
-      controllerAccount,
-      metadata: { name, about },
-      isVerified,
-      entry,
-    } = qMember
-    const txParams = this.generateParamsFromAccountId(rootAccount)
-    const metadata = Utils.metadataFromBytes(MembershipMetadata, txParams.metadata)
-    assert.equal(blake2AsHex(handle), member.handle_hash.toString())
-    assert.equal(handle, txParams.handle)
-    assert.equal(rootAccount, member.root_account.toString())
-    assert.equal(controllerAccount, member.controller_account.toString())
-    assert.equal(name, metadata.name)
-    assert.equal(about, metadata.about)
-    // TODO: avatar
-    assert.equal(isVerified, false)
-    assert.equal(entry, MembershipEntryMethod.Paid)
+  protected assertQueriedMembersAreValid(
+    qMembers: MembershipFieldsFragment[],
+    qEvents: MembershipBoughtEventFieldsFragment[]
+  ): void {
+    this.events.forEach((e, i) => {
+      const account = this.accounts[i]
+      const params = generateParamsFromAccountId(account)
+      const qEvent = this.findMatchingQueryNodeEvent(e, qEvents)
+      const qMember = qMembers.find((m) => m.id === e.memberId.toString())
+      Utils.assert(qMember, 'Query node: Membership not found!')
+      const {
+        handle,
+        rootAccount,
+        controllerAccount,
+        metadata: { name, about },
+        isVerified,
+        entry,
+      } = qMember
+      const metadata = Utils.metadataFromBytes(MembershipMetadata, params.metadata)
+      assert.equal(handle, params.handle)
+      assert.equal(rootAccount, params.root_account)
+      assert.equal(controllerAccount, params.controller_account)
+      assert.equal(name, metadata.name)
+      assert.equal(about, metadata.about)
+      // TODO: avatar
+      assert.equal(isVerified, false)
+      Utils.assert(entry.__typename === 'MembershipEntryPaid', 'Query node: Invalid membership entry method')
+      Utils.assert(entry.membershipBoughtEvent)
+      assert.equal(entry.membershipBoughtEvent.id, qEvent.id)
+    })
   }
 
-  private assertEventMatchQueriedResult(
-    eventDetails: MembershipBoughtEventDetails,
-    account: string,
-    txHash: string,
-    qEvent: MembershipBoughtEventFieldsFragment | null
-  ) {
-    if (!qEvent) {
-      throw new Error('Query node: MembershipBought event not found!')
-    }
-    const txParams = this.generateParamsFromAccountId(account)
+  protected assertQueryNodeEventIsValid(qEvent: MembershipBoughtEventFieldsFragment, i: number): void {
+    const account = this.accounts[i]
+    const event = this.events[i]
+    const txParams = generateParamsFromAccountId(account)
     const metadata = Utils.metadataFromBytes(MembershipMetadata, txParams.metadata)
-    assert.equal(qEvent.event.inBlock.number, eventDetails.blockNumber)
-    assert.equal(qEvent.event.inExtrinsic, txHash)
-    assert.equal(qEvent.event.indexInBlock, eventDetails.indexInBlock)
-    assert.equal(qEvent.event.type, EventType.MembershipBought)
-    assert.equal(qEvent.newMember.id, eventDetails.memberId.toString())
+    assert.equal(qEvent.newMember.id, event.memberId.toString())
     assert.equal(qEvent.handle, txParams.handle)
-    assert.equal(qEvent.rootAccount, txParams.root_account.toString())
-    assert.equal(qEvent.controllerAccount, txParams.controller_account.toString())
+    assert.equal(qEvent.rootAccount, txParams.root_account)
+    assert.equal(qEvent.controllerAccount, txParams.controller_account)
     assert.equal(qEvent.metadata.name, metadata.name || null)
     assert.equal(qEvent.metadata.about, metadata.about || null)
     // TODO: avatar
   }
 
   async execute(): Promise<void> {
-    // Fee estimation and transfer
+    // Add membership-price funds to accounts
     const membershipFee = await this.api.getMembershipFee()
-    const membershipTransactionFee = await this.api.estimateTxFee(
-      this.generateBuyMembershipTx(this.accounts[0]),
-      this.accounts[0]
-    )
-    const estimatedFee = membershipTransactionFee.add(new BN(membershipFee))
-
-    await this.api.treasuryTransferBalanceToAccounts(this.accounts, estimatedFee)
-
-    this.extrinsics = this.accounts.map((a) => this.generateBuyMembershipTx(a))
-    const results = await Promise.all(this.accounts.map((a, i) => this.api.signAndSend(this.extrinsics[i], a)))
-    this.events = await Promise.all(results.map((r) => this.api.retrieveMembershipBoughtEventDetails(r)))
-    this.memberIds = this.events.map((e) => e.memberId)
-
-    this.debug(`Registered ${this.memberIds.length} new members`)
-
-    assert.equal(this.memberIds.length, this.accounts.length)
-
-    // Assert that created members have expected root and controller accounts
-    this.members = await Promise.all(this.memberIds.map((id) => this.api.query.members.membershipById(id)))
-
-    this.members.forEach((member, index) => {
-      assert(member.root_account.eq(this.accounts[index]))
-      assert(member.controller_account.eq(this.accounts[index]))
-    })
+    await Promise.all(this.accounts.map((a) => this.api.treasuryTransferBalance(a, membershipFee)))
+    await super.execute()
   }
 
   async runQueryNodeChecks(): Promise<void> {
     await super.runQueryNodeChecks()
-    // Ensure newly created members were parsed by query node
-    await Promise.all(
-      this.members.map(async (member, i) => {
-        const memberId = this.memberIds[i]
-        await this.query.tryQueryWithTimeout(
-          () => this.query.getMemberById(memberId),
-          (qMember) => this.assertMemberMatchQueriedResult(member, qMember)
-        )
-        // Ensure the query node event is valid
-        const qEvent = await this.query.getMembershipBoughtEvent(memberId)
-        this.assertEventMatchQueriedResult(this.events[i], this.accounts[i], this.extrinsics[i].hash.toString(), qEvent)
-      })
+
+    const qEvents = await this.query.tryQueryWithTimeout(
+      () => this.query.getMembershipBoughtEvents(this.events),
+      (r) => this.assertQueryNodeEventsAreValid(r)
     )
+
+    const qMembers = await this.query.getMembersByIds(this.events.map((e) => e.memberId))
+    this.assertQueriedMembersAreValid(qMembers, qEvents)
   }
 }

+ 6 - 6
tests/integration-tests/src/fixtures/membership/BuyMembershipWithInsufficienFundsFixture.ts

@@ -1,20 +1,20 @@
 import BN from 'bn.js'
 import { Api } from '../../Api'
 import { assert } from 'chai'
-import { QueryNodeApi } from '../../QueryNodeApi'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
-import { BaseMembershipFixture } from './BaseMembershipFixture'
+import { generateParamsFromAccountId } from './utils'
+import { BaseFixture } from '../../Fixture'
 
-export class BuyMembershipWithInsufficienFundsFixture extends BaseMembershipFixture {
+export class BuyMembershipWithInsufficienFundsFixture extends BaseFixture {
   private account: string
 
-  public constructor(api: Api, query: QueryNodeApi, account: string) {
-    super(api, query)
+  public constructor(api: Api, account: string) {
+    super(api)
     this.account = account
   }
 
   private generateBuyMembershipTx(accountId: string): SubmittableExtrinsic<'promise'> {
-    return this.api.tx.members.buyMembership(this.generateParamsFromAccountId(accountId))
+    return this.api.tx.members.buyMembership(generateParamsFromAccountId(accountId))
   }
 
   async execute(): Promise<void> {

+ 75 - 76
tests/integration-tests/src/fixtures/membership/InviteMembersHappyCaseFixture.ts

@@ -2,21 +2,20 @@ import { Api } from '../../Api'
 import { assert } from 'chai'
 import { QueryNodeApi } from '../../QueryNodeApi'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
-import { BaseMembershipFixture } from './BaseMembershipFixture'
 import { MemberContext, MemberInvitedEventDetails } from '../../types'
 import { MemberInvitedEventFieldsFragment, MembershipFieldsFragment } from '../../graphql/generated/queries'
-import { EventType, MembershipEntryMethod } from '../../graphql/generated/schema'
 import { MemberId } from '@joystream/types/common'
 import { MembershipMetadata } from '@joystream/metadata-protobuf'
 import { Utils } from '../../utils'
+import { StandardizedFixture } from '../../Fixture'
+import { generateParamsFromAccountId } from './utils'
+import { SubmittableResult } from '@polkadot/api'
 
-export class InviteMembersHappyCaseFixture extends BaseMembershipFixture {
-  private inviterContext: MemberContext
-  private accounts: string[]
-
-  private initialInvitesCount?: number
-  private extrinsics: SubmittableExtrinsic<'promise'>[] = []
-  private events: MemberInvitedEventDetails[] = []
+export class InviteMembersHappyCaseFixture extends StandardizedFixture {
+  protected inviterContext: MemberContext
+  protected accounts: string[]
+  protected initialInvitesCount?: number
+  protected events: MemberInvitedEventDetails[] = []
 
   public constructor(api: Api, query: QueryNodeApi, inviterContext: MemberContext, accounts: string[]) {
     super(api, query)
@@ -26,54 +25,64 @@ export class InviteMembersHappyCaseFixture extends BaseMembershipFixture {
 
   generateInviteMemberTx(memberId: MemberId, inviteeAccountId: string): SubmittableExtrinsic<'promise'> {
     return this.api.tx.members.inviteMember({
-      ...this.generateParamsFromAccountId(inviteeAccountId),
+      ...generateParamsFromAccountId(inviteeAccountId),
       inviting_member_id: memberId,
     })
   }
 
-  private assertMemberCorrectlyInvited(account: string, qMember: MembershipFieldsFragment | null) {
-    if (!qMember) {
-      throw new Error('Query node: Membership not found!')
-    }
-    const {
-      handle,
-      rootAccount,
-      controllerAccount,
-      metadata: { name, about },
-      isVerified,
-      entry,
-      invitedBy,
-    } = qMember
-    const txParams = this.generateParamsFromAccountId(account)
-    const metadata = Utils.metadataFromBytes(MembershipMetadata, txParams.metadata)
-    assert.equal(handle, txParams.handle)
-    assert.equal(rootAccount, txParams.root_account)
-    assert.equal(controllerAccount, txParams.controller_account)
-    assert.equal(name, metadata.name)
-    assert.equal(about, metadata.about)
-    // TODO: avatar
-    assert.equal(isVerified, false)
-    assert.equal(entry, MembershipEntryMethod.Invited)
-    Utils.assert(invitedBy, 'invitedBy cannot be empty')
-    assert.equal(invitedBy.id, this.inviterContext.memberId.toString())
+  protected async getSignerAccountOrAccounts(): Promise<string> {
+    return this.inviterContext.account
+  }
+
+  protected async getExtrinsics(): Promise<SubmittableExtrinsic<'promise'>[]> {
+    return this.accounts.map((a) => this.generateInviteMemberTx(this.inviterContext.memberId, a))
+  }
+
+  protected async getEventFromResult(result: SubmittableResult): Promise<MemberInvitedEventDetails> {
+    return this.api.retrieveMemberInvitedEventDetails(result)
+  }
+
+  protected assertQueriedInvitedMembersAreValid(
+    qMembers: MembershipFieldsFragment[],
+    qEvents: MemberInvitedEventFieldsFragment[]
+  ): void {
+    this.events.map((e, i) => {
+      const account = this.accounts[i]
+      const txParams = generateParamsFromAccountId(account)
+      const qMember = qMembers.find((m) => m.id === e.newMemberId.toString())
+      const qEvent = this.findMatchingQueryNodeEvent(e, qEvents)
+      Utils.assert(qMember, 'Query node: Membership not found!')
+      const {
+        handle,
+        rootAccount,
+        controllerAccount,
+        metadata: { name, about },
+        isVerified,
+        entry,
+        invitedBy,
+      } = qMember
+      const metadata = Utils.metadataFromBytes(MembershipMetadata, txParams.metadata)
+      assert.equal(handle, txParams.handle)
+      assert.equal(rootAccount, txParams.root_account)
+      assert.equal(controllerAccount, txParams.controller_account)
+      assert.equal(name, metadata.name)
+      assert.equal(about, metadata.about)
+      // TODO: avatar
+      assert.equal(isVerified, false)
+      Utils.assert(entry.__typename === 'MembershipEntryInvited', 'Query node: Invalid member entry method')
+      Utils.assert(entry.memberInvitedEvent, 'Query node: Empty memberInvitedEvent reference')
+      assert.equal(entry.memberInvitedEvent.id, qEvent.id)
+      Utils.assert(invitedBy, 'invitedBy cannot be empty')
+      assert.equal(invitedBy.id, this.inviterContext.memberId.toString())
+    })
   }
 
-  private aseertQueryNodeEventIsValid(
-    eventDetails: MemberInvitedEventDetails,
-    account: string,
-    txHash: string,
-    qEvent: MemberInvitedEventFieldsFragment | null
-  ) {
-    if (!qEvent) {
-      throw new Error('Query node: MemberInvitedEvent not found!')
-    }
-    const txParams = this.generateParamsFromAccountId(account)
+  protected assertQueryNodeEventIsValid(qEvent: MemberInvitedEventFieldsFragment, i: number): void {
+    const account = this.accounts[i]
+    const event = this.events[i]
+    const txParams = generateParamsFromAccountId(account)
     const metadata = Utils.metadataFromBytes(MembershipMetadata, txParams.metadata)
-    assert.equal(qEvent.event.inBlock.number, eventDetails.blockNumber)
-    assert.equal(qEvent.event.inExtrinsic, txHash)
-    assert.equal(qEvent.event.indexInBlock, eventDetails.indexInBlock)
-    assert.equal(qEvent.event.type, EventType.MemberInvited)
-    assert.equal(qEvent.newMember.id, eventDetails.newMemberId.toString())
+    assert.equal(qEvent.newMember.id, event.newMemberId.toString())
     assert.equal(qEvent.handle, txParams.handle)
     assert.equal(qEvent.rootAccount, txParams.root_account)
     assert.equal(qEvent.controllerAccount, txParams.controller_account)
@@ -83,44 +92,34 @@ export class InviteMembersHappyCaseFixture extends BaseMembershipFixture {
   }
 
   async execute(): Promise<void> {
-    this.extrinsics = this.accounts.map((a) => this.generateInviteMemberTx(this.inviterContext.memberId, a))
-    const feePerTx = await this.api.estimateTxFee(this.extrinsics[0], this.inviterContext.account)
-    await this.api.treasuryTransferBalance(this.inviterContext.account, feePerTx.muln(this.accounts.length))
-
     const initialInvitationBalance = await this.api.query.members.initialInvitationBalance()
     // Top up working group budget to allow funding invited members
     await this.api.makeSudoCall(
       this.api.tx.membershipWorkingGroup.setBudget(initialInvitationBalance.muln(this.accounts.length))
     )
-
-    const { invites } = await this.api.query.members.membershipById(this.inviterContext.memberId)
-    this.initialInvitesCount = invites.toNumber()
-
-    const txResults = await Promise.all(
-      this.extrinsics.map((tx) => this.api.signAndSend(tx, this.inviterContext.account))
-    )
-    this.events = await Promise.all(txResults.map((res) => this.api.retrieveMemberInvitedEventDetails(res)))
+    // Load initial invites count
+    this.initialInvitesCount = (
+      await this.api.query.members.membershipById(this.inviterContext.memberId)
+    ).invites.toNumber()
+    // Execute
+    await super.execute()
   }
 
   async runQueryNodeChecks(): Promise<void> {
     await super.runQueryNodeChecks()
-    const invitedMembersIds = this.events.map((e) => e.newMemberId)
-    await Promise.all(
-      this.accounts.map(async (account, i) => {
-        const memberId = invitedMembersIds[i]
-        await this.query.tryQueryWithTimeout(
-          () => this.query.getMemberById(memberId),
-          (qMember) => this.assertMemberCorrectlyInvited(account, qMember)
-        )
-        const qEvent = await this.query.getMemberInvitedEvent(memberId)
-        this.aseertQueryNodeEventIsValid(this.events[i], account, this.extrinsics[i].hash.toString(), qEvent)
-      })
+
+    const qEvents = await this.query.tryQueryWithTimeout(
+      () => this.query.getMemberInvitedEvents(this.events),
+      (res) => this.assertQueryNodeEventsAreValid(res)
     )
 
+    const invitedMembersIds = this.events.map((e) => e.newMemberId)
+    const qInvitedMembers = await this.query.getMembersByIds(invitedMembersIds)
+    this.assertQueriedInvitedMembersAreValid(qInvitedMembers, qEvents)
+
     const qInviter = await this.query.getMemberById(this.inviterContext.memberId)
-    if (!qInviter) {
-      throw new Error('Query node: Inviter member not found!')
-    }
+    Utils.assert(qInviter, 'Query node: Inviter member not found!')
+
     const { inviteCount, invitees } = qInviter
     // Assert that inviteCount was correctly updated
     assert.equal(inviteCount, this.initialInvitesCount! - this.accounts.length)

+ 3 - 5
tests/integration-tests/src/fixtures/membership/RemoveStakingAccountsHappyCaseFixture.ts

@@ -2,12 +2,11 @@ import { Api } from '../../Api'
 import { assert } from 'chai'
 import { QueryNodeApi } from '../../QueryNodeApi'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
-import { BaseMembershipFixture } from './BaseMembershipFixture'
+import { BaseQueryNodeFixture } from '../../Fixture'
 import { EventDetails, MemberContext } from '../../types'
 import { StakingAccountRemovedEventFieldsFragment } from '../../graphql/generated/queries'
-import { EventType } from '../../graphql/generated/schema'
 
-export class RemoveStakingAccountsHappyCaseFixture extends BaseMembershipFixture {
+export class RemoveStakingAccountsHappyCaseFixture extends BaseQueryNodeFixture {
   private memberContext: MemberContext
   private accounts: string[]
 
@@ -27,8 +26,7 @@ export class RemoveStakingAccountsHappyCaseFixture extends BaseMembershipFixture
     qEvents: StakingAccountRemovedEventFieldsFragment[]
   ) {
     const qEvent = this.findMatchingQueryNodeEvent(eventDetails, qEvents)
-    assert.equal(qEvent.event.inExtrinsic, txHash)
-    assert.equal(qEvent.event.type, EventType.StakingAccountRemoved)
+    assert.equal(qEvent.inExtrinsic, txHash)
     assert.equal(qEvent.member.id, this.memberContext.memberId.toString())
     assert.equal(qEvent.account, account)
   }

+ 5 - 5
tests/integration-tests/src/fixtures/membership/SudoUpdateMembershipSystem.ts

@@ -3,7 +3,7 @@ import { Api } from '../../Api'
 import { assert } from 'chai'
 import { QueryNodeApi } from '../../QueryNodeApi'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
-import { BaseMembershipFixture } from './BaseMembershipFixture'
+import { BaseQueryNodeFixture } from '../../Fixture'
 import { AnyQueryNodeEvent, EventDetails, MembershipEventName } from '../../types'
 import { MembershipSystemSnapshotFieldsFragment } from '../../graphql/generated/queries'
 
@@ -14,7 +14,7 @@ type MembershipSystemValues = {
   invitedInitialBalance: BN
 }
 
-export class SudoUpdateMembershipSystem extends BaseMembershipFixture {
+export class SudoUpdateMembershipSystem extends BaseQueryNodeFixture {
   private newValues: Partial<MembershipSystemValues>
 
   private events: EventDetails[] = []
@@ -37,8 +37,8 @@ export class SudoUpdateMembershipSystem extends BaseMembershipFixture {
   }
 
   private async assertBeforeSnapshotIsValid(beforeSnapshot: MembershipSystemSnapshotFieldsFragment) {
-    assert.isNumber(beforeSnapshot.snapshotBlock.number)
-    const chainValues = await this.getMembershipSystemValuesAt(beforeSnapshot.snapshotBlock.number)
+    assert.isNumber(beforeSnapshot.snapshotBlock)
+    const chainValues = await this.getMembershipSystemValuesAt(beforeSnapshot.snapshotBlock)
     assert.equal(beforeSnapshot.referralCut, chainValues.referralCut)
     assert.equal(beforeSnapshot.invitedInitialBalance, chainValues.invitedInitialBalance.toString())
     assert.equal(beforeSnapshot.membershipPrice, chainValues.membershipPrice.toString())
@@ -64,7 +64,7 @@ export class SudoUpdateMembershipSystem extends BaseMembershipFixture {
     if (!qEvent) {
       throw new Error('Missing query-node event')
     }
-    assert.equal(qEvent.event.inExtrinsic, txHash)
+    assert.equal(qEvent.inExtrinsic, txHash)
     return qEvent
   }
 

+ 3 - 10
tests/integration-tests/src/fixtures/membership/TransferInvitesHappyCaseFixture.ts

@@ -2,13 +2,12 @@ import { Api } from '../../Api'
 import { assert } from 'chai'
 import { QueryNodeApi } from '../../QueryNodeApi'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
-import { BaseMembershipFixture } from './BaseMembershipFixture'
+import { BaseQueryNodeFixture } from '../../Fixture'
 import { MemberContext, EventDetails } from '../../types'
 import { InvitesTransferredEventFieldsFragment } from '../../graphql/generated/queries'
-import { EventType } from '../../graphql/generated/schema'
 import { Membership } from '@joystream/types/members'
 
-export class TransferInvitesHappyCaseFixture extends BaseMembershipFixture {
+export class TransferInvitesHappyCaseFixture extends BaseQueryNodeFixture {
   private fromContext: MemberContext
   private toContext: MemberContext
   private invitesToTransfer: number
@@ -39,14 +38,8 @@ export class TransferInvitesHappyCaseFixture extends BaseMembershipFixture {
     if (!qEvent) {
       throw new Error('Query node: InvitesTransferredEvent not found!')
     }
-    const {
-      event: { inExtrinsic, type },
-      sourceMember,
-      targetMember,
-      numberOfInvites,
-    } = qEvent
+    const { inExtrinsic, sourceMember, targetMember, numberOfInvites } = qEvent
     assert.equal(inExtrinsic, txHash)
-    assert.equal(type, EventType.InvitesTransferred)
     assert.equal(sourceMember.id, this.fromContext.memberId.toString())
     assert.equal(targetMember.id, this.toContext.memberId.toString())
     assert.equal(numberOfInvites, this.invitesToTransfer)

+ 3 - 5
tests/integration-tests/src/fixtures/membership/UpdateAccountsHappyCaseFixture.ts

@@ -2,12 +2,11 @@ import { Api } from '../../Api'
 import { assert } from 'chai'
 import { QueryNodeApi } from '../../QueryNodeApi'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
-import { BaseMembershipFixture } from './BaseMembershipFixture'
+import { BaseQueryNodeFixture } from '../../Fixture'
 import { EventDetails, MemberContext } from '../../types'
 import { MemberAccountsUpdatedEventFieldsFragment, MembershipFieldsFragment } from '../../graphql/generated/queries'
-import { EventType } from '../../graphql/generated/schema'
 
-export class UpdateAccountsHappyCaseFixture extends BaseMembershipFixture {
+export class UpdateAccountsHappyCaseFixture extends BaseQueryNodeFixture {
   private memberContext: MemberContext
   // Update data
   private newRootAccount: string
@@ -45,13 +44,12 @@ export class UpdateAccountsHappyCaseFixture extends BaseMembershipFixture {
   ) {
     const qEvent = this.findMatchingQueryNodeEvent(eventDetails, qEvents)
     const {
-      event: { inExtrinsic, type },
+      inExtrinsic,
       member: { id: memberId },
       newControllerAccount,
       newRootAccount,
     } = qEvent
     assert.equal(inExtrinsic, txHash)
-    assert.equal(type, EventType.MemberAccountsUpdated)
     assert.equal(memberId, this.memberContext.memberId.toString())
     assert.equal(newControllerAccount, this.newControllerAccount)
     assert.equal(newRootAccount, this.newRootAccount)

+ 3 - 5
tests/integration-tests/src/fixtures/membership/UpdateProfileHappyCaseFixture.ts

@@ -2,15 +2,14 @@ import { Api } from '../../Api'
 import { assert } from 'chai'
 import { QueryNodeApi } from '../../QueryNodeApi'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
-import { BaseMembershipFixture } from './BaseMembershipFixture'
+import { BaseQueryNodeFixture } from '../../Fixture'
 import { MemberContext, EventDetails } from '../../types'
 import { MembershipFieldsFragment, MemberProfileUpdatedEventFieldsFragment } from '../../graphql/generated/queries'
-import { EventType } from '../../graphql/generated/schema'
 import { MembershipMetadata } from '@joystream/metadata-protobuf'
 import { Utils } from '../../utils'
 
 // TODO: Add partial update to make sure it works too
-export class UpdateProfileHappyCaseFixture extends BaseMembershipFixture {
+export class UpdateProfileHappyCaseFixture extends BaseQueryNodeFixture {
   private memberContext: MemberContext
   // Update data
   private newName = 'New name'
@@ -46,13 +45,12 @@ export class UpdateProfileHappyCaseFixture extends BaseMembershipFixture {
   ) {
     const qEvent = this.findMatchingQueryNodeEvent(eventDetails, qEvents)
     const {
-      event: { inExtrinsic, type },
+      inExtrinsic,
       member: { id: memberId },
       newHandle,
       newMetadata,
     } = qEvent
     assert.equal(inExtrinsic, txHash)
-    assert.equal(type, EventType.MemberProfileUpdated)
     assert.equal(memberId, this.memberContext.memberId.toString())
     assert.equal(newHandle, this.newHandle)
     assert.equal(newMetadata.name, this.newName)

+ 0 - 1
tests/integration-tests/src/fixtures/membership/index.ts

@@ -1,5 +1,4 @@
 export { AddStakingAccountsHappyCaseFixture } from './AddStakingAccountsHappyCaseFixture'
-export { BaseMembershipFixture } from './BaseMembershipFixture'
 export { BuyMembershipHappyCaseFixture } from './BuyMembershipHappyCaseFixture'
 export { BuyMembershipWithInsufficienFundsFixture } from './BuyMembershipWithInsufficienFundsFixture'
 export { InviteMembersHappyCaseFixture } from './InviteMembersHappyCaseFixture'

+ 19 - 0
tests/integration-tests/src/fixtures/membership/utils.ts

@@ -0,0 +1,19 @@
+import { MembershipMetadata } from '@joystream/metadata-protobuf'
+import { CreateInterface } from '@joystream/types'
+import { BuyMembershipParameters } from '@joystream/types/members'
+import { Utils } from '../../utils'
+
+// Common code for Membership fixtures
+export function generateParamsFromAccountId(accountId: string): CreateInterface<BuyMembershipParameters> {
+  const metadataBytes = Utils.metadataToBytes(MembershipMetadata, {
+    name: `name${accountId.substring(0, 14)}`,
+    about: `about${accountId.substring(0, 14)}`,
+  })
+
+  return {
+    root_account: accountId,
+    controller_account: accountId,
+    handle: `handle${accountId.substring(0, 14)}`,
+    metadata: metadataBytes,
+  }
+}

+ 8 - 6
tests/integration-tests/src/fixtures/workingGroups/ApplyOnOpeningsHappyCaseFixture.ts

@@ -11,7 +11,6 @@ import { ApplicationId, Opening, OpeningId } from '@joystream/types/working-grou
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 
 export type ApplicantDetails = {
   memberId: MemberId
@@ -115,13 +114,17 @@ export class ApplyOnOpeningsHappyCaseFixture extends BaseWorkingGroupFixture {
     return metadata
   }
 
-  protected assertQueriedApplicationsAreValid(qApplications: ApplicationFieldsFragment[]): void {
+  protected assertQueriedApplicationsAreValid(
+    qApplications: ApplicationFieldsFragment[],
+    qEvents: AppliedOnOpeningEventFieldsFragment[]
+  ): void {
     this.events.map((e, i) => {
       const applicationDetails = this.applications[i]
       const qApplication = qApplications.find((a) => a.runtimeId === e.applicationId.toNumber())
+      const qEvent = this.findMatchingQueryNodeEvent(e, qEvents)
       Utils.assert(qApplication, 'Query node: Application not found!')
       assert.equal(qApplication.runtimeId, e.applicationId.toNumber())
-      assert.equal(qApplication.createdAtBlock.number, e.blockNumber)
+      assert.equal(qApplication.createdInEvent.id, qEvent.id)
       assert.equal(qApplication.opening.runtimeId, applicationDetails.openingId.toNumber())
       assert.equal(qApplication.applicant.id, applicationDetails.applicant.memberId.toString())
       assert.equal(qApplication.roleAccount, applicationDetails.applicant.roleAccount)
@@ -143,7 +146,6 @@ export class ApplyOnOpeningsHappyCaseFixture extends BaseWorkingGroupFixture {
 
   protected assertQueryNodeEventIsValid(qEvent: AppliedOnOpeningEventFieldsFragment, i: number): void {
     const applicationDetails = this.applications[i]
-    assert.equal(qEvent.event.type, EventType.AppliedOnOpening)
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.opening.runtimeId, applicationDetails.openingId.toNumber())
     assert.equal(qEvent.application.runtimeId, this.events[i].applicationId.toNumber())
@@ -152,7 +154,7 @@ export class ApplyOnOpeningsHappyCaseFixture extends BaseWorkingGroupFixture {
   async runQueryNodeChecks(): Promise<void> {
     await super.runQueryNodeChecks()
     // Query the events
-    await this.query.tryQueryWithTimeout(
+    const qEvents = await this.query.tryQueryWithTimeout(
       () => this.query.getAppliedOnOpeningEvents(this.events),
       (qEvents) => this.assertQueryNodeEventsAreValid(qEvents)
     )
@@ -161,6 +163,6 @@ export class ApplyOnOpeningsHappyCaseFixture extends BaseWorkingGroupFixture {
       this.events.map((e) => e.applicationId),
       this.group
     )
-    this.assertQueriedApplicationsAreValid(qApplications)
+    this.assertQueriedApplicationsAreValid(qApplications, qEvents)
   }
 }

+ 5 - 4
tests/integration-tests/src/fixtures/workingGroups/CancelOpeningsFixture.ts

@@ -6,7 +6,6 @@ import { BaseWorkingGroupFixture } from './BaseWorkingGroupFixture'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { OpeningId } from '@joystream/types/working-group'
 import {
   ApplicationBasicFieldsFragment,
@@ -44,7 +43,8 @@ export class CancelOpeningsFixture extends BaseWorkingGroupFixture {
       const qOpening = qOpenings.find((o) => o.runtimeId === openingId.toNumber())
       Utils.assert(qOpening)
       Utils.assert(qOpening.status.__typename === 'OpeningStatusCancelled', 'Query node: Invalid opening status')
-      assert.equal(qOpening.status.openingCancelledEventId, qEvent.id)
+      Utils.assert(qOpening.status.openingCanceledEvent, 'Query node: Missing openingCanceledEvent relation')
+      assert.equal(qOpening.status.openingCanceledEvent.id, qEvent.id)
       qOpening.applications.forEach((a) => this.assertApplicationStatusIsValid(qEvent, a))
     })
   }
@@ -56,12 +56,13 @@ export class CancelOpeningsFixture extends BaseWorkingGroupFixture {
     // It's possible that some of the applications have been withdrawn
     assert.oneOf(qApplication.status.__typename, ['ApplicationStatusWithdrawn', 'ApplicationStatusCancelled'])
     if (qApplication.status.__typename === 'ApplicationStatusCancelled') {
-      assert.equal(qApplication.status.openingCancelledEventId, qEvent.id)
+      // FIXME: Missing due to Hydra bug now
+      // Utils.assert(qApplication.status.openingCanceledEvent, 'Query node: Missing openingCanceledEvent relation')
+      // assert.equal(qApplication.status.openingCanceledEvent.id, qEvent.id)
     }
   }
 
   protected assertQueryNodeEventIsValid(qEvent: OpeningCanceledEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.OpeningCanceled)
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.opening.runtimeId, this.openingIds[i].toNumber())
   }

+ 9 - 6
tests/integration-tests/src/fixtures/workingGroups/CreateOpeningsFixture.ts

@@ -7,7 +7,7 @@ import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { Utils } from '../../utils'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { OpeningAddedEventFieldsFragment, OpeningFieldsFragment } from '../../graphql/generated/queries'
-import { EventType, WorkingGroupOpeningType } from '../../graphql/generated/schema'
+import { WorkingGroupOpeningType } from '../../graphql/generated/schema'
 import { assert } from 'chai'
 import { MIN_APPLICATION_STAKE, MIN_UNSTANKING_PERIOD } from '../../consts'
 import moment from 'moment'
@@ -109,13 +109,17 @@ export class CreateOpeningsFixture extends BaseCreateOpeningFixture {
     return this.api.retrieveOpeningAddedEventDetails(result, this.group)
   }
 
-  protected assertQueriedOpeningsAreValid(qOpenings: OpeningFieldsFragment[]): void {
+  protected assertQueriedOpeningsAreValid(
+    qOpenings: OpeningFieldsFragment[],
+    qEvents: OpeningAddedEventFieldsFragment[]
+  ): void {
     this.events.map((e, i) => {
       const qOpening = qOpenings.find((o) => o.runtimeId === e.openingId.toNumber())
       const openingParams = this.openingsParams[i]
+      const qEvent = this.findMatchingQueryNodeEvent(e, qEvents)
       Utils.assert(qOpening, 'Query node: Opening not found')
       assert.equal(qOpening.runtimeId, e.openingId.toNumber())
-      assert.equal(qOpening.createdAtBlock.number, e.blockNumber)
+      assert.equal(qOpening.createdInEvent.id, qEvent.id)
       assert.equal(qOpening.group.name, this.group)
       assert.equal(qOpening.rewardPerBlock, openingParams.reward.toString())
       assert.equal(qOpening.type, this.asSudo ? WorkingGroupOpeningType.Leader : WorkingGroupOpeningType.Regular)
@@ -128,7 +132,6 @@ export class CreateOpeningsFixture extends BaseCreateOpeningFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: OpeningAddedEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.OpeningAdded)
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.opening.runtimeId, this.events[i].openingId.toNumber())
   }
@@ -136,7 +139,7 @@ export class CreateOpeningsFixture extends BaseCreateOpeningFixture {
   async runQueryNodeChecks(): Promise<void> {
     await super.runQueryNodeChecks()
     // Query the events
-    await this.query.tryQueryWithTimeout(
+    const qEvents = await this.query.tryQueryWithTimeout(
       () => this.query.getOpeningAddedEvents(this.events),
       (qEvents) => this.assertQueryNodeEventsAreValid(qEvents)
     )
@@ -146,6 +149,6 @@ export class CreateOpeningsFixture extends BaseCreateOpeningFixture {
       this.events.map((e) => e.openingId),
       this.group
     )
-    this.assertQueriedOpeningsAreValid(qOpenings)
+    this.assertQueriedOpeningsAreValid(qOpenings, qEvents)
   }
 }

+ 0 - 3
tests/integration-tests/src/fixtures/workingGroups/CreateUpcomingOpeningsFixture.ts

@@ -6,7 +6,6 @@ import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { Utils } from '../../utils'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { StatusTextChangedEventFieldsFragment, UpcomingOpeningFieldsFragment } from '../../graphql/generated/queries'
-import { EventType } from '../../graphql/generated/schema'
 import { assert } from 'chai'
 import {
   IUpcomingOpeningMetadata,
@@ -116,7 +115,6 @@ export class CreateUpcomingOpeningsFixture extends BaseCreateOpeningFixture {
             ? expectedMeta.minApplicationStake.toString()
             : null
         )
-        assert.equal(qUpcomingOpening.createdAtBlock.number, e.blockNumber)
         Utils.assert(qEvent.result.__typename === 'UpcomingOpeningAdded')
         assert.equal(qEvent.result.upcomingOpeningId, qUpcomingOpening.id)
         this.assertQueriedOpeningMetadataIsValid(qUpcomingOpening.metadata, expectedMeta.metadata)
@@ -128,7 +126,6 @@ export class CreateUpcomingOpeningsFixture extends BaseCreateOpeningFixture {
 
   protected assertQueryNodeEventIsValid(qEvent: StatusTextChangedEventFieldsFragment, i: number): void {
     const params = this.upcomingOpeningsParams[i]
-    assert.equal(qEvent.event.type, EventType.StatusTextChanged)
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.metadata, this.getActionMetadataBytes(params).toString())
     assert.equal(

+ 0 - 2
tests/integration-tests/src/fixtures/workingGroups/DecreaseWorkerStakesFixture.ts

@@ -8,7 +8,6 @@ import { Worker, WorkerId } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { lockIdByWorkingGroup } from '../../consts'
 import { StakeDecreasedEventFieldsFragment, WorkerFieldsFragment } from '../../graphql/generated/queries'
 
@@ -62,7 +61,6 @@ export class DecreaseWorkerStakesFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: StakeDecreasedEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.StakeDecreased)
     assert.equal(qEvent.worker.runtimeId, this.workerIds[i].toNumber())
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.amount, this.amounts[i].toString())

+ 24 - 18
tests/integration-tests/src/fixtures/workingGroups/FillOpeningsFixture.ts

@@ -8,7 +8,6 @@ import { Application, ApplicationId, Opening, OpeningId, WorkerId } from '@joyst
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { JoyBTreeSet } from '@joystream/types/common'
 import { registry } from '@joystream/types'
 import { lockIdByWorkingGroup } from '../../consts'
@@ -55,12 +54,15 @@ export class FillOpeningsFixture extends BaseWorkingGroupFixture {
   }
 
   protected async getExtrinsics(): Promise<SubmittableExtrinsic<'promise'>[]> {
-    const extrinsics = this.openingIds.map((openingId, i) =>
-      this.api.tx[this.group].fillOpening(
-        openingId,
-        new (JoyBTreeSet(ApplicationId))(registry, this.acceptedApplicationsIdsArrays[i])
+    const extrinsics = this.openingIds.map((openingId, i) => {
+      const applicationsSet = new (JoyBTreeSet(ApplicationId))(registry, this.acceptedApplicationsIdsArrays[i])
+      this.debug(
+        'Applications to accept:',
+        this.acceptedApplicationsIdsArrays[i].map((id) => id.toNumber())
       )
-    )
+      this.debug('Encoded BTreeSet:', applicationsSet.toHex())
+      return this.api.tx[this.group].fillOpening(openingId, applicationsSet)
+    })
     return this.asSudo ? extrinsics.map((tx) => this.api.tx.sudo.sudo(tx)) : extrinsics
   }
 
@@ -102,7 +104,6 @@ export class FillOpeningsFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: OpeningFilledEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.OpeningFilled)
     assert.equal(qEvent.opening.runtimeId, this.openingIds[i].toNumber())
     assert.equal(qEvent.group.name, this.group)
     this.acceptedApplicationsIdsArrays[i].forEach((acceptedApplId, j) => {
@@ -119,23 +120,23 @@ export class FillOpeningsFixture extends BaseWorkingGroupFixture {
       const qWorker = qEvent.workersHired.find((w) => w.runtimeId === workerId.toNumber())
       Utils.assert(qWorker, `Query node: Worker not found in OpeningFilled.hiredWorkers (id: ${workerId.toString()})`)
       this.assertHiredWorkerIsValid(
-        this.events[i],
         this.acceptedApplicationsIdsArrays[i][j],
         this.acceptedApplicationsArrays[i][j],
         this.applicationStakesArrays[i][j],
         this.openings[i],
-        qWorker
+        qWorker,
+        qEvent
       )
     })
   }
 
   protected assertHiredWorkerIsValid(
-    eventDetails: OpeningFilledEventDetails,
     applicationId: ApplicationId,
     application: Application,
     applicationStake: BN,
     opening: Opening,
-    qWorker: WorkerFieldsFragment
+    qWorker: WorkerFieldsFragment,
+    qEvent: OpeningFilledEventFieldsFragment
   ): void {
     assert.equal(qWorker.group.name, this.group)
     assert.equal(qWorker.membership.id, application.member_id.toString())
@@ -145,7 +146,7 @@ export class FillOpeningsFixture extends BaseWorkingGroupFixture {
     assert.equal(qWorker.status.__typename, 'WorkerStatusActive')
     assert.equal(qWorker.isLead, true)
     assert.equal(qWorker.stake, applicationStake.toString())
-    assert.equal(qWorker.hiredAtBlock.number, eventDetails.blockNumber)
+    assert.equal(qWorker.entry.id, qEvent.id)
     assert.equal(qWorker.application.runtimeId, applicationId.toNumber())
     assert.equal(qWorker.rewardPerBlock, opening.reward_per_block.toString())
   }
@@ -160,7 +161,8 @@ export class FillOpeningsFixture extends BaseWorkingGroupFixture {
       const qOpening = qOpenings.find((o) => o.runtimeId === openingId.toNumber())
       Utils.assert(qOpening, 'Query node: Opening not found')
       Utils.assert(qOpening.status.__typename === 'OpeningStatusFilled', 'Query node: Invalid opening status')
-      assert.equal(qOpening.status.openingFilledEventId, qEvent.id)
+      Utils.assert(qOpening.status.openingFilledEvent, 'Query node: Missing openingFilledEvent relation')
+      assert.equal(qOpening.status.openingFilledEvent.id, qEvent.id)
     })
   }
 
@@ -178,11 +180,16 @@ export class FillOpeningsFixture extends BaseWorkingGroupFixture {
         const isAccepted = acceptedApplicationsIds.some((id) => id.toNumber() === qApplication.runtimeId)
         if (isAccepted) {
           Utils.assert(qApplication.status.__typename === 'ApplicationStatusAccepted', 'Invalid application status')
-          assert.equal(qApplication.status.openingFilledEventId, qEvent.id)
+          console.log('qApplication.status', qApplication.status)
+          // FIXME: Missing due to Hydra bug now
+          // Utils.assert(qApplication.status.openingFilledEvent, 'Query node: Missing openingFilledEvent relation')
+          // assert.equal(qApplication.status.openingFilledEvent.id, qEvent.id)
         } else {
           assert.oneOf(qApplication.status.__typename, ['ApplicationStatusRejected', 'ApplicationStatusWithdrawn'])
           if (qApplication.status.__typename === 'ApplicationStatusRejected') {
-            assert.equal(qApplication.status.openingFilledEventId, qEvent.id)
+            // FIXME: Missing due to Hydra bug now
+            // Utils.assert(qApplication.status.openingFilledEvent, 'Query node: Missing openingFilledEvent relation')
+            // assert.equal(qApplication.status.openingFilledEvent.id, qEvent.id)
           }
         }
       })
@@ -195,9 +202,8 @@ export class FillOpeningsFixture extends BaseWorkingGroupFixture {
     workerRuntimeId: number
   ): void {
     Utils.assert(qEvent, 'Query node: LeaderSet not found!')
-    assert.equal(qEvent.event.inBlock.timestamp, eventDetails.blockTimestamp)
-    assert.equal(qEvent.event.inExtrinsic, this.extrinsics[0].hash.toString())
-    assert.equal(qEvent.event.type, EventType.LeaderSet)
+    assert.equal(new Date(qEvent.createdAt).getTime(), eventDetails.blockTimestamp)
+    assert.equal(qEvent.inExtrinsic, this.extrinsics[0].hash.toString())
     assert.equal(qEvent.group.name, this.group)
     Utils.assert(qEvent.worker, 'LeaderSet: Worker is empty')
     assert.equal(qEvent.worker.runtimeId, workerRuntimeId)

+ 0 - 2
tests/integration-tests/src/fixtures/workingGroups/IncreaseWorkerStakesFixture.ts

@@ -8,7 +8,6 @@ import { WorkerId, Worker } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { lockIdByWorkingGroup } from '../../consts'
 import { StakeIncreasedEventFieldsFragment, WorkerFieldsFragment } from '../../graphql/generated/queries'
 
@@ -52,7 +51,6 @@ export class IncreaseWorkerStakesFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: StakeIncreasedEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.StakeIncreased)
     assert.equal(qEvent.worker.runtimeId, this.workerIds[i].toNumber())
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.amount, this.stakeIncreases[i].toString())

+ 2 - 3
tests/integration-tests/src/fixtures/workingGroups/LeaveRoleFixture.ts

@@ -7,7 +7,6 @@ import { WorkerId, Worker } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { WorkerFieldsFragment, WorkerStartedLeavingEventFieldsFragment } from '../../graphql/generated/queries'
 
 export class LeaveRoleFixture extends BaseWorkingGroupFixture {
@@ -42,7 +41,6 @@ export class LeaveRoleFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: WorkerStartedLeavingEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.WorkerStartedLeaving)
     assert.equal(qEvent.worker.runtimeId, this.workerIds[i].toNumber())
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.rationale, this.getRationale(this.workerIds[i]))
@@ -61,7 +59,8 @@ export class LeaveRoleFixture extends BaseWorkingGroupFixture {
         worker.status.__typename === 'WorkerStatusLeft',
         `Invalid worker status: ${worker.status.__typename}`
       )
-      assert.equal(worker.status.workerStartedLeavingEventId, qEvent.id)
+      Utils.assert(worker.status.workerStartedLeavingEvent, 'Query node: Missing workerStartedLeavingEvent relation')
+      assert.equal(worker.status.workerStartedLeavingEvent.id, qEvent.id)
     })
   }
 

+ 0 - 2
tests/integration-tests/src/fixtures/workingGroups/RemoveUpcomingOpeningsFixture.ts

@@ -6,7 +6,6 @@ import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { Utils } from '../../utils'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { StatusTextChangedEventFieldsFragment } from '../../graphql/generated/queries'
-import { EventType } from '../../graphql/generated/schema'
 import { assert } from 'chai'
 import { WorkingGroupMetadataAction } from '@joystream/metadata-protobuf'
 import { Bytes } from '@polkadot/types'
@@ -42,7 +41,6 @@ export class RemoveUpcomingOpeningsFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: StatusTextChangedEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.StatusTextChanged)
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.metadata, this.getActionMetadataBytes(this.upcomingOpeningIds[i]).toString())
     Utils.assert(qEvent.result.__typename === 'UpcomingOpeningRemoved', 'Unexpected StatuxTextChangedEvent result type')

+ 0 - 2
tests/integration-tests/src/fixtures/workingGroups/SetBudgetFixture.ts

@@ -7,7 +7,6 @@ import { BaseWorkingGroupFixture } from './BaseWorkingGroupFixture'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { BudgetSetEventFieldsFragment, WorkingGroupFieldsFragment } from '../../graphql/generated/queries'
 
 export class SetBudgetFixture extends BaseWorkingGroupFixture {
@@ -32,7 +31,6 @@ export class SetBudgetFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: BudgetSetEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.BudgetSet)
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.newBudget, this.budgets[i].toString())
   }

+ 0 - 2
tests/integration-tests/src/fixtures/workingGroups/SlashWorkerStakesFixture.ts

@@ -8,7 +8,6 @@ import { Worker, WorkerId } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { lockIdByWorkingGroup } from '../../consts'
 import { StakeSlashedEventFieldsFragment, WorkerFieldsFragment } from '../../graphql/generated/queries'
 
@@ -66,7 +65,6 @@ export class SlashWorkerStakesFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: StakeSlashedEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.StakeSlashed)
     assert.equal(qEvent.worker.runtimeId, this.workerIds[i].toNumber())
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.rationale, this.getRationale(this.workerIds[i]))

+ 0 - 2
tests/integration-tests/src/fixtures/workingGroups/SpendBudgetFixture.ts

@@ -7,7 +7,6 @@ import { BaseWorkingGroupFixture } from './BaseWorkingGroupFixture'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { BudgetSpendingEventFieldsFragment, WorkingGroupFieldsFragment } from '../../graphql/generated/queries'
 
 export class SpendBudgetFixture extends BaseWorkingGroupFixture {
@@ -45,7 +44,6 @@ export class SpendBudgetFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: BudgetSpendingEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.BudgetSpending)
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.amount, this.amounts[i].toString())
     assert.equal(qEvent.reciever, this.recievers[i])

+ 5 - 7
tests/integration-tests/src/fixtures/workingGroups/TerminateWorkersFixture.ts

@@ -8,7 +8,6 @@ import { Worker, WorkerId } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { lockIdByWorkingGroup } from '../../consts'
 import {
   LeaderUnsetEventFieldsFragment,
@@ -78,7 +77,6 @@ export class TerminateWorkersFixture extends BaseWorkingGroupFixture {
     qEvent: TerminatedWorkerEventFieldsFragment | TerminatedLeaderEventFieldsFragment,
     i: number
   ): void {
-    assert.equal(qEvent.event.type, this.asSudo ? EventType.TerminatedLeader : EventType.TerminatedWorker)
     assert.equal(qEvent.worker.runtimeId, this.workerIds[i].toNumber())
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.rationale, this.getRationale(this.workerIds[i]))
@@ -100,7 +98,8 @@ export class TerminateWorkersFixture extends BaseWorkingGroupFixture {
         worker.status.__typename === 'WorkerStatusTerminated',
         `Invalid worker status: ${worker.status.__typename}`
       )
-      assert.equal(worker.status.terminatedWorkerEventId, qEvent.id)
+      Utils.assert(worker.status.terminatedWorkerEvent, 'Query node: Missing terminatedWorkerEvent relation')
+      assert.equal(worker.status.terminatedWorkerEvent.id, qEvent.id)
     })
   }
 
@@ -109,11 +108,10 @@ export class TerminateWorkersFixture extends BaseWorkingGroupFixture {
     qEvent: LeaderUnsetEventFieldsFragment | null
   ): void {
     Utils.assert(qEvent, 'Query node: LeaderUnsetEvent not found!')
-    assert.equal(qEvent.event.inExtrinsic, this.extrinsics[0].hash.toString())
-    assert.equal(qEvent.event.inBlock.number, eventDetails.blockNumber)
-    assert.equal(qEvent.event.inBlock.timestamp, eventDetails.blockTimestamp)
+    assert.equal(qEvent.inExtrinsic, this.extrinsics[0].hash.toString())
+    assert.equal(qEvent.inBlock, eventDetails.blockNumber)
+    assert.equal(new Date(qEvent.createdAt).getTime(), eventDetails.blockTimestamp)
     assert.equal(qEvent.group.name, this.group)
-    assert.equal(qEvent.event.type, EventType.LeaderUnset)
     assert.equal(qEvent.leader.runtimeId, this.workerIds[0].toNumber())
   }
 

+ 3 - 6
tests/integration-tests/src/fixtures/workingGroups/UpdateGroupStatusFixture.ts

@@ -6,7 +6,6 @@ import { BaseWorkingGroupFixture } from './BaseWorkingGroupFixture'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { IWorkingGroupMetadata, WorkingGroupMetadataAction } from '@joystream/metadata-protobuf'
 import {
   StatusTextChangedEventFieldsFragment,
@@ -48,7 +47,6 @@ export class UpdateGroupStatusFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: StatusTextChangedEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.StatusTextChanged)
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.metadata, this.getActionMetadataBytes(this.updates[i]).toString())
     assert.equal(qEvent.result.__typename, 'WorkingGroupMetadataSet')
@@ -80,7 +78,6 @@ export class UpdateGroupStatusFixture extends BaseWorkingGroupFixture {
     assert.equal(postUpdateSnapshot.statusMessage, expectedMeta.statusMessage || null)
     assert.equal(postUpdateSnapshot.description, expectedMeta.description || null)
     assert.equal(postUpdateSnapshot.about, expectedMeta.about || null)
-    assert.equal(postUpdateSnapshot.setAtBlock.number, eventDetails.blockNumber)
   }
 
   async runQueryNodeChecks(): Promise<void> {
@@ -103,8 +100,7 @@ export class UpdateGroupStatusFixture extends BaseWorkingGroupFixture {
     this.events.forEach((postUpdateEvent, i) => {
       const postUpdateSnapshotIndex = snapshots.findIndex(
         (s) =>
-          s.setInEvent.event.id ===
-          this.query.getQueryNodeEventId(postUpdateEvent.blockNumber, postUpdateEvent.indexInBlock)
+          s.setInEvent.id === this.query.getQueryNodeEventId(postUpdateEvent.blockNumber, postUpdateEvent.indexInBlock)
       )
       const postUpdateSnapshot = postUpdateSnapshotIndex > -1 ? snapshots[postUpdateSnapshotIndex] : null
       const preUpdateSnapshot = postUpdateSnapshotIndex > 0 ? snapshots[postUpdateSnapshotIndex - 1] : null
@@ -119,7 +115,8 @@ export class UpdateGroupStatusFixture extends BaseWorkingGroupFixture {
         qEvent.result.__typename === 'WorkingGroupMetadataSet',
         'Invalid StatusTextChanged event result type'
       )
-      assert(qEvent.result.metadataId, postUpdateSnapshot.id)
+      Utils.assert(qEvent.result.metadata, 'Query node: Missing metadata relation')
+      assert(qEvent.result.metadata.id, postUpdateSnapshot.id)
       lastSnapshot = postUpdateSnapshot
     })
 

+ 0 - 2
tests/integration-tests/src/fixtures/workingGroups/UpdateWorkerRewardAccountsFixture.ts

@@ -7,7 +7,6 @@ import { WorkerId, Worker } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { WorkerFieldsFragment, WorkerRewardAccountUpdatedEventFieldsFragment } from '../../graphql/generated/queries'
 import { AccountId } from '@joystream/types/common'
 
@@ -49,7 +48,6 @@ export class UpdateWorkerRewardAccountsFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: WorkerRewardAccountUpdatedEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.WorkerRewardAccountUpdated)
     assert.equal(qEvent.worker.runtimeId, this.workerIds[i].toNumber())
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.newRewardAccount, this.rewardAccounts[i].toString())

+ 0 - 2
tests/integration-tests/src/fixtures/workingGroups/UpdateWorkerRewardAmountsFixture.ts

@@ -8,7 +8,6 @@ import { Worker, WorkerId } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { WorkerFieldsFragment, WorkerRewardAmountUpdatedEventFieldsFragment } from '../../graphql/generated/queries'
 
 export class UpdateWorkerRewardAmountsFixture extends BaseWorkingGroupFixture {
@@ -49,7 +48,6 @@ export class UpdateWorkerRewardAmountsFixture extends BaseWorkingGroupFixture {
 
   protected assertQueryNodeEventIsValid(qEvent: WorkerRewardAmountUpdatedEventFieldsFragment, i: number): void {
     const newReward = this.newRewards[i]
-    assert.equal(qEvent.event.type, EventType.WorkerRewardAmountUpdated)
     assert.equal(qEvent.worker.runtimeId, this.workerIds[i].toNumber())
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.newRewardPerBlock, newReward ? newReward.toString() : '0')

+ 0 - 2
tests/integration-tests/src/fixtures/workingGroups/UpdateWorkerRoleAccountsFixture.ts

@@ -7,7 +7,6 @@ import { WorkerId, Worker } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { WorkerFieldsFragment, WorkerRoleAccountUpdatedEventFieldsFragment } from '../../graphql/generated/queries'
 import { AccountId } from '@joystream/types/common'
 import { Membership } from '@joystream/types/members'
@@ -51,7 +50,6 @@ export class UpdateWorkerRoleAccountsFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: WorkerRoleAccountUpdatedEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.WorkerRoleAccountUpdated)
     assert.equal(qEvent.worker.runtimeId, this.workerIds[i].toNumber())
     assert.equal(qEvent.group.name, this.group)
     assert.equal(qEvent.newRoleAccount, this.roleAccounts[i].toString())

+ 5 - 3
tests/integration-tests/src/fixtures/workingGroups/WithdrawApplicationsFixture.ts

@@ -7,7 +7,6 @@ import { ApplicationId } from '@joystream/types/working-group'
 import { SubmittableExtrinsic } from '@polkadot/api/types'
 import { ISubmittableResult } from '@polkadot/types/types/'
 import { Utils } from '../../utils'
-import { EventType } from '../../graphql/generated/schema'
 import { ApplicationFieldsFragment, ApplicationWithdrawnEventFieldsFragment } from '../../graphql/generated/queries'
 
 export class WithdrawApplicationsFixture extends BaseWorkingGroupFixture {
@@ -39,7 +38,6 @@ export class WithdrawApplicationsFixture extends BaseWorkingGroupFixture {
   }
 
   protected assertQueryNodeEventIsValid(qEvent: ApplicationWithdrawnEventFieldsFragment, i: number): void {
-    assert.equal(qEvent.event.type, EventType.ApplicationWithdrawn)
     assert.equal(qEvent.application.runtimeId, this.applicationIds[i].toNumber())
     assert.equal(qEvent.group.name, this.group)
   }
@@ -56,7 +54,11 @@ export class WithdrawApplicationsFixture extends BaseWorkingGroupFixture {
         qApplication.status.__typename === 'ApplicationStatusWithdrawn',
         'Query node: Invalid application status!'
       )
-      assert.equal(qApplication.status.applicationWithdrawnEventId, qEvent.id)
+      Utils.assert(
+        qApplication.status.applicationWithdrawnEvent,
+        'Query node: Missing applicationWithdrawnEvent relation'
+      )
+      assert.equal(qApplication.status.applicationWithdrawnEvent.id, qEvent.id)
     })
   }
 

+ 1 - 1
tests/integration-tests/src/flows/membership/creatingMemberships.ts

@@ -20,7 +20,7 @@ export default async function creatingMemberships({ api, query, env }: FlowProps
 
   // Assert account can not buy the membership with insufficient funds
   const aAccount = (await api.createKeyPairs(1))[0].address
-  const insufficientFundsFixture = new BuyMembershipWithInsufficienFundsFixture(api, query, aAccount)
+  const insufficientFundsFixture = new BuyMembershipWithInsufficienFundsFixture(api, aAccount)
   await new FixtureRunner(insufficientFundsFixture).run()
 
   debug('Done')

+ 0 - 15
tests/integration-tests/src/graphql/queries/common.graphql

@@ -1,15 +0,0 @@
-fragment BlockFields on Block {
-  number
-  timestamp
-  network
-}
-
-fragment EventFields on Event {
-  id
-  inBlock {
-    ...BlockFields
-  }
-  inExtrinsic
-  indexInBlock
-  type
-}

+ 22 - 10
tests/integration-tests/src/graphql/queries/membership.graphql

@@ -11,11 +11,19 @@ fragment MembershipFields on Membership {
   }
   controllerAccount
   rootAccount
-  registeredAtBlock {
-    ...BlockFields
+  entry {
+    __typename
+    ... on MembershipEntryPaid {
+      membershipBoughtEvent {
+        id
+      }
+    }
+    ... on MembershipEntryInvited {
+      memberInvitedEvent {
+        id
+      }
+    }
   }
-  registeredAtTime
-  entry
   isVerified
   inviteCount
   invitedBy {
@@ -33,11 +41,15 @@ query getMemberById($id: ID!) {
   }
 }
 
-fragment MembershipSystemSnapshotFields on MembershipSystemSnapshot {
-  snapshotBlock {
-    ...BlockFields
+query getMembersByIds($ids: [ID!]) {
+  memberships(where: { id_in: $ids }) {
+    ...MembershipFields
   }
-  snapshotTime
+}
+
+fragment MembershipSystemSnapshotFields on MembershipSystemSnapshot {
+  createdAt
+  snapshotBlock
   referralCut
   invitedInitialBalance
   defaultInviteCount
@@ -45,13 +57,13 @@ fragment MembershipSystemSnapshotFields on MembershipSystemSnapshot {
 }
 
 query getMembershipSystemSnapshotAt($time: DateTime!) {
-  membershipSystemSnapshots(where: { snapshotTime_eq: $time }, orderBy: snapshotTime_DESC, limit: 1) {
+  membershipSystemSnapshots(where: { createdAt_eq: $time }, orderBy: createdAt_DESC, limit: 1) {
     ...MembershipSystemSnapshotFields
   }
 }
 
 query getMembershipSystemSnapshotBefore($time: DateTime!) {
-  membershipSystemSnapshots(where: { snapshotTime_lt: $time }, orderBy: snapshotTime_DESC, limit: 1) {
+  membershipSystemSnapshots(where: { createdAt_lt: $time }, orderBy: createdAt_DESC, limit: 1) {
     ...MembershipSystemSnapshotFields
   }
 }

+ 74 - 51
tests/integration-tests/src/graphql/queries/membershipEvents.graphql

@@ -2,9 +2,11 @@
 
 fragment MembershipBoughtEventFields on MembershipBoughtEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   newMember {
     id
   }
@@ -18,18 +20,19 @@ fragment MembershipBoughtEventFields on MembershipBoughtEvent {
     id
   }
 }
-# FIXME: Can this be a unique result?
-query getMembershipBoughtEventsByMemberId($memberId: ID!) {
-  membershipBoughtEvents(where: { newMemberId_eq: $memberId }) {
+query getMembershipBoughtEventsByEventIds($eventIds: [ID!]) {
+  membershipBoughtEvents(where: { id_in: $eventIds }) {
     ...MembershipBoughtEventFields
   }
 }
 
 fragment MemberProfileUpdatedEventFields on MemberProfileUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   member {
     id
   }
@@ -41,16 +44,18 @@ fragment MemberProfileUpdatedEventFields on MemberProfileUpdatedEvent {
 }
 
 query getMemberProfileUpdatedEventsByMemberId($memberId: ID!) {
-  memberProfileUpdatedEvents(where: { memberId_eq: $memberId }) {
+  memberProfileUpdatedEvents(where: { member: { id_eq: $memberId } }) {
     ...MemberProfileUpdatedEventFields
   }
 }
 
 fragment MemberAccountsUpdatedEventFields on MemberAccountsUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   member {
     id
   }
@@ -59,16 +64,18 @@ fragment MemberAccountsUpdatedEventFields on MemberAccountsUpdatedEvent {
 }
 
 query getMemberAccountsUpdatedEventsByMemberId($memberId: ID!) {
-  memberAccountsUpdatedEvents(where: { memberId_eq: $memberId }) {
+  memberAccountsUpdatedEvents(where: { member: { id_eq: $memberId } }) {
     ...MemberAccountsUpdatedEventFields
   }
 }
 
 fragment MemberInvitedEventFields on MemberInvitedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   invitingMember {
     id
   }
@@ -83,17 +90,19 @@ fragment MemberInvitedEventFields on MemberInvitedEvent {
   }
 }
 
-query getMemberInvitedEventsByNewMemberId($newMemberId: ID!) {
-  memberInvitedEvents(where: { newMemberId_eq: $newMemberId }) {
+query getMemberInvitedEventsByEventIds($eventIds: [ID!]) {
+  memberInvitedEvents(where: { id_in: $eventIds }) {
     ...MemberInvitedEventFields
   }
 }
 
 fragment InvitesTransferredEventFields on InvitesTransferredEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   sourceMember {
     id
   }
@@ -104,16 +113,18 @@ fragment InvitesTransferredEventFields on InvitesTransferredEvent {
 }
 
 query getInvitesTransferredEventsBySourceMemberId($sourceMemberId: ID!) {
-  invitesTransferredEvents(where: { sourceMemberId_eq: $sourceMemberId }) {
+  invitesTransferredEvents(where: { sourceMember: { id_eq: $sourceMemberId } }) {
     ...InvitesTransferredEventFields
   }
 }
 
 fragment StakingAccountAddedEventFields on StakingAccountAddedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   member {
     id
   }
@@ -121,16 +132,18 @@ fragment StakingAccountAddedEventFields on StakingAccountAddedEvent {
 }
 
 query getStakingAccountAddedEventsByMemberId($memberId: ID!) {
-  stakingAccountAddedEvents(where: { memberId_eq: $memberId }) {
+  stakingAccountAddedEvents(where: { member: { id_eq: $memberId } }) {
     ...StakingAccountAddedEventFields
   }
 }
 
 fragment StakingAccountConfirmedEventFields on StakingAccountConfirmedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   member {
     id
   }
@@ -138,16 +151,18 @@ fragment StakingAccountConfirmedEventFields on StakingAccountConfirmedEvent {
 }
 
 query getStakingAccountConfirmedEventsByMemberId($memberId: ID!) {
-  stakingAccountConfirmedEvents(where: { memberId_eq: $memberId }) {
+  stakingAccountConfirmedEvents(where: { member: { id_eq: $memberId } }) {
     ...StakingAccountConfirmedEventFields
   }
 }
 
 fragment StakingAccountRemovedEventFields on StakingAccountRemovedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   member {
     id
   }
@@ -155,63 +170,71 @@ fragment StakingAccountRemovedEventFields on StakingAccountRemovedEvent {
 }
 
 query getStakingAccountRemovedEventsByMemberId($memberId: ID!) {
-  stakingAccountRemovedEvents(where: { memberId_eq: $memberId }) {
+  stakingAccountRemovedEvents(where: { member: { id_eq: $memberId } }) {
     ...StakingAccountRemovedEventFields
   }
 }
 
 fragment ReferralCutUpdatedEventFields on ReferralCutUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   newValue
 }
 
 query getReferralCutUpdatedEventsByEventId($eventId: ID!) {
-  referralCutUpdatedEvents(where: { eventId_eq: $eventId }) {
+  referralCutUpdatedEvents(where: { id_eq: $eventId }) {
     ...ReferralCutUpdatedEventFields
   }
 }
 
 fragment MembershipPriceUpdatedEventFields on MembershipPriceUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   newPrice
 }
 
 query getMembershipPriceUpdatedEventsByEventId($eventId: ID!) {
-  membershipPriceUpdatedEvents(where: { eventId_eq: $eventId }) {
+  membershipPriceUpdatedEvents(where: { id_eq: $eventId }) {
     ...MembershipPriceUpdatedEventFields
   }
 }
 
 fragment InitialInvitationBalanceUpdatedEventFields on InitialInvitationBalanceUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   newInitialBalance
 }
 
 query getInitialInvitationBalanceUpdatedEventsByEventId($eventId: ID!) {
-  initialInvitationBalanceUpdatedEvents(where: { eventId_eq: $eventId }) {
+  initialInvitationBalanceUpdatedEvents(where: { id_eq: $eventId }) {
     ...InitialInvitationBalanceUpdatedEventFields
   }
 }
 
 fragment InitialInvitationCountUpdatedEventFields on InitialInvitationCountUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   newInitialInvitationCount
 }
 
 query getInitialInvitationCountUpdatedEventsByEventId($eventId: ID!) {
-  initialInvitationCountUpdatedEvents(where: { eventId_eq: $eventId }) {
+  initialInvitationCountUpdatedEvents(where: { id_eq: $eventId }) {
     ...InitialInvitationCountUpdatedEventFields
   }
 }

+ 37 - 30
tests/integration-tests/src/graphql/queries/workingGroups.graphql

@@ -4,16 +4,24 @@ fragment ApplicationBasicFields on WorkingGroupApplication {
   status {
     __typename
     ... on ApplicationStatusCancelled {
-      openingCancelledEventId
+      openingCanceledEvent {
+        id
+      }
     }
     ... on ApplicationStatusWithdrawn {
-      applicationWithdrawnEventId
+      applicationWithdrawnEvent {
+        id
+      }
     }
     ... on ApplicationStatusAccepted {
-      openingFilledEventId
+      openingFilledEvent {
+        id
+      }
     }
     ... on ApplicationStatusRejected {
-      openingFilledEventId
+      openingFilledEvent {
+        id
+      }
     }
   }
 }
@@ -21,10 +29,14 @@ fragment ApplicationBasicFields on WorkingGroupApplication {
 fragment OpeningStatusFields on WorkingGroupOpeningStatus {
   __typename
   ... on OpeningStatusFilled {
-    openingFilledEventId
+    openingFilledEvent {
+      id
+    }
   }
   ... on OpeningStatusCancelled {
-    openingCancelledEventId
+    openingCanceledEvent {
+      id
+    }
   }
 }
 
@@ -60,11 +72,17 @@ fragment WorkerFields on Worker {
   status {
     __typename
     ... on WorkerStatusLeft {
-      workerStartedLeavingEventId
-      workerExitedEventId
+      workerStartedLeavingEvent {
+        id
+      }
+      workerExitedEvent {
+        id
+      }
     }
     ... on WorkerStatusTerminated {
-      terminatedWorkerEventId
+      terminatedWorkerEvent {
+        id
+      }
     }
   }
   isLead
@@ -75,10 +93,9 @@ fragment WorkerFields on Worker {
   slashes {
     id
   }
-  hiredAtBlock {
-    ...BlockFields
+  entry {
+    id
   }
-  hiredAtTime
   application {
     ...ApplicationBasicFields
   }
@@ -93,13 +110,8 @@ fragment WorkingGroupMetadataFields on WorkingGroupMetadata {
   statusMessage
   about
   description
-  setAtBlock {
-    ...BlockFields
-  }
   setInEvent {
-    event {
-      ...EventFields
-    }
+    id
   }
 }
 
@@ -122,10 +134,9 @@ fragment OpeningFields on WorkingGroupOpening {
   stakeAmount
   unstakingPeriod
   rewardPerBlock
-  createdAtBlock {
-    ...BlockFields
+  createdInEvent {
+    id
   }
-  createdAt
 }
 
 query getOpeningById($openingId: ID!) {
@@ -142,10 +153,9 @@ query getOpeningsByIds($openingIds: [ID!]) {
 
 fragment ApplicationFields on WorkingGroupApplication {
   ...ApplicationBasicFields
-  createdAtBlock {
-    ...BlockFields
+  createdInEvent {
+    id
   }
-  createdAt
   opening {
     id
     runtimeId
@@ -207,9 +217,6 @@ fragment UpcomingOpeningFields on UpcomingWorkingGroupOpening {
   expectedStart
   stakeAmount
   rewardPerBlock
-  createdAtBlock {
-    ...BlockFields
-  }
   createdInEvent {
     id
   }
@@ -223,19 +230,19 @@ query getUpcomingOpeningById($id: ID!) {
 }
 
 query getUpcomingOpeningsByCreatedInEventIds($createdInEventIds: [ID!]) {
-  upcomingWorkingGroupOpenings(where: { createdInEventId_in: $createdInEventIds }) {
+  upcomingWorkingGroupOpenings(where: { createdInEvent: { id_in: $createdInEventIds } }) {
     ...UpcomingOpeningFields
   }
 }
 
 query getWorkingGroupMetadataSnapshotsByTimeAsc($groupId: ID!) {
-  workingGroupMetadata(where: { groupId_eq: $groupId }, orderBy: createdAt_ASC) {
+  workingGroupMetadata(where: { group: { id_eq: $groupId } }, orderBy: createdAt_ASC) {
     ...WorkingGroupMetadataFields
   }
 }
 
 query getWorkersByRuntimeIds($workerIds: [Int!], $groupId: ID!) {
-  workers(where: { runtimeId_in: $workerIds, groupId_eq: $groupId }) {
+  workers(where: { runtimeId_in: $workerIds, group: { id_eq: $groupId } }) {
     ...WorkerFields
   }
 }

+ 117 - 77
tests/integration-tests/src/graphql/queries/workingGroupsEvents.graphql

@@ -1,8 +1,10 @@
 fragment AppliedOnOpeningEventFields on AppliedOnOpeningEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -17,16 +19,18 @@ fragment AppliedOnOpeningEventFields on AppliedOnOpeningEvent {
 }
 
 query getAppliedOnOpeningEventsByEventIds($eventIds: [ID!]) {
-  appliedOnOpeningEvents(where: { eventId_in: $eventIds }) {
+  appliedOnOpeningEvents(where: { id_in: $eventIds }) {
     ...AppliedOnOpeningEventFields
   }
 }
 
 fragment OpeningAddedEventFields on OpeningAddedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -37,16 +41,18 @@ fragment OpeningAddedEventFields on OpeningAddedEvent {
 }
 
 query getOpeningAddedEventsByEventIds($eventIds: [ID!]) {
-  openingAddedEvents(where: { eventId_in: $eventIds }) {
+  openingAddedEvents(where: { id_in: $eventIds }) {
     ...OpeningAddedEventFields
   }
 }
 
 fragment LeaderSetEventFields on LeaderSetEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -57,16 +63,18 @@ fragment LeaderSetEventFields on LeaderSetEvent {
 }
 
 query getLeaderSetEventsByEventIds($eventIds: [ID!]) {
-  leaderSetEvents(where: { eventId_in: $eventIds }) {
+  leaderSetEvents(where: { id_in: $eventIds }) {
     ...LeaderSetEventFields
   }
 }
 
 fragment OpeningFilledEventFields on OpeningFilledEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -80,16 +88,18 @@ fragment OpeningFilledEventFields on OpeningFilledEvent {
 }
 
 query getOpeningFilledEventsByEventIds($eventIds: [ID!]) {
-  openingFilledEvents(where: { eventId_in: $eventIds }) {
+  openingFilledEvents(where: { id_in: $eventIds }) {
     ...OpeningFilledEventFields
   }
 }
 
 fragment ApplicationWithdrawnEventFields on ApplicationWithdrawnEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -100,16 +110,18 @@ fragment ApplicationWithdrawnEventFields on ApplicationWithdrawnEvent {
 }
 
 query getApplicationWithdrawnEventsByEventIds($eventIds: [ID!]) {
-  applicationWithdrawnEvents(where: { eventId_in: $eventIds }) {
+  applicationWithdrawnEvents(where: { id_in: $eventIds }) {
     ...ApplicationWithdrawnEventFields
   }
 }
 
 fragment OpeningCanceledEventFields on OpeningCanceledEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -120,16 +132,18 @@ fragment OpeningCanceledEventFields on OpeningCanceledEvent {
 }
 
 query getOpeningCancelledEventsByEventIds($eventIds: [ID!]) {
-  openingCanceledEvents(where: { eventId_in: $eventIds }) {
+  openingCanceledEvents(where: { id_in: $eventIds }) {
     ...OpeningCanceledEventFields
   }
 }
 
 fragment StatusTextChangedEventFields on StatusTextChangedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -143,7 +157,9 @@ fragment StatusTextChangedEventFields on StatusTextChangedEvent {
       upcomingOpeningId
     }
     ... on WorkingGroupMetadataSet {
-      metadataId
+      metadata {
+        id
+      }
     }
     ... on InvalidActionMetadata {
       reason
@@ -152,16 +168,18 @@ fragment StatusTextChangedEventFields on StatusTextChangedEvent {
 }
 
 query getStatusTextChangedEventsByEventIds($eventIds: [ID!]) {
-  statusTextChangedEvents(where: { eventId_in: $eventIds }) {
+  statusTextChangedEvents(where: { id_in: $eventIds }) {
     ...StatusTextChangedEventFields
   }
 }
 
 fragment WorkerRoleAccountUpdatedEventFields on WorkerRoleAccountUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -173,16 +191,18 @@ fragment WorkerRoleAccountUpdatedEventFields on WorkerRoleAccountUpdatedEvent {
 }
 
 query getWorkerRoleAccountUpdatedEventsByEventIds($eventIds: [ID!]) {
-  workerRoleAccountUpdatedEvents(where: { eventId_in: $eventIds }) {
+  workerRoleAccountUpdatedEvents(where: { id_in: $eventIds }) {
     ...WorkerRoleAccountUpdatedEventFields
   }
 }
 
 fragment WorkerRewardAccountUpdatedEventFields on WorkerRewardAccountUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -194,16 +214,18 @@ fragment WorkerRewardAccountUpdatedEventFields on WorkerRewardAccountUpdatedEven
 }
 
 query getWorkerRewardAccountUpdatedEventsByEventIds($eventIds: [ID!]) {
-  workerRewardAccountUpdatedEvents(where: { eventId_in: $eventIds }) {
+  workerRewardAccountUpdatedEvents(where: { id_in: $eventIds }) {
     ...WorkerRewardAccountUpdatedEventFields
   }
 }
 
 fragment StakeIncreasedEventFields on StakeIncreasedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -215,16 +237,18 @@ fragment StakeIncreasedEventFields on StakeIncreasedEvent {
 }
 
 query getStakeIncreasedEventsByEventIds($eventIds: [ID!]) {
-  stakeIncreasedEvents(where: { eventId_in: $eventIds }) {
+  stakeIncreasedEvents(where: { id_in: $eventIds }) {
     ...StakeIncreasedEventFields
   }
 }
 
 fragment WorkerStartedLeavingEventFields on WorkerStartedLeavingEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -236,16 +260,18 @@ fragment WorkerStartedLeavingEventFields on WorkerStartedLeavingEvent {
 }
 
 query getWorkerStartedLeavingEventsByEventIds($eventIds: [ID!]) {
-  workerStartedLeavingEvents(where: { eventId_in: $eventIds }) {
+  workerStartedLeavingEvents(where: { id_in: $eventIds }) {
     ...WorkerStartedLeavingEventFields
   }
 }
 
 fragment WorkerRewardAmountUpdatedEventFields on WorkerRewardAmountUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -257,16 +283,18 @@ fragment WorkerRewardAmountUpdatedEventFields on WorkerRewardAmountUpdatedEvent
 }
 
 query getWorkerRewardAmountUpdatedEventsByEventIds($eventIds: [ID!]) {
-  workerRewardAmountUpdatedEvents(where: { eventId_in: $eventIds }) {
+  workerRewardAmountUpdatedEvents(where: { id_in: $eventIds }) {
     ...WorkerRewardAmountUpdatedEventFields
   }
 }
 
 fragment StakeSlashedEventFields on StakeSlashedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -280,16 +308,18 @@ fragment StakeSlashedEventFields on StakeSlashedEvent {
 }
 
 query getStakeSlashedEventsByEventIds($eventIds: [ID!]) {
-  stakeSlashedEvents(where: { eventId_in: $eventIds }) {
+  stakeSlashedEvents(where: { id_in: $eventIds }) {
     ...StakeSlashedEventFields
   }
 }
 
 fragment StakeDecreasedEventFields on StakeDecreasedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -301,16 +331,18 @@ fragment StakeDecreasedEventFields on StakeDecreasedEvent {
 }
 
 query getStakeDecreasedEventsByEventIds($eventIds: [ID!]) {
-  stakeDecreasedEvents(where: { eventId_in: $eventIds }) {
+  stakeDecreasedEvents(where: { id_in: $eventIds }) {
     ...StakeDecreasedEventFields
   }
 }
 
 fragment TerminatedWorkerEventFields on TerminatedWorkerEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -323,16 +355,18 @@ fragment TerminatedWorkerEventFields on TerminatedWorkerEvent {
 }
 
 query getTerminatedWorkerEventsByEventIds($eventIds: [ID!]) {
-  terminatedWorkerEvents(where: { eventId_in: $eventIds }) {
+  terminatedWorkerEvents(where: { id_in: $eventIds }) {
     ...TerminatedWorkerEventFields
   }
 }
 
 fragment TerminatedLeaderEventFields on TerminatedLeaderEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -345,16 +379,18 @@ fragment TerminatedLeaderEventFields on TerminatedLeaderEvent {
 }
 
 query getTerminatedLeaderEventsByEventIds($eventIds: [ID!]) {
-  terminatedLeaderEvents(where: { eventId_in: $eventIds }) {
+  terminatedLeaderEvents(where: { id_in: $eventIds }) {
     ...TerminatedLeaderEventFields
   }
 }
 
 fragment LeaderUnsetEventFields on LeaderUnsetEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -365,16 +401,18 @@ fragment LeaderUnsetEventFields on LeaderUnsetEvent {
 }
 
 query getLeaderUnsetEventsByEventIds($eventIds: [ID!]) {
-  leaderUnsetEvents(where: { eventId_in: $eventIds }) {
+  leaderUnsetEvents(where: { id_in: $eventIds }) {
     ...LeaderUnsetEventFields
   }
 }
 
 fragment BudgetSetEventFields on BudgetSetEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -382,16 +420,18 @@ fragment BudgetSetEventFields on BudgetSetEvent {
 }
 
 query getBudgetSetEventsByEventIds($eventIds: [ID!]) {
-  budgetSetEvents(where: { eventId_in: $eventIds }) {
+  budgetSetEvents(where: { id_in: $eventIds }) {
     ...BudgetSetEventFields
   }
 }
 
 fragment BudgetSpendingEventFields on BudgetSpendingEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -401,7 +441,7 @@ fragment BudgetSpendingEventFields on BudgetSpendingEvent {
 }
 
 query getBudgetSpendingEventsByEventIds($eventIds: [ID!]) {
-  budgetSpendingEvents(where: { eventId_in: $eventIds }) {
+  budgetSpendingEvents(where: { id_in: $eventIds }) {
     ...BudgetSpendingEventFields
   }
 }

+ 5 - 2
tests/integration-tests/src/types.ts

@@ -2,10 +2,13 @@ import { MemberId, PostId, ThreadId } from '@joystream/types/common'
 import { ApplicationId, OpeningId, WorkerId, ApplyOnOpeningParameters } from '@joystream/types/working-group'
 import { Event } from '@polkadot/types/interfaces/system'
 import { BTreeMap } from '@polkadot/types'
-import { EventFieldsFragment } from './graphql/generated/queries'
 import { CategoryId } from '@joystream/types/forum'
+import { MembershipBoughtEvent } from './graphql/generated/schema'
 
-export type AnyQueryNodeEvent = { event: EventFieldsFragment }
+export type AnyQueryNodeEvent = Pick<
+  MembershipBoughtEvent,
+  'createdAt' | 'updatedAt' | 'id' | 'inBlock' | 'inExtrinsic' | 'indexInBlock' | 'network'
+>
 export interface EventDetails {
   event: Event
   blockNumber: number

+ 86 - 39
yarn.lock

@@ -1564,19 +1564,26 @@
     ajv "^6.12.0"
     ajv-keywords "^3.4.1"
 
-"@dzlzv/hydra-common@2.1.0-beta.8", "@dzlzv/hydra-common@^2.1.0-beta.8":
-  version "2.1.0-beta.8"
-  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-common/-/hydra-common-2.1.0-beta.8.tgz#bc57132e603adb4ee6fb03583a6c203b2fa1f088"
-  integrity sha512-N2elG6zySMINO0cTOPqGEDIuGi0tEg4KBde4p2YBnYczxSO1FMaFYeBojp7OfMdkUlEx57vW23xHLIwLcg3y8Q==
+"@dzlzv/hydra-common@3.0.0-beta.6":
+  version "3.0.0-beta.6"
+  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-common/-/hydra-common-3.0.0-beta.6.tgz#7d6e3cb13a1a6487faa4a5975b77003c27c7e8ca"
+  integrity sha512-VFtp9JEJ4PEheACHo2AMLcFW0sudFlo9DWZ3ZPLKFm880QWqxvORLCpog5HoNMyK2BqucC8FDDkcpFo16ueMAA==
   dependencies:
     bn.js "^5.1.3"
 
-"@dzlzv/hydra-db-utils@2.1.0-beta.8", "@dzlzv/hydra-db-utils@^2.1.0-beta.8":
-  version "2.1.0-beta.8"
-  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-db-utils/-/hydra-db-utils-2.1.0-beta.8.tgz#093767d799b8979dcf77d3395835c369ffe82572"
-  integrity sha512-fNMpOZFNgkV4BCJzc4DNsWTH6qShpAPqryL8aIOeFqcnPngwLwZNfpZWbheLsnCNLIl9dvUMRVJPw+OUZVcazw==
+"@dzlzv/hydra-common@^3.0.0-beta.6", "@dzlzv/hydra-common@^3.0.0-hydra-v3.0":
+  version "3.0.0-hydra-v3.0"
+  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-common/-/hydra-common-3.0.0-hydra-v3.0.tgz#e7ca2a578e8a607317600945cdd7ea4eed2d0dae"
+  integrity sha512-WLEQ22U+j/3RmmZFKz4/CbJ3tgbGlNqfMTh67fJhx/UAuXKQx6YukLvfFIjd1onDDqgAXbf8c5+i0damjrkO3w==
   dependencies:
-    "@dzlzv/hydra-common" "^2.1.0-beta.8"
+    bn.js "^5.1.3"
+
+"@dzlzv/hydra-db-utils@3.0.0-beta.6":
+  version "3.0.0-beta.6"
+  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-db-utils/-/hydra-db-utils-3.0.0-beta.6.tgz#b221a24bef89a2493e42ef520fe1abbdb8d83298"
+  integrity sha512-zxH9LialjFu4mxH+0EJhHPRSewy2tbaxqr992w2gJ2hULp2kJAGRLY1kpHFG/EEE1QWvCTmcJnFw9LyC61Q8Wg==
+  dependencies:
+    "@dzlzv/hydra-common" "^3.0.0-beta.6"
     "@types/ioredis" "^4.17.4"
     bn.js "^5.1.3"
     ioredis "^4.17.3"
@@ -1584,17 +1591,30 @@
     shortid "^2.2.16"
     typeorm "^0.2.25"
 
-"@dzlzv/hydra-processor@2.1.0-beta.8":
-  version "2.1.0-beta.8"
-  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-processor/-/hydra-processor-2.1.0-beta.8.tgz#33f042b6892c30e4d69ca63a4a3703811b25d79e"
-  integrity sha512-OkRSaTKaeKUCWHbXmvonurzKeMfInNDXtEI8U3KL1iOvvoNNebpIOZkmR9+xmxgDmtFNShNoL53zLMvPy4sI0g==
+"@dzlzv/hydra-db-utils@^3.0.0-beta.6":
+  version "3.0.0-hydra-v3.0"
+  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-db-utils/-/hydra-db-utils-3.0.0-hydra-v3.0.tgz#c61ff2b6cd8f2229d2377c5c0a09770faead8d14"
+  integrity sha512-qryrvseTrxFeJnJwXqCnKhcM7HmwqIXWdkN0kPK8+HLDg5kFXL88a3mxgyC1XL56SWQKXuCbdj3MTeJeglj4Fw==
   dependencies:
-    "@dzlzv/hydra-common" "^2.1.0-beta.8"
-    "@dzlzv/hydra-db-utils" "^2.1.0-beta.8"
+    "@dzlzv/hydra-common" "^3.0.0-hydra-v3.0"
+    "@types/ioredis" "^4.17.4"
+    bn.js "^5.1.3"
+    ioredis "^4.17.3"
+    lodash "^4.17.20"
+    shortid "^2.2.16"
+    typeorm "^0.2.25"
+
+"@dzlzv/hydra-processor@3.0.0-beta.6":
+  version "3.0.0-beta.6"
+  resolved "https://registry.yarnpkg.com/@dzlzv/hydra-processor/-/hydra-processor-3.0.0-beta.6.tgz#2a79ef2df8288216886881ec3b0adba6f209437e"
+  integrity sha512-J4Vj11jpIC443ffV95xjwiqJIKllA5X0q3q47cvmf38pRZ8BZx5UhHHykxzZpR4MqjrxAze5c/QZTaoWGptNcg==
+  dependencies:
+    "@dzlzv/hydra-common" "^3.0.0-beta.6"
+    "@dzlzv/hydra-db-utils" "^3.0.0-beta.6"
     "@oclif/command" "^1.8.0"
     "@oclif/config" "^1"
     "@oclif/errors" "^1.3.3"
-    bn.js "^5.1.3"
+    bn.js "^5.2.0"
     chalk "^4.1.0"
     delay "^5.0.0"
     dotenv "^8.2.0"
@@ -1602,9 +1622,13 @@
     express "^4.17.1"
     graphql "^15.4.0"
     graphql-request "^3.3.0"
-    p-wait-for "^3.2.0"
+    p-immediate "^3.2.0"
+    p-throttle "~4.1.1"
+    p-wait-for "~3.2.0"
+    p-whilst "~2.1.0"
     prom-client "^12.0.0"
     semver "^7.3.4"
+    shortid "^2.2.16"
     typedi "^0.8.0"
     yaml "^1.10.0"
     yaml-validator "^3.0.0"
@@ -4830,9 +4854,9 @@
     "@types/babel__traverse" "*"
 
 "@types/babel__core@^7.1.0":
-  version "7.1.13"
-  resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.13.tgz#bc6eea53975fdf163aff66c086522c6f293ae4cf"
-  integrity sha512-CC6amBNND16pTk4K3ZqKIaba6VGKAQs3gMjEY17FVd56oI/ZWt9OhS6riYiWv9s8ENbYUi7p8lgqb0QHQvUKQQ==
+  version "7.1.14"
+  resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402"
+  integrity sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==
   dependencies:
     "@babel/parser" "^7.1.0"
     "@babel/types" "^7.0.0"
@@ -4863,9 +4887,9 @@
     "@babel/types" "^7.3.0"
 
 "@types/bluebird@^3.5.20":
-  version "3.5.33"
-  resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.33.tgz#d79c020f283bd50bd76101d7d300313c107325fc"
-  integrity sha512-ndEo1xvnYeHxm7I/5sF6tBvnsA4Tdi3zj1keRKRs12SP+2ye2A27NDJ1B6PqkfMbGAcT+mqQVqbZRIrhfOp5PQ==
+  version "3.5.34"
+  resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.34.tgz#0e9f1f4f5dfab98a421fb973b5f5690d22411893"
+  integrity sha512-QMc57Pf067Rr78l6f4FftvuIXPYxu0VYFRKrZk1Clv+LWy7gN2fTBiAiv68askFHEHZcTLPFd01kNlpKOiSPgQ==
 
 "@types/bn.js@^4.11.5", "@types/bn.js@^4.11.6":
   version "4.11.6"
@@ -7536,17 +7560,17 @@ autoprefixer@^9.5.1, autoprefixer@^9.7.2, autoprefixer@^9.8.6:
     postcss-value-parser "^4.1.0"
 
 aws-credstash@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/aws-credstash/-/aws-credstash-3.0.0.tgz#377de983c149a8a5471e1ff23c4550d35514b726"
-  integrity sha512-SBrCROAOBKQvxD2i/hh7WefhKscgW8W7jLXTYC9s0q1S2cX/1ugxYnlkZkBrXltIPRPBrAd6pcKjHsrPo5gV7Q==
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/aws-credstash/-/aws-credstash-3.0.1.tgz#1d287047b68b069dc34514012564605c848e0d94"
+  integrity sha512-gSl/SO9dmgzUP/YfCMmMH3ap6ytL1TKOZmmlmU5Ulxco9MLoW+WJQgsWR8qOQFDoi6o7pnqlRVuxpAo9yxTSew==
   dependencies:
     aes-js "^3.1.2"
-    debug "^4.1.1"
+    debug "^4.3.1"
 
 aws-sdk@^2.567.0:
-  version "2.866.0"
-  resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.866.0.tgz#8150fb2e0cfecd281968edee7cad84598d8d7a09"
-  integrity sha512-6Z581Ek2Yfm78NpeEFMNuSoyiYG7tipEaqfWNFR1AGyYheZwql4ajhzzlpWn91LBpdm7qcFldSNY9U0tKpKWNw==
+  version "2.906.0"
+  resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.906.0.tgz#c85ebb6257865b97d6a88c6d89aeb9b6075744df"
+  integrity sha512-u/kmVILew/9HFpHwVrc3VMK24m+XrazXEooMxkzbWXEBvtVm1xTYv8xPmdgiYvogWIkWTkeIF9ME4LBeHenYkw==
   dependencies:
     buffer "4.9.2"
     events "1.1.1"
@@ -8223,7 +8247,7 @@ bluebird@^3.1.1, bluebird@^3.3.5, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.
   resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
   integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
 
-bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.8, bn.js@^4.4.0, bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.1.3:
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.8, bn.js@^4.4.0, bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.1.3, bn.js@^5.2.0:
   version "5.1.3"
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b"
   integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==
@@ -10797,7 +10821,7 @@ debounce@^1.2.0:
   resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
   integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
 
-debug@*, debug@4, debug@4.3.1, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.2.1, debug@^4.3.0:
+debug@*, debug@4, debug@4.3.1, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.2.1, debug@^4.3.0, debug@^4.3.1:
   version "4.3.1"
   resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
   integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
@@ -16258,13 +16282,20 @@ is-color-stop@^1.0.0:
     rgb-regex "^1.0.1"
     rgba-regex "^1.0.0"
 
-is-core-module@^2.1.0, is-core-module@^2.2.0:
+is-core-module@^2.1.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a"
   integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==
   dependencies:
     has "^1.0.3"
 
+is-core-module@^2.2.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1"
+  integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==
+  dependencies:
+    has "^1.0.3"
+
 is-data-descriptor@^0.1.4:
   version "0.1.4"
   resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
@@ -21520,6 +21551,11 @@ p-finally@^2.0.0:
   resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561"
   integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==
 
+p-immediate@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/p-immediate/-/p-immediate-3.2.0.tgz#0cc2d006046a5d07f4e6d710ba589f475bc00f34"
+  integrity sha512-XMP80yYZPigpDbhOwICi1Vk2Tf4e42xQ6NIRpKnumZowvJh4ZgFOQuqUB0+hWY5PD9USrKY9rXOdSawnzr99+g==
+
 p-is-promise@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
@@ -21624,6 +21660,11 @@ p-retry@^3.0.1:
   dependencies:
     retry "^0.12.0"
 
+p-throttle@~4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/p-throttle/-/p-throttle-4.1.1.tgz#80b1fbd358af40a8bfa1667f9dc8b72b714ad692"
+  integrity sha512-TuU8Ato+pRTPJoDzYD4s7ocJYcNSEZRvlxoq3hcPI2kZDZ49IQ1Wkj7/gDJc3X7XiEAAvRGtDzdXJI0tC3IL1g==
+
 p-timeout@^3.0.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
@@ -21641,7 +21682,7 @@ p-try@^2.0.0:
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
   integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
 
-p-wait-for@^3.2.0:
+p-wait-for@~3.2.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/p-wait-for/-/p-wait-for-3.2.0.tgz#640429bcabf3b0dd9f492c31539c5718cb6a3f1f"
   integrity sha512-wpgERjNkLrBiFmkMEjuZJEWKKDrNfHCKA1OhyN1wg1FrLkULbviEy6py1AyJUgZ72YWFbZ38FIpnqvVqAlDUwA==
@@ -21655,6 +21696,11 @@ p-waterfall@^1.0.0:
   dependencies:
     p-reduce "^1.0.0"
 
+p-whilst@~2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/p-whilst/-/p-whilst-2.1.0.tgz#d8f3aa3a68f5595ab8b40a62cc3d49d8f9cf082c"
+  integrity sha512-uzp1HPgqzokEmZN+VpfQ9PO4YY5xm+jpLJeL9FN1NPU4d4IZh8eEV+mtQXd+/22R1P7C5j19b7Y//oUc7k0+RQ==
+
 package-hash@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-3.0.0.tgz#50183f2d36c9e3e528ea0a8605dff57ce976f88e"
@@ -22101,7 +22147,7 @@ pg-types@^2.1.0:
     postgres-date "~1.0.4"
     postgres-interval "^1.1.0"
 
-pg@^6.1.0, pg@^7.12.1, pg@^8.4.0:
+pg@8.0.3, pg@^6.1.0, pg@^8.3.2, pg@^8.4.0:
   version "8.6.0"
   resolved "https://registry.yarnpkg.com/pg/-/pg-8.6.0.tgz#e222296b0b079b280cce106ea991703335487db2"
   integrity sha512-qNS9u61lqljTDFvmk/N66EeGq3n6Ujzj0FFyNMGQr6XuEv4tgNTXvJQTfJdcvGit5p5/DWPu+wj920hAJFI+QQ==
@@ -28596,9 +28642,9 @@ warning@^4.0.2, warning@^4.0.3:
   dependencies:
     loose-envify "^1.0.0"
 
-"warthog@https://github.com/metmirr/warthog/releases/download/v2.23.0/warthog-v2.23.0.tgz":
-  version "2.23.0"
-  resolved "https://github.com/metmirr/warthog/releases/download/v2.23.0/warthog-v2.23.0.tgz#4582fc35554580e0af0f43a9b3725aad2eb808c6"
+"warthog@https://github.com/metmirr/warthog/releases/download/v2.30.0/warthog-v2.30.0.tgz":
+  version "2.30.0"
+  resolved "https://github.com/metmirr/warthog/releases/download/v2.30.0/warthog-v2.30.0.tgz#24a0b975f2ad5cba17a934752ac07052e856b49c"
   dependencies:
     "@types/app-root-path" "^1.2.4"
     "@types/bn.js" "^4.11.6"
@@ -28626,6 +28672,7 @@ warning@^4.0.2, warning@^4.0.3:
     apollo-server "^2.9.9"
     apollo-server-express "^2.9.9"
     app-root-path "^3.0.0"
+    bn.js "^5.2.0"
     caller "^1.0.1"
     class-transformer "^0.2.3"
     class-validator "^0.11.0"
@@ -28648,7 +28695,7 @@ warning@^4.0.2, warning@^4.0.3:
     mkdirp "^0.5.1"
     node-emoji "^1.10.0"
     open "^7.0.0"
-    pg "^7.12.1"
+    pg "8.0.3"
     pgtools "^0.3.0"
     prettier "^1.19.1"
     reflect-metadata "^0.1.13"