Browse Source

query node - mappings for events emitted from 2 different extrinsics

ondratra 3 years ago
parent
commit
06009f6b80

+ 70 - 0
query-node/generated/types/members.ts

@@ -613,4 +613,74 @@ export namespace Members {
       ]);
     }
   }
+  /**
+   *  Update member's all or some of handle, avatar and about text.
+   */
+  export class UpdateMembershipCall {
+    public readonly extrinsic: SubstrateExtrinsic;
+    public readonly expectedArgTypes = [
+      "MemberId",
+      "Option<Bytes>",
+      "Option<Bytes>",
+      "Option<Bytes>",
+    ];
+
+    constructor(public readonly ctx: SubstrateEvent) {
+      if (ctx.extrinsic === undefined) {
+        throw new Error(`No call data has been provided`);
+      }
+      this.extrinsic = ctx.extrinsic;
+    }
+
+    get args(): UpdateMembership_Args {
+      return new UpdateMembership_Args(this.extrinsic);
+    }
+
+    validateArgs(): boolean {
+      if (this.expectedArgTypes.length !== this.extrinsic.args.length) {
+        return false;
+      }
+      let valid = true;
+      this.expectedArgTypes.forEach((type, i) => {
+        if (type !== this.extrinsic.args[i].type) {
+          valid = false;
+        }
+      });
+      return valid;
+    }
+  }
+
+  class UpdateMembership_Args {
+    constructor(public readonly extrinsic: SubstrateExtrinsic) {}
+
+    get memberId(): MemberId {
+      return createTypeUnsafe<MemberId & Codec>(typeRegistry, "MemberId", [
+        this.extrinsic.args[0].value,
+      ]);
+    }
+
+    get handle(): Option<Bytes> {
+      return createTypeUnsafe<Option<Bytes> & Codec>(
+        typeRegistry,
+        "Option<Bytes>",
+        [this.extrinsic.args[1].value]
+      );
+    }
+
+    get avatarUri(): Option<Bytes> {
+      return createTypeUnsafe<Option<Bytes> & Codec>(
+        typeRegistry,
+        "Option<Bytes>",
+        [this.extrinsic.args[2].value]
+      );
+    }
+
+    get about(): Option<Bytes> {
+      return createTypeUnsafe<Option<Bytes> & Codec>(
+        typeRegistry,
+        "Option<Bytes>",
+        [this.extrinsic.args[3].value]
+      );
+    }
+  }
 }

+ 1 - 0
query-node/manifest.yml

@@ -74,6 +74,7 @@ typegen:
     - members.changeMemberHandle
     - members.setRootAccount
     - members.setControllerAccount
+    - members.updateMembership
 
     # content directory
     - content.create_curator_group

+ 27 - 14
query-node/mappings/src/common.ts

@@ -106,20 +106,7 @@ export function extractExtrinsicArgs<DataParams, EventObject extends IGenericExt
 
   // sudo extrinsic call
 
-  // see Substrate's sudo frame for more info about sudo extrinsics and `call` argument index
-  const argIndex = false
-    || (rawEvent.extrinsic.method == 'sudoAs' && 1) // who, *call*
-    || (rawEvent.extrinsic.method == 'sudo' && 0) // *call*
-    || (rawEvent.extrinsic.method == 'sudoUncheckedWeight' && 0) // *call*, _weight
-
-  // ensure `call` argument was found
-  if (argIndex === false) {
-    // this could possibly happen in sometime in future if new sudo options are introduced in Substrate
-    throw 'Not implemented situation with sudo'
-  }
-
-  // typecast call arguments
-  const callArgs = rawEvent.extrinsic.args[argIndex].value as unknown as ISudoCallArgs<DataParams>
+  const callArgs = extractSudoCallParameters<DataParams>(rawEvent)
 
   // convert naming convention (underscore_names to camelCase)
   const clearArgs = Object.keys(callArgs.args).reduce((acc, key) => {
@@ -149,6 +136,32 @@ export function extractExtrinsicArgs<DataParams, EventObject extends IGenericExt
   return finalArgs
 }
 
+/*
+  Extracts extrinsic call parameters used inside of sudo call.
+*/
+export function extractSudoCallParameters<DataParams>(rawEvent: SubstrateEvent): ISudoCallArgs<DataParams> {
+  if (!rawEvent.extrinsic) {
+    throw 'Invalid event - no extrinsic set' // this should never happen
+  }
+
+  // see Substrate's sudo frame for more info about sudo extrinsics and `call` argument index
+  const argIndex = false
+    || (rawEvent.extrinsic.method == 'sudoAs' && 1) // who, *call*
+    || (rawEvent.extrinsic.method == 'sudo' && 0) // *call*
+    || (rawEvent.extrinsic.method == 'sudoUncheckedWeight' && 0) // *call*, _weight
+
+  // ensure `call` argument was found
+  if (argIndex === false) {
+    // this could possibly happen in sometime in future if new sudo options are introduced in Substrate
+    throw 'Not implemented situation with sudo'
+  }
+
+  // typecast call arguments
+  const callArgs = rawEvent.extrinsic.args[argIndex].value as unknown as ISudoCallArgs<DataParams>
+
+  return callArgs
+}
+
 /////////////////// Logger /////////////////////////////////////////////////////
 
 /*

+ 58 - 3
query-node/mappings/src/membership.ts

@@ -10,6 +10,7 @@ import {
   inconsistentState,
   logger,
   extractExtrinsicArgs,
+  extractSudoCallParameters,
 } from './common'
 import { Members } from '../../generated/types'
 import { MembershipEntryMethod, Membership } from 'query-node'
@@ -56,7 +57,11 @@ export async function members_MemberRegistered(db: DatabaseManager, event: Subst
 // eslint-disable-next-line @typescript-eslint/naming-convention
 export async function members_MemberUpdatedAboutText(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
   // read event data
-  const { text, memberId } = extractExtrinsicArgs(event, Members.ChangeMemberAboutTextCall, {memberId: 0, text: 1})
+  const { text, memberId } = isUpdateMembershipExtrinsic(event)
+    ? unpackUpdateMembershipOptions(
+        extractExtrinsicArgs(event, Members.UpdateMembershipCall, {memberId: 0, about: 3})
+      )
+    : extractExtrinsicArgs(event, Members.ChangeMemberAboutTextCall, {memberId: 0, text: 1})
 
   // load member
   const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
@@ -82,7 +87,11 @@ export async function members_MemberUpdatedAboutText(db: DatabaseManager, event:
 // eslint-disable-next-line @typescript-eslint/naming-convention
 export async function members_MemberUpdatedAvatar(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
   // read event data
-  const { uri, memberId } = extractExtrinsicArgs(event, Members.ChangeMemberAvatarCall, {memberId: 0, uri: 1})
+  const { uri, memberId } = isUpdateMembershipExtrinsic(event)
+    ? unpackUpdateMembershipOptions(
+        extractExtrinsicArgs(event, Members.UpdateMembershipCall, {memberId: 0, avatarUri: 2})
+      )
+    : extractExtrinsicArgs(event, Members.ChangeMemberAvatarCall, {memberId: 0, uri: 1})
 
   // load member
   const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
@@ -108,7 +117,11 @@ export async function members_MemberUpdatedAvatar(db: DatabaseManager, event: Su
 // eslint-disable-next-line @typescript-eslint/naming-convention
 export async function members_MemberUpdatedHandle(db: DatabaseManager, event: SubstrateEvent): Promise<void> {
   // read event data
-  const { handle, memberId } = extractExtrinsicArgs(event, Members.ChangeMemberHandleCall, {memberId: 0, handle: 1})
+  const { handle, memberId } = isUpdateMembershipExtrinsic(event)
+    ? unpackUpdateMembershipOptions(
+        extractExtrinsicArgs(event, Members.UpdateMembershipCall, {memberId: 0, handle: 1})
+      )
+    : extractExtrinsicArgs(event, Members.ChangeMemberHandleCall, {memberId: 0, handle: 1})
 
   // load member
   const member = await db.get(Membership, { where: { id: memberId.toString() } as FindConditions<Membership> })
@@ -220,3 +233,45 @@ function convertEntryMethod(entryMethod: EntryMethod): MembershipEntryMethod {
   logger.error('Not implemented entry method', {entryMethod: entryMethod.toString()})
   throw 'Not implemented entry method'
 }
+
+/*
+  Returns true if event is emitted inside of `update_membership` extrinsic.
+*/
+function isUpdateMembershipExtrinsic(event: SubstrateEvent): boolean {
+  if (!event.extrinsic) { // this should never happen
+    return false
+  }
+
+  if (event.extrinsic.method == 'updateMembership') {
+    return true
+  }
+
+  // no sudo was used to update membership -> this is not updateMembership
+  if (event.extrinsic.section != 'sudo') {
+    return false
+  }
+
+  const sudoCallParameters = extractSudoCallParameters<unknown[]>(event)
+
+  // very trivial check if update_membership extrinsic was used
+  return sudoCallParameters.args.length == 4 // memberId, handle, avatarUri, about
+}
+
+interface IUnpackedUpdateMembershipOptions {
+  memberId: MemberId
+  handle: Bytes
+  uri: Bytes
+  text: Bytes
+}
+
+/*
+  Returns unwrapped data + unite naming of uri/avatarUri and about/text
+*/
+function unpackUpdateMembershipOptions(args: Members.UpdateMembershipCall['args']): IUnpackedUpdateMembershipOptions {
+  return {
+    memberId: args.memberId,
+    handle: args.handle.unwrapOrDefault(),
+    uri: args.avatarUri.unwrapOrDefault(),
+    text: args.about.unwrapOrDefault(),
+  }
+}