Browse Source

Merge pull request #120 from bwhm/examples-and-tools

Examples and tools
Martin 4 years ago
parent
commit
80ae09e0e0

+ 2 - 0
.gitignore

@@ -1,3 +1,5 @@
 .DS_Store
 node_modules/
 dist/
+lib/
+

+ 48 - 0
joystream-api/README.md

@@ -0,0 +1,48 @@
+# Joystream API Examples
+
+Repo with examples on how to use the @joystream/types package along with @polkadot/api to communicate with a joystream full node.
+
+
+## Examples
+
+```
+yarn && yarn build
+yarn run status
+```
+
+## Example code
+
+```javascript
+import { registerJoystreamTypes } from '@joystream/types';
+import { ApiPromise, WsProvider } from '@polkadot/api';
+
+async function main () {
+  // Initialise the provider to connect to the local node
+  const provider = new WsProvider('ws://127.0.0.1:9944');
+
+  // Register types before creating the API
+  registerJoystreamTypes();
+
+  // Create the API and wait until ready
+  const api = await ApiPromise.create({ provider });
+
+  // Retrieve the chain & node information information via rpc calls
+  const [chain, nodeName, nodeVersion] = await Promise.all([
+    api.rpc.system.chain(),
+    api.rpc.system.name(),
+    api.rpc.system.version()
+  ]);
+
+  console.log(`Chain ${chain} using ${nodeName} v${nodeVersion}`);
+}
+
+main();
+```
+
+### Scripts
+
+You can run scripts that are found in the [./scripts/](./scripts) folder:
+
+```sh
+yarn script example
+```

+ 26 - 0
joystream-api/package.json

@@ -0,0 +1,26 @@
+{
+  "name": "@joystream/api-examples",
+  "version": "0.1.0",
+  "main": "lib/index.js",
+  "license": "MIT",
+  "scripts": {
+    "build": "tsc --build tsconfig.json",
+    "status": "node lib/status",
+    "script": "node lib/script",
+    "postinstall": "yarn build"
+  },
+  "dependencies": {
+    "@joystream/types": "^0.14.0",
+    "@polkadot/api": "1.26.1",
+    "@polkadot/keyring": "^3.0.1",
+    "@polkadot/types": "1.26.1",
+    "@polkadot/util": "^3.0.1",
+    "@polkadot/util-crypto": "^3.0.1",
+    "@types/bn.js": "^4.11.5",
+    "bn.js": "^4.11.8"
+  },
+  "devDependencies": {
+    "@polkadot/ts": "^0.1.56",
+    "typescript": "^3.9.7"
+  }
+}

+ 32 - 0
joystream-api/scripts/example.js

@@ -0,0 +1,32 @@
+/* global api, hashing, keyring, types, util, window, joy */
+
+// run this script with:
+// yarn script example
+//
+// or copy and paste the code into the pioneer javascript toolbox at:
+// https://testnet.joystream.org/#/js
+// 
+// Example works on nicaea release+
+
+const script = async ({ api, hashing, keyring, types, util, joy }) => {
+  // Retrieve the chain & node information information via rpc calls
+  const [chain, nodeName, nodeVersion, runtimeVersion] = await Promise.all([
+    api.rpc.system.chain(),
+    api.rpc.system.name(),
+    api.rpc.system.version(),
+    api.runtimeVersion,
+  ]);
+
+  console.log(`Chain: ${chain}`)
+  console.log(`Software: ${nodeName} v${nodeVersion}`)
+  console.log(`Runtime specVersion: ${runtimeVersion.specVersion}`)
+}
+
+if (typeof module === 'undefined') {
+  // Pioneer js-toolbox
+  // Available globals [api, hashing, keyring, types, util]
+  script({ api, hashing, keyring, types, util, joy })
+} else {
+  // Node
+  module.exports = script
+}

+ 48 - 0
joystream-api/scripts/export-data-directory.js

@@ -0,0 +1,48 @@
+/* global api, hashing, keyring, types, util */
+
+// run this script with:
+// yarn script exportDataDirectory
+//
+// or copy and paste the code into the pioneer javascript toolbox at:
+// https://testnet.joystream.org/#/js
+
+const script = async ({ api, hashing, keyring, types, util }) => {
+  const runtimeSpecVersion = api.runtimeVersion.specVersion
+
+  const ownerAccountToMemberId = async (accountId) => {
+    const memberIds = await api.query.members.memberIdsByRootAccountId(accountId)
+    return memberIds[0] || null
+  }
+
+  const ids = await api.query.dataDirectory.knownContentIds()
+
+  // When a BTreeMap is constructed for injection the node will fail to decode
+  // it if its not sorted.
+  ids.sort()
+
+  let transformed = await Promise.all(ids.map(async (id) => {
+    let obj = await api.query.dataDirectory.dataObjectByContentId(id)
+    if (obj.isNone) { return null }
+    obj = obj.unwrap()
+
+    return [id, {
+      owner: runtimeSpecVersion <= 15 ? await ownerAccountToMemberId(obj.owner) : obj.owner,
+      added_at: obj.added_at,
+      type_id: obj.type_id,
+      size: obj.size_in_bytes,
+      liaison: runtimeSpecVersion <= 15 ? new types.u64(0) : obj.liaison,
+      liaison_judgement: obj.liaison_judgement,
+      ipfs_content_id: obj.ipfs_content_id }]
+  }))
+
+  console.log(JSON.stringify(transformed))
+  console.error(`Exported ${transformed.length} objects`)
+}
+
+if (typeof module === 'undefined') {
+  // Pioneer js-toolbox
+  script({ api, hashing, keyring, types, util })
+} else {
+  // Node
+  module.exports = script
+}

+ 10 - 0
joystream-api/scripts/index.js

@@ -0,0 +1,10 @@
+const typesVersion = require('@joystream/types/package.json')
+
+const exportedScripts = {}
+
+exportedScripts.example = require('./example.js')
+exportedScripts.exportDataDirectory = require('./export-data-directory.js')
+exportedScripts.injectDataObjects = require('./inject-data-objects.js')
+exportedScripts.listDataDirectory = require('./list-data-directory.js')
+
+module.exports = exportedScripts

File diff suppressed because it is too large
+ 17 - 0
joystream-api/scripts/inject-data-objects.js


+ 29 - 0
joystream-api/scripts/list-data-directory.js

@@ -0,0 +1,29 @@
+/* global api, hashing, keyring, types, util */
+
+// run this script with:
+// yarn script listDataDirectory
+//
+// or copy and paste the code into the pioneer javascript toolbox at:
+// https://testnet.joystream.org/#/js
+// requires nicaea release+
+
+const script = async ({ api, joy }) => {
+  const ids = await api.query.dataDirectory.knownContentIds()
+
+  await Promise.all(ids.map(async (id) => {
+    let obj = await api.query.dataDirectory.dataObjectByContentId(id)
+    if (obj.isNone) { return }
+    obj = obj.unwrap()
+    console.log(`contentId: ${new joy.media.ContentId(id).encode()}, ipfs: ${obj.ipfs_content_id}`)
+  }))
+
+  console.error(`Data Directory contains ${ids.length} objects`)
+}
+
+if (typeof module === 'undefined') {
+  // Pioneer js-toolbox
+  script({ api, hashing, keyring, types, util, joy })
+} else {
+  // Node
+  module.exports = script
+}

+ 113 - 0
joystream-api/src/curators/functions.ts

@@ -0,0 +1,113 @@
+import { Actor, CreateEntityOperation, EntityId, Entity, OperationType, UpdatePropertyValuesOperation } from "@joystream/types/content-directory";
+import { ApiPromise } from "@polkadot/api";
+import { u64, Vec } from "@polkadot/types";
+import { EventRecord, Extrinsic, Hash, SignedBlock } from "@polkadot/types/interfaces";
+import { AnyJson } from "@polkadot/types/types";
+
+interface NewBatch {
+  blockHeight: number,
+  action: string,
+  result: string,
+  entityIds: number[],
+  classesOfEntityIds: number[],
+  signer: string,
+  actor: AnyJson
+}
+
+interface Removed {
+  blockHeight: number,
+  action: string,
+  entityId: number,
+  classOfEntity: number,
+  signer: string,
+  actor: AnyJson
+}
+
+export async function getBatchAction(api: ApiPromise, blockHeight:number, blockHash:Hash, index:number, eventsArray: EventRecord[], result: string): Promise<NewBatch|null> {
+  const getBlock = await api.rpc.chain.getBlock(blockHash) as SignedBlock
+  const extrinsics = getBlock.block.extrinsics as Vec<Extrinsic>
+  for (let n=0; n<extrinsics.length; n++) {
+    const extSection = extrinsics[n].method.sectionName
+    const extMethod = extrinsics[n].method.methodName
+    let extrinscIndex = 0
+    if (extSection == "contentDirectory" && extMethod == "transaction") {
+      extrinscIndex +=1
+      if (index == extrinscIndex) {
+        const extrinsic = extrinsics[n]
+        const actor = extrinsic.args[0] as Actor
+        const entityIds:number[] = []
+        const classesOfEntityIds:number[] = []
+        const batchOperation:NewBatch = {
+          blockHeight,
+          action: "",
+          result,
+          entityIds,
+          classesOfEntityIds,
+          signer: extrinsic.signer.toString(),
+          actor: actor.toHuman()
+        }
+        const batch = extrinsic.args[1] as Vec<OperationType>
+        for (let n=0; n<batch.length; n++) {
+          const operationType = batch[n]
+          if (operationType.value instanceof CreateEntityOperation) {
+            classesOfEntityIds.push(operationType.value.class_id.toNumber())
+            if (operationType.value.class_id.toNumber() == 10) {
+              batchOperation.action = "Video Upload"
+            } else if (operationType.value.class_id.toNumber() == 1) {
+              batchOperation.action = "Channel Creation"
+            } else {
+              batchOperation.action = "Entities created in multiple classes"
+            }
+          } else if (operationType.value instanceof UpdatePropertyValuesOperation) {
+            batchOperation.action = "Updated Entity Properties"
+          }
+        }
+        for (let i=0; i<eventsArray.length-1; i++) {
+          const entityId = eventsArray[i].event.data[1]
+          if (entityId instanceof u64) {
+            if (!batchOperation.entityIds.includes(entityId.toNumber())) {
+              batchOperation.entityIds.push(entityId.toNumber())
+            }
+          }
+        }
+        return batchOperation
+      }
+    }
+  }
+  return null
+}
+
+export async function getRemovedAction(api: ApiPromise, blockHeight:number, blockHash:Hash, removIndex: number, event: EventRecord): Promise<Removed|null> {
+  const getBlock = await api.rpc.chain.getBlock(blockHash) as SignedBlock
+  const extrinsics = getBlock.block.extrinsics as Vec<Extrinsic>
+  for (let n=0; n<extrinsics.length; n++) {
+    const extSection = extrinsics[n].method.sectionName
+    const extMethod = extrinsics[n].method.methodName
+    let extrinscIndex = 0
+    if (extSection == "contentDirectory" && extMethod == "removeEntity") {
+      extrinscIndex +=1
+      if (removIndex == extrinscIndex) {
+        const extrinsic = extrinsics[n]
+        const actor = extrinsic.args[0] as Actor
+        let entityId:number = -1
+        let classOfEntity:number = -1
+        const ent = event.event.data[1]
+        if (ent instanceof EntityId) {
+          entityId = ent.toNumber()
+          const previousBlockHash = await api.rpc.chain.getBlockHash(blockHeight-1) as Hash
+          classOfEntity = (await api.query.contentDirectory.entityById.at(previousBlockHash,entityId) as Entity).class_id.toNumber()
+        }
+        const removedEntity:Removed = {
+          blockHeight,
+          action: "Entity removed",
+          entityId,
+          classOfEntity,
+          signer: extrinsic.signer.toString(),
+          actor: actor.toHuman()
+        }
+        return removedEntity
+      }
+    }
+  }
+  return null
+}

+ 58 - 0
joystream-api/src/curators/get-media-change.ts

@@ -0,0 +1,58 @@
+import { WsProvider, ApiPromise } from "@polkadot/api";
+import { types } from "@joystream/types";
+import {  Vec } from "@polkadot/types";
+import { EventRecord, Hash } from "@polkadot/types/interfaces";
+import { getBatchAction, getRemovedAction } from "./functions";
+
+
+async function main() {
+    // Initialise the provider to connect to the local node
+    const provider = new WsProvider('ws://127.0.0.1:9944');
+
+    const api = await ApiPromise.create({ provider, types })
+    const firstBlock = 1292265 // first block after the upgrade to the new Content Directory
+    const lastBlock = 2332000
+    // note that with this blockheight, you will see a lot of jsgenesis initialization and uploads
+    
+    
+    for (let blockHeight=firstBlock; blockHeight<lastBlock; blockHeight++) {
+      const blockHash = await api.rpc.chain.getBlockHash(blockHeight) as Hash
+      const events = await api.query.system.events.at(blockHash) as Vec<EventRecord>;
+      const eventsArray: EventRecord[] = []
+      let index = 0
+      let removIndex = 0
+      for (let i=0; i<events.length; i++) {
+        const section = events[i].event.section
+        const method = events[i].event.method
+        if (section == "contentDirectory") {
+          eventsArray.push(events[i])
+          if (method == "EntityCreated") {
+          }
+          if (method == "EntitySchemaSupportAdded") {
+          }
+          if (method == "EntityPropertyValuesUpdated") {
+          }
+          if (method == "EntityRemoved") {
+            removIndex+=1
+            const cdChange = await getRemovedAction(api, blockHeight, blockHash, removIndex, events[i])
+            console.log("Change",JSON.stringify(cdChange, null, 4))
+          }
+          if (method == "TransactionCompleted") {
+            index+=1
+            const cdChange = await getBatchAction(api, blockHeight, blockHash, index, eventsArray, method)
+            console.log("Change",JSON.stringify(cdChange, null, 4))
+          }
+          if (method == "TransactionFailed") {
+            index+=1
+            const cdChange = await getBatchAction(api, blockHeight, blockHash, index, eventsArray, method)
+            console.log("Change",JSON.stringify(cdChange, null, 4))
+          }
+        }
+      }
+    }
+    
+  api.disconnect()
+}
+
+main()
+

+ 169 - 0
joystream-api/src/examples/council.ts

@@ -0,0 +1,169 @@
+import { WsProvider, ApiPromise } from "@polkadot/api";
+import { types } from "@joystream/types";
+import { Announcing, ElectionStage, Revealing, Seats, Voting } from "@joystream/types/council";
+import { Null, Option, u32 } from "@polkadot/types";
+import { CouncilData, CouncilMemberData, Participant, VoterData } from "./interfaces";
+import { getParticipantAt } from "./functions";
+import { BalanceOf, BlockNumber, Hash } from "@polkadot/types/interfaces";
+import { Mint, MintId } from "@joystream/types/mint";
+
+
+async function main() {
+  // Initialise the provider to connect to the local node
+  const provider = new WsProvider('ws://127.0.0.1:9944');
+  
+  /*
+  If you want to play around on our staging network, go ahead and connect to this staging network instead.
+  const provider = new WsProvider('wss://alexandria-testing-1.joystream.app/staging/rpc:9944');
+  
+  There's a bunch of tokens on the account: 5HdYzMVpJv3c4omqwKKr7SpBgzrdRRYBwoNVhJB2Y8xhUbfK,
+  with seed: "emotion soul hole loan journey what sport inject dwarf cherry ankle lesson"
+  please transfer (what you need only) to your own account, and don't test runtime upgrades :D
+  */
+  
+  // Create the API and wait until ready
+  const api = await ApiPromise.create({ provider, types })
+  // made this example with historical data, so you can check different councils/stages
+  const blocks :number[] = [259200, 259201]
+
+  // discounting this voter
+  const joystreamVoter = "5CJzTaCp5fuqG7NdJQ6oUCwdmFHKichew8w4RZ3zFHM8qSe6"
+
+  const councils: CouncilData[] = []
+  for (let i=0; i<blocks.length; i++) {
+    const councilMembers: CouncilMemberData[] = []
+    const blockHash = await api.rpc.chain.getBlockHash(blocks[i]) as Hash
+    const electionStatus = await api.query.councilElection.stage.at(blockHash) as Option<ElectionStage>
+    const electionRound = await api.query.councilElection.round.at(blockHash) as u32
+    console.log(`
+      at block: ${blocks[i]},
+      the election stage was: ${electionStatus.value.toString()},
+      of election round: ${electionRound.toNumber()},
+    `)
+    if (electionStatus.value instanceof ElectionStage) {
+      const electionStage = electionStatus.unwrap()
+      if (electionStage.value instanceof Announcing) {
+        console.log("In 'Announcing' stage - ends at block", electionStage.value.toNumber())
+      } else if (electionStage.value instanceof Voting) {
+        console.log("In 'Voting' stage - ends at block", electionStage.value.toNumber())
+      } else if (electionStage.value instanceof Revealing) {
+        console.log("In 'Revealing' stage - ends at block", electionStage.value.toNumber())
+      } else {
+      }
+    }
+    const activeCouncil = await api.query.council.activeCouncil.at(blockHash) as Seats
+    if (!activeCouncil.isEmpty) {
+      const elected: Participant[] = []
+      for (let member of activeCouncil) {
+        let otherStake = 0
+        let jsgStake = 0
+        const councilMemberId = await getParticipantAt(api, member.member, blockHash)
+        const voters: VoterData[] = []
+        elected.push(councilMemberId)
+        for (let backer of member.backers) {
+          const voterId = await getParticipantAt(api, backer.member, blockHash)
+          const voter: VoterData = {
+            voterId,
+            voterStake: backer.stake.toNumber(),
+            stakeRatioExJSGvotes: 0,
+            kpiRewardRatio: 0,
+          }
+          otherStake += backer.stake.toNumber()
+          if (backer.member.toString() === joystreamVoter) {
+            jsgStake += backer.stake.toNumber()
+          }
+          voters.push(voter)
+        }
+        const ownStake = member.stake.toNumber()
+        const totalStakeExJSGvotes = member.stake.toNumber() + otherStake - jsgStake
+        const totalStake = member.stake.toNumber() + otherStake
+        const councilMember: CouncilMemberData = {
+          councilMemberId,
+          totalStake,
+          totalStakeExJSGvotes,
+          ownStake,
+          otherStake,
+          otherStakeExJSGvotes: otherStake - jsgStake,
+          stakeRatioExJSGvotes: ownStake/totalStakeExJSGvotes,
+          voters,
+        }
+        councilMembers.push(councilMember)
+      }
+      let totalStakes = 0
+      let totalStakesExJSGvotes = 0
+      let ownStakes = 0
+      let otherStakes = 0
+      let otherStakesExJSGvotes = 0
+      
+      for (let councilMember of councilMembers) {
+        totalStakes += councilMember.totalStake
+        totalStakesExJSGvotes += councilMember.totalStakeExJSGvotes
+        ownStakes += councilMember.ownStake
+        otherStakes += councilMember.otherStake
+        otherStakesExJSGvotes += councilMember.otherStakeExJSGvotes
+      }
+      for (let councilMember of councilMembers) {
+        councilMember.kpiRewardRatio = councilMember.ownStake/totalStakesExJSGvotes
+        for (let voter of councilMember.voters) {
+          if (voter.voterId.accountId != joystreamVoter) {
+            voter.stakeRatioExJSGvotes = voter.voterStake/councilMember.totalStakeExJSGvotes
+            voter.kpiRewardRatio = voter.voterStake/totalStakesExJSGvotes
+          }
+        }
+      }
+      const termEnd = (await api.query.council.termEndsAt.at(blockHash) as BlockNumber).toNumber()
+      const announcing = (await api.query.councilElection.announcingPeriod.at(blockHash) as BlockNumber).toNumber()
+      const voting = (await api.query.councilElection.votingPeriod.at(blockHash) as BlockNumber).toNumber()
+      const revealing = (await api.query.councilElection.votingPeriod.at(blockHash) as BlockNumber).toNumber()
+      const term = (await api.query.councilElection.newTermDuration.at(blockHash) as BlockNumber).toNumber()
+ 
+      // this will not always be correct...
+      const electedAtBlock = termEnd-term
+      const newCouncilStartsAt = termEnd+announcing+voting+revealing
+      const electedHash = await api.rpc.chain.getBlockHash(electedAtBlock) as Hash
+      const getRewardInterval = await api.query.council.payoutInterval.at(electedHash) as Option<BlockNumber>
+
+      const councilMint = await api.query.council.councilMint.at(electedHash) as MintId
+      const mintAtStart = await api.query.minting.mints.at(electedHash,councilMint) as Mint
+      const mintCapacityAtStart = mintAtStart.capacity.toNumber()
+      
+      let rewardInterval = 3600
+      if (!(getRewardInterval.value instanceof Null)) {
+        rewardInterval = getRewardInterval.unwrap().toNumber()
+      }
+
+      const rewardamountPerPayout = (await api.query.council.amountPerPayout.at(electedHash) as BalanceOf).toNumber()
+      const expectedIndividualRewards = rewardamountPerPayout*term/rewardInterval
+
+      const council: CouncilData = {
+        electionCycle: electionRound.toNumber(),
+        electedAtBlock,
+        mintCapacityAtStart,
+        rewardamountPerPayout,
+        rewardInterval,
+        termEnd: termEnd,
+        expectedIndividualRewards,
+        newCouncilStartsAt,
+        totalStakes,
+        totalStakesExJSGvotes,
+        ownStakes,
+        otherStakes,
+        otherStakesExJSGvotes,
+        elected,
+        electionData: councilMembers,
+      }
+      const bestHeight = (await api.derive.chain.bestNumber()).toNumber()
+      if (bestHeight>newCouncilStartsAt) {
+        const endHash = await api.rpc.chain.getBlockHash(newCouncilStartsAt) as Hash
+        const mintAtEnd = await api.query.minting.mints.at(endHash,councilMint) as Mint
+        council.mintCapacityAtEnd = mintAtEnd.capacity.toNumber()
+        council.councilSpending = mintAtEnd.total_minted.toNumber() - mintAtStart.total_minted.toNumber()
+      }
+      councils.push(council)
+    }
+  }
+  console.log("councils",JSON.stringify(councils, null, 4))
+  api.disconnect()
+}
+
+main()

+ 88 - 0
joystream-api/src/examples/functions.ts

@@ -0,0 +1,88 @@
+import { MemberId, Membership } from "@joystream/types/members";
+import { ApiPromise } from "@polkadot/api";
+import { Vec } from "@polkadot/types";
+import AccountId from "@polkadot/types/generic/AccountId";
+import { Hash } from "@polkadot/types/interfaces";
+import { Participant } from './interfaces';
+
+export async function getParticipant(api: ApiPromise, accountId: AccountId): Promise<Participant> {
+  let memberId = -1
+  const isMemberRoot = await api.query.members.memberIdsByRootAccountId(accountId) as Vec<MemberId>
+  const isMemberCtrl = await api.query.members.memberIdsByControllerAccountId(accountId) as Vec<MemberId>
+  if (isMemberRoot[0] === isMemberCtrl[0] && isMemberRoot.length == 1 && isMemberCtrl.length == 1) {
+    console.log("true")
+    memberId = isMemberRoot[0].toNumber()
+    const handle = (await api.query.members.membershipById(isMemberRoot[0]) as Membership).handle.toString()
+    const partipant: Participant = {
+      memberId,
+      handle,
+      accountId:accountId.toString(),
+    }
+    return partipant
+  } else {
+    const memberIds: number[] = []
+    const handle: string[] = []
+    for (let ids of (isMemberRoot && isMemberCtrl)) {
+      if (!memberIds.includes(ids.toNumber())) {
+        memberIds.push(ids.toNumber())
+        handle.push((await api.query.members.membershipById(ids) as Membership).handle.toString())
+      }
+    }
+    if (memberIds.length === 1) {
+      
+      const partipant: Participant = {
+        memberId: memberIds[0],
+        handle,
+        accountId:accountId.toString(),
+      }
+      return partipant
+    } else {
+      const partipant: Participant = {
+        memberId: memberIds,
+        handle,
+        accountId:accountId.toString(),
+      }
+      return partipant
+    }
+  }
+}
+
+export async function getParticipantAt(api: ApiPromise, accountId: AccountId, blockHash: Hash): Promise<Participant> {
+  let memberId = -1
+  const isMemberRoot = await api.query.members.memberIdsByRootAccountId.at(blockHash,accountId) as Vec<MemberId>
+  const isMemberCtrl = await api.query.members.memberIdsByControllerAccountId.at(blockHash,accountId) as Vec<MemberId>
+  if (isMemberRoot[0].toNumber() === isMemberCtrl[0].toNumber() && isMemberRoot.length == 1 && isMemberCtrl.length == 1) {
+    memberId = isMemberRoot[0].toNumber()
+    const handle = (await api.query.members.membershipById.at(blockHash,isMemberRoot[0]) as Membership).handle.toString()
+    const partipant: Participant = {
+      memberId,
+      handle,
+      accountId:accountId.toString(),
+    }
+    return partipant
+  } else {
+    const memberIds: number[] = []
+    const handle: string[] = []
+    for (let ids of (isMemberRoot && isMemberCtrl)) {
+      if (!memberIds.includes(ids.toNumber())) {
+        memberIds.push(ids.toNumber())
+        handle.push((await api.query.members.membershipById.at(blockHash,ids) as Membership).handle.toString())
+      }
+    }
+    if (memberIds.length === 1) {
+      const partipant: Participant = {
+        memberId: memberIds[0],
+        handle : handle[0],
+        accountId:accountId.toString(),
+      }
+      return partipant
+    } else {
+      const partipant: Participant = {
+        memberId: memberIds,
+        handle,
+        accountId:accountId.toString(),
+      }
+      return partipant
+    }
+  }
+}

+ 75 - 0
joystream-api/src/examples/general.ts

@@ -0,0 +1,75 @@
+import { WsProvider, ApiPromise } from "@polkadot/api";
+import { types } from "@joystream/types";
+import { Vec } from "@polkadot/types";
+import { Balance, EventRecord, Extrinsic, SignedBlock } from "@polkadot/types/interfaces";
+
+async function main() {
+    // Initialise the provider to connect to the local node
+    const provider = new WsProvider('ws://127.0.0.1:9944');
+      
+    /*
+    If you want to play around on our staging network, go ahead and connect to this staging network instead.
+    const provider = new WsProvider('wss://alexandria-testing-1.joystream.app/staging/rpc:9944');
+    
+    There's a bunch of tokens on the account: 5HdYzMVpJv3c4omqwKKr7SpBgzrdRRYBwoNVhJB2Y8xhUbfK,
+    with seed: "emotion soul hole loan journey what sport inject dwarf cherry ankle lesson"
+    please transfer (what you need only) to your own account, and don't test runtime upgrades :D
+    */
+
+    // Create the API and wait until ready
+    const api = await ApiPromise.create({ provider, types })
+
+    // get finalized head of chain, as number and hash:
+    const finalizedHeadNumber = await api.derive.chain.bestNumberFinalized()
+    const finalizedHeadHash = await api.rpc.chain.getFinalizedHead()
+    // get head of chain, as hash or number:
+    const headNumber = await api.derive.chain.bestNumber()
+    const headHash = await api.rpc.chain.getBlockHash(headNumber)
+
+    console.log(
+      `Finalized head of chain
+      - as number: ${finalizedHeadNumber}
+      - with hash: ${finalizedHeadHash}`
+      )
+    console.log(
+      `Head of chain
+      - as number: ${headNumber}
+      - with hash: ${headHash}`
+      )
+
+    // get current issuance 
+    const issuance = await api.query.balances.totalIssuance() as Balance
+    console.log(`current issuance is: ${issuance.toNumber()}tJOY`)
+    
+    // get events in newest block:
+    const events = await api.query.system.events() as Vec<EventRecord>;
+    for (let { event } of events) {
+      const section = event.section
+      const method = event.method
+      const data = event.data
+      console.log("section",section)
+      console.log("method",method)
+      console.log("data",data.toHuman())
+      console.log("")
+    }
+
+    // get extrinsics in finalized head block:
+    const getLatestBlock = await api.rpc.chain.getBlock(finalizedHeadHash) as SignedBlock
+    const extrinsics = getLatestBlock.block.extrinsics as Vec<Extrinsic>
+    for (let i=0; i<extrinsics.length; i++) {
+      const section = extrinsics[i].method.sectionName
+      const method = extrinsics[i].method.methodName
+      console.log("section",section)
+      console.log("method",method)
+      console.log("")
+      // get signer of extrinsics if applicable
+      const signer = extrinsics[i].signer
+      if (!signer.isEmpty) {
+        console.log("signer",signer)
+      }
+    }
+    
+    api.disconnect()
+}
+
+main()

+ 64 - 0
joystream-api/src/examples/get-events-and-extrinsics.ts

@@ -0,0 +1,64 @@
+import { WsProvider, ApiPromise } from "@polkadot/api";
+import { types } from "@joystream/types";
+import { Vec } from "@polkadot/types";
+import { EventRecord, Extrinsic, SignedBlock } from "@polkadot/types/interfaces";
+
+async function main() {
+    // Initialise the provider to connect to the local node
+    const provider = new WsProvider('ws://127.0.0.1:9944');
+
+    /*
+    If you want to play around on our staging network, go ahead and connect to this staging network instead.
+    const provider = new WsProvider('wss://alexandria-testing-1.joystream.app/staging/rpc:9944');
+    
+    There's a bunch of tokens on the account: 5HdYzMVpJv3c4omqwKKr7SpBgzrdRRYBwoNVhJB2Y8xhUbfK,
+    with seed: "emotion soul hole loan journey what sport inject dwarf cherry ankle lesson"
+    please transfer (what you need only) to your own account, and don't test runtime upgrades :D
+    */
+
+    // Create the API and wait until ready
+    const api = await ApiPromise.create({ provider, types })
+
+    // get all extrinsic and event types in a range of blocks (only works for last 200 blocks unless you are querying an archival node)
+    // will take a loooong time if you check too many blocks :)
+    const firstBlock = 1
+    const lastBlock = 10000
+    const eventTypes:string[] = []
+    const extrinsicTypes: string[] = []
+    for (let blockHeight=firstBlock; blockHeight<lastBlock; blockHeight++) {
+      const blockHash = await api.rpc.chain.getBlockHash(blockHeight)
+      const events = await api.query.system.events.at(blockHash) as Vec<EventRecord>;
+      const getBlock = await api.rpc.chain.getBlock(blockHash) as SignedBlock
+      const extrinsics = getBlock.block.extrinsics as Vec<Extrinsic>
+      for (let { event } of events) {
+        const section = event.section
+        const method = event.method
+        const eventType = section+`:`+method
+        if (!eventTypes.includes(eventType)) {
+          eventTypes.push(eventType)
+        }
+      }
+      for (let i=0; i<extrinsics.length; i++) {
+        const section = extrinsics[i].method.sectionName
+        const method = extrinsics[i].method.methodName
+        const extrinsicType = section+`:`+method
+        if (!extrinsicTypes.includes(extrinsicType)) {
+          extrinsicTypes.push(extrinsicType)
+        }
+      }
+    }
+    console.log("number of unique event types in range:",eventTypes.length)
+    console.log("list of the unique event types in range:")
+    console.log(JSON.stringify(eventTypes, null, 4))
+
+    console.log("")
+
+    console.log("number of unique extrinsic types in range",extrinsicTypes.length)
+    console.log("list of the unique extrinsic types in range:")
+    console.log(JSON.stringify(extrinsicTypes, null, 4))
+    
+    api.disconnect()
+}
+
+main()
+

+ 44 - 0
joystream-api/src/examples/interfaces.ts

@@ -0,0 +1,44 @@
+export interface Participant {
+  memberId: number | number[],
+  handle: string | string[],
+  accountId: string,
+}
+
+export interface VoterData {
+  voterId: Participant,
+  voterStake: number,
+  stakeRatioExJSGvotes: number,
+  kpiRewardRatio: number,
+}
+
+export interface CouncilMemberData {
+  councilMemberId: Participant,
+  totalStake: number,
+  totalStakeExJSGvotes: number,
+  ownStake: number,
+  otherStake: number,
+  otherStakeExJSGvotes: number,
+  stakeRatioExJSGvotes: number,
+  voters: VoterData[],
+  kpiRewardRatio?: number,
+}
+
+export interface CouncilData {
+  electionCycle: number,
+  electedAtBlock: number,
+  mintCapacityAtStart: number,
+  mintCapacityAtEnd?: number,
+  councilSpending?: number,
+  rewardamountPerPayout: number,
+  rewardInterval: number,
+  termEnd: number,
+  expectedIndividualRewards: number,
+  newCouncilStartsAt: number,
+  totalStakes: number,
+  totalStakesExJSGvotes: number,
+  ownStakes: number,
+  otherStakes: number,
+  otherStakesExJSGvotes: number,
+  elected: Participant[],
+  electionData: CouncilMemberData[],
+}

+ 138 - 0
joystream-api/src/examples/proposals.ts

@@ -0,0 +1,138 @@
+import { WsProvider, ApiPromise } from "@polkadot/api";
+import { types } from "@joystream/types";
+import { Active, Approved, ExecutionFailed, Finalized, Proposal, ProposalDetails, ProposalId } from "@joystream/types/proposals";
+import { StorageKey, Vec } from "@polkadot/types";
+import { Membership } from "@joystream/types/members";
+import { Stake, Staked, StakeId } from "@joystream/types/stake";
+import { AnyJson } from "@polkadot/types/types";
+
+
+interface ProposalOverview {
+  id: number,
+  type: string,
+  title: string,
+  createdBy: [number,string],
+  stakeId: number,
+  stake: number,
+  created: number,
+  status: string,
+  finalizedAt?: number,
+  result?: string,
+  feePaid?: number,
+  executionStatus?: string
+  executeAt?: number,
+  voteResult?: AnyJson,
+  execution?: AnyJson,
+}
+
+async function main() {
+  // Initialise the provider to connect to the local node
+  const provider = new WsProvider('ws://127.0.0.1:9944');
+  
+  /*
+  If you want to play around on our staging network, go ahead and connect to this staging network instead.
+  const provider = new WsProvider('wss://alexandria-testing-1.joystream.app/staging/rpc:9944');
+  
+  There's a bunch of tokens on the account: 5HdYzMVpJv3c4omqwKKr7SpBgzrdRRYBwoNVhJB2Y8xhUbfK,
+  with seed: "emotion soul hole loan journey what sport inject dwarf cherry ankle lesson"
+  please transfer (what you need only) to your own account, and don't test runtime upgrades :D
+  */
+  
+  // Create the API and wait until ready
+  const api = await ApiPromise.create({ provider, types })
+
+  const allProposals: ProposalOverview[] = []
+
+  // get all proposalIds
+  // sort them by id
+  const proposalKeys = await api.query.proposalsEngine.proposals.keys()
+  const proposalIds = proposalKeys.map(({ args: [proposalId]}) => proposalId) as Vec<ProposalId>
+  proposalIds.sort((a,b) => a.toNumber()-b.toNumber())
+  console.log("number of proposals", proposalIds.length);
+  console.log("all IDs:", proposalIds.join(', '));
+
+  // get all stakeIds associated with proposalIds
+  const stakeIdOfProposalId = await api.query.proposalsEngine.stakesProposals.keys() as StorageKey[]
+  const stakeIdsOfProposalIds = stakeIdOfProposalId.map(({ args: [stakeId]}) => stakeId) as Vec<StakeId>
+  stakeIdsOfProposalIds.sort((a,b) => a.toNumber()-b.toNumber())
+  console.log("all stakeIdsOfProposalIds:", stakeIdsOfProposalIds.join(", "));
+
+  for (let id of proposalIds) {
+    const proposal = await api.query.proposalsEngine.proposals(id) as Proposal
+    const proposerHandle = (await api.query.members.membershipById(proposal.proposerId) as Membership).handle.toString()
+    const proposalStatus = proposal.status.value
+    const proposalDetails = await api.query.proposalsCodex.proposalDetailsByProposalId(id) as ProposalDetails
+    let stakeId = (stakeIdsOfProposalIds[proposalIds.indexOf(id)]).toNumber()
+    let stake = 0
+    if ((await api.query.proposalsEngine.stakesProposals(stakeId) as ProposalId).toNumber() === id.toNumber()) {
+      const blockHash = await api.rpc.chain.getBlockHash(proposal.createdAt)
+      const proposalStake = await api.query.stake.stakes.at(blockHash,stakeId) as Stake
+      if (proposalStake.staking_status instanceof Staked) {
+        stake = proposalStake.staking_status.staked_amount.toNumber()
+      }
+    } else {
+      // This should never be the case...
+      stakeId = -1
+    }
+    const proposalData: ProposalOverview = {
+      id: id.toNumber(),
+      type: proposalDetails.type.toString(),
+      title: proposal.title.toString(),
+      createdBy: [proposal.proposerId.toNumber(),proposerHandle],
+      stakeId,
+      stake,
+      created: proposal.createdAt.toNumber(),
+      status: proposal.status.value.toString(),
+    }
+    // these proposals will have an annoyngly large 'execution'
+    if (proposalDetails.type != "Text" && proposalDetails.type!= "RuntimeUpgrade") {
+      proposalData.execution = proposalDetails.value.toHuman()
+    }
+    // check if the proposal is "Active"
+    if (proposalStatus instanceof Active) {
+      proposalData.status = proposalStatus.value.toString()
+    } else {
+      // There really isn't any other options here...
+      if (proposalStatus instanceof Finalized) {
+        proposalData.status = proposalStatus.proposalStatus.type
+        proposalData.finalizedAt = proposalStatus.finalizedAt.toNumber()
+        proposalData.voteResult = proposal.votingResults.toHuman()
+        const proposalResult = proposalStatus.proposalStatus.value
+        // check if the proposal is "Approved"
+        if (proposalResult instanceof Approved) {
+          proposalData.feePaid = 0
+          const gracePeriod = proposal.parameters.gracePeriod.toNumber()
+          proposalData.executeAt = proposalStatus.finalizedAt.toNumber() + gracePeriod
+          proposalData.executionStatus = proposalResult.type
+          // "Executed" and "PendingExecution" works differently than "ExecutionFailed"
+          // the latter will have some information on what went wrong
+          if (proposalResult.isOfType("Executed")) {
+          } else if (proposalResult.isOfType("PendingExecution")) {
+          } else if (proposalResult.value instanceof ExecutionFailed) {
+            proposalData.executionStatus = proposalResult.type + `:` + proposalResult.value.error.toString()
+          }
+        } else {
+          // If not finalized, but not approved, it must be one of...
+          if (proposalStatus.proposalStatus.isOfType("Canceled")) {
+            proposalData.feePaid = 10000
+          } else if (proposalStatus.proposalStatus.isOfType("Slashed")) {
+            proposalData.feePaid = stake
+          } else if (proposalStatus.proposalStatus.isOfType("Vetoed")) {
+            proposalData.feePaid = 0
+          // .. "Expired" or "Rejected", which are treated as the same.
+          } else {
+            proposalData.feePaid = 5000
+          }
+        }
+      }
+    }
+    allProposals.push(proposalData)
+  }
+
+  
+  console.log("allProposals",JSON.stringify(allProposals, null, 4))
+
+  api.disconnect()
+}
+
+main()

+ 169 - 0
joystream-api/src/examples/working-groups.ts

@@ -0,0 +1,169 @@
+import { WsProvider, ApiPromise } from "@polkadot/api";
+import { types } from "@joystream/types";
+import { Worker, WorkerId } from "@joystream/types/working-group";
+import { Null, Vec } from "@polkadot/types";
+import { Curator, CuratorApplication, CuratorApplicationId, CuratorId, CuratorInduction } from "@joystream/types/content-working-group";
+import { RewardRelationship } from "@joystream/types/recurring-rewards";
+import { Stake, StakingStatus, Staked } from "@joystream/types/stake";
+
+interface WorkingGroupStake {
+  stakeId: number,
+  roleStake: number,
+}
+
+interface WorkingGroupReward {
+  rewardRelationshipId: number,
+  rewardSize: number,
+  rewardInterval: number,
+  rewardPerWeek: number,
+  totalEarned: number,
+  totalMissed: number,
+}
+
+
+interface ContentCurator {
+  curatorId: number,
+  memberId: number,
+  roleAccount: string,
+  applicationId: number,
+  stakeProfile?: WorkingGroupStake,
+  rewardRelationship?: WorkingGroupReward, 
+}
+
+
+interface StorageProvider {
+  workerId: number,
+  memberId: number,
+  roleAccount: string,
+  stakeProfile?: WorkingGroupStake,
+  rewardRelationship?: WorkingGroupReward, 
+}
+
+async function main() {
+  // Initialise the provider to connect to the local node
+  const provider = new WsProvider('ws://127.0.0.1:9944');
+  
+  /*
+  If you want to play around on our staging network, go ahead and connect to this staging network instead.
+  const provider = new WsProvider('wss://alexandria-testing-1.joystream.app/staging/rpc:9944');
+  
+  There's a bunch of tokens on the account: 5HdYzMVpJv3c4omqwKKr7SpBgzrdRRYBwoNVhJB2Y8xhUbfK,
+  with seed: "emotion soul hole loan journey what sport inject dwarf cherry ankle lesson"
+  please transfer (what you need only) to your own account, and don't test runtime upgrades :D
+  */
+  
+  // Create the API and wait until ready
+  const api = await ApiPromise.create({ provider, types })
+
+  const storageProviders: StorageProvider[] = []
+  const contentCurators: ContentCurator[] = []
+
+  // get all active storage workers
+  const storageWorkerKeys = await api.query.storageWorkingGroup.workerById.keys()
+  const storageWorkerIds = storageWorkerKeys.map(({ args: [workerId]}) => workerId) as Vec<WorkerId>
+  storageWorkerIds.sort((a,b) => a.toNumber()-b.toNumber())
+  console.log('all storageWorkerIds:', storageWorkerIds.join(', '));
+  for (let key of storageWorkerIds) {
+    const worker = await api.query.storageWorkingGroup.workerById(key) as Worker
+    //console.log("worker",worker.toHuman())
+    const storageProvider: StorageProvider = {
+      workerId: key.toNumber(),
+      memberId: worker.member_id.toNumber(),
+      roleAccount: worker.role_account_id.toString(),
+    }
+    if (worker.reward_relationship.isSome) {
+      const rewardRelationshipId = worker.reward_relationship.unwrap()
+      const rewardRelationship = await api.query.recurringRewards.rewardRelationships(rewardRelationshipId) as RewardRelationship
+      //console.log("rewardRelationship",rewardRelationship.toHuman())
+      let rewardInterval = 0
+      let rewardPerWeek = 0
+      if (!(rewardRelationship.payout_interval.value instanceof Null)) {
+        rewardInterval = rewardRelationship.payout_interval.unwrap().toNumber()
+        rewardPerWeek = rewardRelationship.amount_per_payout.toNumber()*100800/rewardInterval
+      }
+      storageProvider.rewardRelationship = {
+        rewardRelationshipId: rewardRelationshipId.toNumber(),
+        rewardSize: rewardRelationship.amount_per_payout.toNumber(),
+        rewardInterval,
+        rewardPerWeek,
+        totalEarned: rewardRelationship.total_reward_received.toNumber(),
+        totalMissed: rewardRelationship.total_reward_missed.toNumber(),
+      }
+    }
+    if (worker.role_stake_profile.isSome && !(worker.role_stake_profile instanceof Null)) {
+      const stake = worker.role_stake_profile.unwrap()
+      const workerStake = await api.query.stake.stakes(stake.stake_id) as Stake
+      //console.log("workerStake",workerStake.toHuman())
+      const stakingStatus = (workerStake.staking_status as StakingStatus).value
+      if (stakingStatus instanceof Staked) {
+        storageProvider.stakeProfile = {
+          stakeId: stake.stake_id.toNumber(),
+          roleStake: stakingStatus.staked_amount.toNumber(),
+        }
+      }
+    }
+    storageProviders.push(storageProvider)
+  }
+  // get all active content curators
+  const contentCuratorKeys = await api.query.contentWorkingGroup.curatorById.keys()
+  const contentCuratorIds = contentCuratorKeys.map(({ args: [workerId]}) => workerId) as Vec<CuratorId>
+  contentCuratorIds.sort((a,b) => a.toNumber()-b.toNumber())
+  console.log('all contentCuratorIds:', contentCuratorIds.join(', '));
+  for (let key of contentCuratorIds) {
+    const curator = await api.query.contentWorkingGroup.curatorById(key) as Curator
+    // filter out inactive
+    if (curator.is_active) {
+      const curatorApplicationId = (curator.induction as CuratorInduction).curator_application_id as CuratorApplicationId
+      const applicationId = await api.query.contentWorkingGroup.curatorApplicationById(curatorApplicationId) as CuratorApplication
+      const contentCurator: ContentCurator = {
+        curatorId: key.toNumber(),
+        memberId: applicationId.member_id.toNumber(),
+        roleAccount: curator.role_account.toString(),
+        applicationId: applicationId.application_id.toNumber(),
+      }
+      if (curator.reward_relationship.isSome) {
+        const rewardRelationshipId = curator.reward_relationship.unwrap()
+        const rewardRelationship = await api.query.recurringRewards.rewardRelationships(rewardRelationshipId) as RewardRelationship
+        //console.log("rewardRelationship",rewardRelationship.toHuman())
+        let rewardInterval = 0
+        let rewardPerWeek = 0
+        if (!(rewardRelationship.payout_interval.value instanceof Null)) {
+          rewardInterval = rewardRelationship.payout_interval.unwrap().toNumber()
+          rewardPerWeek = rewardRelationship.amount_per_payout.toNumber()*100800/rewardInterval
+        }
+        contentCurator.rewardRelationship = {
+          rewardRelationshipId: rewardRelationshipId.toNumber(),
+          rewardSize: rewardRelationship.amount_per_payout.toNumber(),
+          rewardInterval,
+          rewardPerWeek,
+          totalEarned: rewardRelationship.total_reward_received.toNumber(),
+          totalMissed: rewardRelationship.total_reward_missed.toNumber(),
+        }
+      }
+      if (curator.role_stake_profile.isSome && !(curator.role_stake_profile instanceof Null)) {
+        const stake = curator.role_stake_profile.unwrap()
+        const workerStake = await api.query.stake.stakes(stake.stake_id) as Stake
+        //console.log("workerStake",workerStake.toHuman())
+        const stakingStatus = (workerStake.staking_status as StakingStatus).value
+        if (stakingStatus instanceof Staked) {
+          contentCurator.stakeProfile = {
+            stakeId: stake.stake_id.toNumber(),
+            roleStake: stakingStatus.staked_amount.toNumber(),
+          }
+        }
+      }
+      contentCurators.push(contentCurator)
+    }
+  }
+ console.log("storageProviders",JSON.stringify(storageProviders, null, 4))
+
+ console.log("contentCurators",JSON.stringify(contentCurators, null, 4))
+
+
+
+
+
+  api.disconnect()
+}
+
+main()

+ 21 - 0
joystream-api/src/general/get-code.ts

@@ -0,0 +1,21 @@
+import { ApiPromise, WsProvider } from '@polkadot/api';
+import { types } from '@joystream/types'
+
+async function main () {
+  const provider = new WsProvider('ws://127.0.0.1:9944');
+
+  const api = await ApiPromise.create({ provider, types })
+
+  let current_block_hash = await api.rpc.chain.getBlockHash();
+
+  console.log('getting code as of block hash', current_block_hash.toString())
+
+  const substrateWasm = await api.query.substrate.code.at(current_block_hash.toString());
+  // const substrateWasm = await api.rpc.state.getStorage('0x'+Buffer.from(':code').toString('hex'), current_block_hash);
+
+  console.log(substrateWasm.toHex());
+
+  api.disconnect();
+}
+
+main()

+ 54 - 0
joystream-api/src/general/script.ts

@@ -0,0 +1,54 @@
+// @ts-check
+
+import { ApiPromise, WsProvider } from '@polkadot/api'
+import * as types from '@polkadot/types'
+import * as util from '@polkadot/util'
+import { types as joyTypes } from '@joystream/types'
+import * as joy from '@joystream/types'
+import * as hashing from '@polkadot/util-crypto'
+import { Keyring } from '@polkadot/keyring'
+
+const scripts = require('../scripts')
+
+async function main () {
+  
+
+  const scriptArg = process.argv[2]
+  const script = scripts[scriptArg]
+
+  if (!scriptArg || !script) {
+    console.error('Please specify valid script name.')
+    console.error('Available scripts:', Object.keys(scripts))
+    return
+  }
+
+  const provider = new WsProvider('ws://127.0.0.1:9944')
+
+  const api = await ApiPromise.create({ provider, types: joyTypes })
+
+  // We don't pass a custom signer to the api so we must use a keyPair
+  // when calling signAndSend on transactions
+  const keyring = new Keyring()
+
+  // Optional last argument is a SURI for account to use for signing transactions
+  const suri = process.argv[3]
+  if (suri) {
+    keyring.addFromUri(suri, undefined, 'sr25519')
+  }
+
+  // Add development well known keys to keyring
+  if ((await api.rpc.system.chain()).toString() === 'Development') {
+    keyring.addFromUri('//Alice', undefined, 'sr25519')
+    keyring.addFromUri('//Bob', undefined, 'sr25519')
+  }
+
+  try {
+    await script({ api, types, util, hashing, keyring, joy })
+  } catch (err) {
+    console.error(err)
+  }
+
+  api.disconnect();
+}
+
+main()

+ 53 - 0
joystream-api/src/general/status.ts

@@ -0,0 +1,53 @@
+// @ts-check
+
+import { ApiPromise, WsProvider } from '@polkadot/api';
+import { types } from '@joystream/types'
+import { Seat } from '@joystream/types/council';
+// import { ValidatorId } from '@polkadot/types/interfaces';
+
+// import BN from 'bn.js';
+const BN = require('bn.js');
+
+async function main () {
+  // Initialise the provider to connect to the local node
+  const provider = new WsProvider('ws://127.0.0.1:9944');
+
+  // Create the API and wait until ready
+  const api = await ApiPromise.create({ provider, types })
+
+  // Retrieve the chain & node information information via rpc calls
+  const [chain, nodeName, nodeVersion] = await Promise.all([
+    api.rpc.system.chain(),
+    api.rpc.system.name(),
+    api.rpc.system.version()
+  ]);
+
+  console.log(`Chain '${chain}' - node: ${nodeName} v${nodeVersion}`);
+
+  let council = await api.query.council.activeCouncil() as unknown as Seat[];
+  let validators = await api.query.session.validators() //  as unknown as ValidatorId[];
+  let version  = await api.rpc.state.getRuntimeVersion() // as any;
+
+  console.log(`Runtime Version: ${version.authoringVersion}.${version.specVersion}.${version.implVersion}`);
+
+  // number of council members
+  console.log('Council size:', council.length)
+
+  console.log('Validator count:', validators.length);
+
+  if (validators && validators.length > 0) {
+    // Retrieve the balances of validators' stash accounts
+    const validatorBalances = await Promise.all(
+      validators.map(authorityId => api.derive.balances.all(authorityId))
+    );
+
+    const totalValidatorBalances =
+      validatorBalances.reduce((total, value) => total.add(value.lockedBalance), new BN(0))
+    
+    console.log('Total Validator Locked Balances:', totalValidatorBalances.toString());
+  }
+
+  api.disconnect();
+}
+
+main()

+ 25 - 0
joystream-api/src/general/tobytes.ts

@@ -0,0 +1,25 @@
+
+import { ApiPromise, WsProvider } from '@polkadot/api';
+import { Bytes } from '@polkadot/types';
+import { types } from '@joystream/types'
+
+async function main() {
+  const provider = new WsProvider('ws://127.0.0.1:9944');
+  const api = await ApiPromise.create({ provider, types })
+
+  const input:string = "myInputString"
+  const output = new Bytes(api.registry, input);
+
+  /*
+  Some extrinsics require input as "Bytes".
+  Replace <myInputString> with the string you want, and the output can be pasted in.
+  */
+
+
+  console.log("input string", input)
+  console.log("output, as bytes toHex",output.toHex())
+  api.disconnect()
+}
+
+main()
+

+ 33 - 0
joystream-api/src/general/tohex.ts

@@ -0,0 +1,33 @@
+import { ApiPromise, WsProvider } from '@polkadot/api';
+import { CuratorApplicationId } from '@joystream/types/content-working-group';
+import { BTreeSet } from '@polkadot/types';
+import { types } from '@joystream/types'
+
+async function main() {
+    const provider = new WsProvider('ws://127.0.0.1:9944');
+    const api = await ApiPromise.create({ provider, types })
+
+    let wgId = [1, 2]
+
+    let set = new BTreeSet<CuratorApplicationId>(api.registry, CuratorApplicationId, []);
+    
+    wgId.forEach((id) => {
+        set.add(new CuratorApplicationId(api.registry, id))
+    })
+    
+    /*
+    Replace the integers inside the bracket in:
+    let wgId:number[] = [1, 2];
+    With the "WG ID"s of the curators you wish to hire, in ascending order.
+
+    To hire "WG ID" 18 21 and 16:
+    let wgId:number[] = [16, 18, 21];
+    */
+
+    console.log('copy/paste the output below to hire curator applicant(s) with WG IDs:', wgId )
+    console.log(set.toHex())
+
+    api.disconnect()
+}
+
+main()

+ 38 - 0
joystream-api/tsconfig.json

@@ -0,0 +1,38 @@
+{
+  "compilerOptions": {
+    "target": "esnext",
+    "module": "commonjs",
+    "strict": true,
+    "noImplicitAny": true,
+    "noUnusedLocals": true,
+    "noImplicitReturns": true,
+    "moduleResolution": "node",
+    "allowSyntheticDefaultImports": true,     /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
+    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
+    "experimentalDecorators": true,           /* Enables experimental support for ES7 decorators. */
+    "declaration": true,
+    "resolveJsonModule": true,
+    "types" : [
+      "node"
+    ],
+    "forceConsistentCasingInFileNames": true,
+    "baseUrl": ".",
+    "paths": {
+      "@polkadot/types/augment": ["./node_modules/@joystream/types/augment-codec/augment-types.ts"]
+    },
+    "typeRoots": [
+      "./node_modules/@polkadot/ts",
+      "./node_modules/@types"
+    ],
+    "declarationDir": "lib",
+    "outDir": "lib"
+  },
+  "include": [
+    "src/**/*.ts"
+  ],
+  "exclude": [
+    "node_modules",
+    "**/*.spec.ts",
+    "**/*.d.ts"
+  ]
+}

+ 779 - 0
joystream-api/yarn.lock

@@ -0,0 +1,779 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/runtime@^7.10.5", "@babel/runtime@^7.12.1":
+  version "7.13.9"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.9.tgz#97dbe2116e2630c489f22e0656decd60aaa1fcee"
+  integrity sha512-aY2kU+xgJ3dJ1eU6FMB9EH8dIe8dmusF1xEku52joLvw6eAFN0AI+WxCLDnpev2LEejWBAy2sBvBOBAjI3zmvA==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
+"@joystream/types@^0.14.0":
+  version "0.14.0"
+  resolved "https://registry.yarnpkg.com/@joystream/types/-/types-0.14.0.tgz#3f243fb736d3cdd3dae90a90274c7a767fc96b75"
+  integrity sha512-t9LibCVM5j0NY2OQOXCGkZFFf1pbnQ9ccv0ZXMK7CfseRDwPtAlF/jVQUQQ03PAAGOKFWJQUenFUhPAbt6wKtg==
+  dependencies:
+    "@polkadot/api" "1.26.1"
+    "@polkadot/keyring" "^3.0.1"
+    "@polkadot/types" "1.26.1"
+    "@types/lodash" "^4.14.157"
+    "@types/vfile" "^4.0.0"
+    ajv "^6.11.0"
+    lodash "^4.17.15"
+    moment "^2.24.0"
+
+"@polkadot/api-derive@1.26.1":
+  version "1.26.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-1.26.1.tgz#e9f135b1f2ee0f572392758dcf4a0beb9c9d54a1"
+  integrity sha512-09SCFtf6RibjyFm8aSDUD+opQTPIKqEP8fX8Gs+ZvXlyHSkVbR4ffjaTILgZJQNAPOrLeVSOGmR9dD+xKaKSBQ==
+  dependencies:
+    "@babel/runtime" "^7.10.5"
+    "@polkadot/api" "1.26.1"
+    "@polkadot/rpc-core" "1.26.1"
+    "@polkadot/rpc-provider" "1.26.1"
+    "@polkadot/types" "1.26.1"
+    "@polkadot/util" "^3.0.1"
+    "@polkadot/util-crypto" "^3.0.1"
+    bn.js "^5.1.2"
+    memoizee "^0.4.14"
+    rxjs "^6.6.0"
+
+"@polkadot/api@1.26.1":
+  version "1.26.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-1.26.1.tgz#215268489c10b1a65429c6ce451c8d65bd3ad843"
+  integrity sha512-al8nmLgIU1EKo0oROEgw1mqUvrHJu4gKYBwnFONaEOxHSxBgBSSgNy1MWKNntAQYDKA4ETCj4pz7ZpMXTx2SDA==
+  dependencies:
+    "@babel/runtime" "^7.10.5"
+    "@polkadot/api-derive" "1.26.1"
+    "@polkadot/keyring" "^3.0.1"
+    "@polkadot/metadata" "1.26.1"
+    "@polkadot/rpc-core" "1.26.1"
+    "@polkadot/rpc-provider" "1.26.1"
+    "@polkadot/types" "1.26.1"
+    "@polkadot/types-known" "1.26.1"
+    "@polkadot/util" "^3.0.1"
+    "@polkadot/util-crypto" "^3.0.1"
+    bn.js "^5.1.2"
+    eventemitter3 "^4.0.4"
+    rxjs "^6.6.0"
+
+"@polkadot/keyring@^3.0.1":
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-3.7.1.tgz#91c17ed9824d6ed3f909ab43565f8e34bfbe321c"
+  integrity sha512-Tohw67R8gnQXV4W3FoVr7akGtT59thNzutiQf+5DBV2GRf4Vin97XT4LV2VPHLbk5ACDryBv7lomSiHfSvsUJQ==
+  dependencies:
+    "@babel/runtime" "^7.12.1"
+    "@polkadot/util" "^3.7.1"
+    "@polkadot/util-crypto" "^3.7.1"
+
+"@polkadot/metadata@1.26.1":
+  version "1.26.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/metadata/-/metadata-1.26.1.tgz#64b959415dab6f61ba415b0a337a3ec06e3cad3e"
+  integrity sha512-SyfIIFRx6Oatr1W5KtrmBlxoyJ338tuiuYRMmHuWTGs5jnYQlKf/yd3UiUkibaA372fFEx6/qGWHwutyS0STCA==
+  dependencies:
+    "@babel/runtime" "^7.10.5"
+    "@polkadot/types" "1.26.1"
+    "@polkadot/types-known" "1.26.1"
+    "@polkadot/util" "^3.0.1"
+    "@polkadot/util-crypto" "^3.0.1"
+    bn.js "^5.1.2"
+
+"@polkadot/networks@^3.7.1":
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-3.7.1.tgz#01e568e0f7791c22eb896ffabc23e936ede57c43"
+  integrity sha512-kBPUxt3d1xXeJaFilyVI717TKOZJko/3pvFIDqbSc0i2qdXv8bmRR5r7KMnEB7MvTeMPKHVhcesWksAIdsYRew==
+  dependencies:
+    "@babel/runtime" "^7.12.1"
+
+"@polkadot/rpc-core@1.26.1":
+  version "1.26.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-1.26.1.tgz#bd1574f149a13d458c9fb626123a126daa91266e"
+  integrity sha512-sxZgc4/pbZS9rKgtwnjZzg6BsVY2PZd46yFLLFCF+QYlnM8nhYWD4hSDiEvN0N3/SNNAFJydnwE8qYV0n4dEJw==
+  dependencies:
+    "@babel/runtime" "^7.10.5"
+    "@polkadot/metadata" "1.26.1"
+    "@polkadot/rpc-provider" "1.26.1"
+    "@polkadot/types" "1.26.1"
+    "@polkadot/util" "^3.0.1"
+    memoizee "^0.4.14"
+    rxjs "^6.6.0"
+
+"@polkadot/rpc-provider@1.26.1":
+  version "1.26.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-1.26.1.tgz#85adef601ab7e65925761ac6e7081019de4de1c7"
+  integrity sha512-Cbwk9ydRqbri9peag8tUcmlmhUdK1MYhDcU7UgOJ9BzptnHM5BdstzC3L1lYpfFzxgyCBaDYRhnAKAIqEcQHDw==
+  dependencies:
+    "@babel/runtime" "^7.10.5"
+    "@polkadot/metadata" "1.26.1"
+    "@polkadot/types" "1.26.1"
+    "@polkadot/util" "^3.0.1"
+    "@polkadot/util-crypto" "^3.0.1"
+    bn.js "^5.1.2"
+    eventemitter3 "^4.0.4"
+    isomorphic-fetch "^2.2.1"
+    websocket "^1.0.31"
+
+"@polkadot/ts@^0.1.56":
+  version "0.1.91"
+  resolved "https://registry.yarnpkg.com/@polkadot/ts/-/ts-0.1.91.tgz#e3cc05cea480cc3d15b213110aec082fb0af5e79"
+  integrity sha512-UB8zOFZXb/ih03izzAQ1r1DRpiUXBofxAlXjcx4530jopfiNsiU1LZ2J/uS3dVV1QXaGRhkgm8SIJDLsSMRYIQ==
+  dependencies:
+    "@types/chrome" "^0.0.92"
+
+"@polkadot/types-known@1.26.1":
+  version "1.26.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-1.26.1.tgz#0e377b23d4e1dc69d282c7a96ee88926f6edacaf"
+  integrity sha512-zxdwuLTtHqmhKJCMM/tMEM+/SV6W6zI8J1QxeCw09YT6MKWx13M+uw6C66Owdm9gXyNYyq2XkGHqBH67Zpq5zg==
+  dependencies:
+    "@babel/runtime" "^7.10.5"
+    "@polkadot/types" "1.26.1"
+    "@polkadot/util" "^3.0.1"
+    bn.js "^5.1.2"
+
+"@polkadot/types@1.26.1":
+  version "1.26.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-1.26.1.tgz#e58a823da22bd526b298f7d42384bf59b8994fad"
+  integrity sha512-mrA3+qYyDvfOIOMkY8lg2ziCYpwOl3N1LUxKdiyBDtKM7Dl8ZWQ0nLUCDW5MhbzDlThmYjE4feBRA+2eBShfyA==
+  dependencies:
+    "@babel/runtime" "^7.10.5"
+    "@polkadot/metadata" "1.26.1"
+    "@polkadot/util" "^3.0.1"
+    "@polkadot/util-crypto" "^3.0.1"
+    "@types/bn.js" "^4.11.6"
+    bn.js "^5.1.2"
+    memoizee "^0.4.14"
+    rxjs "^6.6.0"
+
+"@polkadot/util-crypto@^3.0.1", "@polkadot/util-crypto@^3.7.1":
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-3.7.1.tgz#69e1cca5adc521cf0880b244dc1ae0d086c42e4c"
+  integrity sha512-ZxQa10bo85YlxfS8ieDUzmFZMkKWwOp2dGQ0Xy94e4VBkWVPq9JjAfm8RnLy6D7k5KvMhzKuzJk7IcBDDdXGSw==
+  dependencies:
+    "@babel/runtime" "^7.12.1"
+    "@polkadot/networks" "^3.7.1"
+    "@polkadot/util" "^3.7.1"
+    "@polkadot/wasm-crypto" "^1.4.1"
+    base-x "^3.0.8"
+    blakejs "^1.1.0"
+    bn.js "^5.1.3"
+    create-hash "^1.2.0"
+    elliptic "^6.5.3"
+    js-sha3 "^0.8.0"
+    pbkdf2 "^3.1.1"
+    scryptsy "^2.1.0"
+    tweetnacl "^1.0.3"
+    xxhashjs "^0.2.2"
+
+"@polkadot/util@^3.0.1", "@polkadot/util@^3.7.1":
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-3.7.1.tgz#b7585380a6177814f7e28dc2165814864ef2c67b"
+  integrity sha512-nvgzAbT/a213mpUd56YwK/zgbGKcQoMNLTmqcBHn1IP9u5J9XJcb1zPzqmCTg6mqnjrsgzJsWml9OpQftrcB6g==
+  dependencies:
+    "@babel/runtime" "^7.12.1"
+    "@polkadot/x-textdecoder" "^3.7.1"
+    "@polkadot/x-textencoder" "^3.7.1"
+    "@types/bn.js" "^4.11.6"
+    bn.js "^5.1.3"
+    camelcase "^5.3.1"
+    ip-regex "^4.2.0"
+
+"@polkadot/wasm-crypto@^1.4.1":
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-1.4.1.tgz#0a053d0c2587da30fb5313cef81f8d9a52029c68"
+  integrity sha512-GPBCh8YvQmA5bobI4rqRkUhrEHkEWU1+lcJVPbZYsa7jiHFaZpzCLrGQfiqW/vtbU1aBS2wmJ0x1nlt33B9QqQ==
+
+"@polkadot/x-textdecoder@^3.7.1":
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-3.7.1.tgz#2d02bd33df0e5d4818b8d96892a5c8290e967573"
+  integrity sha512-GztrO7O880GR7C64PK30J7oLm+88OMxAUVW35njE+9qFUH6MGEKbtaLGUSn0JLCCtSme2f1i7DZ+1Pdbqowtnw==
+  dependencies:
+    "@babel/runtime" "^7.12.1"
+
+"@polkadot/x-textencoder@^3.7.1":
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-3.7.1.tgz#1fe1884821f255565735b1b5dbb17ee61de51fa3"
+  integrity sha512-39jwEu+gok8hFl/UqBr6WDhSeSr4qblriwM++2Vwrw/298hd5uQ7xtJNZKdrbrPCkExPZhrxwVg/mJTHBpwSng==
+  dependencies:
+    "@babel/runtime" "^7.12.1"
+
+"@types/bn.js@^4.11.5", "@types/bn.js@^4.11.6":
+  version "4.11.6"
+  resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c"
+  integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==
+  dependencies:
+    "@types/node" "*"
+
+"@types/chrome@^0.0.92":
+  version "0.0.92"
+  resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.92.tgz#8630a52fcbcd0b30a2301f2a092386018ece1de6"
+  integrity sha512-bTv1EljZ03bexRJwS5FwSZmrudtw+QNbzwUY2sxVtXWgtxk752G4I2owhZ+Mlzbf3VKvG+rBYSw/FnvzuZ4xOA==
+  dependencies:
+    "@types/filesystem" "*"
+
+"@types/filesystem@*":
+  version "0.0.29"
+  resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.29.tgz#ee3748eb5be140dcf980c3bd35f11aec5f7a3748"
+  integrity sha512-85/1KfRedmfPGsbK8YzeaQUyV1FQAvMPMTuWFQ5EkLd2w7szhNO96bk3Rh/SKmOfd9co2rCLf0Voy4o7ECBOvw==
+  dependencies:
+    "@types/filewriter" "*"
+
+"@types/filewriter@*":
+  version "0.0.28"
+  resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3"
+  integrity sha1-wFTor02d11205jq8dviFFocU1LM=
+
+"@types/lodash@^4.14.157":
+  version "4.14.168"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008"
+  integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==
+
+"@types/node@*":
+  version "14.14.31"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.31.tgz#72286bd33d137aa0d152d47ec7c1762563d34055"
+  integrity sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==
+
+"@types/unist@^2.0.0", "@types/unist@^2.0.2":
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
+  integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==
+
+"@types/vfile@^4.0.0":
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/@types/vfile/-/vfile-4.0.0.tgz#c32d13cbda319bc9f4ab3cacc0263b4ba1dd1ea3"
+  integrity sha512-eleP0/Cz8uVWxARDLi3Axq2+fDdN4ibAXoC6Pv8p6s7znXaUL7XvhgeIhjCiNMnvlLNP+tmCLd+RuCryGgmtEg==
+  dependencies:
+    vfile "*"
+
+ajv@^6.11.0:
+  version "6.12.6"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+  integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+  dependencies:
+    fast-deep-equal "^3.1.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+base-x@^3.0.8:
+  version "3.0.8"
+  resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d"
+  integrity sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==
+  dependencies:
+    safe-buffer "^5.0.1"
+
+blakejs@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5"
+  integrity sha1-ad+S75U6qIylGjLfarHFShVfx6U=
+
+bn.js@^4.11.8, bn.js@^4.11.9:
+  version "4.12.0"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
+  integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
+
+bn.js@^5.1.2, bn.js@^5.1.3:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
+  integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==
+
+brorand@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+  integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
+
+bufferutil@^4.0.1:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.3.tgz#66724b756bed23cd7c28c4d306d7994f9943cc6b"
+  integrity sha512-yEYTwGndELGvfXsImMBLop58eaGW+YdONi1fNjTINSY98tmMmFijBG6WXgdkfuLNt4imzQNtIE+eBp1PVpMCSw==
+  dependencies:
+    node-gyp-build "^4.2.0"
+
+camelcase@^5.3.1:
+  version "5.3.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+  integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+
+cipher-base@^1.0.1, cipher-base@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
+  integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==
+  dependencies:
+    inherits "^2.0.1"
+    safe-buffer "^5.0.1"
+
+create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
+  integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
+  dependencies:
+    cipher-base "^1.0.1"
+    inherits "^2.0.1"
+    md5.js "^1.3.4"
+    ripemd160 "^2.0.1"
+    sha.js "^2.4.0"
+
+create-hmac@^1.1.4:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
+  integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
+  dependencies:
+    cipher-base "^1.0.3"
+    create-hash "^1.1.0"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+cuint@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b"
+  integrity sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=
+
+d@1, d@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
+  integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
+  dependencies:
+    es5-ext "^0.10.50"
+    type "^1.0.1"
+
+debug@^2.2.0:
+  version "2.6.9"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+  integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+  dependencies:
+    ms "2.0.0"
+
+elliptic@^6.5.3:
+  version "6.5.4"
+  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb"
+  integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==
+  dependencies:
+    bn.js "^4.11.9"
+    brorand "^1.1.0"
+    hash.js "^1.0.0"
+    hmac-drbg "^1.0.1"
+    inherits "^2.0.4"
+    minimalistic-assert "^1.0.1"
+    minimalistic-crypto-utils "^1.0.1"
+
+encoding@^0.1.11:
+  version "0.1.13"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
+  integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
+  dependencies:
+    iconv-lite "^0.6.2"
+
+es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
+  version "0.10.53"
+  resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
+  integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
+  dependencies:
+    es6-iterator "~2.0.3"
+    es6-symbol "~3.1.3"
+    next-tick "~1.0.0"
+
+es6-iterator@^2.0.3, es6-iterator@~2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
+  integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
+  dependencies:
+    d "1"
+    es5-ext "^0.10.35"
+    es6-symbol "^3.1.1"
+
+es6-symbol@^3.1.1, es6-symbol@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
+  integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
+  dependencies:
+    d "^1.0.1"
+    ext "^1.1.2"
+
+es6-weak-map@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53"
+  integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==
+  dependencies:
+    d "1"
+    es5-ext "^0.10.46"
+    es6-iterator "^2.0.3"
+    es6-symbol "^3.1.1"
+
+event-emitter@^0.3.5:
+  version "0.3.5"
+  resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
+  integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=
+  dependencies:
+    d "1"
+    es5-ext "~0.10.14"
+
+eventemitter3@^4.0.4:
+  version "4.0.7"
+  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+  integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
+
+ext@^1.1.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244"
+  integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==
+  dependencies:
+    type "^2.0.0"
+
+fast-deep-equal@^3.1.1:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+  integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-json-stable-stringify@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+  integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+hash-base@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
+  integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==
+  dependencies:
+    inherits "^2.0.4"
+    readable-stream "^3.6.0"
+    safe-buffer "^5.2.0"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
+  integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
+  dependencies:
+    inherits "^2.0.3"
+    minimalistic-assert "^1.0.1"
+
+hmac-drbg@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+  integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=
+  dependencies:
+    hash.js "^1.0.3"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.1"
+
+iconv-lite@^0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01"
+  integrity sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==
+  dependencies:
+    safer-buffer ">= 2.1.2 < 3.0.0"
+
+inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+ip-regex@^4.2.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5"
+  integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==
+
+is-buffer@^2.0.0:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
+  integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
+
+is-promise@^2.2.2:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
+  integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+  integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+
+is-typedarray@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+  integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
+
+isomorphic-fetch@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+js-sha3@^0.8.0:
+  version "0.8.0"
+  resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
+  integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
+
+json-schema-traverse@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+  integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+lodash@^4.17.15:
+  version "4.17.21"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+lru-queue@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3"
+  integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=
+  dependencies:
+    es5-ext "~0.10.2"
+
+md5.js@^1.3.4:
+  version "1.3.5"
+  resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
+  integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==
+  dependencies:
+    hash-base "^3.0.0"
+    inherits "^2.0.1"
+    safe-buffer "^5.1.2"
+
+memoizee@^0.4.14:
+  version "0.4.15"
+  resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72"
+  integrity sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==
+  dependencies:
+    d "^1.0.1"
+    es5-ext "^0.10.53"
+    es6-weak-map "^2.0.3"
+    event-emitter "^0.3.5"
+    is-promise "^2.2.2"
+    lru-queue "^0.1.0"
+    next-tick "^1.1.0"
+    timers-ext "^0.1.7"
+
+minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+  integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
+
+minimalistic-crypto-utils@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+  integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
+
+moment@^2.24.0:
+  version "2.29.1"
+  resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
+  integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
+
+ms@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+  integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+next-tick@1, next-tick@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
+  integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
+
+next-tick@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
+  integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
+
+node-fetch@^1.0.1:
+  version "1.7.3"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
+  integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+node-gyp-build@^4.2.0:
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739"
+  integrity sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==
+
+pbkdf2@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94"
+  integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==
+  dependencies:
+    create-hash "^1.1.2"
+    create-hmac "^1.1.4"
+    ripemd160 "^2.0.1"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+punycode@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+  integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+readable-stream@^3.6.0:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
+  integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
+  dependencies:
+    inherits "^2.0.3"
+    string_decoder "^1.1.1"
+    util-deprecate "^1.0.1"
+
+regenerator-runtime@^0.13.4:
+  version "0.13.7"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
+  integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
+  integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==
+  dependencies:
+    hash-base "^3.0.0"
+    inherits "^2.0.1"
+
+rxjs@^6.6.0:
+  version "6.6.6"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70"
+  integrity sha512-/oTwee4N4iWzAMAL9xdGKjkEHmIwupR3oXbQjCKywF1BeFohswF3vZdogbmEF6pZkOsXTzWkrZszrWpQTByYVg==
+  dependencies:
+    tslib "^1.9.0"
+
+safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+  integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+"safer-buffer@>= 2.1.2 < 3.0.0":
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+  integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+scryptsy@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790"
+  integrity sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w==
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+  version "2.4.11"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
+  integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
+  dependencies:
+    inherits "^2.0.1"
+    safe-buffer "^5.0.1"
+
+string_decoder@^1.1.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+  integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+  dependencies:
+    safe-buffer "~5.2.0"
+
+timers-ext@^0.1.7:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6"
+  integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==
+  dependencies:
+    es5-ext "~0.10.46"
+    next-tick "1"
+
+tslib@^1.9.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+  integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
+tweetnacl@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
+  integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
+
+type@^1.0.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
+  integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
+
+type@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/type/-/type-2.3.0.tgz#ada7c045f07ead08abf9e2edd29be1a0c0661132"
+  integrity sha512-rgPIqOdfK/4J9FhiVrZ3cveAjRRo5rsQBAIhnylX874y1DX/kEKSVdLsnuHB6l1KTjHyU01VjiMBHgU2adejyg==
+
+typedarray-to-buffer@^3.1.5:
+  version "3.1.5"
+  resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
+  integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
+  dependencies:
+    is-typedarray "^1.0.0"
+
+typescript@^3.9.7:
+  version "3.9.9"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674"
+  integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==
+
+unist-util-stringify-position@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da"
+  integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==
+  dependencies:
+    "@types/unist" "^2.0.2"
+
+uri-js@^4.2.2:
+  version "4.4.1"
+  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+  integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+  dependencies:
+    punycode "^2.1.0"
+
+utf-8-validate@^5.0.2:
+  version "5.0.4"
+  resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.4.tgz#72a1735983ddf7a05a43a9c6b67c5ce1c910f9b8"
+  integrity sha512-MEF05cPSq3AwJ2C7B7sHAA6i53vONoZbMGX8My5auEVm6W+dJ2Jd/TZPyGJ5CH42V2XtbI5FD28HeHeqlPzZ3Q==
+  dependencies:
+    node-gyp-build "^4.2.0"
+
+util-deprecate@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+  integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
+
+vfile-message@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a"
+  integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==
+  dependencies:
+    "@types/unist" "^2.0.0"
+    unist-util-stringify-position "^2.0.0"
+
+vfile@*:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624"
+  integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==
+  dependencies:
+    "@types/unist" "^2.0.0"
+    is-buffer "^2.0.0"
+    unist-util-stringify-position "^2.0.0"
+    vfile-message "^2.0.0"
+
+websocket@^1.0.31:
+  version "1.0.33"
+  resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.33.tgz#407f763fc58e74a3fa41ca3ae5d78d3f5e3b82a5"
+  integrity sha512-XwNqM2rN5eh3G2CUQE3OHZj+0xfdH42+OFK6LdC2yqiC0YU8e5UK0nYre220T0IyyN031V/XOvtHvXozvJYFWA==
+  dependencies:
+    bufferutil "^4.0.1"
+    debug "^2.2.0"
+    es5-ext "^0.10.50"
+    typedarray-to-buffer "^3.1.5"
+    utf-8-validate "^5.0.2"
+    yaeti "^0.0.6"
+
+whatwg-fetch@>=0.10.0:
+  version "3.6.2"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c"
+  integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==
+
+xxhashjs@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/xxhashjs/-/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8"
+  integrity sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==
+  dependencies:
+    cuint "^0.2.2"
+
+yaeti@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577"
+  integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=

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