Browse Source

Event schema flattening and related adjustments

Leszek Wiesner 3 years ago
parent
commit
d208676917
50 changed files with 1792 additions and 1451 deletions
  1. 11 37
      query-node/mappings/common.ts
  2. 6 12
      query-node/mappings/initializeDb.ts
  3. 36 77
      query-node/mappings/membership.ts
  4. 24 84
      query-node/mappings/workingGroups.ts
  5. 7 67
      query-node/schemas/common.graphql
  6. 20 17
      query-node/schemas/membership.graphql
  7. 252 28
      query-node/schemas/membershipEvents.graphql
  8. 5 20
      query-node/schemas/workingGroups.graphql
  9. 396 44
      query-node/schemas/workingGroupsEvents.graphql
  10. 3 5
      tests/integration-tests/src/Fixture.ts
  11. 29 16
      tests/integration-tests/src/QueryNodeApi.ts
  12. 4 7
      tests/integration-tests/src/fixtures/membership/AddStakingAccountsHappyCaseFixture.ts
  13. 0 24
      tests/integration-tests/src/fixtures/membership/BaseMembershipFixture.ts
  14. 66 91
      tests/integration-tests/src/fixtures/membership/BuyMembershipHappyCaseFixture.ts
  15. 6 6
      tests/integration-tests/src/fixtures/membership/BuyMembershipWithInsufficienFundsFixture.ts
  16. 75 76
      tests/integration-tests/src/fixtures/membership/InviteMembersHappyCaseFixture.ts
  17. 3 5
      tests/integration-tests/src/fixtures/membership/RemoveStakingAccountsHappyCaseFixture.ts
  18. 5 5
      tests/integration-tests/src/fixtures/membership/SudoUpdateMembershipSystem.ts
  19. 3 10
      tests/integration-tests/src/fixtures/membership/TransferInvitesHappyCaseFixture.ts
  20. 3 5
      tests/integration-tests/src/fixtures/membership/UpdateAccountsHappyCaseFixture.ts
  21. 3 5
      tests/integration-tests/src/fixtures/membership/UpdateProfileHappyCaseFixture.ts
  22. 0 1
      tests/integration-tests/src/fixtures/membership/index.ts
  23. 19 0
      tests/integration-tests/src/fixtures/membership/utils.ts
  24. 8 6
      tests/integration-tests/src/fixtures/workingGroups/ApplyOnOpeningsHappyCaseFixture.ts
  25. 0 2
      tests/integration-tests/src/fixtures/workingGroups/CancelOpeningsFixture.ts
  26. 9 6
      tests/integration-tests/src/fixtures/workingGroups/CreateOpeningsFixture.ts
  27. 0 3
      tests/integration-tests/src/fixtures/workingGroups/CreateUpcomingOpeningsFixture.ts
  28. 0 2
      tests/integration-tests/src/fixtures/workingGroups/DecreaseWorkerStakesFixture.ts
  29. 7 10
      tests/integration-tests/src/fixtures/workingGroups/FillOpeningsFixture.ts
  30. 0 2
      tests/integration-tests/src/fixtures/workingGroups/IncreaseWorkerStakesFixture.ts
  31. 0 2
      tests/integration-tests/src/fixtures/workingGroups/LeaveRoleFixture.ts
  32. 0 2
      tests/integration-tests/src/fixtures/workingGroups/RemoveUpcomingOpeningsFixture.ts
  33. 0 2
      tests/integration-tests/src/fixtures/workingGroups/SetBudgetFixture.ts
  34. 0 2
      tests/integration-tests/src/fixtures/workingGroups/SlashWorkerStakesFixture.ts
  35. 0 2
      tests/integration-tests/src/fixtures/workingGroups/SpendBudgetFixture.ts
  36. 3 6
      tests/integration-tests/src/fixtures/workingGroups/TerminateWorkersFixture.ts
  37. 1 5
      tests/integration-tests/src/fixtures/workingGroups/UpdateGroupStatusFixture.ts
  38. 0 2
      tests/integration-tests/src/fixtures/workingGroups/UpdateWorkerRewardAccountsFixture.ts
  39. 0 2
      tests/integration-tests/src/fixtures/workingGroups/UpdateWorkerRewardAmountsFixture.ts
  40. 0 2
      tests/integration-tests/src/fixtures/workingGroups/UpdateWorkerRoleAccountsFixture.ts
  41. 0 2
      tests/integration-tests/src/fixtures/workingGroups/WithdrawApplicationsFixture.ts
  42. 1 1
      tests/integration-tests/src/flows/membership/creatingMemberships.ts
  43. 279 170
      tests/integration-tests/src/graphql/generated/queries.ts
  44. 292 412
      tests/integration-tests/src/graphql/generated/schema.ts
  45. 0 15
      tests/integration-tests/src/graphql/queries/common.graphql
  46. 22 10
      tests/integration-tests/src/graphql/queries/membership.graphql
  47. 68 45
      tests/integration-tests/src/graphql/queries/membershipEvents.graphql
  48. 7 18
      tests/integration-tests/src/graphql/queries/workingGroups.graphql
  49. 114 76
      tests/integration-tests/src/graphql/queries/workingGroupsEvents.graphql
  50. 5 2
      tests/integration-tests/src/types.ts

+ 11 - 37
query-node/mappings/common.ts

@@ -1,28 +1,22 @@
-import { SubstrateEvent, DatabaseManager } from '@dzlzv/hydra-common'
-import { EventType, Network } from 'query-node/dist/src/modules/enums/enums'
+import { SubstrateEvent } from '@dzlzv/hydra-common'
+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 BN from 'bn.js'
 
 export const CURRENT_NETWORK = Network.OLYMPIA
 
-export async function createEvent(
-  db: DatabaseManager,
-  substrateEvent: SubstrateEvent,
-  type: EventType
-): Promise<Event> {
-  const { blockNumber, indexInBlock, extrinsic } = substrateEvent
-  const event = new Event({
+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: await getOrCreateBlock(db, substrateEvent),
+    inBlock: blockNumber,
+    network: CURRENT_NETWORK,
     inExtrinsic: extrinsic?.hash,
     indexInBlock,
-    type,
-  })
-  await db.save<Event>(event)
-
-  return event
+  }
 }
 
 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: new BN(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)).toString()
 }

+ 6 - 12
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-common'
-import { Block, MembershipSystemSnapshot, WorkingGroup } from 'query-node/dist/model'
-import { CURRENT_NETWORK } from './common'
-import BN from 'bn.js'
+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: [],

+ 36 - 77
query-node/mappings/membership.ts

@@ -3,13 +3,11 @@ eslint-disable @typescript-eslint/naming-convention
 */
 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,
@@ -27,6 +25,8 @@ import {
   InitialInvitationBalanceUpdatedEvent,
   StakingAccountAddedEvent,
   LeaderInvitationQuotaUpdatedEvent,
+  MembershipEntryPaid,
+  MembershipEntryInvited,
 } from 'query-node/dist/model'
 
 async function getMemberById(db: DatabaseManager, id: MemberId): Promise<Membership> {
@@ -40,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,23 +50,22 @@ 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)
-  return latestSnapshot.snapshotBlock.number === event_.blockNumber
+  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)
@@ -91,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),
     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,
@@ -104,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,19 +114,12 @@ async function newMembershipFromParams(
 
 export async function members_MembershipBought(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
   const [memberId, buyMembershipParameters] = new Members.MembershipBoughtEvent(event_).params
-  const eventTime = new Date(event_.blockTimestamp)
-  const member = await newMembershipFromParams(
-    db,
-    event_,
-    memberId,
-    MembershipEntryMethod.PAID,
-    buyMembershipParameters
-  )
+
+  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,
@@ -144,6 +133,10 @@ 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> {
@@ -173,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({
@@ -205,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,
@@ -230,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,
   })
@@ -255,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(),
@@ -269,24 +254,17 @@ export async function members_InvitesTransferred(db: DatabaseManager, event_: Su
 export async function members_MemberInvited(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
   const [memberId, inviteMembershipParameters] = new Members.MemberInvitedEvent(event_).params
   const eventTime = new Date(event_.blockTimestamp)
-  const invitedMember = await newMembershipFromParams(
-    db,
-    event_,
-    memberId,
-    MembershipEntryMethod.INVITED,
-    inviteMembershipParameters
-  )
+  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,
@@ -300,16 +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> {
   const [accountId, memberId] = new Members.StakingAccountAddedEvent(event_).params
-  const eventTime = new Date(event_.blockTimestamp)
 
   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(),
   })
@@ -328,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(),
   })
@@ -352,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(),
   })
@@ -368,16 +342,13 @@ export async function members_InitialInvitationCountUpdated(
 ): Promise<void> {
   const [newDefaultInviteCount] = new Members.InitialInvitationCountUpdatedEvent(event_).params
   const membershipSystemSnapshot = await getOrCreateMembershipSnapshot(db, event_)
-  const eventTime = new Date(event_.blockTimestamp)
 
   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(),
   })
 
@@ -387,16 +358,13 @@ export async function members_InitialInvitationCountUpdated(
 export async function members_MembershipPriceUpdated(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
   const [newMembershipPrice] = new Members.MembershipPriceUpdatedEvent(event_).params
   const membershipSystemSnapshot = await getOrCreateMembershipSnapshot(db, event_)
-  const eventTime = new Date(event_.blockTimestamp)
 
   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,
   })
 
@@ -406,16 +374,13 @@ export async function members_MembershipPriceUpdated(db: DatabaseManager, event_
 export async function members_ReferralCutUpdated(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
   const [newReferralCut] = new Members.ReferralCutUpdatedEvent(event_).params
   const membershipSystemSnapshot = await getOrCreateMembershipSnapshot(db, event_)
-  const eventTime = new Date(event_.blockTimestamp)
 
   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(),
   })
 
@@ -428,16 +393,13 @@ export async function members_InitialInvitationBalanceUpdated(
 ): Promise<void> {
   const [newInvitedInitialBalance] = new Members.InitialInvitationBalanceUpdatedEvent(event_).params
   const membershipSystemSnapshot = await getOrCreateMembershipSnapshot(db, event_)
-  const eventTime = new Date(event_.blockTimestamp)
 
   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,
   })
 
@@ -446,12 +408,9 @@ export async function members_InitialInvitationBalanceUpdated(
 
 export async function members_LeaderInvitationQuotaUpdated(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
   const [newQuota] = new Members.LeaderInvitationQuotaUpdatedEvent(event_).params
-  const eventTime = new Date(event_.blockTimestamp)
 
   const leaderInvitationQuotaUpdatedEvent = new LeaderInvitationQuotaUpdatedEvent({
-    createdAt: eventTime,
-    updatedAt: eventTime,
-    event: await createEvent(db, event_, EventType.LeaderInvitationQuotaUpdated),
+    ...genericEventFields(event_),
     newInvitationQuota: newQuota.toNumber(),
   })
 

+ 24 - 84
query-node/mappings/workingGroups.ts

@@ -15,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,
@@ -26,7 +26,6 @@ import {
   ApplicationFormQuestionType,
   OpeningStatusOpen,
   WorkingGroupOpeningType,
-  EventType,
   WorkingGroupApplication,
   ApplicationFormQuestionAnswer,
   AppliedOnOpeningEvent,
@@ -74,7 +73,6 @@ import {
   Event,
 } from 'query-node/dist/model'
 import { createType } from '@joystream/types'
-import _ from 'lodash'
 
 // Reusable functions
 async function getWorkingGroup(
@@ -254,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)
 
@@ -300,7 +297,6 @@ async function handleSetWorkingGroupMetadataAction(
   const newGroupMetadata = new WorkingGroupMetadata({
     createdAt: eventTime,
     updatedAt: eventTime,
-    setAtBlock: await getOrCreateBlock(db, event_),
     setInEvent: statusChangedEvent,
     group,
     status: setNewOptionalString('status'),
@@ -346,13 +342,10 @@ async function handleTerminatedWorker(db: DatabaseManager, event_: SubstrateEven
   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,
@@ -371,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}`)
@@ -396,7 +388,6 @@ export async function workingGroups_OpeningAdded(db: DatabaseManager, event_: Su
   const opening = new WorkingGroupOpening({
     createdAt: eventTime,
     updatedAt: eventTime,
-    createdAtBlock: await getOrCreateBlock(db, event_),
     id: `${group.name}-${openingRuntimeId.toString()}`,
     runtimeId: openingRuntimeId.toNumber(),
     applications: [],
@@ -413,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,
   })
@@ -446,7 +434,6 @@ export async function workingGroups_AppliedOnOpening(db: DatabaseManager, event_
   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 }),
@@ -462,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,
@@ -476,14 +460,10 @@ export async function workingGroups_AppliedOnOpening(db: DatabaseManager, event_
 }
 
 export async function workingGroups_LeaderSet(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
-  const eventTime = new Date(event_.blockTimestamp)
   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,
   })
 
@@ -505,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,
   })
@@ -546,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),
               application,
               group,
               isLead: opening.type === WorkingGroupOpeningType.LEADER,
@@ -581,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,11 +571,8 @@ export async function workingGroups_OpeningCanceled(db: DatabaseManager, event_:
   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,
   })
@@ -638,11 +610,8 @@ export async function workingGroups_ApplicationWithdrawn(db: DatabaseManager, ev
   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,
   })
@@ -661,17 +630,14 @@ export async function workingGroups_ApplicationWithdrawn(db: DatabaseManager, ev
 export async function workingGroups_StatusTextChanged(db: DatabaseManager, event_: SubstrateEvent): Promise<void> {
   const [, optBytes] = new WorkingGroups.StatusTextChangedEvent(event_).params
   const group = await getWorkingGroup(db, event_)
-  const eventTime = new Date(event_.blockTimestamp)
 
   // 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,
   })
@@ -710,10 +676,8 @@ export async function workingGroups_WorkerRoleAccountUpdated(
   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(),
   })
@@ -736,10 +700,8 @@ export async function workingGroups_WorkerRewardAccountUpdated(
   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(),
   })
@@ -759,10 +721,8 @@ export async function workingGroups_StakeIncreased(db: DatabaseManager, event_:
   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,
   })
@@ -782,10 +742,8 @@ export async function workingGroups_RewardPaid(db: DatabaseManager, event_: Subs
   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(),
@@ -811,10 +769,8 @@ export async function workingGroups_NewMissedRewardLevelReached(
   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)),
   })
@@ -835,10 +791,8 @@ export async function workingGroups_WorkerExited(db: DatabaseManager, event_: Su
   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,
   })
 
@@ -856,10 +810,8 @@ export async function workingGroups_LeaderUnset(db: DatabaseManager, event_: Sub
   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,
   })
 
@@ -888,10 +840,8 @@ export async function workingGroups_WorkerRewardAmountUpdated(
   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)),
   })
@@ -911,10 +861,8 @@ export async function workingGroups_StakeSlashed(db: DatabaseManager, event_: Su
   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,
@@ -936,10 +884,8 @@ export async function workingGroups_StakeDecreased(db: DatabaseManager, event_:
   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,
   })
@@ -959,10 +905,8 @@ export async function workingGroups_WorkerStartedLeaving(db: DatabaseManager, ev
   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,
   })
@@ -983,10 +927,8 @@ export async function workingGroups_BudgetSet(db: DatabaseManager, event_: Subst
   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,
   })
 
@@ -1004,10 +946,8 @@ export async function workingGroups_BudgetSpending(db: DatabaseManager, event_:
   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,

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

@@ -5,80 +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
-}
-
-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: https://github.com/Joystream/hydra/issues/359
-# 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!

+ 5 - 20
query-node/schemas/workingGroups.graphql

@@ -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!
 
@@ -91,9 +85,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!
 
@@ -200,8 +191,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!
@@ -209,10 +200,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!
@@ -293,11 +281,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 {

+ 396 - 44
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!
@@ -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,
@@ -172,6 +166,15 @@ import {
   GetLeaderSetEventsByEventIdsQuery,
   GetLeaderSetEventsByEventIdsQueryVariables,
   GetLeaderSetEventsByEventIds,
+  GetMembershipBoughtEventsByEventIdsQuery,
+  GetMembershipBoughtEventsByEventIdsQueryVariables,
+  GetMembershipBoughtEventsByEventIds,
+  GetMembersByIdsQuery,
+  GetMembersByIdsQueryVariables,
+  GetMembersByIds,
+  GetMemberInvitedEventsByEventIdsQuery,
+  GetMemberInvitedEventsByEventIdsQueryVariables,
+  GetMemberInvitedEventsByEventIds,
 } from './graphql/generated/queries'
 import { Maybe } from './graphql/generated/schema'
 import { OperationDefinitionNode } from 'graphql'
@@ -280,11 +283,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[]> {
@@ -301,11 +313,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)
   }
 }

+ 0 - 2
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,
@@ -64,7 +63,6 @@ export class CancelOpeningsFixture extends BaseWorkingGroupFixture {
   }
 
   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())

+ 7 - 10
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'
@@ -105,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) => {
@@ -122,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())
@@ -148,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())
   }
@@ -204,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())

+ 0 - 2
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]))

+ 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])

+ 3 - 6
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]))
@@ -110,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())
   }
 

+ 1 - 5
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

+ 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())

+ 0 - 2
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)
   }

+ 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')

File diff suppressed because it is too large
+ 279 - 170
tests/integration-tests/src/graphql/generated/queries.ts


File diff suppressed because it is too large
+ 292 - 412
tests/integration-tests/src/graphql/generated/schema.ts


+ 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
   }
 }

+ 68 - 45
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: { newMember: { id_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
   }
@@ -48,9 +51,11 @@ query getMemberProfileUpdatedEventsByMemberId($memberId: ID!) {
 
 fragment MemberAccountsUpdatedEventFields on MemberAccountsUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   member {
     id
   }
@@ -66,9 +71,11 @@ query getMemberAccountsUpdatedEventsByMemberId($memberId: ID!) {
 
 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: { newMember: { id_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
   }
@@ -111,9 +120,11 @@ query getInvitesTransferredEventsBySourceMemberId($sourceMemberId: ID!) {
 
 fragment StakingAccountAddedEventFields on StakingAccountAddedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   member {
     id
   }
@@ -128,9 +139,11 @@ query getStakingAccountAddedEventsByMemberId($memberId: ID!) {
 
 fragment StakingAccountConfirmedEventFields on StakingAccountConfirmedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   member {
     id
   }
@@ -145,9 +158,11 @@ query getStakingAccountConfirmedEventsByMemberId($memberId: ID!) {
 
 fragment StakingAccountRemovedEventFields on StakingAccountRemovedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   member {
     id
   }
@@ -162,56 +177,64 @@ query getStakingAccountRemovedEventsByMemberId($memberId: ID!) {
 
 fragment ReferralCutUpdatedEventFields on ReferralCutUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   newValue
 }
 
 query getReferralCutUpdatedEventsByEventId($eventId: ID!) {
-  referralCutUpdatedEvents(where: { event: { id_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: { event: { id_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: { event: { id_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: { event: { id_eq: $eventId } }) {
+  initialInvitationCountUpdatedEvents(where: { id_eq: $eventId }) {
     ...InitialInvitationCountUpdatedEventFields
   }
 }

+ 7 - 18
tests/integration-tests/src/graphql/queries/workingGroups.graphql

@@ -93,10 +93,9 @@ fragment WorkerFields on Worker {
   slashes {
     id
   }
-  hiredAtBlock {
-    ...BlockFields
+  entry {
+    id
   }
-  hiredAtTime
   application {
     ...ApplicationBasicFields
   }
@@ -111,13 +110,8 @@ fragment WorkingGroupMetadataFields on WorkingGroupMetadata {
   statusMessage
   about
   description
-  setAtBlock {
-    ...BlockFields
-  }
   setInEvent {
-    event {
-      ...EventFields
-    }
+    id
   }
 }
 
@@ -140,10 +134,9 @@ fragment OpeningFields on WorkingGroupOpening {
   stakeAmount
   unstakingPeriod
   rewardPerBlock
-  createdAtBlock {
-    ...BlockFields
+  createdInEvent {
+    id
   }
-  createdAt
 }
 
 query getOpeningById($openingId: ID!) {
@@ -160,10 +153,9 @@ query getOpeningsByIds($openingIds: [ID!]) {
 
 fragment ApplicationFields on WorkingGroupApplication {
   ...ApplicationBasicFields
-  createdAtBlock {
-    ...BlockFields
+  createdInEvent {
+    id
   }
-  createdAt
   opening {
     id
     runtimeId
@@ -225,9 +217,6 @@ fragment UpcomingOpeningFields on UpcomingWorkingGroupOpening {
   expectedStart
   stakeAmount
   rewardPerBlock
-  createdAtBlock {
-    ...BlockFields
-  }
   createdInEvent {
     id
   }

+ 114 - 76
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: { event: { id_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: { event: { id_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: { event: { id_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: { event: { id_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: { event: { id_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: { event: { id_in: $eventIds } }) {
+  openingCanceledEvents(where: { id_in: $eventIds }) {
     ...OpeningCanceledEventFields
   }
 }
 
 fragment StatusTextChangedEventFields on StatusTextChangedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -154,16 +168,18 @@ fragment StatusTextChangedEventFields on StatusTextChangedEvent {
 }
 
 query getStatusTextChangedEventsByEventIds($eventIds: [ID!]) {
-  statusTextChangedEvents(where: { event: { id_in: $eventIds } }) {
+  statusTextChangedEvents(where: { id_in: $eventIds }) {
     ...StatusTextChangedEventFields
   }
 }
 
 fragment WorkerRoleAccountUpdatedEventFields on WorkerRoleAccountUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -175,16 +191,18 @@ fragment WorkerRoleAccountUpdatedEventFields on WorkerRoleAccountUpdatedEvent {
 }
 
 query getWorkerRoleAccountUpdatedEventsByEventIds($eventIds: [ID!]) {
-  workerRoleAccountUpdatedEvents(where: { event: { id_in: $eventIds } }) {
+  workerRoleAccountUpdatedEvents(where: { id_in: $eventIds }) {
     ...WorkerRoleAccountUpdatedEventFields
   }
 }
 
 fragment WorkerRewardAccountUpdatedEventFields on WorkerRewardAccountUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -196,16 +214,18 @@ fragment WorkerRewardAccountUpdatedEventFields on WorkerRewardAccountUpdatedEven
 }
 
 query getWorkerRewardAccountUpdatedEventsByEventIds($eventIds: [ID!]) {
-  workerRewardAccountUpdatedEvents(where: { event: { id_in: $eventIds } }) {
+  workerRewardAccountUpdatedEvents(where: { id_in: $eventIds }) {
     ...WorkerRewardAccountUpdatedEventFields
   }
 }
 
 fragment StakeIncreasedEventFields on StakeIncreasedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -217,16 +237,18 @@ fragment StakeIncreasedEventFields on StakeIncreasedEvent {
 }
 
 query getStakeIncreasedEventsByEventIds($eventIds: [ID!]) {
-  stakeIncreasedEvents(where: { event: { id_in: $eventIds } }) {
+  stakeIncreasedEvents(where: { id_in: $eventIds }) {
     ...StakeIncreasedEventFields
   }
 }
 
 fragment WorkerStartedLeavingEventFields on WorkerStartedLeavingEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -238,16 +260,18 @@ fragment WorkerStartedLeavingEventFields on WorkerStartedLeavingEvent {
 }
 
 query getWorkerStartedLeavingEventsByEventIds($eventIds: [ID!]) {
-  workerStartedLeavingEvents(where: { event: { id_in: $eventIds } }) {
+  workerStartedLeavingEvents(where: { id_in: $eventIds }) {
     ...WorkerStartedLeavingEventFields
   }
 }
 
 fragment WorkerRewardAmountUpdatedEventFields on WorkerRewardAmountUpdatedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -259,16 +283,18 @@ fragment WorkerRewardAmountUpdatedEventFields on WorkerRewardAmountUpdatedEvent
 }
 
 query getWorkerRewardAmountUpdatedEventsByEventIds($eventIds: [ID!]) {
-  workerRewardAmountUpdatedEvents(where: { event: { id_in: $eventIds } }) {
+  workerRewardAmountUpdatedEvents(where: { id_in: $eventIds }) {
     ...WorkerRewardAmountUpdatedEventFields
   }
 }
 
 fragment StakeSlashedEventFields on StakeSlashedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -282,16 +308,18 @@ fragment StakeSlashedEventFields on StakeSlashedEvent {
 }
 
 query getStakeSlashedEventsByEventIds($eventIds: [ID!]) {
-  stakeSlashedEvents(where: { event: { id_in: $eventIds } }) {
+  stakeSlashedEvents(where: { id_in: $eventIds }) {
     ...StakeSlashedEventFields
   }
 }
 
 fragment StakeDecreasedEventFields on StakeDecreasedEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -303,16 +331,18 @@ fragment StakeDecreasedEventFields on StakeDecreasedEvent {
 }
 
 query getStakeDecreasedEventsByEventIds($eventIds: [ID!]) {
-  stakeDecreasedEvents(where: { event: { id_in: $eventIds } }) {
+  stakeDecreasedEvents(where: { id_in: $eventIds }) {
     ...StakeDecreasedEventFields
   }
 }
 
 fragment TerminatedWorkerEventFields on TerminatedWorkerEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -325,16 +355,18 @@ fragment TerminatedWorkerEventFields on TerminatedWorkerEvent {
 }
 
 query getTerminatedWorkerEventsByEventIds($eventIds: [ID!]) {
-  terminatedWorkerEvents(where: { event: { id_in: $eventIds } }) {
+  terminatedWorkerEvents(where: { id_in: $eventIds }) {
     ...TerminatedWorkerEventFields
   }
 }
 
 fragment TerminatedLeaderEventFields on TerminatedLeaderEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -347,16 +379,18 @@ fragment TerminatedLeaderEventFields on TerminatedLeaderEvent {
 }
 
 query getTerminatedLeaderEventsByEventIds($eventIds: [ID!]) {
-  terminatedLeaderEvents(where: { event: { id_in: $eventIds } }) {
+  terminatedLeaderEvents(where: { id_in: $eventIds }) {
     ...TerminatedLeaderEventFields
   }
 }
 
 fragment LeaderUnsetEventFields on LeaderUnsetEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -367,16 +401,18 @@ fragment LeaderUnsetEventFields on LeaderUnsetEvent {
 }
 
 query getLeaderUnsetEventsByEventIds($eventIds: [ID!]) {
-  leaderUnsetEvents(where: { event: { id_in: $eventIds } }) {
+  leaderUnsetEvents(where: { id_in: $eventIds }) {
     ...LeaderUnsetEventFields
   }
 }
 
 fragment BudgetSetEventFields on BudgetSetEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -384,16 +420,18 @@ fragment BudgetSetEventFields on BudgetSetEvent {
 }
 
 query getBudgetSetEventsByEventIds($eventIds: [ID!]) {
-  budgetSetEvents(where: { event: { id_in: $eventIds } }) {
+  budgetSetEvents(where: { id_in: $eventIds }) {
     ...BudgetSetEventFields
   }
 }
 
 fragment BudgetSpendingEventFields on BudgetSpendingEvent {
   id
-  event {
-    ...EventFields
-  }
+  createdAt
+  inBlock
+  network
+  inExtrinsic
+  indexInBlock
   group {
     name
   }
@@ -403,7 +441,7 @@ fragment BudgetSpendingEventFields on BudgetSpendingEvent {
 }
 
 query getBudgetSpendingEventsByEventIds($eventIds: [ID!]) {
-  budgetSpendingEvents(where: { event: { id_in: $eventIds } }) {
+  budgetSpendingEvents(where: { id_in: $eventIds }) {
     ...BudgetSpendingEventFields
   }
 }

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

@@ -2,14 +2,17 @@ import { MemberId } 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 { MembershipBoughtEvent } from './graphql/generated/schema'
 
 export type MemberContext = {
   account: string
   memberId: MemberId
 }
 
-export type AnyQueryNodeEvent = { event: EventFieldsFragment }
+export type AnyQueryNodeEvent = Pick<
+  MembershipBoughtEvent,
+  'createdAt' | 'updatedAt' | 'id' | 'inBlock' | 'inExtrinsic' | 'indexInBlock' | 'network'
+>
 
 export interface EventDetails {
   event: Event

Some files were not shown because too many files changed in this diff