diff --git a/packages/api-contract/src/Abi.spec.ts b/packages/api-contract/src/Abi.spec.ts index f7d6268230..f41e278bf8 100644 --- a/packages/api-contract/src/Abi.spec.ts +++ b/packages/api-contract/src/Abi.spec.ts @@ -11,7 +11,7 @@ const abis: Record = { ...testContracts }; function compare (name: string, registry: TypeRegistry, messageIds: string[]): void { try { - const inkAbi = new Abi(registry, abis[name]); + const inkAbi = new Abi(abis[name]); expect(inkAbi.messages.map(({ identifier }) => identifier)).toEqual(messageIds); } catch (error) { diff --git a/packages/api-contract/src/Abi.ts b/packages/api-contract/src/Abi.ts index b892c2d0ee..cf2b919adb 100644 --- a/packages/api-contract/src/Abi.ts +++ b/packages/api-contract/src/Abi.ts @@ -37,8 +37,8 @@ export default class Abi extends ContractRegistry { public readonly messages: AbiMessage[]; - constructor (registry: Registry, json: AnyJson) { - super(registry, json); + constructor (json: AnyJson) { + super(json); this.constructors = this.project.spec.constructors.map((spec: InkConstructorSpec, index) => this._createBase(spec, { @@ -62,13 +62,19 @@ export default class Abi extends ContractRegistry { private _createBase (spec: InkMessageSpec | InkConstructorSpec, add: Partial = {}): AbiMessage { const identifier = spec.name.toString(); - const args = spec.args.map(({ name, type }): AbiMessageParam => { - assert(isObject(type), `Invalid type at index ${type.toString()}`); + const args = spec.args.map((arg, index): AbiMessageParam => { + try { + assert(isObject(arg.type), 'Invalid type definition found'); - return { - name: stringCamelCase(name.toString()), - type: this.typeDefAt(type.type) - }; + return { + name: stringCamelCase(arg.name.toString()), + type: this.typeDefAt(arg.type.type) + }; + } catch (error) { + console.error(`Error expanding argument ${index} in ${JSON.stringify(spec)}`); + + throw error; + } }); const Clazz = createArgClass(this.registry, args, isUndefined(spec.selector) ? {} : { __selector: 'u32' }); diff --git a/packages/api-contract/src/ContractRegistry.spec.ts b/packages/api-contract/src/ContractRegistry.spec.ts index e700c53bff..07eb246b7d 100644 --- a/packages/api-contract/src/ContractRegistry.spec.ts +++ b/packages/api-contract/src/ContractRegistry.spec.ts @@ -5,16 +5,14 @@ import fs from 'fs'; import path from 'path'; -import { TypeRegistry } from '@polkadot/types'; - import ContractRegistry from './ContractRegistry'; import * as testContracts from '../test/contracts'; const abis: Record = { ...testContracts }; -function compare (name: string, registry: TypeRegistry): void { - const inkRegistry = new ContractRegistry(registry, abis[name]); +function compare (name: string): void { + const inkRegistry = new ContractRegistry(abis[name]); try { const cmpPath = path.join(__dirname, `../test/compare/${name}.test.json`); @@ -33,34 +31,32 @@ function compare (name: string, registry: TypeRegistry): void { describe('ContractRegistry', (): void => { describe('construction', (): void => { - const registry = new TypeRegistry(); - it('initializes from a contract ABI (flipper)', (): void => { - compare('flipper', registry); + compare('flipper'); }); it('initializes from a contract ABI (incrementer)', (): void => { - compare('incrementer', registry); + compare('incrementer'); }); it('initializes from a contract ABI (erc20)', (): void => { - compare('erc20', registry); + compare('erc20'); }); it('initializes from a contract ABI (dns)', (): void => { - compare('dns', registry); + compare('dns'); }); it('initializes from a contract ABI (erc721)', (): void => { - compare('erc721', registry); + compare('erc721'); }); it('initializes from a contract ABI (multisig_plain)', (): void => { - compare('multisigPlain', registry); + compare('multisigPlain'); }); it('stores base project as JSON', (): void => { - const inkRegistry = new ContractRegistry(registry, abis.dns); + const inkRegistry = new ContractRegistry(abis.dns); expect(inkRegistry.json).toEqual(abis.dns); }); diff --git a/packages/api-contract/src/ContractRegistry.ts b/packages/api-contract/src/ContractRegistry.ts index fd7d7e23fe..6caf7b9937 100644 --- a/packages/api-contract/src/ContractRegistry.ts +++ b/packages/api-contract/src/ContractRegistry.ts @@ -5,7 +5,7 @@ import { InkProject, MtField, MtLookupTypeId, MtType, MtTypeDefArray, MtTypeDefV import { AnyJson, Registry, TypeDef, TypeDefInfo } from '@polkadot/types/types'; import { assert, isObject, isUndefined } from '@polkadot/util'; -import { withTypeString } from '@polkadot/types'; +import { TypeRegistry, withTypeString } from '@polkadot/types'; // convert the offset into project-specific, index-1 export function getRegistryOffset (id: MtLookupTypeId): number { @@ -15,18 +15,18 @@ export function getRegistryOffset (id: MtLookupTypeId): number { export default class ContractRegistry { public typeDefs: TypeDef[] = []; - public registry: Registry; + public readonly registry: Registry; public project: InkProject; public json: AnyJson; - constructor (registry: Registry, json: AnyJson) { + constructor (json: AnyJson) { assert(isObject(json) && !Array.isArray(json) && json.metadataVersion && isObject(json.spec) && !Array.isArray(json.spec) && Array.isArray(json.spec.constructors) && Array.isArray(json.spec.messages), 'Invalid JSON ABI structure supplied, expected a recent metadata version'); - this.registry = registry; + this.registry = new TypeRegistry(); this.json = json; - this.project = registry.createType('InkProject', json); + this.project = this.registry.createType('InkProject', json); // Generate TypeDefs for each provided registry type this.project.types.forEach((_, index) => this.setTypeDef(this.registry.createType('MtLookupTypeId', index + 1))); @@ -57,8 +57,9 @@ export default class ContractRegistry { this.typeDefs[getRegistryOffset(id)] = typeDef; - // we have a displayName for non-primitives and non-results - if (typeDef.displayName) { + // We have a displayName for non-primitives and non-results + // FIXME here we protect against "Option: 'Option<...something...>' definitions (same with result) + if (typeDef.displayName && typeDef.info !== TypeDefInfo.Plain && !typeDef.type.startsWith(typeDef.displayName)) { this.registry.register({ [typeDef.displayName]: typeDef.type }); } } diff --git a/packages/api-contract/src/base/Base.ts b/packages/api-contract/src/base/Base.ts index 13ea7403f7..8856e20498 100644 --- a/packages/api-contract/src/base/Base.ts +++ b/packages/api-contract/src/base/Base.ts @@ -5,7 +5,6 @@ import { ApiTypes, DecorateMethod } from '@polkadot/api/types'; import { AnyJson, Registry } from '@polkadot/types/types'; import { ApiObject } from '../types'; -import { TypeRegistry } from '@polkadot/types'; import { assert } from '@polkadot/util'; import Abi from '../Abi'; @@ -20,11 +19,11 @@ export default abstract class Base { protected readonly _decorateMethod: DecorateMethod; constructor (api: ApiObject, abi: AnyJson | Abi, decorateMethod: DecorateMethod) { - this.registry = new TypeRegistry(); this.abi = abi instanceof Abi ? abi - : new Abi(this.registry, abi); + : new Abi(abi); this.api = api; + this.registry = this.abi.registry; this._decorateMethod = decorateMethod; assert(this.api.rx.tx.contracts && this.api.rx.tx.contracts.putCode, 'You need to connect to a node with the contracts module, the metadata does not enable api.tx.contracts on this instance');