Leszek Wiesner hace 4 años
padre
commit
5c3869958b

+ 63 - 92
cli/src/Api.ts

@@ -1,13 +1,12 @@
 import BN from 'bn.js'
-import { registerJoystreamTypes } from '@joystream/types/'
+import { types } from '@joystream/types/'
 import { ApiPromise, WsProvider } from '@polkadot/api'
-import { QueryableStorageMultiArg } from '@polkadot/api/types'
+import { QueryableStorageMultiArg, SubmittableExtrinsic, QueryableStorageEntry } from '@polkadot/api/types'
 import { formatBalance } from '@polkadot/util'
-import { Hash, Balance, Moment, BlockNumber } from '@polkadot/types/interfaces'
+import { Balance, Moment, BlockNumber } from '@polkadot/types/interfaces'
 import { KeyringPair } from '@polkadot/keyring/types'
-import { Codec } from '@polkadot/types/types'
-import { Option, Vec } from '@polkadot/types'
-import { u32 } from '@polkadot/types/primitive'
+import { Codec, CodecArg } from '@polkadot/types/types'
+import { Option, Vec, UInt } from '@polkadot/types'
 import {
   AccountSummary,
   CouncilInfoObj,
@@ -24,7 +23,7 @@ import {
   UnstakingPeriods,
   StakingPolicyUnstakingPeriodKey,
 } from './Types'
-import { DerivedFees, DerivedBalances } from '@polkadot/api-derive/types'
+import { DeriveBalancesAll } from '@polkadot/api-derive/types'
 import { CLIError } from '@oclif/errors'
 import ExitCodes from './ExitCodes'
 import {
@@ -46,12 +45,11 @@ import {
 import { MemberId, Membership } from '@joystream/types/members'
 import { RewardRelationship, RewardRelationshipId } from '@joystream/types/recurring-rewards'
 import { Stake, StakeId } from '@joystream/types/stake'
-import { LinkageResult } from '@polkadot/types/codec/Linkage'
 
 import { InputValidationLengthConstraint } from '@joystream/types/common'
 
 export const DEFAULT_API_URI = 'ws://localhost:9944/'
-const DEFAULT_DECIMALS = new u32(12)
+const DEFAULT_DECIMALS = new BN(12)
 
 // Mapping of working group to api module
 export const apiModuleByGroup: { [key in WorkingGroups]: string } = {
@@ -72,8 +70,7 @@ export default class Api {
 
   private static async initApi(apiUri: string = DEFAULT_API_URI): Promise<ApiPromise> {
     const wsProvider: WsProvider = new WsProvider(apiUri)
-    registerJoystreamTypes()
-    const api = await ApiPromise.create({ provider: wsProvider })
+    const api = await ApiPromise.create({ provider: wsProvider, types })
 
     // Initializing some api params based on pioneer/packages/react-api/Api.tsx
     const [properties] = await Promise.all([api.rpc.system.properties()])
@@ -110,8 +107,10 @@ export default class Api {
     return results
   }
 
-  async getAccountsBalancesInfo(accountAddresses: string[]): Promise<DerivedBalances[]> {
-    const accountsBalances: DerivedBalances[] = await this._api.derive.balances.votingBalances(accountAddresses)
+  async getAccountsBalancesInfo(accountAddresses: string[]): Promise<DeriveBalancesAll[]> {
+    const accountsBalances: DeriveBalancesAll[] = await Promise.all(
+      accountAddresses.map((addr) => this._api.derive.balances.all(addr))
+    )
 
     return accountsBalances
   }
@@ -119,7 +118,7 @@ export default class Api {
   // Get on-chain data related to given account.
   // For now it's just account balances
   async getAccountSummary(accountAddresses: string): Promise<AccountSummary> {
-    const balances: DerivedBalances = (await this.getAccountsBalancesInfo([accountAddresses]))[0]
+    const balances: DeriveBalancesAll = (await this.getAccountsBalancesInfo([accountAddresses]))[0]
     // TODO: Some more information can be fetched here in the future
 
     return { balances }
@@ -146,34 +145,29 @@ export default class Api {
     return createCouncilInfoObj(...results)
   }
 
-  // TODO: This formula is probably not too good, so some better implementation will be required in the future
-  async estimateFee(account: KeyringPair, recipientAddr: string, amount: BN): Promise<BN> {
-    const transfer = this._api.tx.balances.transfer(recipientAddr, amount)
-    const signature = account.sign(transfer.toU8a())
-    const transactionByteSize: BN = new BN(transfer.encodedLength + signature.length)
-
-    const fees: DerivedFees = await this._api.derive.balances.fees()
-
-    const estimatedFee = fees.transactionBaseFee.add(fees.transactionByteFee.mul(transactionByteSize))
-
-    return estimatedFee
+  async estimateFee(account: KeyringPair, tx: SubmittableExtrinsic<'promise'>): Promise<Balance> {
+    const paymentInfo = await tx.paymentInfo(account)
+    return paymentInfo.partialFee
   }
 
-  async transfer(account: KeyringPair, recipientAddr: string, amount: BN): Promise<Hash> {
-    const txHash = await this._api.tx.balances.transfer(recipientAddr, amount).signAndSend(account)
-    return txHash
+  createTransferTx(recipient: string, amount: BN) {
+    return this._api.tx.balances.transfer(recipient, amount)
   }
 
   // Working groups
-  // TODO: This is a lot of repeated logic from "/pioneer/joy-roles/src/transport.substrate.ts"
-  // (although simplified a little bit)
-  // Hopefully this will be refactored to "joystream-js" soon
-  protected singleLinkageResult<T extends Codec>(result: LinkageResult) {
-    return result[0] as T
-  }
+  // TODO: This is a lot of repeated logic from "/pioneer/joy-utils/transport"
+  // It will be refactored to "joystream-js" soon
+  async entriesByIds<IDType extends UInt, ValueType extends Codec>(
+    apiMethod: QueryableStorageEntry<'promise'>,
+    firstKey?: CodecArg // First key in case of double maps
+  ): Promise<[IDType, ValueType][]> {
+    const entries: [IDType, ValueType][] = (await apiMethod.entries<ValueType>(firstKey)).map(([storageKey, value]) => [
+      // If double-map (first key is provided), we map entries by second key
+      storageKey.args[firstKey !== undefined ? 1 : 0] as IDType,
+      value,
+    ])
 
-  protected multiLinkageResult<K extends Codec, V extends Codec>(result: LinkageResult): [Vec<K>, Vec<V>] {
-    return [result[0] as Vec<K>, result[1] as Vec<V>]
+    return entries.sort((a, b) => a[0].toNumber() - b[0].toNumber())
   }
 
   protected async blockHash(height: number): Promise<string> {
@@ -214,7 +208,7 @@ export default class Api {
   }
 
   protected async stakeValue(stakeId: StakeId): Promise<Balance> {
-    const stake = this.singleLinkageResult<Stake>((await this._api.query.stake.stakes(stakeId)) as LinkageResult)
+    const stake = await this._api.query.stake.stakes<Stake>(stakeId)
     return stake.value
   }
 
@@ -223,8 +217,8 @@ export default class Api {
   }
 
   protected async workerReward(relationshipId: RewardRelationshipId): Promise<Reward> {
-    const rewardRelationship = this.singleLinkageResult<RewardRelationship>(
-      (await this._api.query.recurringRewards.rewardRelationships(relationshipId)) as LinkageResult
+    const rewardRelationship = await this._api.query.recurringRewards.rewardRelationships<RewardRelationship>(
+      relationshipId
     )
 
     return {
@@ -266,18 +260,16 @@ export default class Api {
   }
 
   async workerByWorkerId(group: WorkingGroups, workerId: number): Promise<Worker> {
-    const nextId = (await this.workingGroupApiQuery(group).nextWorkerId()) as WorkerId
+    const nextId = await this.workingGroupApiQuery(group).nextWorkerId<WorkerId>()
 
     // This is chain specfic, but if next id is still 0, it means no workers have been added yet
     if (workerId < 0 || workerId >= nextId.toNumber()) {
       throw new CLIError('Invalid worker id!')
     }
 
-    const worker = this.singleLinkageResult<Worker>(
-      (await this.workingGroupApiQuery(group).workerById(workerId)) as LinkageResult
-    )
+    const worker = await this.workingGroupApiQuery(group).workerById<Worker>(workerId)
 
-    if (!worker.is_active) {
+    if (worker.isEmpty) {
       throw new CLIError('This worker is not active anymore')
     }
 
@@ -286,67 +278,51 @@ export default class Api {
 
   async groupMember(group: WorkingGroups, workerId: number) {
     const worker = await this.workerByWorkerId(group, workerId)
-    return await this.parseGroupMember(new WorkerId(workerId), worker)
+    return await this.parseGroupMember(this._api.createType('WorkerId', workerId), worker)
   }
 
   async groupMembers(group: WorkingGroups): Promise<GroupMember[]> {
-    const nextId = (await this.workingGroupApiQuery(group).nextWorkerId()) as WorkerId
+    const workerEntries = await this.entriesByIds<WorkerId, Worker>(this.workingGroupApiQuery(group).workerById)
 
-    // This is chain specfic, but if next id is still 0, it means no workers have been added yet
-    if (nextId.eq(0)) {
-      return []
-    }
-
-    const [workerIds, workers] = this.multiLinkageResult<WorkerId, Worker>(
-      (await this.workingGroupApiQuery(group).workerById()) as LinkageResult
+    const groupMembers: GroupMember[] = await Promise.all(
+      workerEntries.map(([id, worker]) => this.parseGroupMember(id, worker))
     )
 
-    const groupMembers: GroupMember[] = []
-    for (const [index, worker] of Object.entries(workers.toArray())) {
-      const workerId = workerIds[parseInt(index)]
-      if (worker.is_active) {
-        groupMembers.push(await this.parseGroupMember(workerId, worker))
-      }
-    }
-
-    return groupMembers.reverse()
+    return groupMembers.reverse() // Sort by newest
   }
 
   async openingsByGroup(group: WorkingGroups): Promise<GroupOpening[]> {
-    const openings: GroupOpening[] = []
-    const nextId = (await this.workingGroupApiQuery(group).nextOpeningId()) as OpeningId
+    let openings: GroupOpening[] = []
+    const nextId = await this.workingGroupApiQuery(group).nextOpeningId<OpeningId>()
 
     // This is chain specfic, but if next id is still 0, it means no openings have been added yet
     if (!nextId.eq(0)) {
-      const highestId = nextId.toNumber() - 1
-      for (let i = highestId; i >= 0; i--) {
-        openings.push(await this.groupOpening(group, i))
-      }
+      const ids = Array.from(Array(nextId.toNumber()).keys()).reverse() // Sort by newest
+      openings = await Promise.all(ids.map((id) => this.groupOpening(group, id)))
     }
 
     return openings
   }
 
   protected async hiringOpeningById(id: number | OpeningId): Promise<Opening> {
-    const result = (await this._api.query.hiring.openingById(id)) as LinkageResult
-    return this.singleLinkageResult<Opening>(result)
+    const result = await this._api.query.hiring.openingById<Opening>(id)
+    return result
   }
 
   protected async hiringApplicationById(id: number | ApplicationId): Promise<Application> {
-    const result = (await this._api.query.hiring.applicationById(id)) as LinkageResult
-    return this.singleLinkageResult<Application>(result)
+    const result = await this._api.query.hiring.applicationById<Application>(id)
+    return result
   }
 
   async wgApplicationById(group: WorkingGroups, wgApplicationId: number): Promise<WGApplication> {
-    const nextAppId = (await this.workingGroupApiQuery(group).nextApplicationId()) as ApplicationId
+    const nextAppId = await this.workingGroupApiQuery(group).nextApplicationId<ApplicationId>()
 
     if (wgApplicationId < 0 || wgApplicationId >= nextAppId.toNumber()) {
       throw new CLIError('Invalid working group application ID!')
     }
 
-    return this.singleLinkageResult<WGApplication>(
-      (await this.workingGroupApiQuery(group).applicationById(wgApplicationId)) as LinkageResult
-    )
+    const result = await this.workingGroupApiQuery(group).applicationById<WGApplication>(wgApplicationId)
+    return result
   }
 
   protected async parseApplication(wgApplicationId: number, wgApplication: WGApplication): Promise<GroupApplication> {
@@ -376,18 +352,15 @@ export default class Api {
   }
 
   protected async groupOpeningApplications(group: WorkingGroups, wgOpeningId: number): Promise<GroupApplication[]> {
-    const applications: GroupApplication[] = []
-
-    const nextAppId = (await this.workingGroupApiQuery(group).nextApplicationId()) as ApplicationId
-    for (let i = 0; i < nextAppId.toNumber(); i++) {
-      const wgApplication = await this.wgApplicationById(group, i)
-      if (wgApplication.opening_id.toNumber() !== wgOpeningId) {
-        continue
-      }
-      applications.push(await this.parseApplication(i, wgApplication))
-    }
+    const wgApplicationEntries = await this.entriesByIds<ApplicationId, WGApplication>(
+      this.workingGroupApiQuery(group).applicationById
+    )
 
-    return applications
+    return Promise.all(
+      wgApplicationEntries
+        .filter(([id, wgApplication]) => wgApplication.opening_id.eqn(wgOpeningId))
+        .map(([id, wgApplication]) => this.parseApplication(id.toNumber(), wgApplication))
+    )
   }
 
   async groupOpening(group: WorkingGroups, wgOpeningId: number): Promise<GroupOpening> {
@@ -397,9 +370,7 @@ export default class Api {
       throw new CLIError('Invalid working group opening ID!')
     }
 
-    const groupOpening = this.singleLinkageResult<WGOpening>(
-      (await this.workingGroupApiQuery(group).openingById(wgOpeningId)) as LinkageResult
-    )
+    const groupOpening = await this.workingGroupApiQuery(group).openingById<WGOpening>(wgOpeningId)
 
     const openingId = groupOpening.hiring_opening_id.toNumber()
     const opening = await this.hiringOpeningById(openingId)
@@ -493,11 +464,11 @@ export default class Api {
   }
 
   async getMemberIdsByControllerAccount(address: string): Promise<MemberId[]> {
-    const ids = (await this._api.query.members.memberIdsByControllerAccountId(address)) as Vec<MemberId>
+    const ids = await this._api.query.members.memberIdsByControllerAccountId<Vec<MemberId>>(address)
     return ids.toArray()
   }
 
   async workerExitRationaleConstraint(group: WorkingGroups): Promise<InputValidationLengthConstraint> {
-    return (await this.workingGroupApiQuery(group).workerExitRationaleText()) as InputValidationLengthConstraint
+    return await this.workingGroupApiQuery(group).workerExitRationaleText<InputValidationLengthConstraint>()
   }
 }

+ 84 - 113
cli/src/Types.ts

@@ -5,7 +5,7 @@ import { Constructor, Codec } from '@polkadot/types/types'
 import { Struct, Vec } from '@polkadot/types/codec'
 import { u32 } from '@polkadot/types/primitive'
 import { BlockNumber, Balance, AccountId } from '@polkadot/types/interfaces'
-import { DerivedBalances } from '@polkadot/api-derive/types'
+import { DeriveBalancesAll } from '@polkadot/api-derive/types'
 import { KeyringPair } from '@polkadot/keyring/types'
 import { WorkerId, OpeningType } from '@joystream/types/working-group'
 import { Membership, MemberId } from '@joystream/types/members'
@@ -25,6 +25,7 @@ import {
 import ajv from 'ajv'
 import { Opening, StakingPolicy, ApplicationStageKeys } from '@joystream/types/hiring'
 import { Validator } from 'inquirer'
+import { JoyStructCustom } from '@joystream/types/common'
 
 // KeyringPair type extended with mandatory "meta.name"
 // It's used for accounts/keys management within CLI.
@@ -37,7 +38,7 @@ export type NamedKeyringPair = KeyringPair & {
 
 // Summary of the account information fetched from the api for "account:current" purposes (currently just balances)
 export type AccountSummary = {
-  balances: DerivedBalances
+  balances: DeriveBalancesAll
 }
 
 // This function allows us to easily transform the tuple into the object
@@ -186,187 +187,157 @@ export type GroupOpening = {
 // Note those types are not part of the runtime etc., we just use them to simplify prompting for values
 // (since there exists functionality that handles that for substrate types like: Struct, Vec etc.)
 interface WithJSONable<T> {
-  toJSON: () => T
+  toJSONObj: () => T
 }
-export class HRTJobSpecificsStruct extends Struct implements WithJSONable<JobSpecifics> {
-  constructor(value?: JobSpecifics) {
-    super(
-      {
-        title: 'Text',
-        description: 'Text',
-      },
-      value
-    )
-  }
+export class HRTJobSpecificsStruct
+  extends JoyStructCustom({
+    title: Text,
+    description: Text,
+  })
+  implements WithJSONable<JobSpecifics> {
   get title(): string {
-    return (this.get('title') as Text).toString()
+    return this.getField('title').toString()
   }
   get description(): string {
-    return (this.get('description') as Text).toString()
+    return this.getField('description').toString()
   }
-  toJSON(): JobSpecifics {
+  toJSONObj(): JobSpecifics {
     const { title, description } = this
     return { title, description }
   }
 }
-export class HRTEntryInMembershipModukeStruct extends Struct implements WithJSONable<EntryInMembershipModuke> {
-  constructor(value?: EntryInMembershipModuke) {
-    super(
-      {
-        handle: 'Text',
-      },
-      value
-    )
-  }
+export class HRTEntryInMembershipModukeStruct
+  extends JoyStructCustom({
+    handle: Text,
+  })
+  implements WithJSONable<EntryInMembershipModuke> {
   get handle(): string {
-    return (this.get('handle') as Text).toString()
+    return this.getField('handle').toString()
   }
-  toJSON(): EntryInMembershipModuke {
+  toJSONObj(): EntryInMembershipModuke {
     const { handle } = this
     return { handle }
   }
 }
-export class HRTCreatorDetailsStruct extends Struct implements WithJSONable<CreatorDetails> {
-  constructor(value?: CreatorDetails) {
-    super(
-      {
-        membership: HRTEntryInMembershipModukeStruct,
-      },
-      value
-    )
-  }
+export class HRTCreatorDetailsStruct
+  extends JoyStructCustom({
+    membership: HRTEntryInMembershipModukeStruct,
+  })
+  implements WithJSONable<CreatorDetails> {
   get membership(): EntryInMembershipModuke {
-    return (this.get('membership') as HRTEntryInMembershipModukeStruct).toJSON()
+    return this.getField('membership').toJSONObj()
   }
-  toJSON(): CreatorDetails {
+  toJSONObj(): CreatorDetails {
     const { membership } = this
     return { membership }
   }
 }
-export class HRTHiringProcessStruct extends Struct implements WithJSONable<HiringProcess> {
-  constructor(value?: HiringProcess) {
-    super(
-      {
-        details: 'Vec<Text>',
-      },
-      value
-    )
-  }
+export class HRTHiringProcessStruct
+  extends JoyStructCustom({
+    details: Vec.with(Text),
+  })
+  implements WithJSONable<HiringProcess> {
   get details(): AdditionalRolehiringProcessDetails {
-    return (this.get('details') as Vec<Text>).toArray().map((v) => v.toString())
+    return this.getField('details')
+      .toArray()
+      .map((v) => v.toString())
   }
-  toJSON(): HiringProcess {
+  toJSONObj(): HiringProcess {
     const { details } = this
     return { details }
   }
 }
-export class HRTQuestionFieldStruct extends Struct implements WithJSONable<QuestionField> {
-  constructor(value?: QuestionField) {
-    super(
-      {
-        title: 'Text',
-        type: 'Text',
-      },
-      value
-    )
-  }
+export class HRTQuestionFieldStruct
+  extends JoyStructCustom({
+    title: Text,
+    type: Text,
+  })
+  implements WithJSONable<QuestionField> {
   get title(): string {
-    return (this.get('title') as Text).toString()
+    return this.getField('title').toString()
   }
   get type(): string {
-    return (this.get('type') as Text).toString()
+    return this.getField('type').toString()
   }
-  toJSON(): QuestionField {
+  toJSONObj(): QuestionField {
     const { title, type } = this
     return { title, type }
   }
 }
 class HRTQuestionsFieldsVec extends Vec.with(HRTQuestionFieldStruct) implements WithJSONable<QuestionsFields> {
-  toJSON(): QuestionsFields {
-    return this.toArray().map((v) => v.toJSON())
+  toJSONObj(): QuestionsFields {
+    return this.toArray().map((v) => v.toJSONObj())
   }
 }
-export class HRTQuestionSectionStruct extends Struct implements WithJSONable<QuestionSection> {
-  constructor(value?: QuestionSection) {
-    super(
-      {
-        title: 'Text',
-        questions: HRTQuestionsFieldsVec,
-      },
-      value
-    )
-  }
+export class HRTQuestionSectionStruct
+  extends JoyStructCustom({
+    title: Text,
+    questions: HRTQuestionsFieldsVec,
+  })
+  implements WithJSONable<QuestionSection> {
   get title(): string {
-    return (this.get('title') as Text).toString()
+    return this.getField('title').toString()
   }
   get questions(): QuestionsFields {
-    return (this.get('questions') as HRTQuestionsFieldsVec).toJSON()
+    return this.getField('questions').toJSONObj()
   }
-  toJSON(): QuestionSection {
+  toJSONObj(): QuestionSection {
     const { title, questions } = this
     return { title, questions }
   }
 }
 export class HRTQuestionSectionsVec extends Vec.with(HRTQuestionSectionStruct)
   implements WithJSONable<QuestionSections> {
-  toJSON(): QuestionSections {
-    return this.toArray().map((v) => v.toJSON())
+  toJSONObj(): QuestionSections {
+    return this.toArray().map((v) => v.toJSONObj())
   }
 }
-export class HRTApplicationDetailsStruct extends Struct implements WithJSONable<ApplicationDetails> {
-  constructor(value?: ApplicationDetails) {
-    super(
-      {
-        sections: HRTQuestionSectionsVec,
-      },
-      value
-    )
-  }
+export class HRTApplicationDetailsStruct
+  extends JoyStructCustom({
+    sections: HRTQuestionSectionsVec,
+  })
+  implements WithJSONable<ApplicationDetails> {
   get sections(): QuestionSections {
-    return (this.get('sections') as HRTQuestionSectionsVec).toJSON()
+    return this.getField('sections').toJSONObj()
   }
-  toJSON(): ApplicationDetails {
+  toJSONObj(): ApplicationDetails {
     const { sections } = this
     return { sections }
   }
 }
-export class HRTStruct extends Struct implements WithJSONable<GenericJoyStreamRoleSchema> {
-  constructor(value?: GenericJoyStreamRoleSchema) {
-    super(
-      {
-        version: 'u32',
-        headline: 'Text',
-        job: HRTJobSpecificsStruct,
-        application: HRTApplicationDetailsStruct,
-        reward: 'Text',
-        creator: HRTCreatorDetailsStruct,
-        process: HRTHiringProcessStruct,
-      },
-      value
-    )
-  }
+export class HRTStruct
+  extends JoyStructCustom({
+    version: u32,
+    headline: Text,
+    job: HRTJobSpecificsStruct,
+    application: HRTApplicationDetailsStruct,
+    reward: Text,
+    creator: HRTCreatorDetailsStruct,
+    process: HRTHiringProcessStruct,
+  })
+  implements WithJSONable<GenericJoyStreamRoleSchema> {
   get version(): number {
-    return (this.get('version') as u32).toNumber()
+    return this.getField('version').toNumber()
   }
   get headline(): string {
-    return (this.get('headline') as Text).toString()
+    return this.getField('headline').toString()
   }
   get job(): JobSpecifics {
-    return (this.get('job') as HRTJobSpecificsStruct).toJSON()
+    return this.getField('job').toJSONObj()
   }
   get application(): ApplicationDetails {
-    return (this.get('application') as HRTApplicationDetailsStruct).toJSON()
+    return this.getField('application').toJSONObj()
   }
   get reward(): string {
-    return (this.get('reward') as Text).toString()
+    return this.getField('reward').toString()
   }
   get creator(): CreatorDetails {
-    return (this.get('creator') as HRTCreatorDetailsStruct).toJSON()
+    return this.getField('creator').toJSONObj()
   }
   get process(): HiringProcess {
-    return (this.get('process') as HRTHiringProcessStruct).toJSON()
+    return this.getField('process').toJSONObj()
   }
-  toJSON(): GenericJoyStreamRoleSchema {
+  toJSONObj(): GenericJoyStreamRoleSchema {
     const { version, headline, job, application, reward, creator, process } = this
     return { version, headline, job, application, reward, creator, process }
   }

+ 5 - 3
cli/src/base/AccountsCommandBase.ts

@@ -8,7 +8,7 @@ import ApiCommandBase from './ApiCommandBase'
 import { Keyring } from '@polkadot/api'
 import { formatBalance } from '@polkadot/util'
 import { NamedKeyringPair } from '../Types'
-import { DerivedBalances } from '@polkadot/api-derive/types'
+import { DeriveBalancesAll } from '@polkadot/api-derive/types'
 import { toFixedLength } from '../helpers/display'
 
 const ACCOUNTS_DIRNAME = 'accounts'
@@ -54,7 +54,9 @@ export default abstract class AccountsCommandBase extends ApiCommandBase {
     const keyring = new Keyring({ type: 'sr25519' })
     keyring.addFromUri('//Alice', { name: 'Alice' })
     keyring.addFromUri('//Bob', { name: 'Bob' })
-    keyring.getPairs().forEach((pair) => this.saveAccount({ ...pair, meta: { name: pair.meta.name } }, '', true))
+    keyring
+      .getPairs()
+      .forEach((pair) => this.saveAccount({ ...pair, meta: { name: pair.meta.name as string } }, '', true))
   }
 
   fetchAccountFromJsonFile(jsonBackupFilePath: string): NamedKeyringPair {
@@ -186,7 +188,7 @@ export default abstract class AccountsCommandBase extends ApiCommandBase {
     message = 'Select an account',
     showBalances = true
   ): Promise<NamedKeyringPair> {
-    let balances: DerivedBalances[]
+    let balances: DeriveBalancesAll[]
     if (showBalances) {
       balances = await this.getApi().getAccountsBalancesInfo(accounts.map((acc) => acc.address))
     }

+ 38 - 25
cli/src/base/ApiCommandBase.ts

@@ -2,13 +2,14 @@ import ExitCodes from '../ExitCodes'
 import { CLIError } from '@oclif/errors'
 import StateAwareCommandBase from './StateAwareCommandBase'
 import Api from '../Api'
-import { getTypeDef, createType, Option, Tuple, Bytes } from '@polkadot/types'
-import { Codec, TypeDef, TypeDefInfo, Constructor } from '@polkadot/types/types'
+import { getTypeDef, Option, Tuple, Bytes } from '@polkadot/types'
+import { Registry } from '@polkadot/types/types'
+import { Codec, CodecArg, TypeDef, TypeDefInfo, Constructor } from '@polkadot/types/types'
 import { Vec, Struct, Enum } from '@polkadot/types/codec'
 import { ApiPromise, WsProvider } from '@polkadot/api'
 import { KeyringPair } from '@polkadot/keyring/types'
 import chalk from 'chalk'
-import { SubmittableResultImpl } from '@polkadot/api/types'
+import { InterfaceTypes } from '@polkadot/types/types/registry'
 import ajv from 'ajv'
 import { ApiMethodArg, ApiMethodNamedArgs, ApiParamsOptions, ApiParamOptions } from '../Types'
 import { createParamOptions } from '../helpers/promptOptions'
@@ -32,6 +33,14 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
     return this.getApi().getOriginalApi()
   }
 
+  getTypesRegistry(): Registry {
+    return this.getOriginalApi().registry
+  }
+
+  createType<K extends keyof InterfaceTypes>(typeName: K, value?: unknown): InterfaceTypes[K] {
+    return this.getOriginalApi().createType(typeName, value)
+  }
+
   async init() {
     await super.init()
     let apiUri: string = this.getPreservedState().apiUri
@@ -90,8 +99,8 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
 
   // This is needed to correctly handle some structs, enums etc.
   // Where the main typeDef doesn't provide enough information
-  protected getRawTypeDef(type: string) {
-    const instance = createType(type as any)
+  protected getRawTypeDef(type: keyof InterfaceTypes) {
+    const instance = this.createType(type)
     return getTypeDef(instance.toRawType())
   }
 
@@ -120,7 +129,7 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
   async promptForSimple(typeDef: TypeDef, paramOptions?: ApiParamOptions): Promise<Codec> {
     // If no default provided - get default value resulting from providing empty string
     const defaultValueString =
-      paramOptions?.value?.default?.toString() || createType(typeDef.type as any, '').toString()
+      paramOptions?.value?.default?.toString() || this.createType(typeDef.type as any, '').toString()
     const providedValue = await this.simplePrompt({
       message: `Provide value for ${this.paramName(typeDef)}`,
       type: 'input',
@@ -129,7 +138,7 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
       default: (defaultValueString === '0x' ? '' : defaultValueString) || undefined,
       validate: paramOptions?.validator,
     })
-    return createType(typeDef.type as any, providedValue)
+    return this.createType(typeDef.type as any, providedValue)
   }
 
   // Prompt for Option<Codec> value
@@ -149,10 +158,10 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
         createParamOptions(subtype.name, defaultValue?.unwrapOr(undefined))
       )
       this.closeIndentGroup()
-      return new Option(subtype.type as any, value)
+      return this.createType(`Option<${subtype.type}>` as any, value)
     }
 
-    return new Option(subtype.type as any, null)
+    return this.createType(`Option<${subtype.type}>` as any, null)
   }
 
   // Prompt for Tuple
@@ -173,7 +182,7 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
     }
     this.closeIndentGroup()
 
-    return new Tuple(subtypes.map((subtype) => subtype.type) as any, result)
+    return new Tuple(this.getTypesRegistry(), subtypes.map((subtype) => subtype.type) as any, result)
   }
 
   // Prompt for Struct
@@ -182,7 +191,7 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
 
     this.openIndentGroup()
     const structType = typeDef.type
-    const rawTypeDef = this.getRawTypeDef(structType)
+    const rawTypeDef = this.getRawTypeDef(structType as keyof InterfaceTypes)
     // We assume struct typeDef always has array of typeDefs inside ".sub"
     const structSubtypes = rawTypeDef.sub as TypeDef[]
     const structDefault = paramOptions?.value?.default as Struct | undefined
@@ -200,7 +209,7 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
     }
     this.closeIndentGroup()
 
-    return createType(structType as any, structValues)
+    return this.createType(structType as any, structValues)
   }
 
   // Prompt for Vec
@@ -228,12 +237,12 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
     } while (addAnother)
     this.closeIndentGroup()
 
-    return new Vec(subtype.type as any, entries)
+    return this.createType(`Vec<${subtype.type}>` as any, entries)
   }
 
   // Prompt for Enum
   async promptForEnum(typeDef: TypeDef, paramOptions?: ApiParamOptions): Promise<Enum> {
-    const enumType = typeDef.type
+    const enumType = typeDef.type as keyof InterfaceTypes
     const rawTypeDef = this.getRawTypeDef(enumType)
     // We assume enum always has array on TypeDefs inside ".sub"
     const enumSubtypes = rawTypeDef.sub as TypeDef[]
@@ -253,12 +262,12 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
 
     if (enumSubtype.type !== 'Null') {
       const subtypeOptions = createParamOptions(enumSubtype.name, defaultValue?.value)
-      return createType(enumType as any, {
+      return this.createType(enumType as any, {
         [enumSubtype.name!]: await this.promptForParam(enumSubtype.type, subtypeOptions),
       })
     }
 
-    return createType(enumType as any, enumSubtype.name)
+    return this.createType(enumType as any, enumSubtype.name)
   }
 
   // Prompt for param based on "paramType" string (ie. Option<MemeberId>)
@@ -268,7 +277,7 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
     paramOptions?: ApiParamOptions // TODO: This is not fully implemented for all types yet
   ): Promise<ApiMethodArg> {
     const typeDef = getTypeDef(paramType)
-    const rawTypeDef = this.getRawTypeDef(paramType)
+    const rawTypeDef = this.getRawTypeDef(paramType as keyof InterfaceTypes)
 
     if (paramOptions?.forcedName) {
       typeDef.name = paramOptions.forcedName
@@ -309,11 +318,15 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
     defaultValue?: Bytes,
     schemaValidator?: ajv.ValidateFunction
   ) {
-    const rawType = new jsonStruct().toRawType()
+    const rawType = new jsonStruct(this.getTypesRegistry()).toRawType()
     const typeDef = getTypeDef(rawType)
 
     const defaultStruct =
-      defaultValue && new jsonStruct(JSON.parse(Buffer.from(defaultValue.toHex().replace('0x', ''), 'hex').toString()))
+      defaultValue &&
+      new jsonStruct(
+        this.getTypesRegistry(),
+        JSON.parse(Buffer.from(defaultValue.toHex().replace('0x', ''), 'hex').toString())
+      )
 
     if (argName) {
       typeDef.name = argName
@@ -338,7 +351,7 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
       }
     } while (!isValid)
 
-    return new Bytes('0x' + Buffer.from(jsonText, 'ascii').toString('hex'))
+    return this.createType('Bytes', '0x' + Buffer.from(jsonText, 'ascii').toString('hex'))
   }
 
   async promptForExtrinsicParams(
@@ -364,18 +377,18 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
     return values
   }
 
-  sendExtrinsic(account: KeyringPair, module: string, method: string, params: Codec[]) {
+  sendExtrinsic(account: KeyringPair, module: string, method: string, params: CodecArg[]) {
     return new Promise((resolve, reject) => {
       const extrinsicMethod = this.getOriginalApi().tx[module][method]
       let unsubscribe: () => void
       extrinsicMethod(...params)
-        .signAndSend(account, {}, (result: SubmittableResultImpl) => {
+        .signAndSend(account, {}, (result) => {
           // Implementation loosely based on /pioneer/packages/react-signer/src/Modal.tsx
           if (!result || !result.status) {
             return
           }
 
-          if (result.status.isFinalized) {
+          if (result.status.isInBlock) {
             unsubscribe()
             result.events
               .filter(({ event: { section } }): boolean => section === 'system')
@@ -401,7 +414,7 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
     account: KeyringPair,
     module: string,
     method: string,
-    params: Codec[],
+    params: CodecArg[],
     warnOnly = false // If specified - only warning will be displayed (instead of error beeing thrown)
   ) {
     try {
@@ -449,7 +462,7 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
       const argName = arg.name.toString()
       const argType = arg.type.toString()
       try {
-        parsedArgs.push({ name: argName, value: createType(argType as any, draftJSONObj[parseInt(index)]) })
+        parsedArgs.push({ name: argName, value: this.createType(argType as any, draftJSONObj[parseInt(index)]) })
       } catch (e) {
         throw new CLIError(`Couldn't parse ${argName} value from draft at ${draftFilePath}!`, {
           exit: ExitCodes.InvalidFile,

+ 1 - 1
cli/src/base/WorkingGroupsCommandBase.ts

@@ -110,7 +110,7 @@ export default abstract class WorkingGroupsCommandBase extends AccountsCommandBa
       })),
     })
 
-    return acceptedApplications
+    return acceptedApplications.sort() // Sort just in case, since runtime expects them to be sorted
   }
 
   async promptForNewOpeningDraftName() {

+ 2 - 3
cli/src/commands/account/current.ts

@@ -1,6 +1,5 @@
 import AccountsCommandBase from '../../base/AccountsCommandBase'
 import { AccountSummary, NameValueObj, NamedKeyringPair } from '../../Types'
-import { DerivedBalances } from '@polkadot/api-derive/types'
 import { displayHeader, displayNameValueTable } from '../../helpers/display'
 import { formatBalance } from '@polkadot/util'
 import moment from 'moment'
@@ -15,7 +14,7 @@ export default class AccountCurrent extends AccountsCommandBase {
 
     displayHeader('Account information')
     const creationDate: string = currentAccount.meta.whenCreated
-      ? moment(currentAccount.meta.whenCreated).format('YYYY-MM-DD HH:mm:ss')
+      ? moment(currentAccount.meta.whenCreated as string | number).format('YYYY-MM-DD HH:mm:ss')
       : '?'
     const accountRows: NameValueObj[] = [
       { name: 'Account name:', value: currentAccount.meta.name },
@@ -25,7 +24,7 @@ export default class AccountCurrent extends AccountsCommandBase {
     displayNameValueTable(accountRows)
 
     displayHeader('Balances')
-    const balances: DerivedBalances = summary.balances
+    const balances = summary.balances
     const balancesRows: NameValueObj[] = [
       { name: 'Total balance:', value: formatBalance(balances.votingBalance) },
       { name: 'Transferable balance:', value: formatBalance(balances.availableBalance) },

+ 4 - 4
cli/src/commands/account/transferTokens.ts

@@ -6,7 +6,6 @@ import { formatBalance } from '@polkadot/util'
 import { Hash } from '@polkadot/types/interfaces'
 import { NamedKeyringPair } from '../../Types'
 import { checkBalance, validateAddress } from '../../helpers/validation'
-import { DerivedBalances } from '@polkadot/api-derive/types'
 
 type AccountTransferArgs = {
   recipient: string
@@ -36,15 +35,16 @@ export default class AccountTransferTokens extends AccountsCommandBase {
 
     // Initial validation
     validateAddress(args.recipient, 'Invalid recipient address')
-    const accBalances: DerivedBalances = (await this.getApi().getAccountsBalancesInfo([selectedAccount.address]))[0]
+    const accBalances = (await this.getApi().getAccountsBalancesInfo([selectedAccount.address]))[0]
     checkBalance(accBalances, amountBN)
 
     await this.requestAccountDecoding(selectedAccount)
 
     this.log(chalk.white('Estimating fee...'))
+    const tx = await this.getApi().createTransferTx(args.recipient, amountBN)
     let estimatedFee: BN
     try {
-      estimatedFee = await this.getApi().estimateFee(selectedAccount, args.recipient, amountBN)
+      estimatedFee = await this.getApi().estimateFee(selectedAccount, tx)
     } catch (e) {
       this.error('Could not estimate the fee.', { exit: ExitCodes.UnexpectedException })
     }
@@ -57,7 +57,7 @@ export default class AccountTransferTokens extends AccountsCommandBase {
     await this.requireConfirmation('Do you confirm the transfer?')
 
     try {
-      const txHash: Hash = await this.getApi().transfer(selectedAccount, args.recipient, amountBN)
+      const txHash: Hash = await tx.signAndSend(selectedAccount)
       this.log(chalk.greenBright('Transaction succesfully sent!'))
       this.log(chalk.white('Hash:', txHash.toString()))
     } catch (e) {

+ 10 - 13
cli/src/commands/api/inspect.ts

@@ -2,9 +2,8 @@ import { flags } from '@oclif/command'
 import { CLIError } from '@oclif/errors'
 import { displayNameValueTable } from '../../helpers/display'
 import { ApiPromise } from '@polkadot/api'
-import { Option } from '@polkadot/types'
 import { Codec } from '@polkadot/types/types'
-import { ConstantCodec } from '@polkadot/api-metadata/consts/types'
+import { ConstantCodec } from '@polkadot/metadata/Decorated/consts/types'
 import ExitCodes from '../../ExitCodes'
 import chalk from 'chalk'
 import { NameValueObj, ApiMethodArg } from '../../Types'
@@ -99,7 +98,7 @@ export default class ApiInspect extends ApiCommandBase {
       return [type.asDoubleMap.key1.toString(), type.asDoubleMap.key2.toString()]
     }
     if (type.isMap) {
-      return type.asMap.linked.isTrue ? [`Option<${type.asMap.key.toString()}>`] : [type.asMap.key.toString()]
+      return [type.asMap.key.toString()]
     }
     return []
   }
@@ -110,14 +109,17 @@ export default class ApiInspect extends ApiCommandBase {
       const {
         meta: { type, modifier },
       } = method.creator
+      let typeName = type.toString()
       if (type.isDoubleMap) {
-        return type.asDoubleMap.value.toString()
+        typeName = type.asDoubleMap.value.toString()
       }
-      if (modifier.isOptional) {
-        return `Option<${type.toString()}>`
+      if (type.isMap) {
+        typeName = type.asMap.value.toString()
       }
+
+      return modifier.isOptional ? `Option<${typeName}>` : typeName
     }
-    // Fallback for "query" and default for "consts"
+    // Fallback for "consts"
     return this.getMethodMeta(apiType, apiModule, apiMethod).type.toString()
   }
 
@@ -155,12 +157,7 @@ export default class ApiInspect extends ApiCommandBase {
     for (const [key, paramType] of Object.entries(paramTypes)) {
       this.log(chalk.bold.white(`Parameter no. ${parseInt(key) + 1} (${paramType}):`))
       const paramValue = await this.promptForParam(paramType)
-      if (paramValue instanceof Option && paramValue.isSome) {
-        result.push(paramValue.unwrap())
-      } else if (!(paramValue instanceof Option)) {
-        result.push(paramValue)
-      }
-      // In case of empty option we MUST NOT add anything to the array (otherwise it causes some error)
+      result.push(paramValue)
     }
 
     return result

+ 1 - 5
cli/src/commands/working-groups/decreaseWorkerStake.ts

@@ -1,6 +1,5 @@
 import WorkingGroupsCommandBase from '../../base/WorkingGroupsCommandBase'
 import { apiModuleByGroup } from '../../Api'
-import { WorkerId } from '@joystream/types/working-group'
 import { Balance } from '@polkadot/types/interfaces'
 import { formatBalance } from '@polkadot/util'
 import { minMaxInt } from '../../validators/common'
@@ -41,10 +40,7 @@ export default class WorkingGroupsDecreaseWorkerStake extends WorkingGroupsComma
 
     await this.requestAccountDecoding(account)
 
-    await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'decreaseStake', [
-      new WorkerId(workerId),
-      balance,
-    ])
+    await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'decreaseStake', [workerId, balance])
 
     this.log(
       chalk.green(

+ 2 - 4
cli/src/commands/working-groups/evictWorker.ts

@@ -1,7 +1,5 @@
 import WorkingGroupsCommandBase from '../../base/WorkingGroupsCommandBase'
 import { apiModuleByGroup } from '../../Api'
-import { WorkerId } from '@joystream/types/working-group'
-import { bool } from '@polkadot/types/primitive'
 import { formatBalance } from '@polkadot/util'
 import chalk from 'chalk'
 import { createParamOptions } from '../../helpers/promptOptions'
@@ -43,9 +41,9 @@ export default class WorkingGroupsEvictWorker extends WorkingGroupsCommandBase {
     await this.requestAccountDecoding(account)
 
     await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'terminateRole', [
-      new WorkerId(workerId),
+      workerId,
       rationale,
-      new bool(shouldSlash),
+      shouldSlash,
     ])
 
     this.log(chalk.green(`Worker ${chalk.white(workerId)} has been evicted!`))

+ 3 - 8
cli/src/commands/working-groups/fillOpening.ts

@@ -1,8 +1,6 @@
 import WorkingGroupsCommandBase from '../../base/WorkingGroupsCommandBase'
 import { OpeningStatus } from '../../Types'
 import { apiModuleByGroup } from '../../Api'
-import { OpeningId } from '@joystream/types/hiring'
-import { ApplicationIdSet, RewardPolicy } from '@joystream/types/working-group'
 import chalk from 'chalk'
 import { createParamOptions } from '../../helpers/promptOptions'
 
@@ -30,16 +28,13 @@ export default class WorkingGroupsFillOpening extends WorkingGroupsCommandBase {
     const opening = await this.getOpeningForLeadAction(openingId, OpeningStatus.InReview)
 
     const applicationIds = await this.promptForApplicationsToAccept(opening)
-    const rewardPolicyOpt = await this.promptForParam(
-      `Option<${RewardPolicy.name}>`,
-      createParamOptions('RewardPolicy')
-    )
+    const rewardPolicyOpt = await this.promptForParam(`Option<RewardPolicy>`, createParamOptions('RewardPolicy'))
 
     await this.requestAccountDecoding(account)
 
     await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'fillOpening', [
-      new OpeningId(openingId),
-      new ApplicationIdSet(applicationIds),
+      openingId,
+      applicationIds,
       rewardPolicyOpt,
     ])
 

+ 1 - 5
cli/src/commands/working-groups/slashWorker.ts

@@ -1,6 +1,5 @@
 import WorkingGroupsCommandBase from '../../base/WorkingGroupsCommandBase'
 import { apiModuleByGroup } from '../../Api'
-import { WorkerId } from '@joystream/types/working-group'
 import { Balance } from '@polkadot/types/interfaces'
 import { formatBalance } from '@polkadot/util'
 import { minMaxInt } from '../../validators/common'
@@ -39,10 +38,7 @@ export default class WorkingGroupsSlashWorker extends WorkingGroupsCommandBase {
 
     await this.requestAccountDecoding(account)
 
-    await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'slashStake', [
-      new WorkerId(workerId),
-      balance,
-    ])
+    await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'slashStake', [workerId, balance])
 
     this.log(
       chalk.green(

+ 1 - 4
cli/src/commands/working-groups/startAcceptingApplications.ts

@@ -1,7 +1,6 @@
 import WorkingGroupsCommandBase from '../../base/WorkingGroupsCommandBase'
 import { OpeningStatus } from '../../Types'
 import { apiModuleByGroup } from '../../Api'
-import { OpeningId } from '@joystream/types/hiring'
 import chalk from 'chalk'
 
 export default class WorkingGroupsStartAcceptingApplications extends WorkingGroupsCommandBase {
@@ -29,9 +28,7 @@ export default class WorkingGroupsStartAcceptingApplications extends WorkingGrou
 
     await this.requestAccountDecoding(account)
 
-    await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'acceptApplications', [
-      new OpeningId(openingId),
-    ])
+    await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'acceptApplications', [openingId])
 
     this.log(
       chalk.green(`Opening ${chalk.white(openingId)} status changed to: ${chalk.white('Accepting Applications')}`)

+ 1 - 4
cli/src/commands/working-groups/startReviewPeriod.ts

@@ -1,7 +1,6 @@
 import WorkingGroupsCommandBase from '../../base/WorkingGroupsCommandBase'
 import { OpeningStatus } from '../../Types'
 import { apiModuleByGroup } from '../../Api'
-import { OpeningId } from '@joystream/types/hiring'
 import chalk from 'chalk'
 
 export default class WorkingGroupsStartReviewPeriod extends WorkingGroupsCommandBase {
@@ -29,9 +28,7 @@ export default class WorkingGroupsStartReviewPeriod extends WorkingGroupsCommand
 
     await this.requestAccountDecoding(account)
 
-    await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'beginApplicantReview', [
-      new OpeningId(openingId),
-    ])
+    await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'beginApplicantReview', [openingId])
 
     this.log(chalk.green(`Opening ${chalk.white(openingId)} status changed to: ${chalk.white('In Review')}`))
   }

+ 2 - 4
cli/src/commands/working-groups/terminateApplication.ts

@@ -1,6 +1,6 @@
 import WorkingGroupsCommandBase from '../../base/WorkingGroupsCommandBase'
 import { apiModuleByGroup } from '../../Api'
-import { ApplicationStageKeys, ApplicationId } from '@joystream/types/hiring'
+import { ApplicationStageKeys } from '@joystream/types/hiring'
 import chalk from 'chalk'
 
 export default class WorkingGroupsTerminateApplication extends WorkingGroupsCommandBase {
@@ -29,9 +29,7 @@ export default class WorkingGroupsTerminateApplication extends WorkingGroupsComm
 
     await this.requestAccountDecoding(account)
 
-    await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'terminateApplication', [
-      new ApplicationId(applicationId),
-    ])
+    await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'terminateApplication', [applicationId])
 
     this.log(chalk.green(`Application ${chalk.white(applicationId)} has been succesfully terminated!`))
   }

+ 1 - 2
cli/src/commands/working-groups/updateRewardAccount.ts

@@ -1,7 +1,6 @@
 import WorkingGroupsCommandBase from '../../base/WorkingGroupsCommandBase'
 import { apiModuleByGroup } from '../../Api'
 import { validateAddress } from '../../helpers/validation'
-import { GenericAccountId } from '@polkadot/types'
 import chalk from 'chalk'
 import ExitCodes from '../../ExitCodes'
 
@@ -40,7 +39,7 @@ export default class WorkingGroupsUpdateRewardAccount extends WorkingGroupsComma
 
     await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'updateRewardAccount', [
       worker.workerId,
-      new GenericAccountId(newRewardAccount),
+      newRewardAccount,
     ])
 
     this.log(chalk.green(`Succesfully updated the reward account to: ${chalk.white(newRewardAccount)})`))

+ 1 - 2
cli/src/commands/working-groups/updateRoleAccount.ts

@@ -1,7 +1,6 @@
 import WorkingGroupsCommandBase from '../../base/WorkingGroupsCommandBase'
 import { apiModuleByGroup } from '../../Api'
 import { validateAddress } from '../../helpers/validation'
-import { GenericAccountId } from '@polkadot/types'
 import chalk from 'chalk'
 
 export default class WorkingGroupsUpdateRoleAccount extends WorkingGroupsCommandBase {
@@ -34,7 +33,7 @@ export default class WorkingGroupsUpdateRoleAccount extends WorkingGroupsCommand
 
     await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'updateRoleAccount', [
       worker.workerId,
-      new GenericAccountId(newRoleAccount),
+      newRoleAccount,
     ])
 
     this.log(chalk.green(`Succesfully updated the role account to: ${chalk.white(newRoleAccount)})`))

+ 1 - 2
cli/src/commands/working-groups/updateWorkerReward.ts

@@ -1,6 +1,5 @@
 import WorkingGroupsCommandBase from '../../base/WorkingGroupsCommandBase'
 import { apiModuleByGroup } from '../../Api'
-import { WorkerId } from '@joystream/types/working-group'
 import { formatBalance } from '@polkadot/util'
 import chalk from 'chalk'
 import { Reward } from '../../Types'
@@ -56,7 +55,7 @@ export default class WorkingGroupsUpdateWorkerReward extends WorkingGroupsComman
     await this.requestAccountDecoding(account)
 
     await this.sendAndFollowExtrinsic(account, apiModuleByGroup[this.group], 'updateRewardAmount', [
-      new WorkerId(workerId),
+      workerId,
       newRewardValue,
     ])
 

+ 2 - 2
cli/src/helpers/validation.ts

@@ -1,7 +1,7 @@
 import BN from 'bn.js'
 import ExitCodes from '../ExitCodes'
 import { decodeAddress } from '@polkadot/util-crypto'
-import { DerivedBalances } from '@polkadot/api-derive/types'
+import { DeriveBalancesAll } from '@polkadot/api-derive/types'
 import { CLIError } from '@oclif/errors'
 
 export function validateAddress(address: string, errorMessage = 'Invalid address'): void {
@@ -12,7 +12,7 @@ export function validateAddress(address: string, errorMessage = 'Invalid address
   }
 }
 
-export function checkBalance(accBalances: DerivedBalances, requiredBalance: BN): void {
+export function checkBalance(accBalances: DeriveBalancesAll, requiredBalance: BN): void {
   if (requiredBalance.gt(accBalances.availableBalance)) {
     throw new CLIError('Not enough balance available', { exit: ExitCodes.InvalidInput })
   }

+ 5 - 9
cli/src/promptOptions/addWorkerOpening.ts

@@ -1,19 +1,15 @@
 import { ApiParamsOptions, ApiParamOptions, HRTStruct } from '../Types'
-import {
-  OpeningType,
-  SlashingTerms,
-  UnslashableTerms,
-  OpeningType_Worker as OpeningTypeWorker,
-  WorkingGroupOpeningPolicyCommitment,
-} from '@joystream/types/working-group'
+import { OpeningType, WorkingGroupOpeningPolicyCommitment } from '@joystream/types/working-group'
+import { SlashingTerms } from '@joystream/types/common'
 import { Bytes } from '@polkadot/types'
 import { schemaValidator } from '@joystream/types/hiring'
+import { createMock } from '@joystream/types'
 
 class OpeningPolicyCommitmentOptions implements ApiParamsOptions {
   [paramName: string]: ApiParamOptions
   public role_slashing_terms: ApiParamOptions<SlashingTerms> = {
     value: {
-      default: SlashingTerms.create('Unslashable', new UnslashableTerms()),
+      default: createMock('SlashingTerms', { Unslashable: null }),
       locked: true,
     },
   }
@@ -37,7 +33,7 @@ class AddWrokerOpeningOptions implements ApiParamsOptions {
   // Lock value for opening_type
   public opening_type: ApiParamOptions<OpeningType> = {
     value: {
-      default: OpeningType.create('Worker', new OpeningTypeWorker()),
+      default: createMock('OpeningType', { Worker: null }),
       locked: true,
     },
   }

+ 5 - 1
cli/tsconfig.json

@@ -9,7 +9,11 @@
     "target": "es2017",
     "esModuleInterop": true,
     "types" : [ "node" ],
-    "noUnusedLocals": true
+    "noUnusedLocals": true,
+    "baseUrl": ".",
+    "paths": {
+      "@polkadot/types/augment": ["../types/augment-codec/augment-types.ts"],
+    }
   },
   "include": [
     "src/**/*"

+ 13 - 0
types/src/index.ts

@@ -15,6 +15,8 @@ import workingGroup from './working-group'
 import discovery from './discovery'
 import media from './media'
 import proposals from './proposals'
+import { InterfaceTypes } from '@polkadot/types/types/registry'
+import { createType, TypeRegistry } from '@polkadot/types'
 
 export {
   common,
@@ -58,3 +60,14 @@ export const types: RegistryTypes = {
   Address: 'AccountId',
   LookupSource: 'AccountId',
 }
+
+// Allows creating types without api instance (it's not a recommended way though, so should be used just for mocks)
+export const mockRegistry = new TypeRegistry()
+mockRegistry.register(types)
+
+export function createMock<TypeName extends keyof InterfaceTypes>(
+  type: TypeName,
+  value: any
+): InterfaceTypes[TypeName] {
+  return createType(mockRegistry, type, value)
+}

+ 2 - 2
yarn.lock

@@ -11565,7 +11565,7 @@ find-babel-config@^1.2.0:
     json5 "^0.5.1"
     path-exists "^3.0.0"
 
-find-cache-dir@^2.1.0:
+find-cache-dir@^2.0.0, find-cache-dir@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7"
   integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==
@@ -19164,7 +19164,7 @@ pirates@^3.0.2:
   dependencies:
     node-modules-regexp "^1.0.0"
 
-pirates@^4.0.1:
+pirates@^4.0.0, pirates@^4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87"
   integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==