Browse Source

ApiCommandBase - improve extrinsics typesafety

Leszek Wiesner 4 years ago
parent
commit
9b86e31b14

+ 19 - 16
cli/src/base/ApiCommandBase.ts

@@ -2,8 +2,8 @@ import ExitCodes from '../ExitCodes'
 import { CLIError } from '@oclif/errors'
 import StateAwareCommandBase from './StateAwareCommandBase'
 import Api from '../Api'
-import { getTypeDef, Option, Tuple, TypeRegistry } from '@polkadot/types'
-import { Registry, Codec, CodecArg, TypeDef, TypeDefInfo } from '@polkadot/types/types'
+import { getTypeDef, Option, Tuple } from '@polkadot/types'
+import { Registry, Codec, TypeDef, TypeDefInfo } from '@polkadot/types/types'
 
 import { Vec, Struct, Enum } from '@polkadot/types/codec'
 import { WsProvider } from '@polkadot/api'
@@ -12,7 +12,7 @@ import chalk from 'chalk'
 import { InterfaceTypes } from '@polkadot/types/types/registry'
 import { ApiMethodArg, ApiMethodNamedArgs, ApiParamsOptions, ApiParamOptions } from '../Types'
 import { createParamOptions } from '../helpers/promptOptions'
-import { SubmittableExtrinsic } from '@polkadot/api/types'
+import { AugmentedSubmittables, SubmittableExtrinsic } from '@polkadot/api/types'
 import { DistinctQuestion } from 'inquirer'
 import { BOOL_PROMPT_OPTIONS } from '../helpers/prompting'
 import { DispatchError } from '@polkadot/types/interfaces/system'
@@ -373,11 +373,7 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
                 let errorMsg = dispatchError.toString()
                 if (dispatchError.isModule) {
                   try {
-                    // Need to assert that registry is of TypeRegistry type, since Registry intefrace
-                    // seems outdated and doesn't include DispatchErrorModule as possible argument for "findMetaError"
-                    const { name, documentation } = (this.getOriginalApi().registry as TypeRegistry).findMetaError(
-                      dispatchError.asModule
-                    )
+                    const { name, documentation } = this.getOriginalApi().registry.findMetaError(dispatchError.asModule)
                     errorMsg = `${name} (${documentation})`
                   } catch (e) {
                     // This probably means we don't have this error in the metadata
@@ -421,11 +417,15 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
     }
   }
 
-  async sendAndFollowNamedTx(
+  async sendAndFollowNamedTx<
+    Module extends keyof AugmentedSubmittables<'promise'>,
+    Method extends keyof AugmentedSubmittables<'promise'>[Module] & string,
+    Submittable extends AugmentedSubmittables<'promise'>[Module][Method]
+  >(
     account: KeyringPair,
-    module: string,
-    method: string,
-    params: CodecArg[],
+    module: Module,
+    method: Method,
+    params: Submittable extends (...args: any[]) => any ? Parameters<Submittable> : [],
     warnOnly = false
   ): Promise<boolean> {
     this.log(chalk.white(`\nSending ${module}.${method} extrinsic...`))
@@ -433,15 +433,18 @@ export default abstract class ApiCommandBase extends StateAwareCommandBase {
     return await this.sendAndFollowTx(account, tx, warnOnly)
   }
 
-  async buildAndSendExtrinsic(
+  async buildAndSendExtrinsic<
+    Module extends keyof AugmentedSubmittables<'promise'>,
+    Method extends keyof AugmentedSubmittables<'promise'>[Module] & string
+  >(
     account: KeyringPair,
-    module: string,
-    method: string,
+    module: Module,
+    method: Method,
     paramsOptions?: ApiParamsOptions,
     warnOnly = false // If specified - only warning will be displayed (instead of error beeing thrown)
   ): Promise<ApiMethodArg[]> {
     const params = await this.promptForExtrinsicParams(module, method, paramsOptions)
-    await this.sendAndFollowNamedTx(account, module, method, params, warnOnly)
+    await this.sendAndFollowNamedTx(account, module, method, params as any, warnOnly)
 
     return params
   }

+ 4 - 4
cli/src/commands/content-directory/updateClassPermissions.ts

@@ -43,10 +43,10 @@ export default class UpdateClassPermissionsCommand extends ContentDirectoryComma
     await this.requestAccountDecoding(account)
     await this.sendAndFollowNamedTx(account, 'contentDirectory', 'updateClassPermissions', [
       classId,
-      newPermissions.any_member,
-      newPermissions.entity_creation_blocked,
-      newPermissions.all_entity_property_values_locked,
-      newPermissions.maintainers,
+      this.createType('Option<bool>', newPermissions.any_member || null),
+      this.createType('Option<bool>', newPermissions.entity_creation_blocked || null),
+      this.createType('Option<bool>', newPermissions.all_entity_property_values_locked || null),
+      this.createType('Option<bool>', newPermissions.maintainers || null),
     ])
 
     console.log(chalk.green(`${chalk.white(className)} class permissions updated to:`))

+ 6 - 1
cli/src/commands/working-groups/fillOpening.ts

@@ -1,6 +1,8 @@
 import WorkingGroupsCommandBase from '../../base/WorkingGroupsCommandBase'
 import { apiModuleByGroup } from '../../Api'
 import chalk from 'chalk'
+import { JoyBTreeSet } from '@joystream/types/common'
+import { ApplicationId } from '@joystream/types/working-group'
 
 export default class WorkingGroupsFillOpening extends WorkingGroupsCommandBase {
   static description = "Allows filling working group opening that's currently in review. Requires lead access."
@@ -30,7 +32,10 @@ export default class WorkingGroupsFillOpening extends WorkingGroupsCommandBase {
 
     await this.requestAccountDecoding(account)
 
-    await this.sendAndFollowNamedTx(account, apiModuleByGroup[this.group], 'fillOpening', [openingId, applicationIds])
+    await this.sendAndFollowNamedTx(account, apiModuleByGroup[this.group], 'fillOpening', [
+      openingId,
+      new (JoyBTreeSet(ApplicationId))(this.getTypesRegistry(), applicationIds),
+    ])
 
     this.log(chalk.green(`Opening ${chalk.white(openingId.toString())} succesfully filled!`))
     this.log(