Kaynağa Gözat

Merge branch 'giza' into giza-protobuf-and-query-node

Leszek Wiesner 3 yıl önce
ebeveyn
işleme
52919e20dc
49 değiştirilmiş dosya ile 627 ekleme ve 476 silme
  1. 12 12
      Cargo.lock
  2. 3 0
      devops/infrastructure/node-network/Pulumi.yaml
  3. 12 1
      devops/infrastructure/node-network/README.md
  4. 26 7
      devops/infrastructure/node-network/index.ts
  5. 21 4
      node/src/chain_spec/mod.rs
  6. 13 22
      pioneer/packages/joy-forum/src/ForumRoot.tsx
  7. 78 14
      pioneer/packages/joy-forum/src/ViewThread.tsx
  8. 3 7
      pioneer/packages/joy-utils/src/transport/proposals.ts
  9. 8 2
      runtime-modules/common/src/working_group.rs
  10. 1 1
      runtime-modules/content/Cargo.toml
  11. 6 13
      runtime-modules/content/src/lib.rs
  12. 7 41
      runtime-modules/content/src/permissions/mod.rs
  13. 0 2
      runtime-modules/content/src/tests/mock.rs
  14. 1 1
      runtime-modules/forum/Cargo.toml
  15. 1 1
      runtime-modules/governance/Cargo.toml
  16. 5 2
      runtime-modules/governance/src/mock.rs
  17. 1 1
      runtime-modules/hiring/Cargo.toml
  18. 1 1
      runtime-modules/membership/Cargo.toml
  19. 22 40
      runtime-modules/membership/src/lib.rs
  20. 5 2
      runtime-modules/membership/src/mock.rs
  21. 1 1
      runtime-modules/memo/Cargo.toml
  22. 1 1
      runtime-modules/proposals/codex/src/lib.rs
  23. 5 2
      runtime-modules/proposals/codex/src/tests/mock.rs
  24. 1 1
      runtime-modules/proposals/discussion/Cargo.toml
  25. 1 1
      runtime-modules/proposals/discussion/src/lib.rs
  26. 5 2
      runtime-modules/proposals/discussion/src/tests/mock.rs
  27. 1 1
      runtime-modules/proposals/engine/Cargo.toml
  28. 1 1
      runtime-modules/proposals/engine/src/lib.rs
  29. 5 2
      runtime-modules/proposals/engine/src/tests/mock/mod.rs
  30. 1 1
      runtime-modules/recurring-reward/Cargo.toml
  31. 1 1
      runtime-modules/stake/Cargo.toml
  32. 2 2
      runtime-modules/storage/src/lib.rs
  33. 5 2
      runtime-modules/storage/src/tests/mocks.rs
  34. 1 1
      runtime-modules/token-minting/Cargo.toml
  35. 1 1
      runtime-modules/working-group/Cargo.toml
  36. 2 2
      runtime-modules/working-group/src/lib.rs
  37. 5 2
      runtime-modules/working-group/src/tests/mock.rs
  38. 1 1
      runtime/src/integration/proposals/membership_origin_validator.rs
  39. 9 1
      runtime/src/integration/proposals/proposal_encoder.rs
  40. 88 156
      runtime/src/integration/working_group.rs
  41. 35 11
      runtime/src/lib.rs
  42. 0 4
      runtime/src/primitives.rs
  43. 169 45
      runtime/src/tests/proposals_integration/working_group_proposals.rs
  44. 6 4
      types/augment-codec/augment-api-events.ts
  45. 6 4
      types/augment/augment-api-events.ts
  46. 1 1
      types/src/JoyEnum.ts
  47. 6 21
      types/src/common.ts
  48. 1 1
      types/src/index.ts
  49. 40 29
      types/src/scripts/generateRegistryJson.ts

+ 12 - 12
Cargo.lock

@@ -3822,7 +3822,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-content"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -3859,7 +3859,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-forum"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -3876,7 +3876,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-governance"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -3919,7 +3919,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-hiring"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -3957,7 +3957,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-membership"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -3975,7 +3975,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-memo"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -4054,7 +4054,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-proposals-discussion"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -4072,7 +4072,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-proposals-engine"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -4106,7 +4106,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-recurring-reward"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -4157,7 +4157,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-stake"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -4259,7 +4259,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-token-mint"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -4337,7 +4337,7 @@ dependencies = [
 
 [[package]]
 name = "pallet-working-group"
-version = "3.1.1"
+version = "3.2.0"
 dependencies = [
  "frame-support",
  "frame-system",

+ 3 - 0
devops/infrastructure/node-network/Pulumi.yaml

@@ -22,3 +22,6 @@ template:
     nodeImage:
       description: Docker image with tag to be used as validator and RPC nodes
       default: 'joystream/node:latest'
+    encryptionKey:
+      description: Key to encrypt the 7z containing secrets with
+      default: '1234'

+ 12 - 1
devops/infrastructure/node-network/README.md

@@ -39,7 +39,7 @@ After cloning this repo, from this working directory, run these commands:
    ```bash
    $ pulumi config set-all --plaintext aws:region=us-east-1 --plaintext aws:profile=joystream-user \
     --plaintext numberOfValidators=2 --plaintext isMinikube=true --plaintext networkSuffix=8122 \
-    --plaintext nodeImage=joystream/node:latest
+    --plaintext nodeImage=joystream/node:latest --plaintext encryptionKey=password
    ```
 
    If you want to build the stack on AWS set the `isMinikube` config to `false`
@@ -67,6 +67,11 @@ After cloning this repo, from this working directory, run these commands:
 
    The ws-rpc endpoint is `https://<ENDPOINT>/ws-rpc` and http-rpc endpoint is `https://<ENDPOINT>/http-rpc`
 
+1. If you are using Minikube, run `minikube service node-network -n $(pulumi stack output namespaceName)`
+
+   This will setup a proxy for your `node-network` service, which can then be accessed at
+   the URL given in the output
+
 1. Access the Kubernetes Cluster using `kubectl`
 
    To access your new Kubernetes cluster using `kubectl`, we need to set up the
@@ -106,6 +111,12 @@ After cloning this repo, from this working directory, run these commands:
    $ kubectl exec --stdin --tty <PODNAME> -c colossus -- /bin/bash
    ```
 
+1. To get the chain-data and secrets, run the below command
+
+   ```bash
+   $ kubectl cp $(kubectl get pods | grep rpc-node | awk '{print $1}'):/chain-data/chain-data.7z ./chain-data.7z
+   ```
+
 1. Once you've finished experimenting, tear down your stack's resources by destroying and removing it:
 
    ```bash

+ 26 - 7
devops/infrastructure/node-network/index.ts

@@ -57,6 +57,7 @@ const numberOfValidators = config.getNumber('numberOfValidators') || 1
 const chainDataPath = '/chain-data'
 const chainSpecPath = `${chainDataPath}/chainspec-raw.json`
 const nodeImage = config.get('nodeImage') || 'joystream/node:latest'
+const encryptKey = config.get('encryptionKey') || '1234'
 
 const subkeyContainers = getSubkeyContainers(numberOfValidators, chainDataPath)
 let pvcClaimName: pulumi.Output<any>
@@ -178,6 +179,18 @@ const chainDataPrepareJob = new k8s.batch.v1.Job(
                 },
               ],
             },
+            {
+              name: '7z',
+              image: 'danielwhatmuff/7z-docker',
+              command: ['/bin/sh', '-c'],
+              args: [`7z a -p${encryptKey} ${chainDataPath}/chain-data.7z ${chainDataPath}/*`],
+              volumeMounts: [
+                {
+                  name: 'config-data',
+                  mountPath: chainDataPath,
+                },
+              ],
+            },
           ],
           volumes: [
             {
@@ -289,6 +302,7 @@ const service = new k8s.core.v1.Service(
       name: 'node-network',
     },
     spec: {
+      type: isMinikube ? 'NodePort' : 'ClusterIP',
       ports: [
         { name: 'port-1', port: 9944 },
         { name: 'port-2', port: 9933 },
@@ -313,11 +327,16 @@ const caddyEndpoints = [
 }`,
 ]
 
-const caddy = new CaddyServiceDeployment(
-  'caddy-proxy',
-  { lbReady, namespaceName: namespaceName, isMinikube, caddyEndpoints },
-  resourceOptions
-)
+export let endpoint1: pulumi.Output<string>
+export let endpoint2: pulumi.Output<string>
 
-export const endpoint1 = caddy.primaryEndpoint
-export const endpoint2 = caddy.secondaryEndpoint
+if (!isMinikube) {
+  const caddy = new CaddyServiceDeployment(
+    'caddy-proxy',
+    { lbReady, namespaceName: namespaceName, isMinikube, caddyEndpoints },
+    resourceOptions
+  )
+
+  endpoint1 = pulumi.interpolate`${caddy.primaryEndpoint}`
+  endpoint2 = pulumi.interpolate`${caddy.secondaryEndpoint}`
+}

+ 21 - 4
node/src/chain_spec/mod.rs

@@ -34,9 +34,10 @@ use node_runtime::{
     membership, wasm_binary_unwrap, AuthorityDiscoveryConfig, BabeConfig, Balance, BalancesConfig,
     ContentConfig, ContentWorkingGroupConfig, CouncilConfig, CouncilElectionConfig,
     DistributionWorkingGroupConfig, ElectionParameters, ForumConfig, GatewayWorkingGroupConfig,
-    GrandpaConfig, ImOnlineConfig, MembersConfig, Moment, OperationsWorkingGroupConfig,
-    ProposalsCodexConfig, SessionConfig, SessionKeys, Signature, StakerStatus, StakingConfig,
-    StorageWorkingGroupConfig, SudoConfig, SystemConfig, DAYS,
+    GrandpaConfig, ImOnlineConfig, MembersConfig, Moment, OperationsWorkingGroupAlphaConfig,
+    OperationsWorkingGroupBetaConfig, OperationsWorkingGroupGammaConfig, ProposalsCodexConfig,
+    SessionConfig, SessionKeys, Signature, StakerStatus, StakingConfig, StorageWorkingGroupConfig,
+    SudoConfig, SystemConfig, DAYS,
 };
 
 // Exported to be used by chain-spec-builder
@@ -314,7 +315,7 @@ pub fn testnet_genesis(
             worker_exit_rationale_text_constraint: default_text_constraint,
             worker_storage_size_constraint: default_storage_size_constraint,
         }),
-        working_group_Instance4: Some(OperationsWorkingGroupConfig {
+        working_group_Instance4: Some(OperationsWorkingGroupAlphaConfig {
             phantom: Default::default(),
             working_group_mint_capacity: 0,
             opening_human_readable_text_constraint: default_text_constraint,
@@ -338,6 +339,22 @@ pub fn testnet_genesis(
             worker_exit_rationale_text_constraint: default_text_constraint,
             worker_storage_size_constraint: default_storage_size_constraint,
         }),
+        working_group_Instance7: Some(OperationsWorkingGroupBetaConfig {
+            phantom: Default::default(),
+            working_group_mint_capacity: 0,
+            opening_human_readable_text_constraint: default_text_constraint,
+            worker_application_human_readable_text_constraint: default_text_constraint,
+            worker_exit_rationale_text_constraint: default_text_constraint,
+            worker_storage_size_constraint: default_storage_size_constraint,
+        }),
+        working_group_Instance8: Some(OperationsWorkingGroupGammaConfig {
+            phantom: Default::default(),
+            working_group_mint_capacity: 0,
+            opening_human_readable_text_constraint: default_text_constraint,
+            worker_application_human_readable_text_constraint: default_text_constraint,
+            worker_exit_rationale_text_constraint: default_text_constraint,
+            worker_storage_size_constraint: default_storage_size_constraint,
+        }),
         content: Some({
             ContentConfig {
                 next_curator_group_id: 1,

+ 13 - 22
pioneer/packages/joy-forum/src/ForumRoot.tsx

@@ -1,7 +1,6 @@
 import React, { useState, useEffect } from 'react';
 import { Link } from 'react-router-dom';
 import styled from 'styled-components';
-import { orderBy } from 'lodash';
 import BN from 'bn.js';
 
 import { Section } from '@polkadot/joy-utils/react/components';
@@ -63,36 +62,28 @@ const InnerRecentActivity: React.FC<RecentActivityProps> = ({ nextPostId, api })
       if (!nextPostId) return;
 
       const newId = (id: number | BN) => api.createType('PostId', id);
-      const apiCalls: Promise<Post>[] = [];
-      let id = newId(1);
+      let id = newId(nextPostId.toNumber() - 1);
 
-      while (nextPostId.gt(id)) {
-        apiCalls.push(api.query.forum.postById(id) as Promise<Post>);
-        id = newId(id.add(newId(1)));
-      }
+      const threadsIdsLookup = {} as Record<number, boolean>;
+      const recentUniquePosts = new Array<Post>();
 
-      const allPosts = await Promise.all(apiCalls);
-      const sortedPosts = orderBy(
-        allPosts,
-        [(x) => x.id.toNumber()],
-        ['desc']
-      );
+      while (id.gt(newId(0))) {
+        const post = await api.query.forum.postById(id) as Post;
 
-      const threadsIdsLookup = {} as Record<number, boolean>;
-      const postsWithUniqueThreads = sortedPosts.reduce((acc, post) => {
         const threadId = post.thread_id.toNumber();
 
-        if (threadsIdsLookup[threadId]) return acc;
+        id = newId(id.toNumber() - 1);
+
+        if (threadsIdsLookup[threadId]) continue;
 
         threadsIdsLookup[threadId] = true;
 
-        return [
-          ...acc,
-          post
-        ];
-      }, [] as Post[]);
+        recentUniquePosts.push(post);
 
-      const recentUniquePosts = postsWithUniqueThreads.slice(0, RecentActivityPostsCount);
+        if (recentUniquePosts.length === RecentActivityPostsCount) {
+          break;
+        }
+      }
 
       setRecentPosts(recentUniquePosts);
       setLoaded(true);

+ 78 - 14
pioneer/packages/joy-forum/src/ViewThread.tsx

@@ -5,7 +5,7 @@ import styled from 'styled-components';
 import { Table, Button, Label, Icon } from 'semantic-ui-react';
 import BN from 'bn.js';
 
-import { ThreadId } from '@joystream/types/common';
+import { PostId, ThreadId } from '@joystream/types/common';
 import { Category, Thread, Post } from '@joystream/types/forum';
 import { Pagination, RepliesPerPage, CategoryCrumbs, TimeAgoDate, usePagination, useQueryParam, ReplyIdxQueryParam, ReplyEditIdQueryParam } from './utils';
 import { ViewReply } from './ViewReply';
@@ -22,6 +22,7 @@ import MemberPreview from '@polkadot/joy-utils/react/components/MemberByAccountP
 import { formatDate } from '@polkadot/joy-utils/functions/date';
 import { NewReply, EditReply } from './EditReply';
 import { useApi } from '@polkadot/react-hooks';
+import { ApiPromise } from '@polkadot/api/promise';
 
 type ThreadTitleProps = {
   thread: Thread;
@@ -124,6 +125,77 @@ type ViewThreadProps = ApiProps & InnerViewThreadProps & {
   nextPostId?: ThreadId;
 };
 
+const POSTS_THREAD_MAP_CACHE_KEY = 'postsThreadMap';
+
+async function refreshPostsInThreadCache (nextPostId: PostId, api: ApiPromise) {
+  const newId = (id: number | BN) => api.createType('PostId', id);
+  const apiCalls: Promise<Post>[] = [];
+  let idToFetch = newId(1);
+
+  let postsToThread = getPostsIdsInThreadCache();
+  const nextThreadId = await api.query.forum.nextThreadId() as ThreadId;
+
+  if (postsToThread.size >= nextThreadId.toNumber()) { // invalid cache
+    postsToThread = new Map<number, number[]>();
+  }
+
+  if (postsToThread.size > 0) {
+    const lastPostIdInCache = Math.max(...Array.from(postsToThread.values()).flat());
+
+    idToFetch = newId(lastPostIdInCache + 1);
+    const lastPost = await api.query.forum.postById(lastPostIdInCache) as Post;
+
+    if (lastPost) {
+      const postsInThread = postsToThread.get(lastPost.thread_id.toNumber());
+
+      if (!postsInThread || !postsInThread.includes(lastPostIdInCache)) { // cache doesn't match the data in chain
+        postsToThread = new Map<number, number[]>();
+      }
+    } else {
+      postsToThread = new Map<number, number[]>();
+    }
+  }
+
+  const lastPostId = nextPostId.sub(new BN(1));
+
+  while (lastPostId.gte(idToFetch)) {
+    apiCalls.push(api.query.forum.postById(idToFetch) as Promise<Post>);
+    idToFetch = newId(idToFetch.add(newId(1)));
+  }
+
+  const newPosts = await Promise.all<Post>(apiCalls);
+
+  const newPostsToThread = new Map<number, number[]>();
+
+  newPosts.forEach((newPost) => {
+    const previousNewPostIds = newPostsToThread.get(newPost.thread_id.toNumber()) ?? [];
+
+    newPostsToThread.set(newPost.thread_id.toNumber(), [...previousNewPostIds, newPost.id.toNumber()]);
+  });
+
+  if (postsToThread.size > 0) {
+    newPostsToThread.forEach((postIds, threadId) => {
+      const existingPostIds = postsToThread.get(threadId) ?? [];
+
+      postsToThread.set(threadId, [...existingPostIds, ...postIds]);
+    });
+  } else {
+    postsToThread = newPostsToThread;
+  }
+
+  localStorage.setItem(POSTS_THREAD_MAP_CACHE_KEY, JSON.stringify([...postsToThread]));
+}
+
+function getPostsIdsInThreadCache (): Map<number, number[]> {
+  const serializedMap = localStorage.getItem(POSTS_THREAD_MAP_CACHE_KEY);
+
+  if (!serializedMap) {
+    return new Map<number, number[]>();
+  }
+
+  return new Map<number, number[]>(JSON.parse(serializedMap));
+}
+
 function InnerViewThread (props: ViewThreadProps) {
   const [showModerateForm, setShowModerateForm] = useState(false);
   const [displayedPosts, setDisplayedPosts] = useState<Post[]>([]);
@@ -154,20 +226,12 @@ function InnerViewThread (props: ViewThreadProps) {
     const loadPosts = async () => {
       if (!nextPostId || totalPostsInThread === 0 || thread.isEmpty) return;
 
-      const newId = (id: number | BN) => api.createType('PostId', id);
-      const apiCalls: Promise<Post>[] = [];
-      let id = newId(1);
-
-      while (nextPostId.gt(id)) {
-        apiCalls.push(api.query.forum.postById(id) as Promise<Post>);
-        id = newId(id.add(newId(1)));
-      }
+      await refreshPostsInThreadCache(nextPostId, api);
+      const mapPostToThread = getPostsIdsInThreadCache();
+      const postIdsInThread = mapPostToThread.get(thread.id.toNumber()) as number[];
+      const postsInThisThread = await Promise.all(postIdsInThread
+        ? postIdsInThread.map((postId: number) => api.query.forum.postById(postId)) : []) as Post[];
 
-      const allPosts = await Promise.all<Post>(apiCalls);
-      const postsInThisThread = allPosts.filter((item) =>
-        !item.isEmpty &&
-        item.thread_id.eq(thread.id)
-      );
       const sortedPosts = orderBy(
         postsInThisThread,
         [(x) => x.nr_in_thread.toNumber()],

+ 3 - 7
pioneer/packages/joy-utils/src/transport/proposals.ts

@@ -187,14 +187,10 @@ export default class ProposalsTransport extends BaseTransport {
   }
 
   async voteByProposalAndMember (proposalId: ProposalId, voterId: MemberId): Promise<VoteKind | null> {
-    const votesEntries = await this.api.query.proposalsEngine.voteExistsByProposalByVoter.entries(proposalId);
-    const voteEntry = votesEntries.find((voteEntry) => {
-      const memberId = voteEntry[0].args[1] as MemberId;
+    const vote = (await this.proposalsEngine.voteExistsByProposalByVoter(proposalId, voterId)) as VoteKind;
+    const hasVoted = (await this.api.query.proposalsEngine.voteExistsByProposalByVoter.size(proposalId, voterId)).toNumber();
 
-      return memberId.eq(voterId);
-    });
-
-    return voteEntry ? voteEntry[1] as VoteKind : null;
+    return hasVoted ? vote : null;
   }
 
   async votes (proposalId: ProposalId): Promise<ProposalVotes> {

+ 8 - 2
runtime-modules/common/src/working_group.rs

@@ -22,11 +22,17 @@ pub enum WorkingGroup {
     Content = 3isize,
 
     /// Operations working group: working_group::Instance4.
-    Operations = 4isize,
+    OperationsAlpha = 4isize,
 
     /// Gateway working group: working_group::Instance5.
     Gateway = 5isize,
 
-    /// Distribution working group: working_group::Instance4.
+    /// Distribution working group: working_group::Instance6.
     Distribution = 6isize,
+
+    /// Operations working group: working_group::Instance7.
+    OperationsBeta = 7isize,
+
+    /// Operations working group: working_group::Instance8.
+    OperationsGamma = 8isize,
 }

+ 1 - 1
runtime-modules/content/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-content'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 6 - 13
runtime-modules/content/src/lib.rs

@@ -127,7 +127,7 @@ pub enum ChannelOwner<MemberId, CuratorGroupId> {
 // simplification type
 pub(crate) type ActorToChannelOwnerResult<T> = Result<
     ChannelOwner<
-        <T as membership::Trait>::MemberId,
+        <T as common::MembershipTypes>::MemberId,
         <T as ContentActorAuthenticator>::CuratorGroupId,
     >,
     Error<T>,
@@ -185,7 +185,7 @@ pub struct ChannelRecord<MemberId, CuratorGroupId, AccountId> {
 
 // Channel alias type for simplification.
 pub type Channel<T> = ChannelRecord<
-    <T as membership::Trait>::MemberId,
+    <T as common::MembershipTypes>::MemberId,
     <T as ContentActorAuthenticator>::CuratorGroupId,
     <T as frame_system::Trait>::AccountId,
 >;
@@ -209,7 +209,7 @@ pub struct ChannelOwnershipTransferRequestRecord<
 // ChannelOwnershipTransferRequest type alias for simplification.
 pub type ChannelOwnershipTransferRequest<T> = ChannelOwnershipTransferRequestRecord<
     <T as storage::Trait>::ChannelId,
-    <T as membership::Trait>::MemberId,
+    <T as common::MembershipTypes>::MemberId,
     <T as ContentActorAuthenticator>::CuratorGroupId,
     BalanceOf<T>,
     <T as frame_system::Trait>::AccountId,
@@ -1446,17 +1446,10 @@ impl<T: Trait> Module<T> {
         match actor {
             // Lead should use their member or curator role to create channels
             ContentActor::Lead => Err(Error::<T>::ActorCannotOwnChannel),
-            ContentActor::Curator(
-                curator_group_id,
-                _curator_id
-            ) => {
+            ContentActor::Curator(curator_group_id, _curator_id) => {
                 Ok(ChannelOwner::CuratorGroup(*curator_group_id))
             }
-            ContentActor::Member(member_id) => {
-                Ok(ChannelOwner::Member(*member_id))
-            }
-            // TODO:
-            // ContentActor::Dao(id) => Ok(ChannelOwner::Dao(id)),
+            ContentActor::Member(member_id) => Ok(ChannelOwner::Member(*member_id)),
         }
     }
 
@@ -1477,7 +1470,7 @@ decl_event!(
         ContentActor = ContentActor<
             <T as ContentActorAuthenticator>::CuratorGroupId,
             <T as ContentActorAuthenticator>::CuratorId,
-            <T as membership::Trait>::MemberId,
+            <T as common::MembershipTypes>::MemberId,
         >,
         CuratorGroupId = <T as ContentActorAuthenticator>::CuratorGroupId,
         CuratorId = <T as ContentActorAuthenticator>::CuratorId,

+ 7 - 41
runtime-modules/content/src/permissions/mod.rs

@@ -11,7 +11,6 @@ use frame_support::{ensure, Parameter};
 pub use serde::{Deserialize, Serialize};
 use sp_arithmetic::traits::BaseArithmetic;
 use sp_runtime::traits::{MaybeSerializeDeserialize, Member};
-// use frame_system::ensure_root;
 
 /// Model of authentication manager.
 pub trait ContentActorAuthenticator: frame_system::Trait + membership::Trait {
@@ -104,26 +103,18 @@ pub fn ensure_actor_authorized_to_create_channel<T: Trait>(
 ) -> DispatchResult {
     match actor {
         // Lead should use their member or curator role to create or update channel assets.
-        ContentActor::Lead => {
-            Err(Error::<T>::ActorCannotOwnChannel.into())
-        }
+        ContentActor::Lead => Err(Error::<T>::ActorCannotOwnChannel.into()),
         ContentActor::Curator(curator_group_id, curator_id) => {
             let sender = ensure_signed(origin)?;
 
             // Authorize curator, performing all checks to ensure curator can act
-            CuratorGroup::<T>::perform_curator_in_group_auth(
-                curator_id,
-                curator_group_id,
-                &sender,
-            )
+            CuratorGroup::<T>::perform_curator_in_group_auth(curator_id, curator_group_id, &sender)
         }
         ContentActor::Member(member_id) => {
             let sender = ensure_signed(origin)?;
 
             ensure_member_auth_success::<T>(member_id, &sender)
         }
-        // TODO:
-        // ContentActor::Dao(_daoId) => ...,
     }
 }
 
@@ -176,8 +167,6 @@ pub fn ensure_actor_authorized_to_update_channel<T: Trait>(
 
             Ok(())
         }
-        // TODO:
-        // ContentActor::Dao(_daoId) => ...,
     }
 }
 
@@ -206,7 +195,7 @@ pub fn ensure_actor_authorized_to_censor<T: Trait>(
         ContentActor::Lead => {
             let sender = ensure_signed(origin)?;
             ensure_lead_auth_success::<T>(&sender)
-        },
+        }
         ContentActor::Curator(curator_group_id, curator_id) => {
             let sender = ensure_signed(origin)?;
 
@@ -223,13 +212,11 @@ pub fn ensure_actor_authorized_to_censor<T: Trait>(
             } else {
                 Ok(())
             }
-        },
+        }
         ContentActor::Member(_) => {
             // Members cannot censore channels!
             Err(Error::<T>::ActorNotAuthorized.into())
         }
-        // TODO:
-        // ContentActor::Dao(_daoId) => ...,
     }
 }
 
@@ -242,40 +229,20 @@ pub fn ensure_actor_authorized_to_manage_categories<T: Trait>(
         ContentActor::Lead => {
             let sender = ensure_signed(origin)?;
             ensure_lead_auth_success::<T>(&sender)
-        },
+        }
         ContentActor::Curator(curator_group_id, curator_id) => {
             let sender = ensure_signed(origin)?;
 
             // Authorize curator, performing all checks to ensure curator can act
-            CuratorGroup::<T>::perform_curator_in_group_auth(
-                curator_id,
-                curator_group_id,
-                &sender,
-            )
-        },
+            CuratorGroup::<T>::perform_curator_in_group_auth(curator_id, curator_group_id, &sender)
+        }
         ContentActor::Member(_) => {
             // Members cannot censore channels!
             Err(Error::<T>::ActorNotAuthorized.into())
         }
-        // TODO:
-        // ContentActor::Dao(_daoId) => ...,
     }
 }
 
-// pub fn ensure_actor_authorized_to_delete_stale_assets<T: Trait>(
-//     origin: T::Origin,
-//     actor: &ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-// ) -> DispatchResult {
-//     // Only Lead and (sudo) can delete assets no longer associated with a channel or person.
-//     if let ContentActor::Lead = actor {
-//         let sender = ensure_signed(origin)?;
-//         ensure_lead_auth_success::<T>(&sender)
-//     } else {
-//         ensure_root(origin)?;
-//         Ok(())
-//     }
-// }
-
 /// Enum, representing all possible `Actor`s
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Eq, PartialEq, Clone, Copy, Debug)]
@@ -287,7 +254,6 @@ pub enum ContentActor<
     Curator(CuratorGroupId, CuratorId),
     Member(MemberId),
     Lead,
-    // Dao,
 }
 
 impl<

+ 0 - 2
runtime-modules/content/src/tests/mock.rs

@@ -153,10 +153,8 @@ parameter_types! {
 
 impl membership::Trait for Test {
     type Event = MetaEvent;
-    type MemberId = u64;
     type PaidTermId = u64;
     type SubscriptionId = u64;
-    type ActorId = u64;
     type ScreenedMemberMaxInitialBalance = ();
 }
 

+ 1 - 1
runtime-modules/forum/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-forum'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 1 - 1
runtime-modules/governance/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-governance'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 5 - 2
runtime-modules/governance/src/mock.rs

@@ -76,12 +76,15 @@ parameter_types! {
     pub const ScreenedMemberMaxInitialBalance: u64 = 500;
 }
 
+impl common::MembershipTypes for Test {
+    type MemberId = u64;
+    type ActorId = u64;
+}
+
 impl membership::Trait for Test {
     type Event = ();
-    type MemberId = u64;
     type SubscriptionId = u32;
     type PaidTermId = u32;
-    type ActorId = u32;
     type ScreenedMemberMaxInitialBalance = ScreenedMemberMaxInitialBalance;
 }
 impl minting::Trait for Test {

+ 1 - 1
runtime-modules/hiring/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-hiring'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 1 - 1
runtime-modules/membership/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-membership'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 22 - 40
runtime-modules/membership/src/lib.rs

@@ -23,18 +23,11 @@ use sp_std::vec;
 use sp_std::vec::Vec;
 
 use common::currency::{BalanceOf, GovernanceCurrency};
-pub trait Trait: frame_system::Trait + GovernanceCurrency + pallet_timestamp::Trait {
+pub trait Trait:
+    frame_system::Trait + GovernanceCurrency + pallet_timestamp::Trait + common::MembershipTypes
+{
     type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
 
-    type MemberId: Parameter
-        + Member
-        + BaseArithmetic
-        + Codec
-        + Default
-        + Copy
-        + MaybeSerialize
-        + PartialEq;
-
     type PaidTermId: Parameter
         + Member
         + BaseArithmetic
@@ -53,17 +46,6 @@ pub trait Trait: frame_system::Trait + GovernanceCurrency + pallet_timestamp::Tr
         + MaybeSerialize
         + PartialEq;
 
-    /// Describes the common type for the working group members (workers).
-    type ActorId: Parameter
-        + Member
-        + BaseArithmetic
-        + Codec
-        + Default
-        + Copy
-        + MaybeSerialize
-        + PartialEq
-        + Ord;
-
     /// The maximum amount of initial funds that may be endowed to new members added by
     /// screening authority. If set to zero, no initial balance can be given.
     type ScreenedMemberMaxInitialBalance: Get<BalanceOf<Self>>;
@@ -246,13 +228,13 @@ decl_storage! {
 decl_event! {
     pub enum Event<T> where
       <T as frame_system::Trait>::AccountId,
-      <T as Trait>::MemberId,
+      <T as common::MembershipTypes>::MemberId,
       <T as Trait>::PaidTermId,
     {
         MemberRegistered(MemberId, AccountId, EntryMethod<PaidTermId, AccountId>),
-        MemberUpdatedAboutText(MemberId),
-        MemberUpdatedAvatar(MemberId),
-        MemberUpdatedHandle(MemberId),
+        MemberUpdatedAboutText(MemberId, Vec<u8>),
+        MemberUpdatedAvatar(MemberId, Vec<u8>),
+        MemberUpdatedHandle(MemberId, Vec<u8>),
         MemberSetRootAccount(MemberId, AccountId),
         MemberSetControllerAccount(MemberId, AccountId),
     }
@@ -312,7 +294,7 @@ decl_module! {
 
             ensure!(membership.controller_account == sender, Error::<T>::ControllerAccountRequired);
 
-            Self::_change_member_about_text(member_id, &text)?;
+            Self::_change_member_about_text(member_id, text)?;
         }
 
         /// Change member's avatar
@@ -324,7 +306,7 @@ decl_module! {
 
             ensure!(membership.controller_account == sender, Error::<T>::ControllerAccountRequired);
 
-            Self::_change_member_avatar(member_id, &uri)?;
+            Self::_change_member_avatar(member_id, uri)?;
         }
 
         /// Change member's handle. Will ensure new handle is unique and old one will be available
@@ -356,10 +338,10 @@ decl_module! {
             ensure!(membership.controller_account == sender, Error::<T>::ControllerAccountRequired);
 
             if let Some(uri) = avatar_uri {
-                Self::_change_member_avatar(member_id, &uri)?;
+                Self::_change_member_avatar(member_id, uri)?;
             }
             if let Some(about) = about {
-                Self::_change_member_about_text(member_id, &about)?;
+                Self::_change_member_about_text(member_id, about)?;
             }
             if let Some(handle) = handle {
                 Self::_change_member_handle(member_id, handle)?;
@@ -588,8 +570,8 @@ impl<T: Trait> Module<T> {
         Ok(())
     }
 
-    fn validate_text(text: &[u8]) -> Vec<u8> {
-        let mut text = text.to_owned();
+    fn validate_text(text: Vec<u8>) -> Vec<u8> {
+        let mut text = text;
         text.truncate(Self::max_about_text_length() as usize);
         text
     }
@@ -612,7 +594,7 @@ impl<T: Trait> Module<T> {
         let handle = handle.ok_or(Error::<T>::HandleMustBeProvidedDuringRegistration)?;
         Self::validate_handle(&handle)?;
 
-        let about = Self::validate_text(&about.unwrap_or_default());
+        let about = Self::validate_text(about.unwrap_or_default());
         let avatar_uri = avatar_uri.unwrap_or_default();
         Self::validate_avatar(&avatar_uri)?;
 
@@ -662,20 +644,20 @@ impl<T: Trait> Module<T> {
         Ok(new_member_id)
     }
 
-    fn _change_member_about_text(id: T::MemberId, text: &[u8]) -> DispatchResult {
+    fn _change_member_about_text(id: T::MemberId, text: Vec<u8>) -> DispatchResult {
         let mut membership = Self::ensure_membership(id)?;
         let text = Self::validate_text(text);
-        membership.about = text;
-        Self::deposit_event(RawEvent::MemberUpdatedAboutText(id));
+        membership.about = text.clone();
+        Self::deposit_event(RawEvent::MemberUpdatedAboutText(id, text));
         <MembershipById<T>>::insert(id, membership);
         Ok(())
     }
 
-    fn _change_member_avatar(id: T::MemberId, uri: &[u8]) -> DispatchResult {
+    fn _change_member_avatar(id: T::MemberId, uri: Vec<u8>) -> DispatchResult {
         let mut membership = Self::ensure_membership(id)?;
-        Self::validate_avatar(uri)?;
+        Self::validate_avatar(&uri)?;
         membership.avatar_uri = uri.to_owned();
-        Self::deposit_event(RawEvent::MemberUpdatedAvatar(id));
+        Self::deposit_event(RawEvent::MemberUpdatedAvatar(id, uri));
         <MembershipById<T>>::insert(id, membership);
         Ok(())
     }
@@ -686,8 +668,8 @@ impl<T: Trait> Module<T> {
         Self::ensure_unique_handle(&handle)?;
         <MemberIdByHandle<T>>::remove(&membership.handle);
         <MemberIdByHandle<T>>::insert(handle.clone(), id);
-        membership.handle = handle;
-        Self::deposit_event(RawEvent::MemberUpdatedHandle(id));
+        membership.handle = handle.clone();
+        Self::deposit_event(RawEvent::MemberUpdatedHandle(id, handle));
         <MembershipById<T>>::insert(id, membership);
         Ok(())
     }

+ 5 - 2
runtime-modules/membership/src/mock.rs

@@ -86,12 +86,15 @@ parameter_types! {
     pub const ScreenedMemberMaxInitialBalance: u64 = 500;
 }
 
+impl common::MembershipTypes for Test {
+    type MemberId = u64;
+    type ActorId = u64;
+}
+
 impl Trait for Test {
     type Event = ();
-    type MemberId = u64;
     type PaidTermId = u32;
     type SubscriptionId = u32;
-    type ActorId = u32;
     type ScreenedMemberMaxInitialBalance = ScreenedMemberMaxInitialBalance;
 }
 

+ 1 - 1
runtime-modules/memo/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-memo'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 1 - 1
runtime-modules/proposals/codex/src/lib.rs

@@ -181,7 +181,7 @@ pub type NegativeImbalance<T> = <<T as stake::Trait>::Currency as Currency<
     <T as frame_system::Trait>::AccountId,
 >>::NegativeImbalance;
 
-type MemberId<T> = <T as membership::Trait>::MemberId;
+type MemberId<T> = <T as common::MembershipTypes>::MemberId;
 
 decl_error! {
     /// Codex module predefined errors

+ 5 - 2
runtime-modules/proposals/codex/src/tests/mock.rs

@@ -50,12 +50,15 @@ parameter_types! {
     pub const ScreenedMemberMaxInitialBalance: u64 = 500;
 }
 
+impl common::MembershipTypes for Test {
+    type MemberId = u64;
+    type ActorId = u64;
+}
+
 impl membership::Trait for Test {
     type Event = ();
-    type MemberId = u64;
     type PaidTermId = u64;
     type SubscriptionId = u64;
-    type ActorId = u64;
     type ScreenedMemberMaxInitialBalance = ScreenedMemberMaxInitialBalance;
 }
 

+ 1 - 1
runtime-modules/proposals/discussion/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-proposals-discussion'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 1 - 1
runtime-modules/proposals/discussion/src/lib.rs

@@ -59,7 +59,7 @@ use sp_std::vec::Vec;
 use common::origin::ActorOriginValidator;
 use types::{DiscussionPost, DiscussionThread, ThreadCounter};
 
-type MemberId<T> = <T as membership::Trait>::MemberId;
+type MemberId<T> = <T as common::MembershipTypes>::MemberId;
 
 decl_event!(
     /// Proposals engine events

+ 5 - 2
runtime-modules/proposals/discussion/src/tests/mock.rs

@@ -77,12 +77,15 @@ parameter_types! {
     pub const ScreenedMemberMaxInitialBalance: u64 = 500;
 }
 
+impl common::MembershipTypes for Test {
+    type MemberId = u64;
+    type ActorId = u64;
+}
+
 impl membership::Trait for Test {
     type Event = TestEvent;
-    type MemberId = u64;
     type PaidTermId = u64;
     type SubscriptionId = u64;
-    type ActorId = u64;
     type ScreenedMemberMaxInitialBalance = ScreenedMemberMaxInitialBalance;
 }
 

+ 1 - 1
runtime-modules/proposals/engine/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-proposals-engine'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 1 - 1
runtime-modules/proposals/engine/src/lib.rs

@@ -143,7 +143,7 @@ use sp_std::vec::Vec;
 
 use common::origin::ActorOriginValidator;
 
-type MemberId<T> = <T as membership::Trait>::MemberId;
+type MemberId<T> = <T as common::MembershipTypes>::MemberId;
 
 /// Proposals engine trait.
 pub trait Trait:

+ 5 - 2
runtime-modules/proposals/engine/src/tests/mock/mod.rs

@@ -90,12 +90,15 @@ parameter_types! {
     pub const ScreenedMemberMaxInitialBalance: u64 = 500;
 }
 
+impl common::MembershipTypes for Test {
+    type MemberId = u64;
+    type ActorId = u64;
+}
+
 impl membership::Trait for Test {
     type Event = TestEvent;
-    type MemberId = u64;
     type PaidTermId = u64;
     type SubscriptionId = u64;
-    type ActorId = u64;
     type ScreenedMemberMaxInitialBalance = ScreenedMemberMaxInitialBalance;
 }
 

+ 1 - 1
runtime-modules/recurring-reward/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-recurring-reward'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 1 - 1
runtime-modules/stake/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-stake'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 2 - 2
runtime-modules/storage/src/lib.rs

@@ -452,10 +452,10 @@ pub type Cid = Vec<u8>;
 type Balances<T> = balances::Module<T>;
 
 /// Alias for the member id.
-pub type MemberId<T> = <T as membership::Trait>::MemberId;
+pub type MemberId<T> = <T as common::MembershipTypes>::MemberId;
 
 /// Type identifier for worker role, which must be same as membership actor identifier
-pub type WorkerId<T> = <T as membership::Trait>::ActorId;
+pub type WorkerId<T> = <T as common::MembershipTypes>::ActorId;
 
 /// Balance alias for `balances` module.
 pub type BalanceOf<T> = <T as balances::Trait>::Balance;

+ 5 - 2
runtime-modules/storage/src/tests/mocks.rs

@@ -189,12 +189,15 @@ parameter_types! {
     pub const ScreenedMemberMaxInitialBalance: u64 = 5000;
 }
 
+impl common::MembershipTypes for Test {
+    type MemberId = u64;
+    type ActorId = u64;
+}
+
 impl membership::Trait for Test {
     type Event = TestEvent;
-    type MemberId = u64;
     type PaidTermId = u64;
     type SubscriptionId = u64;
-    type ActorId = u64;
     type ScreenedMemberMaxInitialBalance = ();
 }
 

+ 1 - 1
runtime-modules/token-minting/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-token-mint'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 1 - 1
runtime-modules/working-group/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'pallet-working-group'
-version = '3.1.1'
+version = '3.2.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 2 - 2
runtime-modules/working-group/src/lib.rs

@@ -78,7 +78,7 @@ pub use types::{
 pub type StakeId<T> = <T as stake::Trait>::StakeId;
 
 /// Member identifier in membership::member module
-pub type MemberId<T> = <T as membership::Trait>::MemberId;
+pub type MemberId<T> = <T as common::MembershipTypes>::MemberId;
 
 /// Workaround for BTreeSet type
 pub type ApplicationIdSet<T> = BTreeSet<ApplicationId<T>>;
@@ -109,7 +109,7 @@ pub type NegativeImbalance<T> = <<T as stake::Trait>::Currency as Currency<
 pub type ApplicationIdToWorkerIdMap<T> = BTreeMap<ApplicationId<T>, WorkerId<T>>;
 
 /// Type identifier for worker role, which must be same as membership actor identifier
-pub type WorkerId<T> = <T as membership::Trait>::ActorId;
+pub type WorkerId<T> = <T as common::MembershipTypes>::ActorId;
 
 /// Alias for the application id from the hiring module.
 pub type HiringApplicationId<T> = <T as hiring::Trait>::ApplicationId;

+ 5 - 2
runtime-modules/working-group/src/tests/mock.rs

@@ -101,12 +101,15 @@ parameter_types! {
     pub const ScreenedMemberMaxInitialBalance: u64 = 500;
 }
 
+impl common::MembershipTypes for Test {
+    type MemberId = u64;
+    type ActorId = u64;
+}
+
 impl membership::Trait for Test {
     type Event = TestEvent;
-    type MemberId = u64;
     type PaidTermId = u64;
     type SubscriptionId = u64;
-    type ActorId = u64;
     type ScreenedMemberMaxInitialBalance = ScreenedMemberMaxInitialBalance;
 }
 

+ 1 - 1
runtime/src/integration/proposals/membership_origin_validator.rs

@@ -6,7 +6,7 @@ use common::origin::ActorOriginValidator;
 use frame_system::ensure_signed;
 
 /// Member of the Joystream organization
-pub type MemberId<T> = <T as membership::Trait>::MemberId;
+pub type MemberId<T> = <T as common::MembershipTypes>::MemberId;
 
 /// Default membership actor origin validator.
 pub struct MembershipOriginValidator<T> {

+ 9 - 1
runtime/src/integration/proposals/proposal_encoder.rs

@@ -23,7 +23,15 @@ macro_rules! wrap_working_group_call {
             WorkingGroup::Distribution => {
                 Call::DistributionWorkingGroup($working_group_instance_call)
             }
-            WorkingGroup::Operations => Call::OperationsWorkingGroup($working_group_instance_call),
+            WorkingGroup::OperationsAlpha => {
+                Call::OperationsWorkingGroupAlpha($working_group_instance_call)
+            }
+            WorkingGroup::OperationsBeta => {
+                Call::OperationsWorkingGroupBeta($working_group_instance_call)
+            }
+            WorkingGroup::OperationsGamma => {
+                Call::OperationsWorkingGroupGamma($working_group_instance_call)
+            }
             WorkingGroup::Gateway => Call::GatewayWorkingGroup($working_group_instance_call),
         }
     }};

+ 88 - 156
runtime/src/integration/working_group.rs

@@ -2,185 +2,117 @@ use frame_support::StorageMap;
 use sp_std::marker::PhantomData;
 
 use crate::{
-    ContentWorkingGroupInstance, GatewayWorkingGroupInstance, OperationsWorkingGroupInstance,
-    StorageWorkingGroupInstance,
+    ContentWorkingGroupInstance, DistributionWorkingGroupInstance, GatewayWorkingGroupInstance,
+    OperationsWorkingGroupInstanceAlpha, OperationsWorkingGroupInstanceBeta,
+    OperationsWorkingGroupInstanceGamma, StorageWorkingGroupInstance,
 };
 use stake::{BalanceOf, NegativeImbalance};
 
+macro_rules! wg_staking_event_impl {
+    ($operation_wg_instance:ident, $operation_wg_staking_event_handler:ty) => {
+        impl<T: stake::Trait + working_group::Trait<$operation_wg_instance>>
+            stake::StakingEventsHandler<T> for $operation_wg_staking_event_handler
+        {
+            /// Unstake remaining sum back to the source_account_id
+            fn unstaked(
+                stake_id: &<T as stake::Trait>::StakeId,
+                _unstaked_amount: BalanceOf<T>,
+                remaining_imbalance: NegativeImbalance<T>,
+            ) -> NegativeImbalance<T> {
+                // Stake not related to a staked role managed by the hiring module.
+                if !hiring::ApplicationIdByStakingId::<T>::contains_key(*stake_id) {
+                return remaining_imbalance;
+            }
+
+            let hiring_application_id = hiring::ApplicationIdByStakingId::<T>::get(*stake_id);
+
+            if working_group::MemberIdByHiringApplicationId::<T, $operation_wg_instance>::contains_key(
+                hiring_application_id,
+            ) {
+                return <working_group::Module<T, $operation_wg_instance>>::refund_working_group_stake(
+                *stake_id,
+                remaining_imbalance,
+                );
+            }
+
+                remaining_imbalance
+            }
+
+            /// Empty handler for the slashing.
+            fn slashed(
+                _: &<T as stake::Trait>::StakeId,
+                _: Option<<T as stake::Trait>::SlashId>,
+                _: BalanceOf<T>,
+                _: BalanceOf<T>,
+                remaining_imbalance: NegativeImbalance<T>,
+            ) -> NegativeImbalance<T> {
+                remaining_imbalance
+            }
+        }
+    }
+}
+
 // Will be removed in the next releases.
 #[allow(clippy::upper_case_acronyms)]
 pub struct ContentDirectoryWgStakingEventsHandler<T> {
     pub marker: PhantomData<T>,
 }
 
-impl<T: stake::Trait + working_group::Trait<ContentWorkingGroupInstance>>
-    stake::StakingEventsHandler<T> for ContentDirectoryWgStakingEventsHandler<T>
-{
-    /// Unstake remaining sum back to the source_account_id
-    fn unstaked(
-        stake_id: &<T as stake::Trait>::StakeId,
-        _unstaked_amount: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        // Stake not related to a staked role managed by the hiring module.
-        if !hiring::ApplicationIdByStakingId::<T>::contains_key(*stake_id) {
-            return remaining_imbalance;
-        }
-
-        let hiring_application_id = hiring::ApplicationIdByStakingId::<T>::get(*stake_id);
-
-        if working_group::MemberIdByHiringApplicationId::<T, ContentWorkingGroupInstance>::contains_key(
-            hiring_application_id,
-        ) {
-            return <working_group::Module<T, ContentWorkingGroupInstance>>::refund_working_group_stake(
-				*stake_id,
-				remaining_imbalance,
-			);
-        }
-
-        remaining_imbalance
-    }
-
-    /// Empty handler for the slashing.
-    fn slashed(
-        _: &<T as stake::Trait>::StakeId,
-        _: Option<<T as stake::Trait>::SlashId>,
-        _: BalanceOf<T>,
-        _: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        remaining_imbalance
-    }
-}
-
 pub struct StorageWgStakingEventsHandler<T> {
     pub marker: PhantomData<T>,
 }
 
-impl<T: stake::Trait + working_group::Trait<StorageWorkingGroupInstance>>
-    stake::StakingEventsHandler<T> for StorageWgStakingEventsHandler<T>
-{
-    /// Unstake remaining sum back to the source_account_id
-    fn unstaked(
-        stake_id: &<T as stake::Trait>::StakeId,
-        _unstaked_amount: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        // Stake not related to a staked role managed by the hiring module.
-        if !hiring::ApplicationIdByStakingId::<T>::contains_key(*stake_id) {
-            return remaining_imbalance;
-        }
-
-        let hiring_application_id = hiring::ApplicationIdByStakingId::<T>::get(*stake_id);
-
-        if working_group::MemberIdByHiringApplicationId::<T, StorageWorkingGroupInstance>::contains_key(
-            hiring_application_id,
-        ) {
-            return <working_group::Module<T, StorageWorkingGroupInstance>>::refund_working_group_stake(
-				*stake_id,
-				remaining_imbalance,
-			);
-        }
-
-        remaining_imbalance
-    }
-
-    /// Empty handler for the slashing.
-    fn slashed(
-        _: &<T as stake::Trait>::StakeId,
-        _: Option<<T as stake::Trait>::SlashId>,
-        _: BalanceOf<T>,
-        _: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        remaining_imbalance
-    }
+pub struct OperationsWgStakingEventsHandlerAlpha<T> {
+    pub marker: PhantomData<T>,
 }
 
-pub struct OperationsWgStakingEventsHandler<T> {
+pub struct OperationsWgStakingEventsHandlerBeta<T> {
     pub marker: PhantomData<T>,
 }
 
-impl<T: stake::Trait + working_group::Trait<OperationsWorkingGroupInstance>>
-    stake::StakingEventsHandler<T> for OperationsWgStakingEventsHandler<T>
-{
-    /// Unstake remaining sum back to the source_account_id
-    fn unstaked(
-        stake_id: &<T as stake::Trait>::StakeId,
-        _unstaked_amount: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        // Stake not related to a staked role managed by the hiring module.
-        if !hiring::ApplicationIdByStakingId::<T>::contains_key(*stake_id) {
-            return remaining_imbalance;
-        }
-
-        let hiring_application_id = hiring::ApplicationIdByStakingId::<T>::get(*stake_id);
-
-        if working_group::MemberIdByHiringApplicationId::<T, OperationsWorkingGroupInstance>::contains_key(
-            hiring_application_id,
-        ) {
-            return <working_group::Module<T, OperationsWorkingGroupInstance>>::refund_working_group_stake(
-				*stake_id,
-				remaining_imbalance,
-			);
-        }
-
-        remaining_imbalance
-    }
-
-    /// Empty handler for the slashing.
-    fn slashed(
-        _: &<T as stake::Trait>::StakeId,
-        _: Option<<T as stake::Trait>::SlashId>,
-        _: BalanceOf<T>,
-        _: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        remaining_imbalance
-    }
+pub struct OperationsWgStakingEventsHandlerGamma<T> {
+    pub marker: PhantomData<T>,
 }
 
 pub struct GatewayWgStakingEventsHandler<T> {
     pub marker: PhantomData<T>,
 }
 
-impl<T: stake::Trait + working_group::Trait<GatewayWorkingGroupInstance>>
-    stake::StakingEventsHandler<T> for GatewayWgStakingEventsHandler<T>
-{
-    /// Unstake remaining sum back to the source_account_id
-    fn unstaked(
-        stake_id: &<T as stake::Trait>::StakeId,
-        _unstaked_amount: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        // Stake not related to a staked role managed by the hiring module.
-        if !hiring::ApplicationIdByStakingId::<T>::contains_key(*stake_id) {
-            return remaining_imbalance;
-        }
-
-        let hiring_application_id = hiring::ApplicationIdByStakingId::<T>::get(*stake_id);
-
-        if working_group::MemberIdByHiringApplicationId::<T, GatewayWorkingGroupInstance>::contains_key(
-            hiring_application_id,
-        ) {
-            return <working_group::Module<T, GatewayWorkingGroupInstance>>::refund_working_group_stake(
-				*stake_id,
-				remaining_imbalance,
-			);
-        }
+pub struct DistributionWgStakingEventsHandler<T> {
+    pub marker: PhantomData<T>,
+}
 
-        remaining_imbalance
-    }
+wg_staking_event_impl!(
+    ContentWorkingGroupInstance,
+    ContentDirectoryWgStakingEventsHandler<T>
+);
 
-    /// Empty handler for the slashing.
-    fn slashed(
-        _: &<T as stake::Trait>::StakeId,
-        _: Option<<T as stake::Trait>::SlashId>,
-        _: BalanceOf<T>,
-        _: BalanceOf<T>,
-        remaining_imbalance: NegativeImbalance<T>,
-    ) -> NegativeImbalance<T> {
-        remaining_imbalance
-    }
-}
+wg_staking_event_impl!(
+    StorageWorkingGroupInstance,
+    StorageWgStakingEventsHandler<T>
+);
+
+wg_staking_event_impl!(
+    GatewayWorkingGroupInstance,
+    GatewayWgStakingEventsHandler<T>
+);
+
+wg_staking_event_impl!(
+    OperationsWorkingGroupInstanceAlpha,
+    OperationsWgStakingEventsHandlerAlpha<T>
+);
+
+wg_staking_event_impl!(
+    OperationsWorkingGroupInstanceBeta,
+    OperationsWgStakingEventsHandlerBeta<T>
+);
+
+wg_staking_event_impl!(
+    OperationsWorkingGroupInstanceGamma,
+    OperationsWgStakingEventsHandlerGamma<T>
+);
+
+wg_staking_event_impl!(
+    DistributionWorkingGroupInstance,
+    DistributionWgStakingEventsHandler<T>
+);

+ 35 - 11
runtime/src/lib.rs

@@ -471,15 +471,24 @@ impl stake::Trait for Runtime {
     type Currency = <Self as common::currency::GovernanceCurrency>::Currency;
     type StakePoolId = StakePoolId;
     type StakingEventsHandler = (
-        crate::integration::proposals::StakingEventsHandler<Self>,
         (
             (
+                crate::integration::proposals::StakingEventsHandler<Self>,
                 crate::integration::working_group::ContentDirectoryWgStakingEventsHandler<Self>,
+            ),
+            (
                 crate::integration::working_group::StorageWgStakingEventsHandler<Self>,
+                crate::integration::working_group::OperationsWgStakingEventsHandlerAlpha<Self>,
+            ),
+        ),
+        (
+            (
+                crate::integration::working_group::OperationsWgStakingEventsHandlerBeta<Self>,
+                crate::integration::working_group::OperationsWgStakingEventsHandlerGamma<Self>,
             ),
             (
-                crate::integration::working_group::OperationsWgStakingEventsHandler<Self>,
                 crate::integration::working_group::GatewayWgStakingEventsHandler<Self>,
+                crate::integration::working_group::DistributionWgStakingEventsHandler<Self>,
             ),
         ),
     );
@@ -522,10 +531,8 @@ parameter_types! {
 
 impl membership::Trait for Runtime {
     type Event = Event;
-    type MemberId = MemberId;
     type PaidTermId = u64;
     type SubscriptionId = u64;
-    type ActorId = ActorId;
     type ScreenedMemberMaxInitialBalance = ScreenedMemberMaxInitialBalance;
 }
 
@@ -545,12 +552,18 @@ pub type ContentWorkingGroupInstance = working_group::Instance3;
 // The distribution working group instance alias.
 pub type DistributionWorkingGroupInstance = working_group::Instance6;
 
-// The builder working group instance alias.
-pub type OperationsWorkingGroupInstance = working_group::Instance4;
-
 // The gateway working group instance alias.
 pub type GatewayWorkingGroupInstance = working_group::Instance5;
 
+// The operation working group alpha instance alias.
+pub type OperationsWorkingGroupInstanceAlpha = working_group::Instance4;
+
+// The operation working group beta instance alias .
+pub type OperationsWorkingGroupInstanceBeta = working_group::Instance7;
+
+// The operation working group gamma instance alias .
+pub type OperationsWorkingGroupInstanceGamma = working_group::Instance8;
+
 parameter_types! {
     pub const MaxWorkerNumberLimit: u32 = 100;
 }
@@ -570,7 +583,7 @@ impl working_group::Trait<DistributionWorkingGroupInstance> for Runtime {
     type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
 }
 
-impl working_group::Trait<OperationsWorkingGroupInstance> for Runtime {
+impl working_group::Trait<OperationsWorkingGroupInstanceAlpha> for Runtime {
     type Event = Event;
     type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
 }
@@ -580,6 +593,16 @@ impl working_group::Trait<GatewayWorkingGroupInstance> for Runtime {
     type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
 }
 
+impl working_group::Trait<OperationsWorkingGroupInstanceBeta> for Runtime {
+    type Event = Event;
+    type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
+}
+
+impl working_group::Trait<OperationsWorkingGroupInstanceGamma> for Runtime {
+    type Event = Event;
+    type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
+}
+
 parameter_types! {
     pub const ProposalCancellationFee: u64 = 10000;
     pub const ProposalRejectionFee: u64 = 5000;
@@ -779,14 +802,15 @@ construct_runtime!(
         ProposalsEngine: proposals_engine::{Module, Call, Storage, Event<T>},
         ProposalsDiscussion: proposals_discussion::{Module, Call, Storage, Event<T>},
         ProposalsCodex: proposals_codex::{Module, Call, Storage, Config<T>},
+        Storage: storage::{Module, Call, Storage, Event<T>},
         // --- Working groups
         // reserved for the future use: ForumWorkingGroup: working_group::<Instance1>::{Module, Call, Storage, Config<T>, Event<T>},
         StorageWorkingGroup: working_group::<Instance2>::{Module, Call, Storage, Config<T>, Event<T>},
         ContentWorkingGroup: working_group::<Instance3>::{Module, Call, Storage, Config<T>, Event<T>},
-        OperationsWorkingGroup: working_group::<Instance4>::{Module, Call, Storage, Config<T>, Event<T>},
+        OperationsWorkingGroupAlpha: working_group::<Instance4>::{Module, Call, Storage, Config<T>, Event<T>},
         GatewayWorkingGroup: working_group::<Instance5>::{Module, Call, Storage, Config<T>, Event<T>},
         DistributionWorkingGroup: working_group::<Instance6>::{Module, Call, Storage, Config<T>, Event<T>},
-        //
-        Storage: storage::{Module, Call, Storage, Event<T>},
+        OperationsWorkingGroupBeta: working_group::<Instance7>::{Module, Call, Storage, Config<T>, Event<T>},
+        OperationsWorkingGroupGamma: working_group::<Instance8>::{Module, Call, Storage, Config<T>, Event<T>},
     }
 );

+ 0 - 4
runtime/src/primitives.rs

@@ -14,10 +14,6 @@ pub type TransactionPriority = u64;
 /// Alias for ContentId, used in various places.
 pub type ContentId = sp_core::H256;
 
-#[allow(clippy::upper_case_acronyms)]
-/// Alias for DAOId, used in various places.
-pub type DAOId = u64;
-
 /// Alias for DataObjectTypeId, used in various places.
 pub type DataObjectTypeId = u64;
 

+ 169 - 45
runtime/src/tests/proposals_integration/working_group_proposals.rs

@@ -13,8 +13,10 @@ use working_group::{OpeningPolicyCommitment, RewardPolicy};
 use crate::{
     Balance, BlockNumber, ContentWorkingGroup, ContentWorkingGroupInstance,
     DistributionWorkingGroup, DistributionWorkingGroupInstance, GatewayWorkingGroup,
-    GatewayWorkingGroupInstance, OperationsWorkingGroup, OperationsWorkingGroupInstance,
-    StorageWorkingGroup, StorageWorkingGroupInstance,
+    GatewayWorkingGroupInstance, OperationsWorkingGroupAlpha, OperationsWorkingGroupBeta,
+    OperationsWorkingGroupGamma, OperationsWorkingGroupInstanceAlpha,
+    OperationsWorkingGroupInstanceBeta, OperationsWorkingGroupInstanceGamma, StorageWorkingGroup,
+    StorageWorkingGroupInstance,
 };
 use sp_std::collections::btree_set::BTreeSet;
 
@@ -62,11 +64,27 @@ fn add_opening(
             >>::contains_key(opening_id));
             opening_id
         }
-        WorkingGroup::Operations => {
-            let opening_id = OperationsWorkingGroup::next_opening_id();
+        WorkingGroup::OperationsAlpha => {
+            let opening_id = OperationsWorkingGroupAlpha::next_opening_id();
             assert!(!<working_group::OpeningById<
                 Runtime,
-                OperationsWorkingGroupInstance,
+                OperationsWorkingGroupInstanceAlpha,
+            >>::contains_key(opening_id));
+            opening_id
+        }
+        WorkingGroup::OperationsBeta => {
+            let opening_id = OperationsWorkingGroupBeta::next_opening_id();
+            assert!(!<working_group::OpeningById<
+                Runtime,
+                OperationsWorkingGroupInstanceBeta,
+            >>::contains_key(opening_id));
+            opening_id
+        }
+        WorkingGroup::OperationsGamma => {
+            let opening_id = OperationsWorkingGroupGamma::next_opening_id();
+            assert!(!<working_group::OpeningById<
+                Runtime,
+                OperationsWorkingGroupInstanceGamma,
             >>::contains_key(opening_id));
             opening_id
         }
@@ -362,10 +380,22 @@ fn create_add_working_group_leader_opening_proposal_execution_succeeds() {
                     DistributionWorkingGroupInstance,
                 >(group);
             }
-            WorkingGroup::Operations => {
+            WorkingGroup::OperationsAlpha => {
                 run_create_add_working_group_leader_opening_proposal_execution_succeeds::<
                     Runtime,
-                    OperationsWorkingGroupInstance,
+                    OperationsWorkingGroupInstanceAlpha,
+                >(group);
+            }
+            WorkingGroup::OperationsBeta => {
+                run_create_add_working_group_leader_opening_proposal_execution_succeeds::<
+                    Runtime,
+                    OperationsWorkingGroupInstanceBeta,
+                >(group);
+            }
+            WorkingGroup::OperationsGamma => {
+                run_create_add_working_group_leader_opening_proposal_execution_succeeds::<
+                    Runtime,
+                    OperationsWorkingGroupInstanceGamma,
                 >(group);
             }
             WorkingGroup::Gateway => {
@@ -384,7 +414,7 @@ fn run_create_add_working_group_leader_opening_proposal_execution_succeeds<
 >(
     working_group: WorkingGroup,
 ) where
-    <T as membership::Trait>::MemberId: From<u64>,
+    <T as common::MembershipTypes>::MemberId: From<u64>,
     <T as hiring::Trait>::OpeningId: From<u64>,
 {
     initial_test_ext().execute_with(|| {
@@ -434,16 +464,29 @@ fn create_begin_review_working_group_leader_applications_proposal_execution_succ
             }
             WorkingGroup::Distribution => {
                 run_create_begin_review_working_group_leader_applications_proposal_execution_succeeds::<
-                Runtime,
+                    Runtime,
                     DistributionWorkingGroupInstance,
+                >(group);
+            }
+            WorkingGroup::OperationsAlpha => {
+                run_create_begin_review_working_group_leader_applications_proposal_execution_succeeds::<
+                Runtime,
+                OperationsWorkingGroupInstanceAlpha,
+            >(group);
+            }
+            WorkingGroup::OperationsBeta => {
+                run_create_begin_review_working_group_leader_applications_proposal_execution_succeeds::<
+                Runtime,
+                OperationsWorkingGroupInstanceBeta,
             >(group);
             }
-            WorkingGroup::Operations => {
+            WorkingGroup::OperationsGamma => {
                 run_create_begin_review_working_group_leader_applications_proposal_execution_succeeds::<
                 Runtime,
-                OperationsWorkingGroupInstance,
+                OperationsWorkingGroupInstanceGamma,
             >(group);
             }
+
             WorkingGroup::Gateway => {
                 run_create_begin_review_working_group_leader_applications_proposal_execution_succeeds::<
                 Runtime,
@@ -536,12 +579,25 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
                     DistributionWorkingGroupInstance,
                 >(group);
             }
-            WorkingGroup::Operations => {
+            WorkingGroup::OperationsAlpha => {
+                run_create_fill_working_group_leader_opening_proposal_execution_succeeds::<
+                    Runtime,
+                    OperationsWorkingGroupInstanceAlpha,
+                >(group);
+            }
+            WorkingGroup::OperationsBeta => {
+                run_create_fill_working_group_leader_opening_proposal_execution_succeeds::<
+                    Runtime,
+                    OperationsWorkingGroupInstanceBeta,
+                >(group);
+            }
+            WorkingGroup::OperationsGamma => {
                 run_create_fill_working_group_leader_opening_proposal_execution_succeeds::<
                     Runtime,
-                    OperationsWorkingGroupInstance,
+                    OperationsWorkingGroupInstanceGamma,
                 >(group);
             }
+
             WorkingGroup::Gateway => {
                 run_create_fill_working_group_leader_opening_proposal_execution_succeeds::<
                     Runtime,
@@ -558,7 +614,7 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
         working_group: WorkingGroup,
     ) where
         <T as frame_system::Trait>::AccountId: From<[u8; 32]>,
-        <T as membership::Trait>::MemberId: From<u64>,
+        <T as common::MembershipTypes>::MemberId: From<u64>,
         <T as hiring::Trait>::OpeningId: From<u64>,
     {
         initial_test_ext().execute_with(|| {
@@ -631,12 +687,25 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
                         DistributionWorkingGroupInstance,
                     >(group);
                 }
-                WorkingGroup::Operations => {
+                WorkingGroup::OperationsAlpha => {
+                    run_create_decrease_group_leader_stake_proposal_execution_succeeds::<
+                        Runtime,
+                        OperationsWorkingGroupInstanceAlpha,
+                    >(group);
+                }
+                WorkingGroup::OperationsBeta => {
+                    run_create_decrease_group_leader_stake_proposal_execution_succeeds::<
+                        Runtime,
+                        OperationsWorkingGroupInstanceBeta,
+                    >(group);
+                }
+                WorkingGroup::OperationsGamma => {
                     run_create_decrease_group_leader_stake_proposal_execution_succeeds::<
                         Runtime,
-                        OperationsWorkingGroupInstance,
+                        OperationsWorkingGroupInstanceGamma,
                     >(group);
                 }
+
                 WorkingGroup::Gateway => {
                     run_create_decrease_group_leader_stake_proposal_execution_succeeds::<
                         Runtime,
@@ -655,8 +724,8 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
     ) where
         <T as frame_system::Trait>::AccountId: From<[u8; 32]>,
         <T as hiring::Trait>::OpeningId: From<u64>,
-        <T as membership::Trait>::MemberId: From<u64>,
-        <T as membership::Trait>::ActorId: Into<u64>,
+        <T as common::MembershipTypes>::MemberId: From<u64>,
+        <T as common::MembershipTypes>::ActorId: Into<u64>,
         <<T as stake::Trait>::Currency as traits::Currency<
             <T as frame_system::Trait>::AccountId,
         >>::Balance: From<u128>,
@@ -766,10 +835,22 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
                         DistributionWorkingGroupInstance,
                     >(group)
                 }
-                WorkingGroup::Operations => {
+                WorkingGroup::OperationsAlpha => {
+                    run_create_slash_group_leader_stake_proposal_execution_succeeds::<
+                        Runtime,
+                        OperationsWorkingGroupInstanceAlpha,
+                    >(group)
+                }
+                WorkingGroup::OperationsBeta => {
+                    run_create_slash_group_leader_stake_proposal_execution_succeeds::<
+                        Runtime,
+                        OperationsWorkingGroupInstanceBeta,
+                    >(group)
+                }
+                WorkingGroup::OperationsGamma => {
                     run_create_slash_group_leader_stake_proposal_execution_succeeds::<
                         Runtime,
-                        OperationsWorkingGroupInstance,
+                        OperationsWorkingGroupInstanceGamma,
                     >(group)
                 }
                 WorkingGroup::Gateway => {
@@ -790,8 +871,8 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
     ) where
         <T as frame_system::Trait>::AccountId: From<[u8; 32]>,
         <T as hiring::Trait>::OpeningId: From<u64>,
-        <T as membership::Trait>::MemberId: From<u64>,
-        <T as membership::Trait>::ActorId: Into<u64>,
+        <T as common::MembershipTypes>::MemberId: From<u64>,
+        <T as common::MembershipTypes>::ActorId: Into<u64>,
         <<T as stake::Trait>::Currency as traits::Currency<
             <T as frame_system::Trait>::AccountId,
         >>::Balance: From<u128>,
@@ -902,11 +983,23 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
                         DistributionWorkingGroupInstance,
                     >(group);
                 }
-                WorkingGroup::Operations => {
+                WorkingGroup::OperationsAlpha => {
                     run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
                         Runtime,
-                        OperationsWorkingGroupInstance,
-                    >(group);
+                        OperationsWorkingGroupInstanceAlpha,
+                    >(group)
+                }
+                WorkingGroup::OperationsBeta => {
+                    run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
+                        Runtime,
+                        OperationsWorkingGroupInstanceBeta,
+                    >(group)
+                }
+                WorkingGroup::OperationsGamma => {
+                    run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
+                        Runtime,
+                        OperationsWorkingGroupInstanceGamma,
+                    >(group)
                 }
                 WorkingGroup::Gateway => {
                     run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
@@ -924,7 +1017,7 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
             working_group: WorkingGroup,
         ) where
             <T as frame_system::Trait>::AccountId: From<[u8; 32]>,
-            <T as membership::Trait>::MemberId: From<u64>,
+            <T as common::MembershipTypes>::MemberId: From<u64>,
             <T as minting::Trait>::MintId: From<u64>,
             <<T as minting::Trait>::Currency as traits::Currency<
                 <T as frame_system::Trait>::AccountId,
@@ -959,31 +1052,43 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
             for group in WorkingGroup::iter() {
                 match group {
                     WorkingGroup::Content => {
-                        run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
+                        run_create_set_group_leader_reward_proposal_execution_succeeds::<
                             Runtime,
                             ContentWorkingGroupInstance,
                         >(group);
                     }
                     WorkingGroup::Storage => {
-                        run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
+                        run_create_set_group_leader_reward_proposal_execution_succeeds::<
                             Runtime,
                             StorageWorkingGroupInstance,
                         >(group);
                     }
                     WorkingGroup::Distribution => {
-                        run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
+                        run_create_set_group_leader_reward_proposal_execution_succeeds::<
                             Runtime,
                             DistributionWorkingGroupInstance,
                         >(group);
                     }
-                    WorkingGroup::Operations => {
-                        run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
+                    WorkingGroup::OperationsAlpha => {
+                        run_create_set_group_leader_reward_proposal_execution_succeeds::<
                             Runtime,
-                            OperationsWorkingGroupInstance,
-                        >(group);
+                            OperationsWorkingGroupInstanceAlpha,
+                        >(group)
+                    }
+                    WorkingGroup::OperationsBeta => {
+                        run_create_set_group_leader_reward_proposal_execution_succeeds::<
+                            Runtime,
+                            OperationsWorkingGroupInstanceBeta,
+                        >(group)
+                    }
+                    WorkingGroup::OperationsGamma => {
+                        run_create_set_group_leader_reward_proposal_execution_succeeds::<
+                            Runtime,
+                            OperationsWorkingGroupInstanceGamma,
+                        >(group)
                     }
                     WorkingGroup::Gateway => {
-                        run_create_set_working_group_mint_capacity_proposal_execution_succeeds::<
+                        run_create_set_group_leader_reward_proposal_execution_succeeds::<
                             Runtime,
                             GatewayWorkingGroupInstance,
                         >(group);
@@ -999,8 +1104,8 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
             working_group: WorkingGroup,
         ) where
             <T as frame_system::Trait>::AccountId: From<[u8; 32]>,
-            <T as membership::Trait>::MemberId: From<u64>,
-            <T as membership::Trait>::ActorId: Into<u64>,
+            <T as common::MembershipTypes>::MemberId: From<u64>,
+            <T as common::MembershipTypes>::ActorId: Into<u64>,
             <T as minting::Trait>::MintId: From<u64>,
             <T as hiring::Trait>::OpeningId: From<u64>,
             <<T as minting::Trait>::Currency as traits::Currency<
@@ -1117,12 +1222,25 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
                             DistributionWorkingGroupInstance,
                         >(group);
                     }
-                    WorkingGroup::Operations => {
+                    WorkingGroup::OperationsAlpha => {
                         run_create_terminate_group_leader_role_proposal_execution_succeeds::<
                             Runtime,
-                            OperationsWorkingGroupInstance,
-                        >(group);
+                            OperationsWorkingGroupInstanceAlpha,
+                        >(group)
+                    }
+                    WorkingGroup::OperationsBeta => {
+                        run_create_terminate_group_leader_role_proposal_execution_succeeds::<
+                            Runtime,
+                            OperationsWorkingGroupInstanceBeta,
+                        >(group)
+                    }
+                    WorkingGroup::OperationsGamma => {
+                        run_create_terminate_group_leader_role_proposal_execution_succeeds::<
+                            Runtime,
+                            OperationsWorkingGroupInstanceGamma,
+                        >(group)
                     }
+
                     WorkingGroup::Gateway => {
                         run_create_terminate_group_leader_role_proposal_execution_succeeds::<
                             Runtime,
@@ -1140,8 +1258,8 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
             working_group: WorkingGroup,
         ) where
             <T as frame_system::Trait>::AccountId: From<[u8; 32]>,
-            <T as membership::Trait>::MemberId: From<u64>,
-            <T as membership::Trait>::ActorId: Into<u64>,
+            <T as common::MembershipTypes>::MemberId: From<u64>,
+            <T as common::MembershipTypes>::ActorId: Into<u64>,
             <T as minting::Trait>::MintId: From<u64>,
             <T as hiring::Trait>::OpeningId: From<u64>,
             <<T as stake::Trait>::Currency as traits::Currency<
@@ -1251,8 +1369,14 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
                     WorkingGroup::Distribution => {
                         run_create_terminate_group_leader_role_proposal_with_slashing_execution_succeeds::<Runtime, DistributionWorkingGroupInstance>(group);
                     }
-                    WorkingGroup::Operations => {
-                        run_create_terminate_group_leader_role_proposal_with_slashing_execution_succeeds::<Runtime, OperationsWorkingGroupInstance>(group);
+                    WorkingGroup::OperationsAlpha => {
+                        run_create_terminate_group_leader_role_proposal_with_slashing_execution_succeeds::<Runtime, OperationsWorkingGroupInstanceAlpha>(group);
+                    }
+                    WorkingGroup::OperationsBeta => {
+                        run_create_terminate_group_leader_role_proposal_with_slashing_execution_succeeds::<Runtime, OperationsWorkingGroupInstanceBeta>(group);
+                    }
+                    WorkingGroup::OperationsGamma => {
+                        run_create_terminate_group_leader_role_proposal_with_slashing_execution_succeeds::<Runtime, OperationsWorkingGroupInstanceGamma>(group);
                     }
                     WorkingGroup::Gateway => {
                         run_create_terminate_group_leader_role_proposal_with_slashing_execution_succeeds::<Runtime, GatewayWorkingGroupInstance>(group);
@@ -1268,8 +1392,8 @@ fn create_fill_working_group_leader_opening_proposal_execution_succeeds() {
             working_group: WorkingGroup,
         ) where
             <T as frame_system::Trait>::AccountId: From<[u8; 32]>,
-            <T as membership::Trait>::MemberId: From<u64>,
-            <T as membership::Trait>::ActorId: Into<u64>,
+            <T as common::MembershipTypes>::MemberId: From<u64>,
+            <T as common::MembershipTypes>::ActorId: Into<u64>,
             <T as minting::Trait>::MintId: From<u64>,
             <T as hiring::Trait>::OpeningId: From<u64>,
             <<T as stake::Trait>::Currency as traits::Currency<

+ 6 - 4
types/augment-codec/augment-api-events.ts

@@ -565,9 +565,9 @@ declare module '@polkadot/api/types/events' {
       MemberRegistered: AugmentedEvent<ApiType, [MemberId, AccountId, EntryMethod]>;
       MemberSetControllerAccount: AugmentedEvent<ApiType, [MemberId, AccountId]>;
       MemberSetRootAccount: AugmentedEvent<ApiType, [MemberId, AccountId]>;
-      MemberUpdatedAboutText: AugmentedEvent<ApiType, [MemberId]>;
-      MemberUpdatedAvatar: AugmentedEvent<ApiType, [MemberId]>;
-      MemberUpdatedHandle: AugmentedEvent<ApiType, [MemberId]>;
+      MemberUpdatedAboutText: AugmentedEvent<ApiType, [MemberId, Bytes]>;
+      MemberUpdatedAvatar: AugmentedEvent<ApiType, [MemberId, Bytes]>;
+      MemberUpdatedHandle: AugmentedEvent<ApiType, [MemberId, Bytes]>;
     };
     memo: {
       MemoUpdated: AugmentedEvent<ApiType, [AccountId]>;
@@ -950,8 +950,10 @@ declare module '@polkadot/api/types/events' {
        * Params
        * - dynamic bag ID
        * - optional DynamicBagDeletionPrize instance
+       * - assigned storage buckets' IDs
+       * - assigned distribution buckets' IDs
        **/
-      DynamicBagCreated: AugmentedEvent<ApiType, [DynamicBagId, Option<DynamicBagDeletionPrizeRecord>]>;
+      DynamicBagCreated: AugmentedEvent<ApiType, [DynamicBagId, Option<DynamicBagDeletionPrizeRecord>, BTreeSet<StorageBucketId>, BTreeSet<DistributionBucketId>]>;
       /**
        * Emits on deleting a dynamic bag.
        * Params

+ 6 - 4
types/augment/augment-api-events.ts

@@ -565,9 +565,9 @@ declare module '@polkadot/api/types/events' {
       MemberRegistered: AugmentedEvent<ApiType, [MemberId, AccountId, EntryMethod]>;
       MemberSetControllerAccount: AugmentedEvent<ApiType, [MemberId, AccountId]>;
       MemberSetRootAccount: AugmentedEvent<ApiType, [MemberId, AccountId]>;
-      MemberUpdatedAboutText: AugmentedEvent<ApiType, [MemberId]>;
-      MemberUpdatedAvatar: AugmentedEvent<ApiType, [MemberId]>;
-      MemberUpdatedHandle: AugmentedEvent<ApiType, [MemberId]>;
+      MemberUpdatedAboutText: AugmentedEvent<ApiType, [MemberId, Bytes]>;
+      MemberUpdatedAvatar: AugmentedEvent<ApiType, [MemberId, Bytes]>;
+      MemberUpdatedHandle: AugmentedEvent<ApiType, [MemberId, Bytes]>;
     };
     memo: {
       MemoUpdated: AugmentedEvent<ApiType, [AccountId]>;
@@ -950,8 +950,10 @@ declare module '@polkadot/api/types/events' {
        * Params
        * - dynamic bag ID
        * - optional DynamicBagDeletionPrize instance
+       * - assigned storage buckets' IDs
+       * - assigned distribution buckets' IDs
        **/
-      DynamicBagCreated: AugmentedEvent<ApiType, [DynamicBagId, Option<DynamicBagDeletionPrizeRecord>]>;
+      DynamicBagCreated: AugmentedEvent<ApiType, [DynamicBagId, Option<DynamicBagDeletionPrizeRecord>, BTreeSet<StorageBucketId>, BTreeSet<DistributionBucketId>]>;
       /**
        * Emits on deleting a dynamic bag.
        * Params

+ 1 - 1
types/src/JoyEnum.ts

@@ -33,7 +33,7 @@ export function JoyEnum<Types extends Record<string, Constructor>>(types: Types)
     }
 
     // eslint-disable-next-line no-useless-constructor
-    constructor(registry: Registry, value?: any, index?: number) {
+    constructor(registry: Registry, value?: unknown, index?: number) {
       super(registry, value, index)
     }
 

+ 6 - 21
types/src/common.ts

@@ -1,7 +1,6 @@
 import { Struct, Option, Text, bool, u16, u32, u64, Null, U8aFixed, BTreeSet, UInt, u128 } from '@polkadot/types'
 import { BlockNumber, Hash as PolkadotHash, Moment } from '@polkadot/types/interfaces'
 import { Codec, Constructor, RegistryTypes } from '@polkadot/types/types'
-import { u8aConcat, u8aToHex, compactToU8a } from '@polkadot/util'
 // we get 'moment' because it is a dependency of @polkadot/util, via @polkadot/keyring
 import moment from 'moment'
 import { JoyStructCustom, JoyStructDecorated } from './JoyStruct'
@@ -16,30 +15,16 @@ export { JoyEnum, JoyStructCustom, JoyStructDecorated }
 export interface ExtendedBTreeSet<V extends UInt> extends BTreeSet<V> {
   toArray(): V[]
 }
+
 export function JoyBTreeSet<V extends UInt>(valType: Constructor<V>): Constructor<ExtendedBTreeSet<V>> {
   return class extends BTreeSet.with(valType) {
-    public toArray(): V[] {
-      return Array.from(this)
-    }
-
-    public toU8a(isBare?: boolean): Uint8Array {
-      const encoded = new Array<Uint8Array>()
-
-      if (!isBare) {
-        encoded.push(compactToU8a(this.size))
-      }
-
-      const sorted = Array.from(this).sort((a, b) => (a.lt(b) ? -1 : 1))
-
-      sorted.forEach((v: V) => {
-        encoded.push(v.toU8a(isBare))
-      })
-
-      return u8aConcat(...encoded)
+    public forEach(callbackFn: (value: V, value2: V, set: Set<V>) => void, thisArg?: unknown): void {
+      const sorted = this.toArray()
+      return new Set(sorted).forEach(callbackFn, thisArg)
     }
 
-    public toHex(): string {
-      return u8aToHex(this.toU8a())
+    public toArray() {
+      return Array.from(this).sort((a, b) => (a.lt(b) ? -1 : 1))
     }
   }
 }

+ 1 - 1
types/src/index.ts

@@ -86,7 +86,7 @@ type CreateInterface_NoOption<T extends Codec> =
       ? CreateInterface<S>[]
       : T extends BTreeMap<infer K, infer V>
       ? Map<K, V>
-      : any)
+      : unknown)
 
 // Wrapper for CreateInterface_NoOption that includes resolving an Option
 // (nested Options like Option<Option<Codec>> will resolve to Option<any>, but there are very edge case)

+ 40 - 29
types/src/scripts/generateRegistryJson.ts

@@ -5,63 +5,74 @@ import { Constructor, Codec, RegistryTypes, Registry } from '@polkadot/types/typ
 import { TypeRegistry } from '@polkadot/types'
 import fs from 'fs'
 import path from 'path'
+import _ from 'lodash'
 
 const OUTPUT_PATH = path.join(__dirname, '../../augment/all/defs.json')
 
-function normalizeDef(registry: Registry, defOrConstructor: any, typeName: string): RegistryTypes[string] {
+function normalizeDef(registry: Registry, defOrConstructor: unknown, typeName: string): RegistryTypes[string] {
   if (typeof defOrConstructor === 'string') {
+    let typeName: string = defOrConstructor
     // Replace unhandled BTreeSet with Vec
     // FIXME: Remove after updating @polkadot/api!
-    defOrConstructor = defOrConstructor.replace('BTreeSet<', 'Vec<')
+    typeName = typeName.replace('BTreeSet<', 'Vec<')
     // Workaround for "Unhandled type VecFixed"
-    defOrConstructor = defOrConstructor.replace('[u8;32]', 'Hash')
-    return defOrConstructor
-  } else if (typeof defOrConstructor === 'function') {
-    const defString = new (defOrConstructor as Constructor<Codec>)(registry).toRawType().toString()
-    let obj: any
+    typeName = typeName.replace('[u8;32]', 'Hash')
+    return typeName
+  }
+
+  if (typeof defOrConstructor === 'function') {
+    const TypeConstructor = defOrConstructor as Constructor<Codec>
+    const defString = new TypeConstructor(registry).toRawType().toString()
+    let obj: RegistryTypes[string]
 
     try {
       obj = JSON.parse(defString)
     } catch (e) {
-      // def if just a type name:
+      // def is a string (type name)
       return defString
     }
 
-    // def is an object:
-    const normalizedObj: any = {}
-    if (obj._enum && Array.isArray(obj._enum)) {
-      // Enum as array - No need to normalize
+    // String (type name) - no need to normalize
+    if (typeof obj === 'string') {
       return obj
-    } else if (obj._enum && !Array.isArray(obj._enum)) {
-      // Enum as object - normalize properties
-      normalizedObj._enum = {}
-      Object.entries(obj._enum).forEach(([key, value]) => {
+    }
+
+    // Enum as array - no need to normalize
+    if (typeof obj === 'object' && '_enum' in obj && Array.isArray(obj._enum)) {
+      return obj
+    }
+
+    // Enum as object - normalize properties
+    if (typeof obj === 'object' && '_enum' in obj && typeof obj._enum === 'object' && !Array.isArray(obj._enum)) {
+      const normalizedEnumDef = _.mapValues(obj._enum, (value, key) => {
         const normalizedValue = normalizeDef(registry, value, `${typeName}[${key}]`)
         if (typeof normalizedValue !== 'string') {
           throw new Error(
             `Too many nested definitions in ${typeName} enum. Did you forget to expose some types in the registry?`
           )
         }
-        normalizedObj._enum[key] = normalizedValue
-      })
-    } else if (obj._set) {
-      // Set - we don't need those now, but perhaps worth looking into at some point
+        return normalizedValue
+      }) as Record<string, string>
+      return { _enum: normalizedEnumDef }
+    }
+
+    // Set - not supported now
+    if ('_set' in obj) {
       throw new Error('_set definitions are not supported yet!')
-    } else {
-      // Struct - normalize properties
-      for (const [key, value] of Object.entries(obj)) {
-        // Prevent interface clashes
+    }
+
+    // Struct - normalize properties
+    if (typeof obj === 'object' && !('_enum' in obj) && !('_set' in obj)) {
+      return _.mapValues(obj, (value, key) => {
         const normalizedValue = normalizeDef(registry, value, `${typeName}[${key}]`)
         if (typeof normalizedValue !== 'string') {
           throw new Error(
             `Too many nested definitions in ${typeName} struct. Did you forget to expose some types in the registry?`
           )
         }
-        normalizedObj[key] = normalizedValue
-      }
+        return normalizedValue
+      })
     }
-
-    return normalizedObj
   }
 
   throw new Error(`Unkown type entry for ${typeName} found in registry!`)
@@ -72,7 +83,7 @@ function defsFromTypes(types: RegistryTypes) {
   registry.setKnownTypes({ types })
   registry.register(types)
   const defs: RegistryTypes = {}
-  Object.entries(registry.knownTypes.types as any).forEach(([typeName, defOrConstructor]) => {
+  Object.entries(registry.knownTypes.types as Omit<RegistryTypes, string>).forEach(([typeName, defOrConstructor]) => {
     const def = normalizeDef(registry, defOrConstructor, typeName)
     defs[typeName] = def
   })